Full Code of terrapower/armi for AI

main 65813317319d cached
703 files
6.8 MB
1.8M tokens
7732 symbols
1 requests
Download .txt
Showing preview only (7,264K chars total). Download the full file or copy to clipboard to get everything.
Repository: terrapower/armi
Branch: main
Commit: 65813317319d
Files: 703
Total size: 6.8 MB

Directory structure:
gitextract_528z7ijz/

├── .github/
│   ├── .codecov.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── coverage.yaml
│       ├── docs.yaml
│       ├── find_test_crumbs.py
│       ├── licensechecker.yaml
│       ├── linting.yaml
│       ├── mac_tests.yaml
│       ├── stale.yaml
│       ├── unittests.yaml
│       ├── validatemanifest.py
│       ├── validatemanifest.yaml
│       ├── wheels.yaml
│       └── wintests.yaml
├── .gitignore
├── .gitmodules
├── .licenserc.json
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE.md
├── README.rst
├── armi/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _bootstrap.py
│   ├── apps.py
│   ├── bookkeeping/
│   │   ├── __init__.py
│   │   ├── db/
│   │   │   ├── __init__.py
│   │   │   ├── compareDB3.py
│   │   │   ├── database.py
│   │   │   ├── databaseInterface.py
│   │   │   ├── factory.py
│   │   │   ├── jaggedArray.py
│   │   │   ├── layout.py
│   │   │   ├── passiveDBLoadPlugin.py
│   │   │   ├── permissions.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_comparedb3.py
│   │   │   │   ├── test_database.py
│   │   │   │   ├── test_databaseInterface.py
│   │   │   │   ├── test_jaggedArray.py
│   │   │   │   ├── test_layout.py
│   │   │   │   └── test_passiveDBLoadPlugin.py
│   │   │   └── typedefs.py
│   │   ├── historyTracker.py
│   │   ├── mainInterface.py
│   │   ├── memoryProfiler.py
│   │   ├── report/
│   │   │   ├── __init__.py
│   │   │   ├── data.py
│   │   │   ├── reportInterface.py
│   │   │   ├── reportingUtils.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       └── test_report.py
│   │   ├── snapshotInterface.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── _constants.py
│   │   │   ├── test_historyTracker.py
│   │   │   ├── test_memoryProfiler.py
│   │   │   └── test_snapshot.py
│   │   └── visualization/
│   │       ├── __init__.py
│   │       ├── dumper.py
│   │       ├── entryPoint.py
│   │       ├── tests/
│   │       │   ├── __init__.py
│   │       │   ├── test_vis.py
│   │       │   └── test_xdmf.py
│   │       ├── utils.py
│   │       ├── vtk.py
│   │       └── xdmf.py
│   ├── cases/
│   │   ├── __init__.py
│   │   ├── case.py
│   │   ├── inputModifiers/
│   │   │   ├── __init__.py
│   │   │   ├── inputModifiers.py
│   │   │   ├── neutronicsModifiers.py
│   │   │   ├── pinTypeInputModifiers.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── test_inputModifiers.py
│   │   │       └── test_pinTypeInputModifiers.py
│   │   ├── suite.py
│   │   ├── suiteBuilder.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_cases.py
│   │       └── test_suiteBuilder.py
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── checkInputs.py
│   │   ├── cleanTemps.py
│   │   ├── clone.py
│   │   ├── compareCases.py
│   │   ├── database.py
│   │   ├── entryPoint.py
│   │   ├── gridGui.py
│   │   ├── migrateInputs.py
│   │   ├── modify.py
│   │   ├── reportsEntryPoint.py
│   │   ├── run.py
│   │   ├── runSuite.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_runEntryPoint.py
│   │       └── test_runSuite.py
│   ├── conftest.py
│   ├── context.py
│   ├── interfaces.py
│   ├── matProps/
│   │   ├── __init__.py
│   │   ├── constituent.py
│   │   ├── function.py
│   │   ├── interpolationFunctions.py
│   │   ├── material.py
│   │   ├── materialType.py
│   │   ├── piecewiseFunction.py
│   │   ├── point.py
│   │   ├── prop.py
│   │   ├── reference.py
│   │   ├── symbolicFunction.py
│   │   ├── tableFunction.py
│   │   ├── tableFunction1D.py
│   │   ├── tableFunction2D.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── invalidTestFiles/
│   │       │   ├── badFileFormat.YAML
│   │       │   ├── badProperty.yaml
│   │       │   └── duplicateComposition.yaml
│   │       ├── testDir1/
│   │       │   ├── a.yaml
│   │       │   └── b.yaml
│   │       ├── testDir2/
│   │       │   ├── c.yml
│   │       │   └── d.yaml
│   │       ├── testDir3/
│   │       │   ├── a.yaml
│   │       │   └── e.yaml
│   │       ├── testDir4/
│   │       │   └── sampleProperty.yaml
│   │       ├── testMaterialsData/
│   │       │   ├── materialA.yaml
│   │       │   ├── materialB.yaml
│   │       │   └── materialsSubDir/
│   │       │       ├── materialC.yaml
│   │       │       └── materialD.yaml
│   │       ├── test_1DSymbolicFunction.py
│   │       ├── test_composition.py
│   │       ├── test_constituent.py
│   │       ├── test_functions.py
│   │       ├── test_hashing.py
│   │       ├── test_interpolationFunctions.py
│   │       ├── test_material.py
│   │       ├── test_materialType.py
│   │       ├── test_parsing.py
│   │       ├── test_performance.py
│   │       ├── test_piecewiseFunction.py
│   │       ├── test_point.py
│   │       ├── test_property.py
│   │       ├── test_references.py
│   │       ├── test_symbolicFunction.py
│   │       └── test_tableFunctions.py
│   ├── materials/
│   │   ├── __init__.py
│   │   ├── air.py
│   │   ├── alloy200.py
│   │   ├── b4c.py
│   │   ├── be9.py
│   │   ├── caH2.py
│   │   ├── californium.py
│   │   ├── concrete.py
│   │   ├── copper.py
│   │   ├── cs.py
│   │   ├── custom.py
│   │   ├── graphite.py
│   │   ├── hafnium.py
│   │   ├── hastelloyN.py
│   │   ├── ht9.py
│   │   ├── inconel.py
│   │   ├── inconel600.py
│   │   ├── inconel625.py
│   │   ├── inconel800.py
│   │   ├── inconelPE16.py
│   │   ├── inconelX750.py
│   │   ├── lead.py
│   │   ├── leadBismuth.py
│   │   ├── lithium.py
│   │   ├── magnesium.py
│   │   ├── material.py
│   │   ├── mgO.py
│   │   ├── mixture.py
│   │   ├── molybdenum.py
│   │   ├── mox.py
│   │   ├── nZ.py
│   │   ├── potassium.py
│   │   ├── scandiumOxide.py
│   │   ├── siC.py
│   │   ├── sodium.py
│   │   ├── sodiumChloride.py
│   │   ├── sulfur.py
│   │   ├── tZM.py
│   │   ├── tantalum.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test__init__.py
│   │   │   ├── test_air.py
│   │   │   ├── test_b4c.py
│   │   │   ├── test_be9.py
│   │   │   ├── test_fluids.py
│   │   │   ├── test_graphite.py
│   │   │   ├── test_lithium.py
│   │   │   ├── test_materials.py
│   │   │   ├── test_sic.py
│   │   │   ├── test_sulfur.py
│   │   │   ├── test_thoriumOxide.py
│   │   │   ├── test_uZr.py
│   │   │   └── test_water.py
│   │   ├── thU.py
│   │   ├── thorium.py
│   │   ├── thoriumOxide.py
│   │   ├── uZr.py
│   │   ├── uranium.py
│   │   ├── uraniumOxide.py
│   │   ├── void.py
│   │   ├── water.py
│   │   ├── yttriumOxide.py
│   │   ├── zincOxide.py
│   │   └── zr.py
│   ├── meta.py
│   ├── migration/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── m0_1_3.py
│   │   ├── m0_1_6.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_m0_1_6.py
│   │       └── test_migration_base.py
│   ├── mpiActions.py
│   ├── nucDirectory/
│   │   ├── __init__.py
│   │   ├── elements.py
│   │   ├── nucDir.py
│   │   ├── nuclideBases.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test_elements.py
│   │   │   ├── test_nucDirectory.py
│   │   │   ├── test_nuclideBases.py
│   │   │   ├── test_thermalScattering.py
│   │   │   └── test_transmutations.py
│   │   ├── thermalScattering.py
│   │   └── transmutations.py
│   ├── nuclearDataIO/
│   │   ├── __init__.py
│   │   ├── cccc/
│   │   │   ├── __init__.py
│   │   │   ├── cccc.py
│   │   │   ├── compxs.py
│   │   │   ├── dif3d.py
│   │   │   ├── fixsrc.py
│   │   │   ├── gamiso.py
│   │   │   ├── geodst.py
│   │   │   ├── isotxs.py
│   │   │   ├── labels.py
│   │   │   ├── nhflux.py
│   │   │   ├── pmatrx.py
│   │   │   ├── pwdint.py
│   │   │   ├── rtflux.py
│   │   │   ├── rzflux.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── fixtures/
│   │   │       │   ├── labels.binary
│   │   │       │   ├── simple_cartesian.pwdint
│   │   │       │   ├── simple_cartesian.rtflux
│   │   │       │   ├── simple_cartesian.rzflux
│   │   │       │   ├── simple_hexz.dif3d
│   │   │       │   ├── simple_hexz.geodst
│   │   │       │   ├── simple_hexz.nhflux
│   │   │       │   └── simple_hexz.nhflux.variant
│   │   │       ├── test_cccc.py
│   │   │       ├── test_compxs.py
│   │   │       ├── test_dif3d.py
│   │   │       ├── test_fixsrc.py
│   │   │       ├── test_gamiso.py
│   │   │       ├── test_geodst.py
│   │   │       ├── test_isotxs.py
│   │   │       ├── test_labels.py
│   │   │       ├── test_nhflux.py
│   │   │       ├── test_pmatrx.py
│   │   │       ├── test_pwdint.py
│   │   │       ├── test_rtflux.py
│   │   │       └── test_rzflux.py
│   │   ├── nuclearFileMetadata.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── fixtures/
│   │   │   │   ├── AA.gamiso
│   │   │   │   ├── AA.pmatrx
│   │   │   │   ├── AB.gamiso
│   │   │   │   ├── AB.pmatrx
│   │   │   │   ├── ISOAA
│   │   │   │   ├── ISOAB
│   │   │   │   ├── combined-AA-AB.gamiso
│   │   │   │   ├── combined-AA-AB.isotxs
│   │   │   │   ├── combined-AA-AB.pmatrx
│   │   │   │   ├── combined-and-lumped-AA-AB.gamiso
│   │   │   │   ├── combined-and-lumped-AA-AB.isotxs
│   │   │   │   ├── combined-and-lumped-AA-AB.pmatrx
│   │   │   │   ├── mc2v3-AA.gamiso
│   │   │   │   ├── mc2v3-AA.isotxs
│   │   │   │   ├── mc2v3-AA.pmatrx
│   │   │   │   ├── mc2v3-AB.gamiso
│   │   │   │   ├── mc2v3-AB.isotxs
│   │   │   │   └── mc2v3-AB.pmatrx
│   │   │   ├── library-file-generation/
│   │   │   │   ├── combine-AA-AB.inp
│   │   │   │   ├── combine-and-lump-AA-AB.inp
│   │   │   │   ├── mc2v3-AA.inp
│   │   │   │   └── mc2v3-AB.inp
│   │   │   ├── simple_hexz.inp
│   │   │   ├── test_xsCollections.py
│   │   │   ├── test_xsLibraries.py
│   │   │   └── test_xsNuclides.py
│   │   ├── xsCollections.py
│   │   ├── xsLibraries.py
│   │   └── xsNuclides.py
│   ├── operators/
│   │   ├── __init__.py
│   │   ├── operator.py
│   │   ├── operatorMPI.py
│   │   ├── runTypes.py
│   │   ├── snapshots.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_operatorSnapshots.py
│   │       └── test_operators.py
│   ├── physics/
│   │   ├── __init__.py
│   │   ├── constants.py
│   │   ├── executers.py
│   │   ├── fuelCycle/
│   │   │   ├── __init__.py
│   │   │   ├── assemblyRotationAlgorithms.py
│   │   │   ├── fuelHandlerFactory.py
│   │   │   ├── fuelHandlerInterface.py
│   │   │   ├── fuelHandlers.py
│   │   │   ├── hexAssemblyFuelMgmtUtils.py
│   │   │   ├── settings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── _customFuelHandlerModule.py
│   │   │   │   ├── test_assemblyRotationAlgorithms.py
│   │   │   │   ├── test_fuelHandlerFactory.py
│   │   │   │   ├── test_fuelHandlers.py
│   │   │   │   ├── test_hexAssemblyFuelMgmtUtils.py
│   │   │   │   └── test_utils.py
│   │   │   └── utils.py
│   │   ├── fuelPerformance/
│   │   │   ├── __init__.py
│   │   │   ├── executers.py
│   │   │   ├── parameters.py
│   │   │   ├── plugin.py
│   │   │   ├── settings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_executers.py
│   │   │   │   ├── test_fuelPerformancePlugin.py
│   │   │   │   ├── test_fuelPerformanceSymmetry.py
│   │   │   │   └── test_fuelPerformanceUtils.py
│   │   │   └── utils.py
│   │   ├── neutronics/
│   │   │   ├── __init__.py
│   │   │   ├── const.py
│   │   │   ├── crossSectionGroupManager.py
│   │   │   ├── crossSectionSettings.py
│   │   │   ├── diffIsotxs.py
│   │   │   ├── energyGroups.py
│   │   │   ├── fissionProductModel/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── fissionProductModel.py
│   │   │   │   ├── fissionProductModelSettings.py
│   │   │   │   ├── lumpedFissionProduct.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_fissionProductModel.py
│   │   │   │       └── test_lumpedFissionProduct.py
│   │   │   ├── globalFlux/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── globalFluxInterface.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       └── test_globalFluxInterface.py
│   │   │   ├── isotopicDepletion/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── crossSectionTable.py
│   │   │   │   └── isotopicDepletionInterface.py
│   │   │   ├── latticePhysics/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── latticePhysicsInterface.py
│   │   │   │   ├── latticePhysicsWriter.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_latticeInterface.py
│   │   │   │       └── test_latticeWriter.py
│   │   │   ├── macroXSGenerationInterface.py
│   │   │   ├── parameters.py
│   │   │   ├── plugin.py
│   │   │   ├── settings.py
│   │   │   └── tests/
│   │   │       ├── ISOXA
│   │   │       ├── __init__.py
│   │   │       ├── rzmflxYA
│   │   │       ├── test_crossSectionManager.py
│   │   │       ├── test_crossSectionSettings.py
│   │   │       ├── test_crossSectionTable.py
│   │   │       ├── test_energyGroups.py
│   │   │       ├── test_macroXSGenerationInterface.py
│   │   │       ├── test_neutronicsPlugin.py
│   │   │       └── test_neutronicsSymmetry.py
│   │   ├── safety/
│   │   │   └── __init__.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_executers.py
│   │   └── thermalHydraulics/
│   │       ├── __init__.py
│   │       ├── const.py
│   │       ├── parameters.py
│   │       ├── plugin.py
│   │       └── tests/
│   │           ├── __init__.py
│   │           └── test_thermalHydraulicsSymmetry.py
│   ├── pluginManager.py
│   ├── plugins.py
│   ├── reactor/
│   │   ├── __init__.py
│   │   ├── assemblies.py
│   │   ├── assemblyParameters.py
│   │   ├── blockParameters.py
│   │   ├── blocks/
│   │   │   ├── __init__.py
│   │   │   ├── block.py
│   │   │   ├── cartesianBlock.py
│   │   │   ├── hexBlock.py
│   │   │   └── thRZBlock.py
│   │   ├── blueprints/
│   │   │   ├── __init__.py
│   │   │   ├── assemblyBlueprint.py
│   │   │   ├── blockBlueprint.py
│   │   │   ├── componentBlueprint.py
│   │   │   ├── gridBlueprint.py
│   │   │   ├── isotopicOptions.py
│   │   │   ├── reactorBlueprint.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── test_assemblyBlueprints.py
│   │   │       ├── test_blockBlueprints.py
│   │   │       ├── test_blueprints.py
│   │   │       ├── test_componentBlueprint.py
│   │   │       ├── test_customIsotopics.py
│   │   │       ├── test_gridBlueprints.py
│   │   │       ├── test_materialModifications.py
│   │   │       └── test_reactorBlueprints.py
│   │   ├── components/
│   │   │   ├── __init__.py
│   │   │   ├── basicShapes.py
│   │   │   ├── complexShapes.py
│   │   │   ├── component.py
│   │   │   ├── componentParameters.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_basicShapes.py
│   │   │   │   └── test_complexShapes.py
│   │   │   └── volumetricShapes.py
│   │   ├── composites.py
│   │   ├── converters/
│   │   │   ├── __init__.py
│   │   │   ├── axialExpansionChanger/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── assemblyAxialLinkage.py
│   │   │   │   ├── axialExpansionChanger.py
│   │   │   │   ├── expansionData.py
│   │   │   │   └── redistributeMass.py
│   │   │   ├── blockConverters.py
│   │   │   ├── geometryConverters.py
│   │   │   ├── meshConverters.py
│   │   │   ├── parameterSweeps/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── generalParameterSweepConverters.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       └── test_paramSweepConverters.py
│   │   │   ├── pinTypeBlockConverters.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_assemblyAxialLinkage.py
│   │   │   │   ├── test_axialExpansionChanger.py
│   │   │   │   ├── test_axialExpansionChanger_MultiPin.py
│   │   │   │   ├── test_blockConverter.py
│   │   │   │   ├── test_geometryConverters.py
│   │   │   │   ├── test_meshConverters.py
│   │   │   │   ├── test_pinTypeBlockConverters.py
│   │   │   │   └── test_uniformMesh.py
│   │   │   └── uniformMesh.py
│   │   ├── cores.py
│   │   ├── excoreStructure.py
│   │   ├── flags.py
│   │   ├── geometry.py
│   │   ├── grids/
│   │   │   ├── __init__.py
│   │   │   ├── axial.py
│   │   │   ├── cartesian.py
│   │   │   ├── constants.py
│   │   │   ├── grid.py
│   │   │   ├── hexagonal.py
│   │   │   ├── locations.py
│   │   │   ├── structuredGrid.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   └── test_grids.py
│   │   │   └── thetarz.py
│   │   ├── parameters/
│   │   │   ├── __init__.py
│   │   │   ├── exceptions.py
│   │   │   ├── parameterCollections.py
│   │   │   ├── parameterDefinitions.py
│   │   │   └── resolveCollections.py
│   │   ├── reactorParameters.py
│   │   ├── reactors.py
│   │   ├── spentFuelPool.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test_assemblies.py
│   │   │   ├── test_blocks.py
│   │   │   ├── test_components.py
│   │   │   ├── test_composites.py
│   │   │   ├── test_cores.py
│   │   │   ├── test_excoreStructures.py
│   │   │   ├── test_flags.py
│   │   │   ├── test_geometry.py
│   │   │   ├── test_hexBlockRotate.py
│   │   │   ├── test_parameters.py
│   │   │   ├── test_reactors.py
│   │   │   ├── test_rz_reactors.py
│   │   │   ├── test_zones.py
│   │   │   └── zonesFile.yaml
│   │   └── zones.py
│   ├── resources/
│   │   ├── burn-chain.yaml
│   │   └── mcc-nuclides.yaml
│   ├── runLog.py
│   ├── settings/
│   │   ├── __init__.py
│   │   ├── caseSettings.py
│   │   ├── fwSettings/
│   │   │   ├── __init__.py
│   │   │   ├── databaseSettings.py
│   │   │   ├── globalSettings.py
│   │   │   ├── reportSettings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_fwSettings.py
│   │   │   │   └── test_tightCouplingSettings.py
│   │   │   └── tightCouplingSettings.py
│   │   ├── setting.py
│   │   ├── settingsIO.py
│   │   ├── settingsValidation.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_inspectors.py
│   │       ├── test_settings.py
│   │       └── test_settingsIO.py
│   ├── testing/
│   │   ├── __init__.py
│   │   ├── reactors/
│   │   │   ├── anl-afci-177/
│   │   │   │   ├── anl-afci-177-blueprints.yaml
│   │   │   │   ├── anl-afci-177-coreMap.yaml
│   │   │   │   ├── anl-afci-177-fuelManagement.py
│   │   │   │   └── anl-afci-177.yaml
│   │   │   ├── c5g7/
│   │   │   │   ├── c5g7-blueprints.yaml
│   │   │   │   └── c5g7-settings.yaml
│   │   │   ├── godiva/
│   │   │   │   ├── godiva-blueprints.yaml
│   │   │   │   └── godiva.armi.unittest.yaml
│   │   │   ├── smallHexReactor/
│   │   │   │   ├── smallHexReactor-bp.yaml
│   │   │   │   └── smallHexReactor.yaml
│   │   │   └── thirdSmallHexReactor/
│   │   │       ├── thirdSmallHexReactor-bp.yaml
│   │   │       └── thirdSmallHexReactor.yaml
│   │   ├── resources/
│   │   │   └── armiRun-SHUFFLES.yaml
│   │   ├── singleMixedAssembly.py
│   │   ├── symmetryTesting.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       └── test_symmetryTesting.py
│   ├── tests/
│   │   ├── 1DslabXSByCompTest.yaml
│   │   ├── ISOAA
│   │   ├── __init__.py
│   │   ├── armiRun.yaml
│   │   ├── detailedAxialExpansion/
│   │   │   ├── armiRun.yaml
│   │   │   ├── refSmallCoreGrid.yaml
│   │   │   ├── refSmallReactor.yaml
│   │   │   └── refSmallReactorBase.yaml
│   │   ├── mockRunLogs.py
│   │   ├── refSmallCartesian.yaml
│   │   ├── refSmallCoreGrid.yaml
│   │   ├── refSmallReactor.yaml
│   │   ├── refSmallReactorBase.yaml
│   │   ├── refSmallReactorShuffleLogic.py
│   │   ├── refSmallSfpGrid.yaml
│   │   ├── refTestCartesian.yaml
│   │   ├── smallestTestReactor/
│   │   │   ├── armiRunSmallest.yaml
│   │   │   ├── refOneBlockReactor.yaml
│   │   │   └── refSmallestReactor.yaml
│   │   ├── test_apps.py
│   │   ├── test_armiTestHelper.py
│   │   ├── test_cartesian.py
│   │   ├── test_context.py
│   │   ├── test_interfaces.py
│   │   ├── test_lwrInputs.py
│   │   ├── test_mpiActions.py
│   │   ├── test_mpiFeatures.py
│   │   ├── test_mpiParameters.py
│   │   ├── test_plugins.py
│   │   ├── test_runLog.py
│   │   ├── test_symmetry.py
│   │   ├── test_tests.py
│   │   ├── test_user_plugins.py
│   │   ├── tutorials/
│   │   │   ├── data_model.ipynb
│   │   │   ├── param_sweep.ipynb
│   │   │   └── pin-rotations.ipynb
│   │   ├── zpprTest.yaml
│   │   └── zpprTestGeom.yaml
│   └── utils/
│       ├── __init__.py
│       ├── asciimaps.py
│       ├── codeTiming.py
│       ├── customExceptions.py
│       ├── densityTools.py
│       ├── directoryChangers.py
│       ├── directoryChangersMpi.py
│       ├── dynamicImporter.py
│       ├── flags.py
│       ├── gridEditor.py
│       ├── hexagon.py
│       ├── iterables.py
│       ├── mathematics.py
│       ├── outputCache.py
│       ├── parsing.py
│       ├── pathTools.py
│       ├── plotting.py
│       ├── properties.py
│       ├── reportPlotting.py
│       ├── tabulate.py
│       ├── tests/
│       │   ├── __init__.py
│       │   ├── resources/
│       │   │   ├── lower/
│       │   │   │   ├── includeA.yaml
│       │   │   │   └── includeB.yaml
│       │   │   └── root.yaml
│       │   ├── test_asciimaps.py
│       │   ├── test_codeTiming.py
│       │   ├── test_custom_exceptions.py
│       │   ├── test_densityTools.py
│       │   ├── test_directoryChangers.py
│       │   ├── test_directoryChangersMpi.py
│       │   ├── test_flags.py
│       │   ├── test_hexagon.py
│       │   ├── test_iterables.py
│       │   ├── test_mathematics.py
│       │   ├── test_outputCache.py
│       │   ├── test_parsing.py
│       │   ├── test_pathTools.py
│       │   ├── test_plotting.py
│       │   ├── test_properties.py
│       │   ├── test_reportPlotting.py
│       │   ├── test_tabulate.py
│       │   ├── test_textProcessors.py
│       │   ├── test_triangle.py
│       │   ├── test_units.py
│       │   └── test_utils.py
│       ├── textProcessors.py
│       ├── triangle.py
│       └── units.py
├── doc/
│   ├── .static/
│   │   ├── __init__.py
│   │   ├── automateScr.py
│   │   ├── cleanup_test_results.py
│   │   ├── css/
│   │   │   └── theme_fixes.css
│   │   ├── dochelpers.py
│   │   ├── looseCouplingIllustration.dot
│   │   └── tightCouplingIllustration.dot
│   ├── Makefile
│   ├── __init__.py
│   ├── conf.py
│   ├── developer/
│   │   ├── documenting.rst
│   │   ├── entrypoints.rst
│   │   ├── first_time_contributors.rst
│   │   ├── guide.rst
│   │   ├── index.rst
│   │   ├── making_armi_based_apps.rst
│   │   ├── parallel_coding.rst
│   │   ├── profiling.rst
│   │   ├── standards_and_practices.rst
│   │   ├── testing.rst
│   │   └── tooling.rst
│   ├── gallery-src/
│   │   ├── README.rst
│   │   ├── analysis/
│   │   │   ├── README.rst
│   │   │   ├── run_blockMcnpMaterialCard.py
│   │   │   ├── run_hexBlockToRZConversion.py
│   │   │   └── run_hexReactorToRZ.py
│   │   └── framework/
│   │       ├── README.rst
│   │       ├── run_blockVolumeFractions.py
│   │       ├── run_chartOfNuclides.py
│   │       ├── run_computeReactionRates.py
│   │       ├── run_fuelManagement.py
│   │       ├── run_grids1_hex.py
│   │       ├── run_grids2_cartesian.py
│   │       ├── run_grids3_rzt.py
│   │       ├── run_isotxs.py
│   │       ├── run_isotxs2_matrix.py
│   │       ├── run_materials.py
│   │       ├── run_programmaticReactorDefinition.py
│   │       ├── run_reactorFacemap.py
│   │       └── run_transmutationMatrix.py
│   ├── getTestResults.py
│   ├── glossary.rst
│   ├── index.rst
│   ├── installation.rst
│   ├── make.bat
│   ├── qa_docs/
│   │   ├── index.rst
│   │   ├── scr/
│   │   │   ├── 0.1.rst
│   │   │   ├── 0.2.rst
│   │   │   ├── 0.3.rst
│   │   │   ├── 0.4.rst
│   │   │   ├── 0.5.rst
│   │   │   ├── 0.6.rst
│   │   │   ├── index.rst
│   │   │   └── latest_scr.rst
│   │   ├── sdid.rst
│   │   ├── srsd/
│   │   │   ├── bookkeeping_reqs.rst
│   │   │   ├── cases_reqs.rst
│   │   │   ├── cli_reqs.rst
│   │   │   ├── framework_reqs.rst
│   │   │   ├── materials_reqs.rst
│   │   │   ├── nucDirectory_reqs.rst
│   │   │   ├── nuclearDataIO_reqs.rst
│   │   │   ├── physics_reqs.rst
│   │   │   ├── reactors_reqs.rst
│   │   │   ├── runLog_reqs.rst
│   │   │   ├── settings_reqs.rst
│   │   │   └── utils_reqs.rst
│   │   ├── srsd.rst
│   │   └── str.rst
│   ├── readme.rst
│   ├── release/
│   │   └── index.rst
│   ├── skip_str.py
│   ├── tutorials/
│   │   ├── data_model.nblink
│   │   ├── index.rst
│   │   ├── making_your_first_app.rst
│   │   ├── materials_demo.ipynb
│   │   ├── nuclide_demo.ipynb
│   │   ├── param_sweep.nblink
│   │   ├── pin-rotations.nblink
│   │   ├── walkthrough_inputs.rst
│   │   └── walkthrough_lwr_inputs.rst
│   └── user/
│       ├── _gallery/
│       │   └── index.rst
│       ├── accessingEntryPoints.rst
│       ├── index.rst
│       ├── inputs.rst
│       ├── manual_data_access.rst
│       ├── outputs.rst
│       ├── params_report.rst
│       ├── physics_coupling.rst
│       ├── radial_and_axial_expansion.rst
│       ├── settings_report.rst
│       ├── spatial_block_data.rst
│       ├── symmetry_handling.rst
│       └── user_install.rst
└── pyproject.toml

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/.codecov.yml
================================================
coverage:
  status:
    project:
      default:
        target: 80%    # the required coverage value
        threshold: 1%  # allows a 1% drop from the previous base commit coverage

================================================
FILE: .github/pull_request_template.md
================================================
## What is the change? Why is it being made?

<!-- MANDATORY: Describe the change -->


## SCR Information

<!-- MANDATORY: uncomment one-and-only-one of these -->
<!-- Change Type: features -->
<!-- Change Type: fixes -->
<!-- Change Type: trivial -->
<!-- Change Type: docs -->

<!-- MANDATORY: Describe why this change is needed, in one sentence -->
One-Sentence Rationale: TBD

<!-- MANDATORY: Describe any impact on the requirements, all on one line -->
One-line Impact on Requirements: NA


---

## Checklist

<!--
    The pull request author should check the box if the condition is met OR if it does not apply.
-->

- [ ] This PR has only [one purpose or idea](https://terrapower.github.io/armi/developer/tooling.html#one-idea-one-pr).
- [ ] [Tests](https://terrapower.github.io/armi/developer/tooling.html#test-it) have been added/updated to verify any new/changed code.
- [ ] The [documentation](https://terrapower.github.io/armi/developer/tooling.html#document-it) is still up-to-date in the `doc` folder.
- [ ] The code style follows [good practices](https://terrapower.github.io/armi/developer/standards_and_practices.html).
- [ ] The dependencies are still up-to-date in `pyproject.toml`.


================================================
FILE: .github/workflows/coverage.yaml
================================================
name: Coverage

permissions:
  contents: read

on:
  push:
    branches:
      - main
    paths-ignore:
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'doc/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    # Deploying coverage to codecov.io should not happen on forks
    if: github.repository == 'terrapower/armi'
    runs-on: ubuntu-24.04
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.13'
      - name: Install ARMI and MPI
        run: |
          sudo apt-get -y install libopenmpi-dev
          pip install -e .[memprof,mpi,test]
          pip install codecov
      - name: Run Coverage
        run: |
          set -x
          coverage run --rcfile=pyproject.toml -m pytest -n 4 --cov=armi --cov-config=pyproject.toml --cov-report=xml --ignore=venv armi
          mpiexec -n 2 --use-hwthread-cpus coverage run --rcfile=pyproject.toml -m pytest --cov=armi --cov-config=pyproject.toml --cov-report=xml --cov-append --ignore=venv armi/tests/test_mpiFeatures.py || true
          mpiexec -n 2 --use-hwthread-cpus coverage run --rcfile=pyproject.toml -m pytest --cov=armi --cov-config=pyproject.toml --cov-report=xml --cov-append --ignore=venv armi/tests/test_mpiParameters.py || true
          mpiexec -n 2 --use-hwthread-cpus coverage run --rcfile=pyproject.toml -m pytest --cov=armi --cov-config=pyproject.toml --cov-report=xml --cov-append --ignore=venv armi/tests/test_mpiDirectoryChangers.py || true
          coverage combine --rcfile=pyproject.toml --keep -a
          coverage report --rcfile=pyproject.toml -i --skip-empty --skip-covered --sort=cover --fail-under=90
      - name: Publish to codecov.io
        continue-on-error: true
        if: github.ref == 'refs/heads/main'
        uses: codecov/codecov-action@v5
        with:
          fail_ci_if_error: false
          token: ${{ secrets.CODECOV_TOKEN }}


================================================
FILE: .github/workflows/docs.yaml
================================================
name: Documentation

on:
  push:
    branches:
      - main
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    # Building and deploying docs is broken on forked repos
    if: github.repository == 'terrapower/armi'
    runs-on: ubuntu-22.04

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.13
      - name: Update package index
        run: sudo apt-get update
      - name: Install apt-get libs
        run: sudo apt-get -y install texlive-xetex=2021.20220204-1 texlive-latex-base=2021.20220204-1 texlive-fonts-recommended=2021.20220204-1 texlive-latex-extra=2021.20220204-1 texlive-full=2021.20220204-1 pandoc libopenmpi-dev
      - name: Setup Graphviz
        uses: ts-graphviz/setup-graphviz@v2.0.2
      - name: Make html/pdf Docs
        continue-on-error: true
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ github.ref == 'refs/heads/main' && -1 || github.event.number }}
          GIT_COMMIT: ${{ github.sha }}
        run: |
          echo "Installing ARMI..."
          set -x
          pip install -U pip
          pip install -e .[memprof,mpi,test,docs]

          echo "Run unit tests..."
          pytest --junit-xml=test_results.xml -v -n 4 armi > pytest_verbose.log
          mpiexec -n 2 --use-hwthread-cpus pytest --junit-xml=test_results_mpi1.xml armi/tests/test_mpiFeatures.py > pytest_verbose_mpi1.log
          mpiexec -n 2 --use-hwthread-cpus pytest --junit-xml=test_results_mpi2.xml armi/tests/test_mpiParameters.py > pytest_verbose_mpi2.log
          mpiexec -n 2 --use-hwthread-cpus pytest --junit-xml=test_results_mpi3.xml armi/utils/tests/test_directoryChangersMpi.py > pytest_verbose_mpi3.log
          python doc/.static/cleanup_test_results.py test_results.xml

          echo "Git magic so the SCR will build on GitHub Actions..."
          git fetch --depth=2000

          echo "Build HTML docs..."
          cd doc
          git submodule init
          git submodule update
          make html

          echo "Build PDF docs..."
          make latex
          cd _build/latex/
          latexmk -pdf -f -interaction=nonstopmode ARMI.tex
      - name: Deploy
        if: github.ref == 'refs/heads/main'
        uses: JamesIves/github-pages-deploy-action@v4.6.1
        with:
          token: ${{ secrets.ACCESS_TOKEN }}
          repository-name: ${{ github.repository_owner }}/terrapower.github.io
          branch: main
          folder: doc/_build/html
          target-folder: armi
      - name: Archive HTML Docs
        if: github.ref != 'refs/heads/main'
        uses: actions/upload-artifact@v4
        with:
          name: html-docs
          path: doc/_build/html
          retention-days: 5
      - name: Archive PDF Docs
        uses: actions/upload-artifact@v4
        with:
          name: pdf-docs
          path: doc/_build/latex/ARMI.pdf
          retention-days: 5


================================================
FILE: .github/workflows/find_test_crumbs.py
================================================
# Copyright 2024 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This script exists so we can determine if new tests in CI are leaving crumbs."""

import subprocess

# A list of objects we expect during a run, and don't mind (like pycache dirs).
IGNORED_OBJECTS = [
    ".pytest_cache",
    ".tox",
    "__pycache__",
    "armi.egg-info",
    "logs/",
]


def main():
    # use "git clean" to find all non-tracked files
    proc = subprocess.Popen(["git", "clean", "-xnd"], stdout=subprocess.PIPE)
    lines = proc.communicate()[0].decode("utf-8").split("\n")

    # clean up the whitespace
    lines = [ln.strip() for ln in lines if len(ln.strip())]

    # ignore certain untracked object, like __pycache__ dirs
    for ignore in IGNORED_OBJECTS:
        lines = [ln for ln in lines if ignore not in ln]

    # fail hard if there are still untracked files
    if len(lines):
        for line in lines:
            print(line)

        raise ValueError("The workspace is dirty; the tests are leaving crumbs!")


if __name__ == "__main__":
    main()


================================================
FILE: .github/workflows/licensechecker.yaml
================================================
name: Check License Lines

permissions:
  contents: read

on: [push]

jobs:
  check-license-lines:
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@master
    - name: Check License Lines
      uses: kt3k/license_checker@v1.0.6


================================================
FILE: .github/workflows/linting.yaml
================================================
name: Linting

permissions:
  contents: read

on: [push]

jobs:
  build:

    runs-on: ubuntu-24.04

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'
      - name: Run Linter
        run:  |
          set -x
          pip install -e .[test]
          ruff format --check .
          ruff check .


================================================
FILE: .github/workflows/mac_tests.yaml
================================================
name: ARMI MacOS Tests

permissions:
  contents: read

on:
  push:
    branches:
      - main
    paths-ignore:
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'doc/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    if: github.repository == 'terrapower/armi'
    runs-on: macos-14

    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.11'
      - name: Upgrade PIP
        run: python -m pip install --upgrade pip
      - name: Run Unit Tests on MacOS
        run: |
          brew install openmpi
          pip install -e .[memprof,mpi,test]
          pytest -n 4 armi


================================================
FILE: .github/workflows/stale.yaml
================================================
# This workflow warns and then closes PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see: https://github.com/actions/stale
name: Mark Stale PRs

on:
  schedule:
  # once a day at 3:14 AM
  - cron: '14 3 * * *'

permissions:
  pull-requests: write

jobs:
  stale:
    # This workflow is not designed to make sense on forks
    if: github.repository == 'terrapower/armi'
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/stale@v8
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          stale-pr-message: "This pull request has been automatically marked as stale because it has not had any activity in the last 100 days. It will be closed in 7 days if no further activity occurs. Thank you for your contributions."
          stale-pr-label: "stale"
          days-before-pr-stale: 100
          days-before-pr-close: 7
          days-before-issue-stale: -1
          operations-per-run: 100

================================================
FILE: .github/workflows/unittests.yaml
================================================
name: ARMI unit tests

permissions:
  contents: read

on:
  push:
    paths-ignore:
      - 'doc/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:

    runs-on: ubuntu-24.04
    strategy:
      matrix:
        python: [3.9, '3.10', '3.11', '3.12', '3.13', '3.14']

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python }}
      - name: Install mpi libs
        run: sudo apt-get -y install libopenmpi-dev
      - name: Run Tests
        run: |
          set -x
          pip install -e .[memprof,mpi,test]
          pytest -n 4 armi
          mpiexec -n 2 --use-hwthread-cpus pytest armi/tests/test_mpiFeatures.py
          mpiexec -n 2 --use-hwthread-cpus pytest armi/tests/test_mpiParameters.py
          mpiexec -n 2 --use-hwthread-cpus pytest armi/utils/tests/test_directoryChangersMpi.py


================================================
FILE: .github/workflows/validatemanifest.py
================================================
# Copyright 2022 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Validating the package-data in the pyproject.toml.

Validate that we aren't trying to include files that don't exist.
"""

import os
from glob import glob

import toml

# CONSTANTS
ARMI_DIR = "armi/"
PRPROJECT = "pyproject.toml"


def main():
    # parse the data files out of the pyproject.toml
    txt = open(PRPROJECT, "r").read()
    data = toml.loads(txt)
    fileChunks = data["tool"]["setuptools"]["package-data"]["armi"]

    # loop through each line in the package-data and find all the file paths
    errors = []
    for i, line in enumerate(fileChunks):
        # make sure the file exists
        path = ARMI_DIR + line.strip()
        if "*" in path:
            paths = [f for f in glob(path) if len(f) > 3]
            if not len(paths):
                errors.append((i, path))
        else:
            if not os.path.exists(path):
                errors.append((i, path))

    # If there were any missing files, raise an Error.
    if errors:
        for i, line in errors:
            print("Nonexistant file on line {}: {}".format(i, line))
        raise ValueError("Package-data file is incorrect: includes non-existant files.")


if __name__ == "__main__":
    main()


================================================
FILE: .github/workflows/validatemanifest.yaml
================================================
name: Validate Manifest

permissions:
  contents: read

on: [push]

jobs:
  build:

    runs-on: ubuntu-24.04

    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.11'
      - name: Validate Manifest
        run: |
          pip install toml
          python .github/workflows/validatemanifest.py


================================================
FILE: .github/workflows/wheels.yaml
================================================
name: Build Wheel

permissions:
  contents: read

on:
  push:
    branches:
      - main

jobs:
  build:
    if: github.repository == 'terrapower/armi'

    runs-on: ubuntu-24.04

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - name: Install PIP Packages
        run: |
          pip install -U pip
          pip install -e .
          pip install -U wheel
      - name: Build Wheels
        run: |
          mkdir dist
          pip wheel . -w dist/
          chmod 664 dist/armi*.whl
      - name: Archive PIP wheel artifacts
        uses: actions/upload-artifact@v4
        with:
          name: armi-wheels
          path: |
            dist/armi*.whl
          retention-days: 7

================================================
FILE: .github/workflows/wintests.yaml
================================================
name: ARMI Windows tests

permissions:
  contents: read

on:
  push:
    branches:
      - main
    paths-ignore:
      - 'doc/**'
  pull_request:
    paths-ignore:
      - 'doc/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:

    runs-on: windows-2022

    steps:
      - uses: actions/checkout@v2
      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.11'
      - name: Upgrade PIP
        run: python -m pip install --upgrade pip
      - name: Run Unit Tests on Windows
        run: |
          pip install mpi4py==3.1.6
          pip install -e .[memprof,mpi,test]
          pytest -n 4 armi
      - name: Find Test Crumbs
        run: python .github/workflows/find_test_crumbs.py


================================================
FILE: .gitignore
================================================
# No non-source python resources
*.pyc
*.pyd
*.pyo
*.pyx

# No build artifacts
*.aux
*.dll
*.fdb_latexmk
*.fls
*.lib
armi/tests/tutorials/case-suite
bdist*/
bin
build
coverage.lcov
coverage.xml
coverage_results.*
dist*/
doc/.apidocs
doc/_build
doc/anl-afci-177
doc/gallery
doc/gallery-src/framework/*.yaml
doc/tutorials/anl-afci-177*
doc/tutorials/case-suite
doc/user/tutorials
htmlcov/
monkeytype.*
test_results.*
wheelhouse

# No workspace crumbs
**/.coverage*
**/__pycache__
**/logs/*
*.ascii
*.egg-info/
*.sublime-project
*.sublime-workspace
*.temp
*~
.*.swp
.cache/
.coverage
.DS_Store
.externalToolBuilders/
.hypothesis/
.idea/
.ipynb_checkpoints
.metadata
.mypy_cache/
.project
.pydevproject
.pytest_cache/
.ruff_cache/
.settings
.tox
.vim-bookmarks
.vscode
armi-venv/*
dump-temp-*
dump-tests*
phabricator-lint.txt
pytest_verbose.log
pytestdebug.log
python_details.log
reportsOutputFiles/
system_info.log
tags
temp-*
venv*/

# Ignore certain data files
*.avi
*.diff
*.flux_bg
*.flux_ufg
*.h5
*.html
*.mp4
*.nucdata
*.out
*.ppm
*.sum
*.txt
*.vtd
*.vtu
*.xdmf
*dlayxs*


================================================
FILE: .gitmodules
================================================
[submodule "doc/tutorials/armi-example-app"]
	path = doc/tutorials/armi-example-app
	url = https://github.com/terrapower/armi-example-app.git


================================================
FILE: .licenserc.json
================================================
{
  "**/*.py": "# Copyright "
}


================================================
FILE: AUTHORS
================================================
# This is the list of ARMI's contributors.
#
# This may not list everyone who has ever contributed code, important ideas, or discussions to ARMI. But this is a good
# faith attempt to give credit where it is due.
TerraPower, LLC
Aaron Reynolds (aaronjamesreynolds)
Aidan McDonald (AidanMcDonald)
Alex James (alexhjames)
Antoine Margeride (amargeride)
Arrielle Opotowsky (opotowsky)
Ashley Thompson (Ashlita6)
Bharat Medasani (mbk-tp)
Brandon LaFleur (bdlafleur)
Brian Sculac (bsculac)
Casey Stocking (clstocking)
Chris Keckler (keckler)
Chris Wong (crswong888)
Christen McKenzie (chris10mckenz)
David Pham (dpham-materials)
Drew Johnson (drewejohnson, drewj-tp, drewj-usnctech)
Dustin Langewisch (dlangewisch)
Evan Albright
Graham Malmgren
Hunter Smith (HunterPSmith)
Jacob Hader (jakehader)
James Marshall
Jason Meng (jasonbmeng)
Jeff Baylor (jeffbaylor)
Jinan Yang (jyang-TP)
John Stilley (john-science)
Jonathon Shimwell (shimwell)
Joshua Chen (joshuavictorchen)
Kayla Clements (clemekay)
Lim Swee Kiat (greentfrapp)
Mark Onufer (onufer)
Michael Castillo (kasticrunch, mcastillo10)
Michael Huang (LMikeH)
Michael Jarrett (mgjarrett)
Michael Johnson (mikepjohnson)
Mitch Young (youngmit)
Nick Touran (ntouran, partofthething)
Nicole Powell (nipowell)
Paul Romano (paulromano)
Peter McNabb
Samual Miller (sammiller11235)
Scott Yak (scottyak)
Tian Jing (TianJingwd)
Tommy Cisneros (sombrereau)
Tony Alberti (albeanth)
Virinder Sandhu (Nebbychadnezzar)
Wyatt Scherer (wcscherer)
Zachary Prince (zachmprince)


================================================
FILE: CONTRIBUTING.md
================================================
# Contribution License Agreement

For information on how to contribute to ARMI, see [our official documentation](https://terrapower.github.io/armi/developer/first_time_contributors.html).

This Contribution License Agreement (**"Agreement"**) is agreed to by the party signing below (**"You"**), and conveys certain license rights to TerraPower, LLC and its affiliates (**"TerraPower"**) for Your contributions to TerraPower open source projects. This Agreement is effective as of the latest signature date below.

## 1. Definitions.

**"Code"** means the computer software code, whether in human-readable or machine-executable form, that is delivered by You to TerraPower under this Agreement.

**"Project"** means any of the projects owned or managed by TerraPower in which software is offered under a license approved by the Open Source Initiative (OSI) ([www.opensource.org](http://www.opensource.org)) and documentation offered under an OSI or a Creative Commons license (https://creativecommons.org/licenses).

**"Submit"** is the act of uploading, submitting, transmitting, or distributing code or other content to any Project, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Project for the purpose of discussing and improving that Project, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Submission."

**"Submission"** means the Code and any other copyrightable material Submitted by You, including any associated comments and documentation.

## 2. Your Submission.

You must agree to the terms of this Agreement before making a Submission to any Project. This Agreement covers any and all Submissions that You, now or in the future (except as described in Section 4 below), Submit to any Project.

## 3. Originality of Work.

You represent that each of Your Submissions is entirely Your original work. Should You wish to Submit materials that are not Your original work, You may Submit them separately to the Project if You (a) retain all copyright and license information that was in the materials as You received them, (b) in the description accompanying Your Submission, include the phrase "Submission containing materials of a third party:" followed by the names of the third party and any licenses or other restrictions of which You are aware, and (c) follow any other instructions in the Project’s written guidelines concerning Submissions.

## 4. Your Employer.

References to "employer" in this Agreement include Your employer or anyone else for whom You are acting in making Your Submission, e.g. as a contractor, vendor, or agent. If Your Submission is made in the course of Your work for an employer or Your employer has intellectual property rights in Your Submission by contract or applicable law, You must secure permission from Your employer to make the Submission before signing this Agreement. In that case, the term "You" in this Agreement will refer to You and the employer collectively. If You change employers in the future and desire to Submit additional Submissions for the new employer, then You agree to sign a new Agreement and secure permission from the new employer before Submitting those Submissions.

## 5. Licenses.

### a. Copyright License.

You grant TerraPower, and those who receive the Submission directly or indirectly from TerraPower, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license in the Submission to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute the Submission and such derivative works, and to sublicense any or all of the foregoing rights to third parties.

### b. Patent License.

You grant TerraPower, and those who receive the Submission directly or indirectly from TerraPower, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under Your patent claims that are necessarily infringed by the Submission or the combination of the Submission with the Project to which it was Submitted to make, have made, use, offer to sell, sell and import or otherwise dispose of the Submission alone or with the Project.

### c. Other Rights Reserved.

Each party reserves all rights not expressly granted in this Agreement. No additional licenses or rights whatsoever (including, without limitation, any implied licenses) are granted by implication, exhaustion, estoppel or otherwise.

## 6. Representations and Warranties.

You represent that You are legally entitled to grant the above licenses. You represent that each of Your Submissions is entirely Your original work (except as You may have disclosed under Section 3). You represent that You have secured permission from Your employer to make the Submission in cases where Your Submission is made in the course of Your work for Your employer or Your employer has intellectual property rights in Your Submission by contract or applicable law. If You are signing this Agreement on behalf of Your employer, You represent and warrant that You have the necessary authority to bind the listed employer to the obligations contained in this Agreement. You are not expected to provide support for Your Submission, unless You choose to do so. UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, AND EXCEPT FOR THE WARRANTIES EXPRESSLY STATED IN SECTIONS 3, 4, AND 6, THE SUBMISSION PROVIDED UNDER THIS AGREEMENT IS PROVIDED WITHOUT WARRANTY OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF NONINFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.

## 7. Notice to TerraPower.

You agree to notify TerraPower in writing of any facts or circumstances of which You later become aware that would make Your representations in this Agreement inaccurate in any respect.

## 8. Information about Submissions.

You agree that contributions to Projects and information about contributions may be maintained indefinitely and disclosed publicly, including Your name and other information that You submit with Your Submission.

## 9. Governing Law/Jurisdiction.

This Agreement is governed by the laws of the State of Washington, USA and the parties consent to exclusive jurisdiction and venue in the federal courts located in King County, Washington, USA unless no federal subject matter jurisdiction exists, in which case the parties consent to exclusive jurisdiction and venue in the Superior Court of King County, Washington, USA. The parties waive all defenses of lack of personal jurisdiction and forum non-conveniens.

## 10. Entire Agreement/Assignment.

This Agreement is the entire agreement between the parties, and supersedes any and all prior agreements, understandings or communications, written or oral, between the parties relating to the subject matter hereof. This Agreement may be assigned by TerraPower.

Please select one of the options below and sign as indicated. By signing, You accept and agree to the terms of this Contribution License Agreement for Your present and future Submissions to TerraPower.


================================================
FILE: LICENSE.md
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2020 TerraPower, LLC

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.rst
================================================

|Build Status| |Code Coverage| |Commit Activity| |Good First Issues|

#################
ARMI Introduction
#################

The Advanced Reactor Modeling Interface (ARMI\ :sup:`®`) is an open-source tool that streamlines your nuclear reactor
design/analysis needs by providing a software *reactor at your fingertips* and a rich ecosystem of utilities working in
concert. It is made for and by professional reactor analysis teams and is maintained by
`TerraPower LLC <http://terrapower.com/>`_, a nuclear technology development company.

ARMI:

* Provides a hub-and-spoke mechanism to standardize communication and coupling between physics kernels and the
  specialist analysts who use them,

* Facilitates the creation and execution of detailed models and complex analysis methodologies,

* Provides an ecosystem within which to rapidly and collaboratively build new analysis and physics simulation
  capabilities, and

* Provides useful utilities to assist in reactor development.

A few demos of ARMI can be seen in the `ARMI example gallery <https://terrapower.github.io/armi/gallery/index.html>`_.

Using ARMI plus a collection of ARMI-aware physics plugins, an engineering team can perform a full analysis of a reactor
system and then repeat the same level of analysis with some changed input parameters for almost no additional cost. Even
better, thousands of perturbed cases can be executed in parallel on large clusters, helping conceptual design teams home
in on an optimal design. Or design teams can analyze sensitivities all the way from, for example, an impurity in a
control material to the peak structural temperature in a design-basis transient.

.. note:: ARMI does not come with a full selection of physics kernels. They will need to be acquired or developed for
   your specific project in order to make full use of this tool. Many of the example use-cases discussed in this manual
   require functionality that is not included in the open-source ARMI Framework.

In general, ARMI aims to enhance the quality, ease, and rigor of computational nuclear reactor design and analysis.
Additional high-level overview about this system can be found in [#touranarmi]_.


.. list-table:: Quick links
   :widths: 30 70

   * - Source code
     - https://github.com/terrapower/armi
   * - Documentation
     - https://terrapower.github.io/armi
   * - First time contributor's guide
     - https://terrapower.github.io/armi/developer/first_time_contributors.html
   * - Bug tracker
     - https://github.com/terrapower/armi/issues
   * - Plugin directory
     - https://github.com/terrapower/armi-plugin-directory
   * - Contact
     - armi-devs@terrapower.com

Quick start
***********
Before starting, you need to have `Python <https://www.python.org/downloads/>`_ 3.9+.

Get the ARMI code, install the prerequisites, and fire up the launcher with the following commands. You probably want to
do this in a virtual environment as described in the
`Installation documentation <https://terrapower.github.io/armi/installation.html>`_. Otherwise, the dependencies could
conflict with your system dependencies.

First, upgrade your version of pip::

    $ pip install -U pip>=22.1

Now clone and install ARMI::

    $ git clone https://github.com/terrapower/armi
    $ cd armi
    $ pip install -e .
    $ armi --help

The ARMI tests are meant to be run using `pytest <https://docs.pytest.org/en/8.0.x/>`_ locally::

    $ pip install -e ".[test]"
    $ pytest -n 4 armi

From here, we recommend going through a few of our
`gallery examples <https://terrapower.github.io/armi/gallery/index.html>`_ and
`tutorials <https://terrapower.github.io/armi/tutorials/index.html>`_ to start touring the features and capabilities and
then move on to the `User Manual <https://terrapower.github.io/armi/user/index.html>`_.


Background
**********
Nuclear reactor design requires, among other things, answers to the following questions:

* Where are the neutrons? How fast are they moving? In which direction?

* How quickly are atomic nuclei splitting? How long until the fuel runs out? How many atoms in the structure are being
  energetically displaced?

* How much heat do these reactions produce? How quickly must coolant flow past the fuel to maintain appropriate
  temperatures? What are the temperatures of the fuel, coolant, and structure?

* Can the structural arrangement support itself given the temperatures and pressures induced by the flowing coolant? For
  how long?

* If a pump loses power or a control rod accidentally withdraws, how quickly will the chain reaction stop while keeping
  radiation contained?

* How much used nuclear fuel is generated per useful energy produced? How long until it decays to stability?

* Where and when should we move the fuel to most economically maintain the chain reaction?

* What's the dose and activation above the head and in the secondary loop?

* How does containment handle various postulated accidents?

* How does the building handle earthquakes?

Digital computers have assisted in nuclear technology development since the days of the ENIAC in the 1940s. We now
understand reactor physics well enough to build detailed simulations, which can answer many of these design questions in
a cost-effective, and flexible manner. This allows us to simulate all kinds of different reactors with different fuels,
coolants, moderators, power levels, safety systems, and power cycles. We can run our virtual reactors through the
decades, tossing various off-normal conditions at them now and then, to see how they perform in terms of capability,
economics, and safety.

Perhaps surprisingly, some nuclear software written in the 1960s is still in use today. These codes are validated
against physical experiments that no longer exist. Meanwhile, new cutting-edge nuclear software is being developed for
todays powerful computers. Both old and new, these tools are often challenging to operate and coordinate to produce a
full reactor analysis.

The ARMI approach was born out of this situation: how can we best leverage an eclectic mix of legacy and modern tools
with a small team to do full-scope analysis? We built a framework that lets us automate the tedious, uncoupled, and
error-prone parts of reactor engineering/analysis work. We can turn around a very meaningful and detailed core analysis
given a major change (e.g. change power by 50%) in just a few weeks. We can dispatch hundreds of parameter sweeps to
multiple machines and then perform multi-objective optimization on the resulting design space.

The ARMI system is largely written in the Python programming language. Its high-level nature allows nuclear and
mechanical engineers to rapidly automate their analysis tasks from their sub-specialties. This helps eliminate the
translation step between computer-scientists and power plant design engineers. This allows good division of labor: the
computer scientists can focus on the overall performance and maintainability of the framework, while the power plant
engineers focus on power plant engineering.

We have spent over 10 years developing this system. Because of ARMI's high-level nature, we believe we can collaborate
effectively with all ongoing reactor software developments.

Communication and coupling
**************************
ARMI provides a central place for all physics kernels to interact: the Reactor Model. All modules read *state*
information from this Reactor and write their output to it. This common interface allows seamless communication and
coupling between different physics sub-specialties. If you plug one new physics kernel into ARMI, it becomes coupled to
N other kernels. The ARMI Framework, depicted in green below, is the majority of the open source package. Several
skeletal analysis routines are included as well to perform basic data management and to help align efforts on external
physics kernels.

.. figure:: https://terrapower.github.io/armi/_static/armiSchematicView.png
   :figclass: align-center

   **Figure 1.** The schematic representation of the ARMI data model.


Automation
**********
ARMI can quickly and easily produce complex input files with high levels of detail in various approximations. This
enables users to perform rapid high-fidelity analyses to make sure all important physics are captured. It also enables
sensitivity studies of different modeling approximations (e.g. symmetries, transport vs. diffusion vs. Monte Carlo,
subchannel vs. CFD, etc.).


.. figure:: https://terrapower.github.io/armi/_static/armiGeometries.png
   :figclass: align-center

   **Figure 2.** A variety of approximations in hexagonal geometry (1/3-core, full core, pin detailed, etc.) are shown,
   all derived from one consistent input file. ARMI supports Cartesian, Hex, RZ, and RZTheta geometric grids and
   includes many geometric components. Additionally, users can provide custom geometric elements.


New analysis and physics capabilities
*************************************
The ARMI reactor model is fully accessible via a Python-based API, meaning that power-users and developers have full
access to the details of the plant at all times. Developers adding new physics features can take advantage of the ARMI
data management structure by simply reading and writing to the Reactor state. Leveraging the infrastructure of ARMI,
progress can be made rapidly.

Power-user analysts can modify the plant in many ways. For instance, removing all sodium coolant is a one-liner::

    core.setNumberDensity('NA23',0.0)

and finding the peak power density is easy::

    core.getMaxParam('pdens')

Any ARMI state can be written out to whichever format the user desires, meaning that nominally identical cases can be
produced for multiple similar codes in sensitivity studies. To read power densities, simply read them off the assembly
objects. Instead of producing spreadsheets and making plots manually, analysts may write scripts to generate output
reports that run automatically.

Writing a module within ARMI automatically features access to the ARMI API, including:

* Cross section processing
* Material properties
* Thermal expansion
* Database persistence
* Data visualization
* A code testing, documentation, and version control system


Use cases
*********
Given an input describing a reactor, a typical ARMI run loops over a set of plugins in a certain sequence. Some plugins
trigger third-party simulation codes, producing input files for them, executing them, and translating the output back
onto the reactor model. Other plugins perform physics simulations directly.

For example, one ARMI sequence may involve the calculation of:

* nuclear cross sections
* global flux and power
* subchannel temperatures
* duct wall pressures
* cladding strain and wastage
* fission gas pressure
* reactivity feedbacks
* flow orificing
* the equilibrium fuel cycle
* control rod worth
* shutdown margin
* frequency stability margins
* peak cladding temperature
* transient analysis
* total levelized cost of electricity for the run

Another ARMI sequence may simply compute the cost of feed uranium and enrichment in an initial core and quit.

Larger siumulations may also run through the multi-objective design optimization system, which runs many cases with
input perturbations to help find the best overall system, considering all important physics at the same time.

Other interest may come from the following:

The Research Scientist
======================
A nuclear reactor research scientist, at a national lab or university, may benefit from ARMI. An ARMI workflow can
reduce the time spent on data management. ARMI can handle the tedium so that researchers can better focus on designing
and testing their research.

For example, if an ARMI input file describing the FFTF reactor is provided, the researcher can start running benchmark
cases with their new code method very rapidly, rather than spending the time building their own FFTF model.

If someone wants to try varying nuclear cross sections by a percent here and there to compute sensitivities, ARMI is a
perfect platform upon which to operate.

If a reactor designer wants to try out a new Machine Learning algorithm for fuel management, plugging it into ARMI and
having it run on all the physics kernels of the ARMI ecosystem will be a great way to prove its true value (note that
this requires a rich ARMI physics ecosystem).

The Nuclear Startup Engineer
============================
As various companies evaluate their ideas, they need tools for analysis. They can pick up ARMI and save 10 years of
development and hit the ground running by plugging in their design-specific physics kernels and proprietary design
inputs. ARMI's parameter sweep features, reactor model, and parallel utilities will all come in handy immediately.


Operating and Vendor Engineers
==============================
People at well-established utilities or vendors can hook ARMI into their legacy systems and increase their overall
productivity.

The Enthusiast
==============
If an enthusiast wants to try out a reactor idea they have, they can use ARMI (plus some physics kernels) to quickly get
some performance metrics. They can see if their idea has wings, and if it does, they can then find a way to bring it to
engineering and commercial reality.


History of ARMI
***************
ARMI was originally created by TerraPower, LLC near Seattle WA starting in 2009. Its founding mission was to determine
the optimal fuel management operations required to transition a fresh Traveling Wave Reactor core from startup into an
equilibrium state. It started out automating the Argonne National Lab (ANL) fast reactor neutronics codes, MC2 and
REBUS. The reactor model design was made with the intention of adding other physics capabilities later. Soon, simple
thermal hydraulics were added and it's grown ever since. It has continuously evolved towards a general reactor analysis
framework.

Following requests by outside parties to use ARMI, we started working on a more modular architecture for ARMI, allowing
some of the intertwined physics capabilities to be separated out as plugins from the standalone framework.

The nuclear industry is small, and it faces many challenges. It also has a tradition of secrecy. As a result, there is
risk of overlapping work being done by other entities.

We hypothesize that collaborating on software systems can help align some efforts worldwide, increasing quality and
efficiency. In reactor development, the idea is generally cheap. It's the shakedown, technology and supply chain
development, engineering demo, and commercial demo that are the hard parts.

Thus, ARMI was released under an open-source license in 2019 to facilitate mutually beneficial collaboration across the
nuclear industry, where many teams are independently developing similar reactor analysis/automation frameworks.

We also hope that if more people can rapidly analyze the performance of their reactor ideas, limited available funding
can be spent more effectively.


System Requirements
*******************
Being largely written in the Python programming language, the ARMI system works on most platforms.  It can perform
meaningful analysis on a single laptop, but the full value of design optimization and large problems is realized with
parallel runs over large clusters (using the optional ``mpi4py`` library).

.. _getting-help:

Getting Help
************
You can get help with ARMI by either making issues on our `github page <https://github.com/terrapower/armi/issues>`_ or
by e-mailing armi-devs@terrapower.com.

Disclaimers
***********
Due to TerraPower goals and priorities, many ARMI modules were developed with the sodium-cooled fast reactors as a
target, and are not necessarily yet optimized for other plants. This is a known issue with code organization and we are
working on it. On the other hand, the framework is sufficiently general that people have modeled other reactor types
with ARMI, including thermal reactors.

ARMI was developed within a rapidly changing R&D environment. It evolved accordingly, and naturally carries some legacy.
We continuously attempt to identify and update problematic parts of the code. Users should understand that ARMI is not a
polished consumer software product, but rather a powerful and flexible engineering tool. It has the potential to
accelerate work on many kinds of reactors.

ARMI has been written to support specific engineering/design tasks. As such, polish in the GUIs and output is somewhat
lacking.

The ARMI framework uses the ``camelCase`` style, which is not the standard style for Python. As this is an issue of
style, it is not considered worth the API-breaking cost to our downstream users to change it.


License
*******
TerraPower and ARMI are registered trademarks of TerraPower, LLC. Other trademarks and registered trademarks used in
this Manual are the property of the respective trademark holders.

The ARMI system is licensed as follows:

.. code-block:: none

	Copyright 2009 TerraPower, LLC

	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at

	    http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.

Be careful when including any dependency in ARMI (say in the ``pyproject.toml`` file) not to include anything with a
license that supersedes our Apache license. For instance, any third-party Python library included in ARMI with a GPL
license will make the whole project fall under the GPL license. But a lot of potential users of ARMI will want to keep
some of their work private, so we can't allow any GPL dependencies.

For that reason, it is generally considered best-practice in the ARMI ecosystem to only use third-party Python libraries
that have MIT or BSD licenses.

.. [#touranarmi] Touran, Nicholas W., et al. "Computational tools for the integrated design of advanced nuclear reactors."
   Engineering 3.4 (2017): 518-526. https://doi.org/10.1016/J.ENG.2017.04.016

.. |Build Status| image:: https://github.com/terrapower/armi/actions/workflows/unittests.yaml/badge.svg?branch=main
    :target: https://github.com/terrapower/armi/actions/workflows/unittests.yaml

.. |Code Coverage| image:: https://codecov.io/gh/terrapower/armi/branch/main/graph/badge.svg
    :target: https://app.codecov.io/gh/terrapower/armi/tree/main

.. |Commit Activity| image:: https://img.shields.io/github/commit-activity/m/terrapower/armi
    :target: https://github.com/terrapower/armi/pulse

.. |Good First Issues| image:: https://img.shields.io/github/issues/terrapower/armi/good%20first%20issue
    :target: https://github.com/terrapower/armi/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22


================================================
FILE: armi/__init__.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Welcome to the Advanced Reactor Modeling Interface (ARMI).

This module initializes the ARMI platform. The bootstrap process is broken into several phases:

* Import fundamental dependencies in Python library and some third-party libs
* Investigate environment: Check Python version, code version, MPI situation, and TTY/GUI/interactivity,
* Set up temp dirs
* Set up printout table formats (in preparation of logging info)
* Initialize all possible nuclide objects in the nuclide directory
* Discover and register available built-in :py:mod:`plugins <armi.plugins>` (custom ones are registered after inputs)
* Discover and define all potential configuration settings from available plugins
* Read input files
* Update :py:mod:`nuclide directory <armi.nucDirectory>` with depletion info based on config
* Discover and define all state :py:mod:`Parameters <armi.reactor.parameters>` on data model (maybe dependent on config)
* Discover :py:mod:`Entry points <armi.cli>` from plugins
* Choose entry point based on user command

If using the ``run`` entry point, additional work is done:

* Build :py:mod:`reactor model <armi.reactor>` based on input
* Build :py:mod:`operator object <armi.operators>` with specific calculation loop
* Build ordered interface stack based on configuration settings
* Begin looping over interface stack, operating upon data model according to operator design
* Loop until complete
* Wrap up
* Quit
"""

# ruff: noqa: F401
import atexit
import datetime
import importlib
import os
import signal
import subprocess
import sys
import traceback
import warnings
from typing import List, Optional, Type

import __main__ as main

# The _bootstrap module performs operations that may need to occur before it is necessarily safe to import the rest of
# the ARMI system. Things like:
# - configure the MPI environment
# - detect the nature of interaction with the user (terminal UI, GUI, unsupervized, etc)
# - Initialize the nuclide database
import armi._bootstrap
from armi import apps, cli, context, pluginManager, plugins, runLog
from armi.context import (
    APP_DATA,
    CURRENT_MODE,
    DOC,
    MPI_COMM,
    MPI_DISTRIBUTABLE,
    MPI_NODENAME,
    MPI_NODENAMES,
    MPI_RANK,
    MPI_SIZE,
    RES,
    ROOT,
    START_TIME,
    USER,
    Mode,
)
from armi.meta import __version__
from armi.nucDirectory import nuclideBases
from armi.reactor import flags, parameters

# ARMI does not configure its own application by default. This is mostly to catch issues involving calling code that
# requires the framework to be configured before that has explicitly taken place. An application should call
# `configure()` with its App class in order for ARMI to work properly
_app: Optional[apps.App] = None

_ARMI_CONFIGURE_CONTEXT: Optional[str] = None

# Advanced flag used in documentation builds to avoid isConfigured guards.
_ignoreConfigures = False


def disableFutureConfigures():
    """Exposed function to ensure armi.configure() isn't called more than once."""
    global _ignoreConfigures
    _ignoreConfigures = True


def isStableReleaseVersion(version=None):
    """Determine if the version should be considered a stable release."""
    version = version or __version__
    return "-" not in version


def init(fName=None, cs=None, skipInspection=False, choice=None):
    """
    Scan a directory for armi inputs and load one to interact with.

    .. impl:: Settings are used to define an ARMI run.
        :id: I_ARMI_SETTING1
        :implements: R_ARMI_SETTING

        This method initializes an ARMI run, and if successful returns an Operator. That operator is designed to drive
        the reactor simulation through time steps to simulate its operation. This method takes in a settings file or
        object to initialize the operator. Whether a settings file or object is supplied, the operator will be built
        based on the those settings. Because the total collection of settings can be modified by developers of ARMI
        applications, providing these settings allow ARMI end-users to granularly define their simulations.

    Parameters
    ----------
    fName : str, optional
        The path to a settings file to load: my_case.yaml
    cs : Settings, optional
        If supplied, this CS object will supersede the other case input methods and use the object directly.
    skipInspection : bool, optional
        Whether or not the inputs should be checked for valid settings. Default is False.
    choice : int, optional
        Automatically run with this item out of the menu that would be produced by the existing YAML files.

    Examples
    --------
    >>> o = armi.init()
    """
    from armi import cases, settings

    if cs is None:
        if fName is None:
            fName = settings.promptForSettingsFile(choice)
        cs = settings.Settings(fName)

    armiCase = cases.Case(cs=cs)
    if not skipInspection:
        armiCase.checkInputs()

    try:
        return armiCase.initializeOperator()
    except:  # Catch any and all errors. Naked exception on purpose.
        # Concatenate errors to the primary log file.
        runLog.close()
        raise


def getDefaultPlugins() -> List[Type[plugins.ArmiPlugin]]:
    """
    Return a list containing the default set of ARMI Framework plugins.

    This is useful for an application to fold all of the ARMI Framework's capabilities into its own set of plugins.
    """
    from armi import bookkeeping, cli, reactor
    from armi.physics import fuelCycle, neutronics, safety

    defaultPlugins = [
        cli.EntryPointsPlugin,
        bookkeeping.BookkeepingPlugin,
        fuelCycle.FuelHandlerPlugin,
        neutronics.NeutronicsPlugin,
        safety.SafetyPlugin,
        reactor.ReactorPlugin,
    ]

    return defaultPlugins


def getDefaultPluginManager() -> pluginManager.ArmiPluginManager:
    """
    Return a plugin manager containing the default set of ARMI Framework plugins.

    This is useful when using standalone facilities of ARMI without a specific application.
    """
    pm = plugins.getNewPluginManager()
    for plugin in getDefaultPlugins():
        pm.register(plugin)

    return pm


def isConfigured():
    """Returns whether ARMI has been configured with an App."""
    return _app is not None


def getPluginManager() -> Optional[pluginManager.ArmiPluginManager]:
    """Return the plugin manager, if there is one."""
    global _app
    if _app is None:
        return None
    return _app.pluginManager


def getPluginManagerOrFail() -> pluginManager.ArmiPluginManager:
    """Return the plugin manager. Raise an error if there is none."""
    global _app
    assert _app is not None, (
        "The ARMI plugin manager was requested, no App has been configured. Ensure that `armi.configure()` has been "
        "called before attempting to interact with the plugin manager."
    )

    return _app.pluginManager


def getApp() -> Optional[apps.App]:
    global _app
    return _app


def _cleanupOnCancel(signum, _frame):
    """Helper function to clean up upon cancellation."""
    print(f"Caught Cancel signal ({signum}); cleaning temporary files and exiting...", file=sys.stderr)
    context.cleanFastPathAfterSimulation()
    sys.stdout.flush()
    sys.stderr.flush()
    sys.exit(1)  # since we're handling the signal we have to cancel


def _liveInterpreter():
    """Return whether we are running within a live/interactive python interpreter."""
    return not hasattr(main, "__file__")


def configure(app: Optional[apps.App] = None, permissive=False):
    """
    Set the plugin manager for the Framework and configure internals to those plugins.

    Parameters
    ----------
    app :
        An :py:class:`armi.apps.App` instance with which the framework is to be configured. If it is not provided, then
        the default ARMI App will be used.
    permissive :
        Whether or not an error should be produced if ``configure`` is called more than once. This should only be set to
        ``True`` under testing or demonstration purposes, where the contents of otherwise independent scripts need to be
        run under the same python instance.

    Important
    ---------
    Since this affects the behavior of several modules at their import time, it is generally not safe to re-configure
    the ARMI framework once it has been configured. Therefore this will raise an ``RuntimeError`` if such a
    re-configuration is attempted, unless ``permissive`` is set to ``True``.

    Notes
    -----
    We are planning on encapsulating much of the global ARMI state that gets configured with an App into the App object
    itself (with some other things going into the Case object). This will provide a number of benefits, the main one
    being that it will become trivial to re-configure the framework, which is currently not possible.
    """
    global _app
    global _ARMI_CONFIGURE_CONTEXT

    if _ignoreConfigures:
        return

    app = app or apps.App()

    if _app is not None:
        if permissive and isinstance(app, apps.App):
            return
        else:
            raise RuntimeError(
                f"Multiple calls to armi.configure() are not allowed. Previous call from:\n{_ARMI_CONFIGURE_CONTEXT}"
            )

    assert not context.BLUEPRINTS_IMPORTED, (
        "ARMI can no longer be configured after blueprints have been imported. Blueprints were imported from"
        f":\n{context.BLUEPRINTS_IMPORT_CONTEXT}"
    )

    _ARMI_CONFIGURE_CONTEXT = "".join(traceback.format_stack())

    _app = app
    context.APP_NAME = app.name

    if _liveInterpreter():
        runLog.LOG.startLog(name=f"interactive-{app.name}")
        cli.splash()

    pm = app.pluginManager
    parameters.collectPluginParameters(pm)
    parameters.applyAllParameters()
    _app.registerPluginFlags()


def applyAsyncioWindowsWorkaround() -> None:
    """
    Apply Asyncio workaround for Windows and Python 3.8.

    This prevents a NotImplementedError on Windows with Python 3.8 his error showed up during jupyter notebook built-
    tests and documentation. See https://bugs.python.org/issue37373
    """
    import asyncio

    if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith("win"):
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())


applyAsyncioWindowsWorkaround()

# The ``atexit`` handler is like putting it in a finally after everything.
atexit.register(context.cleanFastPathAfterSimulation)

# register cleanups upon HPC cancellations. Linux clusters will send a different signal. SIGBREAK doesn't exist on
# non-windows This actually doesn't work in mpi runs because MSMPI's mpiexec does not pass signals.
if os.name == "nt":
    signal.signal(signal.SIGBREAK, _cleanupOnCancel)
signal.signal(signal.SIGINT, _cleanupOnCancel)


================================================
FILE: armi/__main__.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Primary entry point into ARMI.

There are a variety of entry points in the ``cli`` package that define the various run options.
This invokes them according to command-line user input.
"""

import sys
import traceback

from armi import apps, configure, context, isConfigured, runLog
from armi.cli import ArmiCLI


def main():
    # Main entry point into ARMI
    try:
        if not isConfigured():
            configure(apps.App())
        code = ArmiCLI().run()
        # sys exit interprets None as 0
        sys.exit(code)
    except Exception:
        # Make sure not to catch all BaseExceptions, lest we catch the expected SystemExit exception
        runLog.error(
            f"Unhandled exception in __main__, rank {context.MPI_RANK} on {context.MPI_NODENAME}.",
            file=sys.__stderr__,
        )
        runLog.error(traceback.format_exc(), file=sys.__stderr__)
        if context.MPI_SIZE > 1:
            runLog.error(
                f"Killing all MPI tasks from __main__, rank {context.MPI_RANK}.",
                file=sys.__stderr__,
            )
            # cleanFastPathAfterSimulation has @atexit.register so it should be called at the end, but mpi. Abort
            # in main will not allow for @atexit.register or except/finally code to be called so
            # calling here as well
            context.cleanFastPathAfterSimulation()
            # .Abort will not allow for @atexit.register or except/finally code to be called
            context.MPI_COMM.Abort(errorcode=-1)

        raise SystemExit(1)


if __name__ == "__main__":
    main()


================================================
FILE: armi/_bootstrap.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Code that needs to be executed before most ARMI components are safe to import."""

from armi.nucDirectory import nuclideBases  # noqa: E402

# Nuclide bases get built explicitly here to have better determinism
# about when they get instantiated. The burn chain is not applied
# at this point, but only after input is read. Nuclides need to be built super early
# because some import-time code needs them to function. Namely, Block parameter
# collection uses them to create number density params.
nuclideBases.factory()


================================================
FILE: armi/apps.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
The base ARMI App class.

This module defines the :py:class:`App` class, which is used to configure the ARMI
Framework for a specific application. An ``App`` implements a simple interface for
customizing much of the Framework's behavior.
"""

# ruff: noqa: E402
import collections
import importlib
import sys
from typing import Dict, List, Optional, Tuple

from armi import context, meta, pluginManager, plugins, settings
from armi.reactor import parameters
from armi.reactor.flags import Flags
from armi.settings import Setting, fwSettings


class App:
    """
    The highest-level of abstraction for defining what happens during an ARMI run.

    .. impl:: An App has a plugin manager.
        :id: I_ARMI_APP_PLUGINS
        :implements: R_ARMI_APP_PLUGINS

        The App class is intended to be subclassed in order to customize the functionality
        and look-and-feel of the ARMI Framework for a specific use case. An App contains a
        plugin manager, which should be populated in ``__init__()`` with a collection of
        plugins that are deemed suitable for a given application, as well as other methods
        which provide further customization.

        The base App class is also a good place to expose some more convenient ways to get
        data out of the Plugin API; calling the ``pluggy`` hooks directly can sometimes be a
        pain, as the results returned by the individual plugins may need to be merged and/or
        checked for errors. Adding that logic here reduces boilerplate throughout the rest
        of the code.
    """

    name = "armi"
    """
    The program name of the app. This should be the actual name of the python entry
    point that loads the app, or the name of the module that contains the appropriate
    __main__ function. For example, if the app is expected to be invoked with ``python
    -m myapp``, ``name`` should be ``"myapp"``
    """

    def __init__(self):
        """
        This mostly initializes the default plugin manager. Subclasses are free to adopt
        this plugin manager and register more plugins of their own, or to throw it away
        and start from scratch if they do not wish to use the default Framework plugins.

        For a description of the things that an ARMI plugin can do, see the
        :py:mod:`armi.plugins` module.
        """
        self._pluginFlagsRegistered: bool = False
        self._pm: Optional[pluginManager.ArmiPluginManager] = None
        self._paramRenames: Optional[Tuple[Dict[str, str], int]] = None
        self.__initNewPlugins()

    def __initNewPlugins(self):
        from armi import bookkeeping, cli, reactor
        from armi.physics import (
            fuelCycle,
            fuelPerformance,
            neutronics,
            safety,
            thermalHydraulics,
        )

        self._pm = plugins.getNewPluginManager()
        for plugin in (
            cli.EntryPointsPlugin,
            bookkeeping.BookkeepingPlugin,
            fuelCycle.FuelHandlerPlugin,
            fuelPerformance.FuelPerformancePlugin,
            neutronics.NeutronicsPlugin,
            safety.SafetyPlugin,
            thermalHydraulics.ThermalHydraulicsPlugin,
            reactor.ReactorPlugin,
        ):
            self._pm.register(plugin)

        self._paramRenames = None

    @property
    def version(self) -> str:
        """Grab the version of this app (defaults to ARMI version).

        Notes
        -----
        This is designed to be over-ridable by Application developers.
        """
        return meta.__version__

    @property
    def pluginManager(self) -> pluginManager.ArmiPluginManager:
        """Return the App's PluginManager."""
        return self._pm

    def getSettings(self) -> Dict[str, Setting]:
        """Return a dictionary containing all Settings defined by the framework and all plugins."""
        # Start with framework settings
        settingDefs = {setting.name: setting for setting in fwSettings.getFrameworkSettings()}

        # The optionsCache stores options that may have come from a plugin before the setting to
        # which they apply. Whenever a new setting is added, we check to see if there are any
        # options in the cache, popping them out and adding them to the setting. If all plugins'
        # settings have been processed and the cache is not empty, that's an error, because a plugin
        # must have provided options to a setting that doesn't exist.
        optionsCache: Dict[str, List[settings.Option]] = collections.defaultdict(list)
        defaultsCache: Dict[str, settings.Default] = {}

        for pluginSettings in self._pm.hook.defineSettings():
            for pluginSetting in pluginSettings:
                if isinstance(pluginSetting, settings.Setting):
                    name = pluginSetting.name
                    if name in settingDefs:
                        raise ValueError(f"The setting {pluginSetting.name} already exists and cannot be redefined.")
                    settingDefs[name] = pluginSetting
                    # handle when new setting has modifier in the cache (modifier loaded first)
                    if name in optionsCache:
                        settingDefs[name].addOptions(optionsCache.pop(name))
                    if name in defaultsCache:
                        settingDefs[name].changeDefault(defaultsCache.pop(name))
                elif isinstance(pluginSetting, settings.Option):
                    if pluginSetting.settingName in settingDefs:
                        # modifier loaded after setting, so just apply it (no cache needed)
                        settingDefs[pluginSetting.settingName].addOption(pluginSetting)
                    else:
                        # no setting yet, cache it and apply when it arrives
                        optionsCache[pluginSetting.settingName].append(pluginSetting)
                elif isinstance(pluginSetting, settings.Default):
                    if pluginSetting.settingName in settingDefs:
                        # modifier loaded after setting, so just apply it (no cache needed)
                        settingDefs[pluginSetting.settingName].changeDefault(pluginSetting)
                    else:
                        # no setting yet, cache it and apply when it arrives
                        defaultsCache[pluginSetting.settingName] = pluginSetting
                else:
                    raise TypeError(
                        "Invalid setting definition found: {} ({})".format(pluginSetting, type(pluginSetting))
                    )

        if optionsCache:
            raise ValueError(
                "The following options were provided for settings that do "
                "not exist. Make sure that the set of active plugins is "
                "consistent.\n{}".format(optionsCache)
            )

        if defaultsCache:
            raise ValueError(
                "The following defaults were provided for settings that do "
                "not exist. Make sure that the set of active plugins is "
                "consistent.\n{}".format(defaultsCache)
            )

        return settingDefs

    def getParamRenames(self) -> Dict[str, str]:
        """
        Return the parameter renames from all registered plugins.

        This renders a merged dictionary containing all parameter renames from all of the registered
        plugins. It also performs simple error checking. The result of this operation is cached,
        since it is somewhat expensive to perform. If the App detects that its plugin manager's set
        of registered plugins has changed, the cache will be invalidated and recomputed.
        """
        cacheInvalid = False
        if self._paramRenames is not None:
            renames, counter = self._paramRenames
            if counter != self._pm.counter:
                cacheInvalid = True
        else:
            cacheInvalid = True

        if cacheInvalid:
            currentNames = {pd.name for pd in parameters.ALL_DEFINITIONS}

            renames = dict()
            for pluginRenames in self._pm.hook.defineParameterRenames():
                collisions = currentNames & pluginRenames.keys()
                if collisions:
                    raise plugins.PluginError(
                        "The following parameter renames from a plugin collide with "
                        "currently-defined parameters:\n{}".format(collisions)
                    )
                pluginCollisions = renames.keys() & pluginRenames.keys()
                if pluginCollisions:
                    raise plugins.PluginError(
                        "The following parameter renames are already defined by another plugin:\n{}".format(
                            pluginCollisions
                        )
                    )
                renames.update(pluginRenames)
            self._paramRenames = renames, self._pm.counter
        return renames

    def registerPluginFlags(self):
        """
        Apply flags specified in the passed ``PluginManager`` to the ``Flags`` class.

        See Also
        --------
        armi.plugins.ArmiPlugin.defineFlags
        """
        if self._pluginFlagsRegistered:
            raise RuntimeError("Plugin flags have already been registered. Cannot do it twice!")

        for pluginFlags in self._pm.hook.defineFlags():
            Flags.extend(pluginFlags)

        self._pluginFlagsRegistered = True

    def registerUserPlugins(self, pluginPaths):
        r"""
        Register additional plugins passed in by importable paths.
        These plugins may be provided e.g. by an application during startup
        based on user input.

        Format expected to be a list of full namespaces to plugin classes.
        There should be a comma between individual plugins and dots representing
        the file path or importable python namespace.

        Examples
        --------
        importable namespace:
        ``armi.stuff.plugindir.pluginMod.pluginCls,armi.whatever.plugMod2.plugCls2``

        or on Linux/Unix:
        ``/path/to/pluginMod.py:pluginCls,/path/to/plugMod2.py:plugCls2``

        or on Windows:
        ``C:\\path\\to\\pluginMod.py:pluginCls,C:\\\\path\\to\\plugMod2.py:plugCls2``

        Notes
        -----
        These paths are meant to be taken from a settings file, though this method
        is public. The idea is that these "user plugins" differ from regular plugins
        because they are defined during run time, not import time. As such, we
        restrict their flexibility and power as compared to the usual ArmiPlugins.
        """
        for pluginPath in pluginPaths:
            if self._isPluginRegistered(pluginPath):
                continue
            if ".py:" in pluginPath:
                # The path is of the form: /path/to/why.py:MyPlugin
                self.__registerUserPluginsAbsPath(pluginPath)
            else:
                # The path is of the form: armi.thing.what.MyPlugin
                self.__registerUserPluginsInternalImport(pluginPath)

    def _isPluginRegistered(self, pluginPath: str):
        r"""
        Check if the plugin at the provided path is already registered.

        The expected path formats are:
        ------------------------------
        importable namespace:
        ``armi.stuff.plugindir.pluginMod.pluginCls``

        or on Linux/Unix:
        ``/path/to/pluginMod.py:pluginCls``

        or on Windows:
        ``C:\\path\\to\\pluginMod.py:pluginCls``

        Parameters
        ----------
        pluginPath : str
            String path to a userPlugin.

        Returns
        -------
        bool
            Whether or not the plugin name is already registered with the manager.
        """
        if ":" in pluginPath:
            pluginName = pluginPath.strip().split(":")[-1]
        else:
            pluginName = pluginPath.strip().split(".")[-1]

        return self._pm.has_plugin(pluginName)

    def __registerUserPluginsAbsPath(self, pluginPath):
        """Helper method to register a single UserPlugin via absolute path.

        Here the given path is of the form: /path/to/why.py:MyPlugin
        """
        assert pluginPath.count(".py:") == 1, f"Invalid plugin path: {pluginPath}"

        # split the settings string into file path and class name
        filePath, className = pluginPath.split(".py:")
        filePath += ".py"

        spec = importlib.util.spec_from_file_location(className, filePath)
        mod = importlib.util.module_from_spec(spec)
        sys.modules[spec.name] = mod
        spec.loader.exec_module(mod)
        plugin = getattr(mod, className)
        assert issubclass(plugin, plugins.UserPlugin)
        self._pm.register(plugin)

        # ensure UserPlugin flags are loaded
        newFlags = plugin.defineFlags()
        if newFlags:
            Flags.extend(newFlags)

    def __registerUserPluginsInternalImport(self, pluginPath):
        """Helper method to register a single UserPlugin via internal import.

        Here the given path is of the form: armi.thing.what.MyPlugin
        """
        names = pluginPath.strip().split(".")
        modPath = ".".join(names[:-1])
        clsName = names[-1]
        mod = importlib.import_module(modPath)
        plugin = getattr(mod, clsName)
        assert issubclass(plugin, plugins.UserPlugin)
        self._pm.register(plugin)

        # ensure UserPlugin flags are loaded
        newFlags = plugin.defineFlags()
        if newFlags:
            Flags.extend(newFlags)

    @property
    def splashText(self):
        """
        Return a textual splash screen.

        Specific applications will want to customize this, but by default the ARMI one
        is produced, with extra data on the App name and version, if available.
        """
        # typical ARMI splash text
        splash = r"""
+===================================================+
|            _      ____     __  __    ___          |
|           / \    |  _ \   |  \/  |  |_ _|         |
|          / _ \   | |_) |  | |\/| |   | |          |
|         / ___ \  |  _ <   | |  | |   | |          |
|        /_/   \_\ |_| \_\  |_|  |_|  |___|         |
|        Advanced  Reactor  Modeling Interface      |
|                                                   |
|                    version {0:10s}             |
|                                                   |""".format(meta.__version__)

        # add the name/version of the current App, if it's not the default
        if context.APP_NAME != "armi":
            from armi import getApp

            splash += r"""
|---------------------------------------------------|
|   {0:>17s} app version {1:10s}        |""".format(context.APP_NAME, getApp().version)

        # bottom border of the splash
        splash += r"""
+===================================================+
"""

        return splash


================================================
FILE: armi/bookkeeping/__init__.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""The bookkeeping package handles data persistence, reporting, and some debugging."""

from armi import plugins


class BookkeepingPlugin(plugins.ArmiPlugin):
    @staticmethod
    @plugins.HOOKIMPL
    def exposeInterfaces(cs):
        from armi.bookkeeping import (
            historyTracker,
            mainInterface,
            memoryProfiler,
            snapshotInterface,
        )
        from armi.bookkeeping.db import databaseInterface
        from armi.bookkeeping.report import reportInterface

        interfaceInfo = []
        interfaceInfo += plugins.collectInterfaceDescriptions(mainInterface, cs)
        interfaceInfo += plugins.collectInterfaceDescriptions(databaseInterface, cs)
        interfaceInfo += plugins.collectInterfaceDescriptions(historyTracker, cs)
        interfaceInfo += plugins.collectInterfaceDescriptions(memoryProfiler, cs)
        interfaceInfo += plugins.collectInterfaceDescriptions(reportInterface, cs)
        interfaceInfo += plugins.collectInterfaceDescriptions(snapshotInterface, cs)

        return interfaceInfo

    @staticmethod
    @plugins.HOOKIMPL
    def defineEntryPoints():
        from armi.bookkeeping import visualization
        from armi.cli import database

        entryPoints = []
        entryPoints.append(database.ExtractInputs)
        entryPoints.append(database.InjectInputs)
        entryPoints.append(visualization.VisFileEntryPoint)

        return entryPoints

    @staticmethod
    @plugins.HOOKIMPL
    def defineCaseDependencies(case, suite):
        if case.cs["loadStyle"] == "fromDB":
            # the ([^\/]) capture basically gets the file name portion and excludes any
            # directory separator
            return case.getPotentialParentFromSettingValue(
                case.cs["reloadDBName"],
                r"^(?P<dirName>.*[\/\\])?(?P<title>[^\/\\]+?)(\.[hH]5)?$",
            )
        return None

    @staticmethod
    @plugins.HOOKIMPL
    def mpiActionRequiresReset(cmd) -> bool:
        """
        Prevent reactor resets after certain mpi actions.

        * Memory profiling is small enough that we don't want to reset
        * distributing state would be undone by this so we don't want that.

        See Also
        --------
        armi.operators.operatorMPI.OperatorMPI.workerOperate
        """
        from armi import mpiActions
        from armi.bookkeeping import memoryProfiler

        if isinstance(cmd, mpiActions.MpiAction):
            for donotReset in (
                mpiActions.DistributeStateAction,
                mpiActions.DistributionAction,
                memoryProfiler.PrintSystemMemoryUsageAction,
                memoryProfiler.ProfileMemoryUsageAction,
            ):
                if isinstance(cmd, donotReset):
                    return False

        return True


================================================
FILE: armi/bookkeeping/db/__init__.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
The db package is responsible for reading and writing the state of the reactor to/from disk.

As an ARMI run progresses, this is periodically updated as the primary output file.
It can also be an input file for follow-on analysis or restart runs.

This module contains factories for selecting and building DB-related objects.

When updating a db version
--------------------------
The code associated with reading and writing database files may not benefit from Don't
Repeat Yourself (DRY) practices in the same way as other code. Therefore, do not share
code between different major versions of the databases. Create a new module if you are
creating a new major database version.

Database revision changelog
---------------------------
 - 1: Originally, calculation results were stored in a SQL database.

 - 2: The storage format was changed to HDF5. This required less external
   infrastructure than SQL. However, the implementation did not store a complete
   model of a reactor, but a ghost of assembly, block, and reactor parameters that
   could be applied to an existing reactor model (so long as the dimensions were
   consistent). This was inconvenient and error prone.

 - 3: The HDF5 format was kept, but the schema was made more flexible to permit
   storing the entire reactor model. All objects in the ARMI Composite Model are
   written to the database, and the model can be completely recovered from just the
   HDF5 file.

     - 3.1: Improved the handling of reading/writing grids.

     - 3.2: Changed the strategy for storing large attributes to using a special
       string starting with an "@" symbol (e.g., "@/c00n00/attrs/5_linkedDims"). This
       was done to support copying time node datasets from one file to another without
       invalidating the references. Support was maintained for reading previous
       versions, by performing a ``mergeHistory()`` and converting to the new naming
       strategy, but the old version cannot be written.

     - 3.3: Compressed the way locations are stored in the database and allow
       MultiIndex locations to be read and written.

     - 3.4: Modified the way locations are stored in the database to include complete
       indices for indices that can be composed from multiple grids. Having complete
       indices allows for more efficient means of extracting information based on
       location, without having to compose the full model.
"""

import os

from armi import runLog
from armi.bookkeeping.db.compareDB3 import compareDatabases

# re-export package components for easier import
from armi.bookkeeping.db.database import Database
from armi.bookkeeping.db.databaseInterface import DatabaseInterface
from armi.bookkeeping.db.factory import databaseFactory

__all__ = [
    "Database",
    "DatabaseInterface",
    "compareDatabases",
    "databaseFactory",
]


def loadOperator(
    pathToDb,
    loadCycle,
    loadNode,
    statePointName=None,
    allowMissing=False,
    handleInvalids=True,
    callReactorConstructionHook=False,
):
    """
    Return an operator given the path to a database.

    Parameters
    ----------
    pathToDb : str
        The path of the database to load from.
    loadCycle : int
        The cycle to load the reactor state from.
    loadNode : int
        The time node to load the reactor from.
    statePointName: str
        State point name at the end, E.G. `EOC` or `EOL`.
        Full name would be C0N2EOC, see database.getH5GroupName
    allowMissing : bool
        Whether to emit a warning, rather than crash if reading a database
        with undefined parameters. Default False.
    handleInvalids : bool
        Whether to check for invalid settings. Default True.
    callReactorConstructionHook : bool
        Flag for whether the beforeReactorConstruction plugin hook should be executed. Default is False.

    See Also
    --------
    armi.operator.Operator.loadState:
        A method for loading reactor state that is useful if you already have an
        operator and a reactor object. loadOperator varies in that it supplies these
        given only a database file. loadState should be used if you are in the
        middle of an ARMI calculation and need load a different time step.

    Notes
    -----
    The operator will have a reactor attached that is loaded to the specified cycle
    and node. The operator will not be in the same state that it was at that cycle and
    node, only the reactor.

    Examples
    --------
    >>> o = db.loadOperator(r"pathToDatabase", 0, 1)
    >>> r = o.r
    >>> cs = o.cs
    >>> r.p.timeNode
    1
    >>> r.getFPMass()  # Note since it is loaded from step 1 there are fission products.
    12345.67
    """
    # `import armi` doesn't work if imported at top
    from armi import cases

    if not os.path.exists(pathToDb):
        raise ValueError(
            f"Specified database at path {pathToDb} does not exist. \n\n"
            "Double check that escape characters were correctly processed.\n"
            "Consider sending the full path, or change directory to be the directory "
            "of the database."
        )

    db = Database(pathToDb, "r")
    with db:
        # init Case here as it keeps track of execution time and assigns a reactor
        # attribute. This attribute includes the time it takes to initialize the reactor
        # so creating a reactor from the database should be included.
        cs = db.loadCS(handleInvalids=handleInvalids)
        thisCase = cases.Case(cs)
        r = db.load(
            loadCycle,
            loadNode,
            cs=cs,
            statePointName=statePointName,
            allowMissing=allowMissing,
            handleInvalids=handleInvalids,
            callReactorConstructionHook=callReactorConstructionHook,
        )

    o = thisCase.initializeOperator(r=r)
    runLog.important(
        "The operator will not be in the same state that it was at that cycle and "
        "node, only the reactor.\n"
        "The operator should have access to the same interface stack, but the "
        "interfaces will not be in the same state (they will be fresh instances "
        "of each interface as if __init__ was just called rather than the state "
        "during the run at this time node.)\n"
        "ARMI does not support loading operator states, as they are not stored."
    )
    return o


def _getH5File(db):
    """Return the underlying h5py File that provides the backing storage for a database.

    This is done here because HDF5 isn't an official aspect of the base Database
    abstraction, and thus making this part of the base Database class interface wouldn't
    be ideal. **However**, we violate this assumption when working with "auxiliary"
    data, which use HDF5 features directly. To be able to convert, we need to be able to
    access and copy these groups, so we need access to the HDF5 file under the hood. To
    avoid this, we would need to come up with our own formalization of what a
    storage-agnostic aux data concept looks like. We can tackle that if/when we decode
    that we want to start using protobufs or whatever.

    All this being said, we are probably violating this already with genAuxiliaryData,
    but we have to start somewhere.
    """
    if isinstance(db, Database):
        return db.h5db
    else:
        raise TypeError("Unsupported Database type ({})!".format(type(db)))


================================================
FILE: armi/bookkeeping/db/compareDB3.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Use the generic database class to compare two ARMI databases.

This assumes some intimate knowledge about how the database is structured internally.
For instance, it knows that the database is composed of HDF5 data (the attrs of a
dataset are used, and h5py Groups are indexed), and it knows how special data is
structured within the HDF5 dataset and what the corresponding attributes are used for.
Some of this could be easily pulled up to the public interfaces of the Database class,
which may allow for cross-version database checking, but there is probably little value
in doing so if one is able to convert between versions.

Speaking of conversions, there are some common issues that may arise from comparing
against databases that were converted from an old version. The process of reading in the
old database values can sometimes lead to more parameters being written out to the new
database than were in the original database (set to the parameter's default value). That
means that one generally should not be worried about a converted database having more
parameters in it that the one produced directly may not, assuming that the extra
converted parameters are the default. Also, especially at the Component level, some of
the parameters are expected to be different. Specifically the following:

* temperatures: The old database format simply did not store these on the component
  level, so when converting a database, the components in a block will uniformly get
  whatever the Block temperature was.
* serial numbers: At all levels, we cannot really expect the serial numbers to line
  up from object to object. These are not really supposed to be the same.
* volume: Component volumes also are not stored on the database, and come from
  temperatures
* memory usage: Relatively self-evident. Resource usage will vary from run to run,
  even if the code hasn't changed.

"""

import collections
import os
import re
import traceback
from typing import Optional, Pattern, Sequence, Tuple

import h5py
import numpy as np

from armi import runLog
from armi.bookkeeping.db import database
from armi.bookkeeping.db.database import Database
from armi.bookkeeping.db.factory import databaseFactory
from armi.bookkeeping.db.permissions import Permissions
from armi.reactor.composites import ArmiObject
from armi.utils.tabulate import tabulate


class OutputWriter:
    """Basically a tee to writeln to runLog and the output file."""

    def __init__(self, fname):
        self.fname = fname
        self._stream = None

    def __enter__(self):
        self._stream = open(self.fname, "w")
        return self

    def __exit__(self, *args):
        self._stream.close()

    def writeln(self, msg: str) -> None:
        runLog.info(msg)
        self._stream.write(msg)
        self._stream.write("\n")


class DiffResults:
    """Utility class for storing differences between database data.

    This class is used to store the differences between reference data and other
    ("source") data. It is configured with a tolerance, below which differences are
    ignored. Differences that exceed the tolerance are stored in a collection of
    differences, organized by time step to be outputted later. It also keeps track of
    the number of issues that may have been encountered in attempting to compare two
    databases. For instance, missing datasets on one database or the other, or datasets
    with incompatible dimensions and the like.

    All differences are based on a weird type of relative difference, which uses the
    mean of the reference and source data elements as the normalization value:
    2*(C-E)/(C+E). This is somewhat strange, in that if the two are very different, the
    reported relative difference will be smaller than expected. It does have the useful
    property that if the reference value is zero and the source value is non-zero, the
    diff will not be infinite. We do not typically report these in any rigorous manner,
    so this should be fine, though we may wish to revisit this in the future.
    """

    def __init__(self, tolerance):
        self._columns = []
        self._structureDiffs = []
        self.tolerance = tolerance
        # diffs is a dictionary, keyed on strings describing the object to which the
        # diffs apply, and the different diff metrics that we use (e.g. mean(abs(diff)),
        # max(abs(diff))), with the values being a list of diffs by time step. If the
        # diff doesn't exceed the tolerance, a None is inserted instead.
        self.diffs = collections.defaultdict(self._getDefault)

    def addDiff(self, compType: str, paramName: str, absMean: float, mean: float, absMax: float) -> None:
        """Add a collection of diffs to the diff dictionary if they exceed the tolerance."""
        absMean = absMean if absMean > self.tolerance else None
        self.diffs["{}/{} mean(abs(diff))".format(compType, paramName)].append(absMean)

        mean = mean if abs(mean) > self.tolerance else None
        self.diffs["{}/{} mean(diff)".format(compType, paramName)].append(mean)

        absMax = absMax if absMax > self.tolerance else None
        self.diffs["{}/{} max(abs(diff))".format(compType, paramName)].append(absMax)

    def addStructureDiffs(self, nDiffs: int) -> None:
        if not self._structureDiffs:
            self._structureDiffs = [0]

        self._structureDiffs[-1] += nDiffs

    def addTimeStep(self, tsName: str) -> None:
        self._structureDiffs.append(0)
        self._columns.append(tsName)

    def _getDefault(self) -> list:
        return [None] * (len(self._columns) - 1)

    def reportDiffs(self, stream: OutputWriter) -> None:
        """Print out a well-formatted table of the non-zero diffs."""
        # filter out empty rows
        diffsToPrint = {key: value for key, value in self.diffs.items() if not all(v is None for v in value)}
        stream.writeln(
            tabulate(
                [k.split() + val for k, val in sorted(diffsToPrint.items())],
                headers=self._columns,
            )
        )

    def nDiffs(self) -> int:
        """Return the number of differences that exceeded the tolerance."""
        return sum(1 for _, value in self.diffs.items() if any(v is not None for v in value)) + sum(
            self._structureDiffs
        )


def compareDatabases(
    refFileName: str,
    srcFileName: str,
    exclusions: Optional[Sequence[str]] = None,
    tolerance: float = 0.0,
    timestepCompare: Optional[Sequence[Tuple[int, int]]] = None,
) -> Optional[DiffResults]:
    """High-level method to compare two ARMI H5 files, given file paths."""
    compiledExclusions = None
    if exclusions is not None:
        compiledExclusions = [re.compile(ex) for ex in exclusions]

    outputName = os.path.basename(refFileName) + "_vs_" + os.path.basename(srcFileName) + ".txt"

    diffResults = DiffResults(tolerance)
    with OutputWriter(outputName) as out:
        ref = databaseFactory(refFileName, Permissions.READ_ONLY_FME)
        src = databaseFactory(srcFileName, Permissions.READ_ONLY_FME)
        if not isinstance(ref, Database) or not isinstance(src, Database):
            raise TypeError(
                "This database comparer only knows how to deal with database version 3; received {} and {}".format(
                    type(ref), type(src)
                )
            )

        with ref, src:
            if not timestepCompare:
                _, nDiff = _compareH5Groups(out, ref, src, "timesteps")

                if nDiff > 0:
                    runLog.warning(
                        "{} and {} have differing timestep groups, and are "
                        "probably not safe to compare. This is likely due to one of "
                        "the cases having failed to complete.".format(ref, src)
                    )
                    return None

            for refGroup, srcGroup in zip(
                ref.genTimeStepGroups(timeSteps=timestepCompare),
                src.genTimeStepGroups(timeSteps=timestepCompare),
            ):
                runLog.info(
                    f"Comparing ref time step {refGroup.name.split('/')[1]} to src time "
                    f"step {srcGroup.name.split('/')[1]}"
                )
                diffResults.addTimeStep(refGroup.name)
                _compareTimeStep(out, refGroup, srcGroup, diffResults, exclusions=compiledExclusions)

        diffResults.reportDiffs(out)

    return diffResults


def _compareH5Groups(out: OutputWriter, ref: h5py.Group, src: h5py.Group, name: str) -> Tuple[Sequence[str], int]:
    refGroups = set(ref.keys())
    srcGroups = set(src.keys())

    n = _compareSets(srcGroups, refGroups, out, name)

    return sorted(refGroups & srcGroups), n


def _compareTimeStep(
    out: OutputWriter,
    refGroup: h5py.Group,
    srcGroup: h5py.Group,
    diffResults: DiffResults,
    exclusions: Optional[Sequence[Pattern]] = None,
):
    groupNames, structDiffs = _compareH5Groups(out, refGroup, srcGroup, "composite objects/auxiliary data")
    diffResults.addStructureDiffs(structDiffs)

    componentTypes = {gn for gn in groupNames if gn in ArmiObject.TYPES}
    auxData = set(groupNames) - componentTypes
    auxData.discard("layout")

    for componentType in componentTypes:
        refTypeGroup = refGroup[componentType]
        srcTypeGroup = srcGroup[componentType]

        _compareComponentData(out, refTypeGroup, srcTypeGroup, diffResults, exclusions=exclusions)

    for aux in auxData:
        _compareAuxData(out, refGroup[aux], srcGroup[aux], diffResults)


def _compareAuxData(
    out: OutputWriter,
    refGroup: h5py.Group,
    srcGroup: h5py.Group,
    diffResults: DiffResults,
):
    """
    Compare auxiliary datasets, which aren't stored as Parameters on the Composite model.

    Some parts of ARMI directly create HDF5 groups under the time step group to store
    arbitrary data. These still need to be compared. Missing datasets will be treated as
    structure differences and reported.
    """
    data = dict()

    def visitor(name, obj):
        if isinstance(obj, h5py.Dataset):
            data[name] = obj

    refGroup.visititems(visitor)
    refData = data

    data = dict()
    srcGroup.visititems(visitor)
    srcData = data

    n = _compareSets(set(srcData.keys()), set(refData.keys()), out, name="auxiliary dataset")
    diffResults.addStructureDiffs(n)
    matchedSets = set(srcData.keys()) & set(refData.keys())
    for name in matchedSets:
        _diffSimpleData(refData[name], srcData[name], diffResults)


def _compareSets(src: set, ref: set, out: OutputWriter, name: Optional[str] = None) -> int:
    nDiffs = 0
    printName = "" if name is None else name + " "
    if ref - src:
        nDiffs += len(ref - src)
        out.writeln("ref has {}not in src: {}".format(printName, list(ref - src)))

    if src - ref:
        nDiffs += len(src - ref)
        out.writeln("src has {}not in ref: {}".format(printName, list(src - ref)))

    return nDiffs


def _diffSpecialData(
    refData: h5py.Dataset,
    srcData: h5py.Dataset,
    out: OutputWriter,
    diffResults: DiffResults,
):
    """
    Compare specially-formatted datasets.

    This employs the pack/unpackSpecialData functions to reconstitute complicated
    datasets for comparison. These usually don't behave well as giant numpy arrays, so
    we go element-by-element to calculate the diffs, then concatenate them.
    """
    name = refData.name
    paramName = refData.name.split("/")[-1]
    compName = refData.name.split("/")[-2]

    nDiffs = _compareSets(set(srcData.attrs.keys()), set(refData.attrs.keys()), out, "formatting data")
    keysMatch = nDiffs == 0
    diffResults.addStructureDiffs(nDiffs)

    if not keysMatch:
        diffResults.addDiff(name, name, np.inf, np.inf, np.inf)
        return

    if srcData.attrs.get("dict", False):
        out.writeln(f"Not comparing {name} as it is a dictionary.")
        return

    attrsMatch = True
    for k, srcAttr in srcData.attrs.items():
        refAttr = refData.attrs[k]

        if isinstance(srcAttr, np.ndarray) and isinstance(refAttr, np.ndarray):
            srcFlat = srcAttr.flatten()
            refFlat = refAttr.flatten()
            if len(srcFlat) != len(refFlat):
                same = False
            else:
                same = all(srcFlat == refFlat)
        else:
            same = srcAttr == refAttr

        if not same:
            attrsMatch = False
            out.writeln(
                "Special formatting parameters for {} do not match for {}. Src: {} Ref: {}".format(
                    name, k, srcData.attrs[k], refData.attrs[k]
                )
            )
            break

    if not attrsMatch:
        diffResults.addDiff(compName, paramName, np.inf, np.inf, np.inf)
        return

    try:
        src = database.unpackSpecialData(srcData[()], srcData.attrs, paramName)
        ref = database.unpackSpecialData(refData[()], refData.attrs, paramName)
    except Exception:
        runLog.error(
            f"Unable to unpack special data for paramName {paramName}. {traceback.format_exc()}",
        )
        return

    diff = []
    for dSrc, dRef in zip(src.tolist(), ref.tolist()):
        if isinstance(dSrc, np.ndarray) and isinstance(dRef, np.ndarray):
            if dSrc.shape != dRef.shape:
                out.writeln("Shapes did not match for {}".format(refData))
                diffResults.addDiff(compName, paramName, np.inf, np.inf, np.inf)
                return

            if dSrc.dtype.type == np.bytes_ or dRef.dtype.type == np.bytes_:
                # data is byte strings; can't be diffed like numbers
                if np.array_equal(dSrc, dRef):
                    diffResults.addDiff(name, name, 0.0, 0.0, 0.0)
                else:
                    diffResults.addDiff(name, name, np.inf, np.inf, np.inf)
                return

            # Make sure not to try to compare empty arrays. Numpy is mediocre at these;
            # they are super degenerate and cannot participate in concatenation.
            if 0 not in dSrc.shape:
                # Use the mean of the two to calc relative error. This is more robust to
                # changes that cause one of the values to be zero, while the other is
                # non-zero, leading to infinite relative error
                dMean = (dSrc + dRef) / 2
                diff.append((dSrc - dRef) / dMean)
            continue

        if (dSrc is None) ^ (dRef is None):
            out.writeln("Mismatched Nones for {} in {}".format(paramName, compName))
            diff.append([np.inf])
            continue

        if dSrc is None:
            diff.append([0.0])
            continue

        try:
            # Use mean to avoid some infinities; see above
            dMean = (dSrc + dRef) / 2
            diff.append([(dSrc - dRef) / dMean])
        except ZeroDivisionError:
            if dSrc == dRef:
                diff.append([0.0])
            else:
                diff.append([np.inf])

    if diff:
        try:
            diff = [np.array(d).flatten() for d in diff]
            diff = np.concatenate(diff)
        except ValueError as e:
            out.writeln("Failed to concatenate diff data for {} in {}: {}".format(paramName, compName, diff))
            out.writeln("Because: {}".format(e))
            return
        absDiff = np.abs(diff)
        mean = np.nanmean(diff)
        absMax = np.nanmax(absDiff)
        absMean = np.nanmean(absDiff)

        diffResults.addDiff(compName, paramName, absMean, mean, absMax)


def _diffSimpleData(ref: h5py.Dataset, src: h5py.Dataset, diffResults: DiffResults):
    paramName = ref.name.split("/")[-1]
    compName = ref.name.split("/")[-2]

    try:
        # use mean to avoid some unnecessary infinities
        mean = (src[()] + ref[()]) / 2.0
        diff = (src[()] - ref[()]) / mean
    except TypeError:
        # Strings are persnickety
        if src.dtype.kind == ref.dtype.kind and src.dtype.kind in {"U", "S"}:
            return
        else:
            runLog.error("Failed to compare {} in {}".format(paramName, compName))
            runLog.error("source: {}".format(src))
            runLog.error("reference: {}".format(ref))
            diff = np.array([np.inf])
    except ValueError:
        runLog.error("Failed to compare {} in {}".format(paramName, compName))
        runLog.error("source: {}".format(src))
        runLog.error("reference: {}".format(ref))
        diff = np.array([np.inf])

    if 0 in diff.shape:
        # Empty list, no diff
        return

    absDiff = np.abs(diff)
    mean = np.nanmean(diff)
    absMax = np.nanmax(absDiff)
    absMean = np.nanmean(absDiff)

    diffResults.addDiff(compName, paramName, absMean, mean, absMax)


def _compareComponentData(
    out: OutputWriter,
    refGroup: h5py.Group,
    srcGroup: h5py.Group,
    diffResults: DiffResults,
    exclusions: Optional[Sequence[Pattern]] = None,
):
    exclusions = exclusions or []
    compName = refGroup.name
    paramNames, nDiff = _compareH5Groups(out, refGroup, srcGroup, "{} parameters".format(compName))
    diffResults.addStructureDiffs(nDiff)

    for paramName in paramNames:
        fullName = "/".join((refGroup.name, paramName))
        if any(pattern.match(fullName) for pattern in exclusions):
            runLog.debug("Skipping comparison of {} since it is being ignored.".format(fullName))
            continue
        refDataset = refGroup[paramName]
        srcDataset = srcGroup[paramName]

        srcSpecial = srcDataset.attrs.get("specialFormatting", False)
        refSpecial = refDataset.attrs.get("specialFormatting", False)

        if srcSpecial ^ refSpecial:
            out.writeln(
                "Could not compare data for parameter {} because one uses special "
                "formatting, and the other does not. Ref: {} Src: {}".format(paramName, refSpecial, srcSpecial)
            )
            diffResults.addDiff(refGroup.name, paramName, np.inf, np.inf, np.inf)
            continue

        if srcSpecial or refSpecial:
            _diffSpecialData(refDataset, srcDataset, out, diffResults)
        else:
            _diffSimpleData(refDataset, srcDataset, diffResults)


================================================
FILE: armi/bookkeeping/db/database.py
================================================
# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
ARMI Database implementation, version 3.4.

A reactor model should be fully recoverable from the database; all the way down to the component level. As a result, the
structure of the underlying data is bound to the hierarchical Composite Reactor Model. Furthermore, this database format
is intended to be more dynamic, permitting as-yet undeveloped levels and classes in the Composite Reactor Model to be
supported as they are added. More high-level discussion is contained in :ref:`database-file`.

The :py:class:`Database` class contains most of the functionality for interacting with the underlying data. This
includes things like dumping a Reactor state to the database and loading it back again, as well as extracting historical
data for a given object or collection of object from the database file. However, for the nitty-gritty details of how the
hierarchical Composite Reactor Model is translated to the flat file database, please refer to
:py:mod:`armi.bookkeeping.db.layout`.

Refer to :py:mod:`armi.bookkeeping.db` for information about versioning.
"""

import collections
import copy
import gc
import io
import itertools
import os
import pathlib
import re
import shutil
import subprocess
import sys
from platform import uname
from typing import (
    Any,
    Dict,
    Generator,
    List,
    Optional,
    Sequence,
    Tuple,
    Type,
    Union,
)

import h5py
import numpy as np

from armi import context, getApp, getPluginManagerOrFail, meta, runLog, settings
from armi.bookkeeping.db.jaggedArray import JaggedArray
from armi.bookkeeping.db.layout import (
    DB_VERSION,
    LOC_COORD,
    Layout,
    replaceNonesWithNonsense,
    replaceNonsenseWithNones,
)
from armi.bookkeeping.db.typedefs import Histories, History
from armi.physics.neutronics.settings import CONF_LOADING_FILE
from armi.reactor import grids, parameters
from armi.reactor.assemblies import Assembly
from armi.reactor.blocks import Block
from armi.reactor.components import Component
from armi.reactor.composites import ArmiObject
from armi.reactor.parameters import parameterCollections
from armi.reactor.reactorParameters import makeParametersReadOnly
from armi.reactor.reactors import Core, Reactor
from armi.settings.fwSettings.globalSettings import (
    CONF_GROW_TO_FULL_CORE_AFTER_LOAD,
    CONF_SORT_REACTOR,
)
from armi.utils import getNodesPerCycle, safeCopy, safeMove
from armi.utils.textProcessors import resolveMarkupInclusions

# CONSTANTS
_SERIALIZER_NAME = "serializerName"
_SERIALIZER_VERSION = "serializerVersion"


def getH5GroupName(cycle: int, timeNode: int, statePointName: str = None) -> str:
    """
    Naming convention specifier.

    ARMI defines the naming convention cXXnYY for groups of simulation data. That is, data is grouped by cycle and time
    node information during a simulated run.
    """
    return "c{:0>2}n{:0>2}{}".format(cycle, timeNode, statePointName or "")


class Database:
    """
    ARMI Database, handling serialization and loading of Reactor states.

    This implementation of the database pushes all objects in the Composite Reactor Model into the database. This
    process is aided by the ``Layout`` class, which handles the packing and unpacking of the structure of the objects,
    their relationships, and their non-parameter attributes.

    .. impl:: The database files are H5, and thus language agnostic.
        :id: I_ARMI_DB_H51
        :implements: R_ARMI_DB_H5

        This class implements a light wrapper around H5 files, so they can be used to store ARMI outputs. H5 files are
        commonly used in scientific applications in Fortran and C++. As such, they are entirely language agnostic binary
        files. The implementation here is that ARMI wraps the ``h5py`` library, and uses its extensive tooling, instead
        of re-inventing the wheel.

    See Also
    --------
    `doc/user/outputs/database` for more details.
    """

    # Allows matching for, e.g., c01n02EOL
    timeNodeGroupPattern = re.compile(r"^c(\d\d)n(\d\d).*$")

    def __init__(self, fileName: os.PathLike, permission: str = "r"):
        """
        Create a new Database object.

        Parameters
        ----------
        fileName:
            name of the file
        permission:
            file permissions, write ("w") or read ("r")
        """
        self._fileName = fileName
        # No full path yet; we will determine this based on FAST_PATH and permissions
        self._fullPath: Optional[str] = None
        self._permission = permission
        self.h5db: Optional[h5py.File] = None

        # Allows context management on open files. If context management is used on a file that is already open, it will
        # not reopen and it will also not close after leaving that context. This allows the treatment of all databases
        # the same whether they are open or closed.
        self._openCount: int = 0

        if permission == "w":
            self.version = DB_VERSION
        else:
            # will be set upon read
            self._version = None
            self._versionMajor = None
            self._versionMinor = None

    @property
    def version(self) -> str:
        return self._version

    @version.setter
    def version(self, value: str):
        self._version = value
        self._versionMajor, self._versionMinor = (int(v) for v in value.split("."))
        if self.versionMajor != 3:
            raise ValueError(f"This version of ARMI only supports version 3 of the ARMI DB, found {self.versionMajor}.")

    @property
    def versionMajor(self):
        return self._versionMajor

    @property
    def versionMinor(self):
        return self._versionMinor

    def __repr__(self):
        return "<{} {}>".format(self.__class__.__name__, repr(self.h5db).replace("<", "").replace(">", ""))

    def open(self):
        if self.h5db is not None:
            raise ValueError("This database is already open; make sure to close it before trying to open it again.")

        filePath = self._fileName
        self._openCount += 1

        if self._permission in {"r", "a"}:
            self._fullPath = os.path.abspath(filePath)
            self.h5db = h5py.File(filePath, self._permission)
            self.version = self.h5db.attrs["databaseVersion"]
            return

        if self._permission == "w":
            # assume fast path!
            filePath = os.path.join(context.getFastPath(), filePath)
            self._fullPath = os.path.abspath(filePath)

        else:
            runLog.error(f"Unrecognized file permissions `{self._permission}`")
            raise ValueError(f"Cannot open database with permission `{self._permission}`")

        # open the database, and write a bunch of metadata to it
        runLog.info("Opening database file at {}".format(os.path.abspath(filePath)))
        self.h5db = h5py.File(filePath, self._permission)
        self.h5db.attrs["successfulCompletion"] = False
        self.h5db.attrs["version"] = meta.__version__
        self.h5db.attrs["databaseVersion"] = self.version
        self.writeSystemAttributes(self.h5db)

        # store app and plugin data
        app = getApp()
        self.h5db.attrs["appName"] = app.name
        plugins = app.pluginManager.list_name_plugin()
        ps = [(os.path.abspath(sys.modules[p[1].__module__].__file__), p[1].__name__) for p in plugins]
        ps = np.array([str(p[0]) + ":" + str(p[1]) for p in ps]).astype("S")
        self.h5db.attrs["pluginPaths"] = ps
        self.h5db.attrs["localCommitHash"] = Database.grabLocalCommitHash()

    def isOpen(self):
        return self.h5db is not None

    @staticmethod
    def writeSystemAttributes(h5db):
        """Write system attributes to the database.

        .. impl:: Add system attributes to the database.
            :id: I_ARMI_DB_QA
            :implements: R_ARMI_DB_QA

            This method writes some basic system information to the H5 file. This is designed as a starting point, so
            users can see information about the system their simulations were run on. As ARMI is used on Windows and
            Linux, the tooling here has to be platform independent. The two major sources of information are the ARMI
            :py:mod:`context <armi.context>` module and the Python standard library ``platform``.
        """
        h5db.attrs["user"] = context.USER
        h5db.attrs["python"] = sys.version
        h5db.attrs["armiLocation"] = os.path.dirname(context.ROOT)
        h5db.attrs["startTime"] = context.START_TIME
        h5db.attrs["machines"] = np.array(context.MPI_NODENAMES).astype("S")

        # store platform data
        platform_data = uname()
        h5db.attrs["platform"] = platform_data.system
        h5db.attrs["hostname"] = platform_data.node
        h5db.attrs["platformRelease"] = platform_data.release
        h5db.attrs["platformVersion"] = platform_data.version
        h5db.attrs["platformArch"] = platform_data.processor

    @staticmethod
    def grabLocalCommitHash():
        """
        Try to determine the local Git commit.

        We have to be sure to handle the errors where the code is run on a system that doesn't have Git installed. Or if
        the code is simply not run from inside a repo.

        Returns
        -------
        str
            The commit hash if it exists, otherwise "unknown".
        """
        unknown = "unknown"
        if not shutil.which("git"):
            # no git available. cannot check git info
            return unknown
        repo_exists = (
            subprocess.run(
                "git rev-parse --git-dir".split(),
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            ).returncode
            == 0
            and subprocess.run(
                ["git", "describe"],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            ).returncode
            == 0
        )
        if repo_exists:
            try:
                commit_hash = subprocess.check_output(["git", "describe"])
                return commit_hash.decode("utf-8").strip()
            except Exception:
                return unknown
        else:
            return unknown

    def close(self, completedSuccessfully=False):
        """Close the DB and perform cleanups and auto-conversions."""
        self._openCount = 0
        if self.h5db is None:
            return

        if self._permission == "w":
            self.h5db.attrs["successfulCompletion"] = completedSuccessfully
            # a bit redundant to call flush, but with unreliable IO issues, why not?
            self.h5db.flush()

        self.h5db.close()
        self.h5db = None

        if self._permission == "w":
            # move out of the FAST_PATH and into the working directory
            newPath = safeMove(self._fullPath, self._fileName)
            self._fullPath = os.path.abspath(newPath)

    def splitDatabase(self, keepTimeSteps: Sequence[Tuple[int, int]], label: str) -> str:
        """
        Discard all data except for specific time steps, retaining old data in a separate file.

        This is useful when performing more exotic analyses, where each "time step" may not represent a specific point
        in time, but something more nuanced. For example, equilibrium cases store a new "cycle" for each iteration as it
        attempts to converge the equilibrium cycle. At the end of the run, the last "cycle" is the converged equilibrium
        cycle, whereas the previous cycles constitute the path to convergence, which we typically wish to discard before
        further analysis.

        Parameters
        ----------
        keepTimeSteps
            A collection of the time steps to retain
        label
            An informative label for the backed-up database. Usually something like "-all-iterations". Will be
            interposed between the source name and the ".h5" extension.

        Returns
        -------
        str
            The name of the new, backed-up database file.
        """
        if self.h5db is None:
            raise ValueError("There is no open database to split.")

        self.h5db.close()

        backupDBPath = os.path.abspath(label.join(os.path.splitext(self._fileName)))
        runLog.info(f"Retaining full database history in {backupDBPath}")
        if self._fullPath is not None:
            safeMove(self._fullPath, backupDBPath)

        self.h5db = h5py.File(self._fullPath, self._permission)
        dbOut = self.h5db

        with h5py.File(backupDBPath, "r") as dbIn:
            dbOut.attrs.update(dbIn.attrs)

            # Copy everything except time node data
            timeSteps = set()
            for groupName, _ in dbIn.items():
                m = self.timeNodeGroupPattern.match(groupName)
                if m:
                    timeSteps.add((int(m.group(1)), int(m.group(2))))
                else:
                    dbIn.copy(groupName, dbOut)

            if not set(keepTimeSteps).issubset(timeSteps):
                raise ValueError(f"Not all desired time steps ({keepTimeSteps}) are even present in the database")

            minCycle = next(iter(sorted(keepTimeSteps)))[0]
            for cycle, node in keepTimeSteps:
                offsetCycle = cycle - minCycle
                offsetGroupName = getH5GroupName(offsetCycle, node)
                dbIn.copy(getH5GroupName(cycle, node), dbOut, name=offsetGroupName)
                dbOut[offsetGroupName + "/Reactor/cycle"][()] = offsetCycle

        return backupDBPath

    @property
    def fileName(self):
        return self._fileName

    @fileName.setter
    def fileName(self, fName):
        if self.h5db is not None:
            raise RuntimeError("Cannot change Database file name while it's opened!")
        self._fileName = fName

    def loadCS(self, handleInvalids=True):
        """Attempt to load settings from the database file.

        Parameters
        ----------
        handleInvalids : bool
            Whether to check for invalid settings. Default True.

        Notes
        -----
        There are no guarantees here. If the database was written from a different version of ARMI than you are using,
        these results may not be usable. Or if the database was written using a custom Application you do not have
        access to, the DB may not be usable.
        """
        cs = settings.Settings()
        cs.path = self.fileName
        cs.loadFromString(self.h5db["inputs/settings"].asstr()[()], handleInvalids=handleInvalids)

        return cs

    def loadBlueprints(self, cs=None):
        """Attempt to load reactor blueprints from the database file.

        Notes
        -----
        There are no guarantees here. If the database was written from a different version of ARMI than you are using,
        these results may not be usable. Or if the database was written using a custom Application you do not have
        access to, the DB may not be usable.
        """
        # Blueprints use the yamlize package, which uses class attributes to define much of the class's behavior through
        # metaclassing. Therefore, we need to be able to import all plugins before importing blueprints.
        from armi.reactor.blueprints import Blueprints

        bpString = None

        try:
            bpString = self.h5db["inputs/blueprints"].asstr()[()]
            # Need to update the blueprint file to be the database so that its not pointing at a source that doesn't
            # exist anymore (the original blueprints yaml).
            if cs:
                # Update the settings to point at where the file was actually read from
                cs[CONF_LOADING_FILE] = os.path.basename(self.fileName)
        except KeyError:
            # not all reactors need to be created from blueprints, so they may not exist
            pass

        if not bpString:
            # looks like no blueprints contents
            return None

        stream = io.StringIO(bpString)
        stream = Blueprints.migrate(stream)
        return Blueprints.load(stream)

    def writeInputsToDB(self, cs, csString=None, bpString=None):
        """
        Write inputs into the database based the Settings.

        This is not DRY on purpose. The goal is that any particular Database implementation should be very stable, so we
        dont want it to be easy to change one Database implementation's behavior when trying to change another's.

        .. impl:: The run settings are saved the settings file.
            :id: I_ARMI_DB_CS
            :implements: R_ARMI_DB_CS

            A ``Settings`` object is passed into this method, and then the settings are converted into a YAML string
            stream. That stream is then written to the H5 file. Optionally, this method can take a pre-build settings
            string to be written directly to the file.

        .. impl:: The reactor blueprints are saved the settings file.
            :id: I_ARMI_DB_BP
            :implements: R_ARMI_DB_BP

            A ``Blueprints`` string is optionally passed into this method, and then written to the H5 file. If it is not
            passed in, this method will attempt to find the blueprints input file in the settings, and read the contents
            of that file into a stream to be written to the H5 file.

        Notes
        -----
        This is hard-coded to read the entire file contents into memory and write that directly into the database. We
        could have the cs/blueprints/geom write to a string, however the ARMI log file contains a hash of each files'
        contents. In the future, we should be able to reproduce a calculation with confidence that the inputs are
        identical.
        """
        caseTitle = cs.caseTitle if cs is not None else os.path.splitext(self.fileName)[0]
        self.h5db.attrs["caseTitle"] = caseTitle
        if csString is None:
            # Don't read file; use what's in the cs now. Sometimes settings are modified in tests.
            stream = io.StringIO()
            cs.writeToYamlStream(stream)
            stream.seek(0)
            csString = stream.read()

        if bpString is None:
            bpPath = pathlib.Path(cs.inputDirectory) / cs[CONF_LOADING_FILE]
            if bpPath.suffix.lower() in (".h5", ".hdf5"):
                # The blueprints are in a database file, they need to be read
                try:
                    db = h5py.File(bpPath, "r")
                    bpString = db["inputs/blueprints"].asstr()[()]
                except KeyError:
                    # not all reactors need to be created from blueprints, so they may not exist
                    bpString = ""
            else:
                # The blueprints are a standard blueprints yaml that can be read.
                if bpPath.exists() and bpPath.is_file():
                    # Only store blueprints if we actually loaded from them. Ensure that the input as stored in the DB
                    # is complete
                    bpString = resolveMarkupInclusions(pathlib.Path(cs.inputDirectory) / cs[CONF_LOADING_FILE]).read()
                else:
                    bpString = ""

        self.h5db["inputs/settings"] = csString
        self.h5db["inputs/blueprints"] = bpString

    def readInputsFromDB(self):
        return (
            self.h5db["inputs/settings"].asstr()[()],
            self.h5db["inputs/blueprints"].asstr()[()],
        )

    def mergeHistory(self, inputDB, startCycle, startNode):
        """
        Copy time step data up to, but not including the passed cycle and node.

        Notes
        -----
        This is used for restart runs with the standard operator for example. The current time step (being loaded from)
        should not be copied, as that time steps data will be written at the end of the time step.
        """
        if self.versionMajor != 3:
            raise ValueError(f"Only version 3 of the ARMI DB is supported, found {self.versionMajor}.")
        elif inputDB.versionMajor != 3:
            raise ValueError(f"Only version 3 of the ARMI DB is supported, found {inputDB.versionMajor}.")

        # iterate over the top level H5Groups and copy
        for time, h5ts in zip(inputDB.genTimeSteps(), inputDB.genTimeStepGroups()):
            cyc, tn = time
            if cyc == startCycle and tn == startNode:
                # all data up to current state are merged
                return
            self.h5db.copy(h5ts, h5ts.name)

    def __enter__(self):
        """Context management support."""
        if self._openCount == 0:
            # open also increments _openCount
            self.open()
        else:
            self._openCount += 1

        return self

    def __exit__(self, type, value, traceback):
        """Typically we don't care why it broke but we want the DB to close."""
        self._openCount -= 1
        # always close if there is a traceback.
        if self._openCount == 0 or traceback:
            self.close(all(i is None for i in (type, value, traceback)))

    def __del__(self):
        if self.h5db is not None:
            self.close(False)

    def __delitem__(self, tn: Tuple[int, int, Optional[str]]):
        cycle, timeNode, statePointName = tn
        name = getH5GroupName(cycle, timeNode, statePointName)
        if self.h5db is not None:
            del self.h5db[name]

    def genTimeStepGroups(
        self, timeSteps: Sequence[Tuple[int, int]] = None
    ) -> Generator[h5py._hl.group.Group, None, None]:
        """Returns a generator of HDF5 Groups for all time nodes, or for the passed selection."""
        assert self.h5db is not None, "Must open the database before calling genTimeStepGroups"
        if timeSteps is None:
            for groupName, h5TimeNodeGroup in sorted(self.h5db.items()):
                match = self.timeNodeGroupPattern.match(groupName)
                if match:
                    yield h5TimeNodeGroup
        else:
            for step in timeSteps:
                yield self.h5db[getH5GroupName(*step)]

    def getLayout(self, cycle, node):
        """Return a Layout object representing the requested cycle and time node."""
        version = (self._versionMajor, self._versionMinor)
        timeGroupName = getH5GroupName(cycle, node)

        return Layout(version, self.h5db[timeGroupName])

    def genTimeSteps(self) -> Generator[Tuple[int, int], None, None]:
        """Returns a generator of (cycle, node) tuples that are present in the DB."""
        assert self.h5db is not None, "Must open the database before calling genTimeSteps"
        for groupName in sorted(self.h5db.keys()):
            match = self.timeNodeGroupPattern.match(groupName)
            if match:
                cycle = int(match.groups()[0])
                node = int(match.groups()[1])
                yield (cycle, node)

    def genAuxiliaryData(self, ts: Tuple[int, int]) -> Generator[str, None, None]:
        """Returns a generator of names of auxiliary data on the requested time point."""
        assert self.h5db is not None, "Must open the database before calling genAuxiliaryData"
        cycle, node = ts
        groupName = getH5GroupName(cycle, node)
        timeGroup = self.h5db[groupName]
        exclude = set(ArmiObject.TYPES.keys())
        exclude.add("layout")
        return (groupName + "/" + key for key in timeGroup.keys() if key not in exclude)

    @staticmethod
    def getAuxiliaryDataPath(ts: Tuple[int, int], name: str) -> str:
        return getH5GroupName(*ts) + "/" + name

    def keys(self):
        return (g.name for g in self.genTimeStepGroups())

    def getH5Group(self, r, statePointName=None):
        """
        Get the H5Group for the current ARMI timestep.

        This method can be used to allow other interfaces to place data into the database at the correct timestep.
        """
        groupName = getH5GroupName(r.p.cycle, r.p.timeNode, statePointName)
        if groupName in self.h5db:
            return self.h5db[groupName]
        else:
            group = self.h5db.create_group(groupName, track_order=True)
            group.attrs["cycle"] = r.p.cycle
            group.attrs["timeNode"] = r.p.timeNode
            return group

    def hasTimeStep(self, cycle, timeNode, statePointName=""):
        """Returns True if (cycle, timeNode, statePointName) is contained in the database."""
        return getH5GroupName(cycle, timeNode, statePointName) in self.h5db

    def writeToDB(self, reactor, statePointName=None):
        assert self.h5db is not None, "Database must be open before writing."
        # _createLayout is recursive
        h5group = self.getH5Group(reactor, statePointName)
        runLog.info("Writing to database for statepoint: {}".format(h5group.name))
        layout = Layout((self.versionMajor, self.versionMinor), comp=reactor)
        layout.writeToDB(h5group)
        groupedComps = layout.groupedComps

        for comps in groupedComps.values():
            self._writeParams(h5group, comps)

    def syncToSharedFolder(self):
        """
        Copy DB to run working directory.

        Needed when multiple MPI processes need to read the same db, for example when a history is needed from
        independent runs (e.g. for fuel performance on a variety of assemblies).

        Notes
        -----
        At some future point, we may implement a client-server like DB system which would render this kind of operation
        unnecessary.
        """
        runLog.extra("Copying DB to shared working directory.")
        self.h5db.flush()

        # Close the h5 file so it can be copied
        self.h5db.close()
        self.h5db = None
        safeCopy(self._fullPath, self._fileName)

        # Garbage collect so we don't have multiple databases hanging around in memory
        gc.collect()

        # Reload the file in append mode and continue on our merry way
        self.h5db = h5py.File(self._fullPath, "r+")

    def load(
        self,
        cycle,
        node,
        cs=None,
        bp=None,
        statePointName=None,
        allowMissing=False,
        handleInvalids=True,
        callReactorConstructionHook=False,
    ):
        """Load a new reactor from a DB at (cycle, node).

        Case settings and blueprints can be provided, or read from the database. Providing  can be useful for snapshot
        runs or when you want to change settings mid-simulation. Geometry is read from the database.

        .. impl:: Users can load a reactor from a DB.
            :id: I_ARMI_DB_TIME1
            :implements: R_ARMI_DB_TIME

            This method creates a ``Reactor`` object by reading the reactor state out of an ARMI database file. This is
            done by passing in mandatory arguments that specify the exact place in time you want to load the reactor
            from. (That is, the cycle and node numbers.) Users can either pass the settings and blueprints directly into
            this method, or it will attempt to read them from the database file. The primary work done here is to read
            the hierarchy of reactor objects from the data file, then reconstruct them in the correct order.

        Parameters
        ----------
        cycle : int
            Cycle number
        node : int
            Time node. If value is negative, will be indexed from EOC backwards like a list.
        cs : armi.settings.Settings, optional
            If not provided one is read from the database
        bp : armi.reactor.Blueprints, optional
            If not provided one is read from the database
        statePointName : str, optional
            Statepoint name (e.g., "special" for "c00n00-special/")
        allowMissing : bool, optional
            Whether to emit a warning, rather than crash if reading a database
            with undefined parameters. Default False.
        handleInvalids : bool
            Whether to check for invalid settings. Default True.
        callReactorConstructionHook : bool
            Flag for whether the beforeReactorConstruction plugin hook should be executed. Default is False.

        Returns
        -------
        root : Reactor
            The top-level object stored in the database; a Reactor.
        """
        runLog.info(f"Loading reactor state for time node ({cycle}, {node})")

        if cs is None:
            cs = self.loadCS(handleInvalids=handleInvalids)
        if bp is None:
            bp = self.loadBlueprints(cs)

        if callReactorConstructionHook:
            getPluginManagerOrFail().hook.beforeReactorConstruction(cs=cs)

        if node < 0:
            numNodes = getNodesPerCycle(cs)[cycle]
            if (node + numNodes) < 0:
                raise ValueError(f"Node {node} specified does not exist for cycle {cycle}")
            node = numNodes + node

        h5group = self.h5db[getH5GroupName(cycle, node, statePointName)]

        layout = Layout((self.versionMajor, self.versionMinor), h5group=h5group)
        comps, groupedComps = layout._initComps(cs.caseTitle, bp)

        # populate data onto initialized components
        for compType, compTypeList in groupedComps.items():
            self._readParams(h5group, compType, compTypeList, allowMissing=allowMissing)

        # assign params from blueprints
        if bp is not None:
            self._assignBlueprintsParams(bp, groupedComps)

        # stitch together
        self._compose(iter(comps), cs)

        # also, make sure to update the global serial number so we don't reuse a number
        parameterCollections.GLOBAL_SERIAL_NUM = max(parameterCollections.GLOBAL_SERIAL_NUM, layout.serialNum.max())
        root = comps[0][0]

        # return a Reactor object
        if cs[CONF_SORT_REACTOR]:
            root.sort()
        else:
            runLog.warning(
                "DeprecationWarning: This Reactor is not being sorted on DB load. Due to the setting "
                f"{CONF_SORT_REACTOR}, this Reactor is unsorted. But this feature is temporary and will be removed by "
                "2024."
            )

        if cs[CONF_GROW_TO_FULL_CORE_AFTER_LOAD] and not root.core.isFullCore:
            root.core.growToFullCore(cs)

        return root

    def loadReadOnly(self, cycle, node, statePointName=None):
        """Load a new reactor, in read-only mode from a DB at (cycle, node).

        Parameters
        ----------
        cycle : int
            Cycle number
        node : int
            Time node. If value is negative, will be indexed from EOC backwards like a list.
        statePointName : str, optional
            Statepoint name (e.g., "special" for "c00n00-special/")

        Returns
        -------
        Reactor
            The top-level object stored in the database; a Reactor.
        """
        r = self.load(cycle, node, statePointName=statePointName, allowMissing=True)
        self._setParamsBeforeFreezing(r)
        makeParametersReadOnly(r)
        return r

    @staticmethod
    def _setParamsBeforeFreezing(r: Reactor):
        """Set some special case parameters before they are made read-only."""
        for child in r.iterChildren(deep=True, predicate=lambda c: isinstance(c, Component)):
            # calling Component.getVolume() sets the volume parameter
            child.getVolume()

    @staticmethod
    def _assignBlueprintsParams(blueprints, groupedComps):
        for compType, designs in (
            (Block, blueprints.blockDesigns),
            (Assembly, blueprints.assemDesigns),
        ):
            paramsToSet = {pDef.name for pDef in compType.pDefs.inCategory(parameters.Category.assignInBlueprints)}

            for comp in groupedComps[compType]:
                design = designs[comp.p.type]
                for pName in paramsToSet:
                    val = getattr(design, pName)
                    if val is not None:
                        comp.p[pName] = val

    def _compose(self, comps, cs, parent=None):
        """Given a flat collection of all of the ArmiObjects in the model, reconstitute the hierarchy."""
        comp, _, numChildren, location, locationType = next(comps)

        # attach the parent early, if provided; some cases need the parent attached for the rest of _compose to work
        # properly.
        comp.parent = parent

        # The Reactor adds a Core child by default, this is not ideal
        for spontaneousChild in list(comp):
            comp.remove(spontaneousChild)

        if isinstance(comp, Core):
            pass
        elif isinstance(comp, Assembly):
            # Assemblies force their name to be something based on assemNum. When the assembly is created it gets a new
            # assemNum, and throws out the correct name read from the DB.
            comp.name = comp.makeNameFromAssemNum(comp.p.assemNum)
            comp.lastLocationLabel = Assembly.DATABASE

        # set the spatialLocators on each component
        if location is not None:
            if parent is not None and parent.spatialGrid is not None:
                if locationType != LOC_COORD:
                    # We can directly index into the spatial grid for IndexLocation and MultiIndexLocators to get
                    # equivalent spatial locators
                    comp.spatialLocator = parent.spatialGrid[location]
                else:
                    comp.spatialLocator = grids.CoordinateLocation(
                        location[0], location[1], location[2], parent.spatialGrid
                    )
            else:
                comp.spatialLocator = grids.CoordinateLocation(location[0], location[1], location[2], None)

        # Need to keep a collection of Component instances for linked dimension resolution, before they can be add()ed
        # to their parents. Not just filtering out of `children`, since resolveLinkedDims() needs a dict
        childComponents = collections.OrderedDict()
        children = []

        for _ in range(numChildren):
            child = self._compose(comps, cs, parent=comp)
            children.append(child)
            if isinstance(child, Component):
                childComponents[child.name] = child

        for _childName, child in childComponents.items():
            child.resolveLinkedDims(childComponents)

        for child in children:
            comp.add(child)

        if isinstance(comp, Core):
            comp.processLoading(cs, dbLoad=True)
        elif isinstance(comp, Assembly):
            comp.calculateZCoords()
        elif isinstance(comp, Component):
            comp.finalizeLoadingFromDB()

        return comp

    @staticmethod
    def _getArrayShape(arr: Union[np.ndarray, List, Tuple]):
        """Get the shape of a np.ndarray, list, or tuple."""
        if isinstance(arr, np.ndarray):
            return arr.shape
        elif isinstance(arr, (list, tuple)):
            return (len(arr),)
        else:
            # not a list, tuple, or array (likely int, float, or None)
            return 1

    def _writeParams(self, h5group, comps) -> tuple:
        c = comps[0]
        groupName = c.__class__.__name__
        if groupName not in h5group:
            # Only create the group if it doesn't already exist. This happens when re-writing params in the same time
            # node (e.g. something changed between EveryNode and EOC).
            g = h5group.create_group(groupName, track_order=True)
        else:
            g = h5group[groupName]

        for paramDef in c.p.paramDefs.toWriteToDB():
            attrs = {}

            if hasattr(c, "DIMENSION_NAMES") and paramDef.name in c.DIMENSION_NAMES:
                linkedDims = []
                data = []

                for _, c in enumerate(comps):
                    val = c.p[paramDef.name]
                    if isinstance(val, tuple):
                        linkedDims.append("{}.{}".format(val[0].name, val[1]))
                        data.append(val[0].getDimension(val[1]))
                    else:
                        linkedDims.append("")
                        data.append(val)

                data = np.array(data)
                if any(linkedDims):
                    attrs["linkedDims"] = np.array(linkedDims).astype("S")
            else:
                # NOTE: after loading, the previously unset values will be defaulted
                temp = [c.p.get(paramDef.name, paramDef.default) for c in comps]
                if paramDef.serializer is not None:
                    data, sAttrs = paramDef.serializer.pack(temp)
                    assert data.dtype.kind != "O", "{} failed to convert {} to a numpy-supported type.".format(
                        paramDef.serializer.__name__, paramDef.name
                    )
                    attrs.update(sAttrs)
                    attrs[_SERIALIZER_NAME] = paramDef.serializer.__name__
                    attrs[_SERIALIZER_VERSION] = paramDef.serializer.version
                else:
                    # check if temp is a jagged array
                    if any(isinstance(x, (np.ndarray, list)) for x in temp):
                        jagged = len(set([self._getArrayShape(x) for x in temp])) != 1
                    else:
                        jagged = False
                    data = JaggedArray(temp, paramDef.name) if jagged else np.array(temp)
                    del temp

            # - Check to see if the array is jagged. If so, flatten, store the data offsets and array shapes, and None
            #   locations as attrs.
            # - If not jagged, all top-level ndarrays are the same shape, so it is easier to replace Nones with ndarrays
            #   filled with special values.
            if isinstance(data, JaggedArray):
                data, specialAttrs = packSpecialData(data, paramDef.name)
                attrs.update(specialAttrs)

            else:  # np.ndarray
                # Convert Unicode to byte-string
                if data.dtype.kind == "U":
                    data = data.astype("S")

                if data.dtype.kind == "O":
                    # Something was added to the data array that caused np to want to treat it as a general-purpose
                    # Object array. This usually happens because:
                    # - the data contain NoDefaults
                    # - the data contain one or more Nones,
                    # - the data contain special types like tuples, dicts, etc
                    # - there is some sort of honest-to-goodness weird object
                    # We want to support the first two cases with minimal intrusion, since these should be pretty easy
                    # to faithfully represent in the db. The last case isn't really worth supporting.
                    if parameters.NoDefault in data:
                        data = None
                    else:
                        data, specialAttrs = packSpecialData(data, paramDef.name)
                        attrs.update(specialAttrs)

            if data is None:
                continue

            try:
                if paramDef.name in g:
                    raise ValueError(f"`{paramDef.name}` was already in `{g}`. This time node should have been empty")

                dataset = g.create_dataset(paramDef.name, data=data, compression="gzip", track_order=True)
                if any(attrs):
                    Database._writeAttrs(dataset, h5group, attrs)
            except Exception:
                runLog.error(f"Failed to write {paramDef.name} to database. Data: {data}")
                raise

        if isinstance(c, Block):
            self._addHomogenizedNumberDensityParams(comps, g)

    @staticmethod
    def _addHomogenizedNumberDensityParams(blocks, h5group):
        """
        Create on-the-fly block homog. number density params for XTVIEW viewing.

        See Also
        --------
        collectBlockNumberDensities
        """
        nDens = collectBlockNumberDensities(blocks)

        for nucName, numDens in nDens.items():
            h5group.create_dataset(nucName, data=numDens, compression="gzip", track_order=True)

    @staticmethod
    def _readParams(h5group, compTypeName, comps, allowMissing=False):
        g = h5group[compTypeName]

        renames = getApp().getParamRenames()

        pDefs = comps[0].pDefs

        # this can also be made faster by specializing the method by type
        for paramName, dataSet in g.items():
            # Honor historical databases where the parameters may have changed names since.
            while paramName in renames:
                paramName = renames[paramName]

            try:
                pDef = pDefs[paramName]
            except KeyError:
                if re.match(r"^n[A-Z][a-z]?\d*", paramName):
                    # This is a temporary viz param (number density) made by _addHomogenizedNumberDensityParams ignore
                    # it safely
                    continue
                else:
                    # If a parameter exists in the database but not in the application reading it, we can technically
                    # keep going. Since this may lead to potential correctness issues, raise a warning
                    if allowMissing:
                        runLog.warning(
                            "Found `{}` parameter `{}` in the database, which is not defined. Ignoring it.".format(
                                compTypeName, paramName
                            )
                        )
                        continue
                    else:
                        raise

            data = dataSet[:]
            attrs = Database._resolveAttrs(dataSet.attrs, h5group)

            if pDef.serializer is not None:
                assert _SERIALIZER_NAME in dataSet.attrs
                assert dataSet.attrs[_SERIALIZER_NAME] == pDef.serializer.__name__
                assert _SERIALIZER_VERSION in dataSet.attrs

                data = np.array(pDef.serializer.unpack(data, dataSet.attrs[_SERIALIZER_VERSION], attrs))

            # nuclides are a special case where we want to keep in np.bytes_ format
            if data.dtype.type is np.bytes_ and "nuclides" not in paramName.lower():
                data = np.char.decode(data)

            if attrs.get("specialFormatting", False):
                data = unpackSpecialData(data, attrs, paramName)

            linkedDims = []
            if "linkedDims" in attrs:
                linkedDims = np.char.decode(attrs["linkedDims"])

            unpackedData = data.tolist()
            if len(comps) != len(unpackedData):
                msg = (
                    "While unpacking special data for {}, encountered composites and parameter "
                    "data with unmatched sizes.\nLength of composites list = {}\nLength of data "
                    "list = {}\nThis could indicate an error in data unpacking, which could "
                    "result in faulty data on the resulting reactor model.".format(
                        paramName, len(comps), len(unpackedData)
                    )
                )
                runLog.error(msg)
                raise ValueError(msg)

            if paramName == "numberDensities" and attrs.get("dict", False):
                Database._applyComponentNumberDensitiesMigration(comps, unpackedData)
            else:
                # iterating of np is not fast...
                for c, val, linkedDim in itertools.zip_longest(comps, unpackedData, linkedDims, fillvalue=""):
                    try:
                        if linkedDim != "":
                            c.p[paramName] = linkedDim
                        else:
                            c.p[paramName] = val
                    except AssertionError as ae:
                        # happens when a param was deprecated but being loaded from old DB
                        runLog.warning(
                            f"{str(ae)}\nSkipping load of invalid param `{paramName}` (possibly loading from old DB)\n"
                        )

    def getHistoryByLocation(
        self,
        comp: ArmiObject,
        params: Optional[List[str]] = None,
        timeSteps: Optional[Sequence[Tuple[int, int]]] = None,
    ) -> History:
        """Get the parameter histories at a specific location."""
        return self.getHistoriesByLocation([comp], params=params, timeSteps=timeSteps)[comp]

    def getHistoriesByLocation(
        self,
        comps: Sequence[ArmiObject],
        params: Optional[List[str]] = None,
        timeSteps: Optional[Sequence[Tuple[int, int]]] = None,
    ) -> Histories:
        """
        Get the parameter histories at specific locations.

        This has a number of limitations, which should in practice not be too limiting:
         - The passed objects must have IndexLocations. This type of operation doesn't make much sense otherwise.
         - The passed objects must exist in a hierarchy that leads to a Core object, which serves as an anchor that can
           fully define all index locations. This could possibly be made more general by extending grids, but that gets
           a little more complicated.
         - All requested objects must exist under the **same** anchor object, and at the same depth below it.
         - All requested objects must have the same type.

        Parameters
        ----------
        comps : list of ArmiObject
            The components/composites that currently occupy the location that you want histories at. ArmiObjects are
            passed, rather than locations, because this makes it easier to figure out things related to layout.
        params : List of str, optional
            The parameter names for the parameters that we want the history of. If None, all parameter history is given.
        timeSteps : List of (cycle, node) tuples, optional
            The time nodes that you want history for. If None, all available time nodes will be returned.
        """
        if self.versionMajor != 3:
            raise ValueError(f"This version of ARMI only supports version 3 of the ARMI DB, found {self.versionMajor}.")
        elif self.versionMinor < 4:
            raise ValueError(
                "Location-based histories are only supported for db version 3.4 and greater. This database is version "
                f"{self.versionMajor}, {self.versionMinor}."
            )

        locations = [c.spatialLocator.getCompleteIndices() for c in comps]

        histData: Histories = {c: collections.defaultdict(collections.OrderedDict) for c in comps}

        # Check our assumptions about the passed locations: All locations must have the same parent and bear the same
        # relationship to the anchor object.
        anchors = {obj.getAncestorAndDistance(lambda a: isinstance(a, Core)) for obj in comps}

        if len(anchors) != 1:
            raise ValueError(
                "The passed objects do not have the same anchor or distance to that anchor; encountered the following: "
                f"{anchors}"
            )

        anchorInfo = anchors.pop()
        if anchorInfo is not None:
            anchor, anchorDistance = anchorInfo
        else:
            raise ValueError("Could not determine an anchor object for the passed components")

        anchorSerialNum = anchor.p.serialNum

        # All objects of the same type
        objectTypes = {type(obj) for obj in comps}
        if len(objectTypes) != 1:
            raise TypeError(f"The passed objects must be the same type; got objects of types `{objectTypes}`")

        compType = objectTypes.pop()
        objClassName = compType.__name__

        locToComp = {c.spatialLocator.getCompleteIndices(): c for c in comps}

        for h5TimeNodeGroup in self.genTimeStepGroups(timeSteps):
            if "layout" not in h5TimeNodeGroup:
                # Layout hasn't been written for this time step, so we can't get anything useful here. Perhaps the
                # current value is of use, in which case the DatabaseInterface should be used.
                continue

            cycle = h5TimeNodeGroup.attrs["cycle"]
            timeNode = h5TimeNodeGroup.attrs["timeNode"]
            layout = Layout((self.versionMajor, self.versionMinor), h5group=h5TimeNodeGroup)
            ancestors = layout.computeAncestors(layout.serialNum, layout.numChildren, depth=anchorDistance)

            lLocation = layout.location
            # filter for objects that live under the desired ancestor and at a desired location
            objectIndicesInLayout = np.array(
                [
                    i
                    for i, (ancestor, loc) in enumerate(zip(ancestors, lLocation))
                    if ancestor == anchorSerialNum and loc in locations
                ]
            )

            # This could also be way more efficient if lLocation were a numpy array
            objectLocationsInLayout = [lLocation[i] for i in objectIndicesInLayout]
            objectIndicesInData = np.array(layout.indexInData)[objectIndicesInLayout].tolist()

            try:
                h5GroupForType = h5TimeNodeGroup[objClassName]
            except KeyError as ee:
                runLog.error(f"{objClassName} not found in {h5TimeNodeGroup} of {self}")
                raise ee

            for paramName in params or h5GroupForType.keys():
                if paramName == "location":
                    # location is special, since it is stored in layout/
                    data = np.array(layout.location)[objectIndicesInLayout]
                elif paramName in h5GroupForType:
                    dataSet = h5GroupForType[paramName]
                    try:
                        data = dataSet[objectIndicesInData]
                    except:
                        runLog.error(f"Failed to load index {objectIndicesInData} from {dataSet}@{(cycle, timeNode)}")
                        raise

                    if data.dtype.type is np.bytes_:
                        data = np.char.decode(data)

                    if dataSet.attrs.get("specialFormatting", False):
                        if dataSet.attrs.get("nones", False):
                            data = replaceNonsenseWithNones(data, paramName)
                        else:
                            raise ValueError(
                                "History tracking for non-None, special-formatted parameters is not supported: "
                                "{}, {}".format(paramName, {k: v for k, v in dataSet.attrs.items()})
                            )
                else:
                    # Nothing in the database for this param, so use the default value
                    data = np.repeat(
                        parameters.byNameAndType(paramName, compType).default,
                        len(comps),
                    )

                # store data to the appropriate comps. This is where taking components as the argument (rather than
                # locations) is a little bit peculiar.
                #
                # At this point, `data` are arranged by the order of elements in `objectIndicesInData`, which
                # corresponds to the order of `objectIndicesInLayout`
                for loc, val in zip(objectLocationsInLayout, data.tolist()):
                    comp = locToComp[loc]
                    histData[comp][paramName][cycle, timeNode] = val

        return histData

    def getHistory(
        self,
        comp: ArmiObject,
        params: Optional[Sequence[str]] = None,
        timeSteps: Optional[Sequence[Tuple[int, int]]] = None,
    ) -> History:
        """
        Get parameter history for a single ARMI Object.

        Parameters
        ----------
        comps
            An individual ArmiObject
        params
            parameters to gather

        Returns
        -------
        dict
            Dictionary of str/list pairs.
        """
        return self.getHistories([comp], params, timeSteps)[comp]

    def getHistories(
        self,
        comps: Sequence[ArmiObject],
        params: Optional[Sequence[str]] = None,
        timeSteps: Optional[Sequence[Tuple[int, int]]] = None,
    ) -> Histories:
        """
        Get the parameter histories for a sequence of ARMI Objects.

        This implementation is unaware of the state of the reactor outside of the database itself, and is therefore not
        usually what client code should be calling directly during normal ARMI operation. It only knows about historical
        data that have actually been written to the database. Usually one wants to be able to get historical, plus
        current data, for which the similar method on the DatabaseInterface may be more useful.

        Parameters
        ----------
        comps
            Something that is iterable multiple times
        params
            parameters to gather.
        timeSteps
            Selection of time nodes to get data for. If omitted, return full history

        Returns
        -------
        dict
            Dictionary ArmiObject (input): dict of str/list pairs containing ((cycle, node), value).
        """
        histData: Histories = {c: collections.defaultdict(collections.OrderedDict) for c in comps}
        types = {c.__class__ for c in comps}
        compsByTypeThenSerialNum: Dict[Type[ArmiObject], Dict[int, ArmiObject]] = {t: dict() for t in types}

        for c in comps:
            compsByTypeThenSerialNum[c.__class__][c.p.serialNum] = c

        for h5TimeNodeGroup in self.genTimeStepGroups(timeSteps):
            if "layout" not in h5TimeNodeGroup:
                # Layout hasn't been written for this time step, so whatever is in there didn't come from the
                # DatabaseInterface. Probably because it's the current time step and something has created the group to
                # store aux data
                continue

            # might save as int or np.int64, so forcing int keeps things predictable
            cycle = int(h5TimeNodeGroup.attrs["cycle"])
            timeNode = int(h5TimeNodeGroup.attrs["timeNode"])
            layout = Layout((self.versionMajor, self.versionMinor), h5group=h5TimeNodeGroup)

            for compType, compsBySerialNum in compsByTypeThenSerialNum.items():
                compTypeName = compType.__name__
                try:
                    h5GroupForType = h5TimeNodeGroup[compTypeName]
                except KeyError as ee:
                    runLog.error("{} not found in {} of {}".format(compTypeName, h5TimeNodeGroup, self))
                    raise ee
                layoutIndicesForType = np.where(layout.type == compTypeName)[0]
                serialNumsForType = layout.serialNum[layoutIndicesForType].tolist()
                layoutIndexInData = layout.indexInData[layoutIndicesForType].tolist()

                indexInData = []
                reorderedComps = []

                for ii, sn in zip(layoutIndexInData, serialNumsForType):
                    d = compsBySerialNum.get(sn, None)
                    if d is not None:
                        indexInData.append(ii)
                        reorderedComps.append(d)

                if not indexInData:
                    continue

                # note this is very similar to _readParams but there are some important differences.
                # 1) we are not assigning to p[paramName]
                # 2) not using linkedDims at all
                # 3) not performing parameter renaming. This may become necessary
                for paramName in params or h5GroupForType.keys():
                    if paramName == "location":
                        locs = []
                        for id in indexInData:
                            locs.append((layout.location[layoutIndicesForType[id]]))
                        data = np.array(locs)
                    elif paramName in h5GroupForType:
                        dataSet = h5GroupForType[paramName]
                        try:
                            data = dataSet[indexInData]
                        except:
                            runLog.error(
                                "Failed to load index {} from {}@{}".format(indexInData, dataSet, (cycle, timeNode))
                            )
                            raise

                        if data.dtype.type is np.bytes_:
                            data = np.char.decode(data)

                        if dataSet.attrs.get("specialFormatting", False):
                            if dataSet.attrs.get("nones", False):
                                data = replaceNonsenseWithNones(data, paramName)
                            else:
                                raise ValueError(
                                    "History tracking for non-none special formatting not supported: {}, {}".format(
                                        paramName,
                                        {k: v for k, v in dataSet.attrs.items()},
                                    )
                                )
                    else:
                        # Nothing in the database, so use the default value
                        data = np.repeat(
                            parameters.byNameAndType(paramName, compType).default,
                            len(reorderedComps),
                        )

                    # iterating of np is not fast..
                    for c, val in zip(reorderedComps, data.tolist()):
                        if paramName == "location":
                            val = tuple(val)
                        elif isinstance(val, list):
                            val = np.array(val)

                        histData[c][paramName][cycle, timeNode] = val

        r = comps[0].getAncestor(lambda c: isinstance(c, Reactor))
        cycleNode = r.p.cycle, r.p.timeNode
        for c, paramHistories in histData.items():
            for paramName, hist in paramHistories.items():
                if cycleNode not in hist:
                    try:
                        hist[cycleNode] = c.p[paramName]
                    except Exception:
                        if paramName == "location":
                            hist[cycleNode] = tuple(c.spatialLocator.indices)

        return histData

    @staticmethod
    def _writeAttrs(obj, group, attrs):
        """
        Handle safely writing attributes to a dataset, handling large data if necessary.

        This will attempt to store attributes directly onto an HDF5 object if possible, falling back to proper datasets
        and reference attributes if necessary. This is needed because HDF5 tries to fit attributes into the object
        header, which has limited space. If an attribute is too large, h5py raises a RuntimeError. In such cases, this
        will store the attribute data in a proper dataset and place a reference to that dataset in the attribute
        instead.

        In practice, this takes ``linkedDims`` attrs from a particular component type (like ``c00n00/Circle/id``) and
        stores them in new datasets (like ``c00n00/attrs/1_linkedDims``, ``c00n00/attrs/2_linkedDims``) and then sets
        the object's attrs to links to those datasets.
        """
        for key, value in attrs.items():
            try:
                obj.attrs[key] = value
            except RuntimeError as err:
                if "object header message is too large" not in err.args[0]:
                    raise

                runLog.info(f"Storing attribute `{key}` for `{obj}` into it's own dataset within `{group}/attrs`")

                if "attrs" not in group:
                    attrGroup = group.create_group("attrs")
                else:
                    attrGroup = group["attrs"]
                dataName = str(len(attrGroup)) + "_" + key
                attrGroup[dataName] = value

                # using a soft link here allows us to cheaply copy time nodes without needing to crawl through and
                # update object references.
                linkName = attrGroup[dataName].name
                obj.attrs[key] = "@{}".format(linkName)

    @staticmethod
    def _resolveAttrs(attrs, group):
        """
        Reverse the action of _writeAttrs.

        This reads actual attrs and looks for the real data in the datasets that the attrs were pointing to.
        """
        attr_link = re.compile("^@(.*)$")

        resolved = {}
        for key, val in attrs.items():
            try:
                if isinstance(val, h5py.h5r.Reference):
                    # Old style object reference. If this cannot be dereferenced, it is likely because mergeHistory was
                    # used to get the current database, which does not preserve references.
                    resolved[key] = group[val]
                elif isinstance(val, str):
                    m = attr_link.match(val)
                    if m:
                        # dereference the path to get the data out of the dataset.
                        resolved[key] = group[m.group(1)][()]
                    else:
                        resolved[key] = val
                else:
                    resolved[key] = val
            except ValueError:
                runLog.error(f"HDF error loading {key} : {val}\nGroup: {group}")
                raise

        return resolved

    @staticmethod
    def _applyComponentNumberDensitiesMigration(comps, unpackedData):
        """
        Special migration from <= v0.5.1 component numberDensities parameter data type.

        old format: dict[str: float]
        new format: two numpy arrays
        - nuclides = np.array(dtype="S6")
        - numberDensities = np.array(dtype=np.float64)
        """
        for c, ndensDict in zip(comps, unpackedData):
            nuclides = np.array(list(ndensDict.keys()), dtype="S6")
            numberDensities = np.array(list(ndensDict.values()), dtype=np.float64)
            c.p.nuclides = nuclides
            c.p.numberDensities = numberDensities

    @staticmethod
    def getCycleNodeAtTime(dbPath, startTime, endTime, errorIfNotExactlyOne=True):
        """Given the path to an ARMI database file and a start and end time (in years), return the full set of all time
        nodes that correspond to that time period in the database.

        Parameters
        ----------
        dbPath : str
            File path to an ARMI database.
        startTime : int
            In years, start of the desired interval.
        endTime : int
            In years, end of the desired interval.
        errorIfNotExactlyOne : boolean
            Raise an error if more than one cycle/node combination is returned. Default is True.

        Returns
        -------
        list of strings
            A list of strings to the desired time interval, e.g.: ["c01n08", "c14n18EOL"]
        """
        # basic sanity checks
        assert startTime >= 0.0, f"The start time cannot be negative: {startTime}."
        assert endTime >= startTime, f"The end time ({endTime}) is not greater than the start time ({startTime})."

        # open the H5 file directly
        with h5py.File(dbPath, "r") as h5:
            # read time steps in H5 file
            thisTime = 0.0
            cycleNodes = []
            for h5Key in h5.keys():
                if h5Key == "inputs":
                    continue

                thisTime = h5[h5Key]["Reactor"]["time"][0]
                if thisTime >= endTime:
                    cycleNodes.append(h5Key)
                    break
                elif thisTime >= startTime:
                    cycleNodes.append(h5Key)

        # more validation
        if not cycleNodes:
            raise ValueError(f"Provided start time ({startTime}) was greater than the modeled period: {thisTime}.")
        elif errorIfNotExactlyOne and len(cycleNodes) != 1:
            raise ValueError(f"Did not find exactly one cycle/node pair: {cycleNodes}")

        return cycleNodes


def packSpecialData(
    arrayData: [np.ndarray, JaggedArray], paramName: str
) -> Tuple[Optional[np.ndarray], Dict[str, Any]]:
    """
    Reduce data that wouldn't otherwise play nicely with HDF5/numpy arrays to a format that will.

    This is the main entry point for conforming "strange" data into something that will both fit
    into a numpy array/HDF5 dataset, and be recoverable to its original-ish state when reading it
    back in. This is accomplished by detecting a handful of known offenders and using various HDF5
    attributes to store necessary auxiliary data. It is important to keep in mind that the data that
    is passed in has already been converted to a numpy array, so the top dimension is always
    representing the collection of composites that are storing the parameters. For instance, if we
    are dealing with a Block parameter, the first index in the numpy array of data is the block
    index; so if each block has a parameter that is a dictionary, ``data`` would be a ndarray,
    where each element is a dictionary. This routine supports a number of different things:

    * Dict[str, float]: These are stored by finding the set of all keys for all instances, and
      storing those keys as a list in an attribute. The data themselves are stored as arrays indexed
      by object, then key index. Dictionaries lacking data for a key store a nan in it's place. This
      will work well in instances where most objects have data for most keys.
    * Jagged arrays: These are stored by concatenating all of the data into a single, one-
      dimensional array, and storing attributes to describe the shapes of each object's data, and an
      offset into the beginning of each object's data.
    * Arrays with ``None`` in them: These are stored by replacing each instance of ``None`` with a
      magical value that shouldn't be encountered in realistic scenarios.

    Parameters
    ----------
    arrayData
        An ndarray or JaggedArray object storing the data that we want to stuff into the database.
        If the data is jagged, a special JaggedArray instance is passed in, which contains a 1D
        array with offsets and shapes.
    paramName
        The parameter name that we are trying to store. This is mostly used for diagnostics.

    See Also
    --------
    unpackSpecialData
    """
    if isinstance(arrayData, JaggedArray):
        data = arrayData.flattenedArray
    else:
        # Check to make sure that we even need to do this. If the numpy data type is not "O",
        # chances are we have nice, clean data.
        if arrayData.dtype != "O":
            return arrayData, {}
        else:
            data = arrayData

    attrs: Dict[str, Any] = {"specialFormatting": True}

    # make a copy of the data, so that the original is unchanged
    data = copy.copy(data)

    # Find locations of Nones.
    nones = np.where([d is None for d in data])[0]
    if len(nones) == data.shape[0]:
        # Everything is None, so why bother?
        return None, attrs

    if len(nones) > 0:
        attrs["nones"] = True

    # Pack different types of data
    if any(isinstance(d, dict) for d in data):
        # We're assuming that a dict is {str: float}.
        attrs["dict"] = True
        keys = sorted({k for d in data for k in d})
        data = np.array([[d.get(k, np.nan) for k in keys] for d in data])
        if data.dtype == "O":
            raise TypeError(f"Unable to coerce dictionary data into usable numpy array for {paramName}")
        # We store the union of all of the keys for all of the objects as a special "keys"
        # attribute, and store a value for all of those keys for all objects, whether or not there
        # is actually data associated with that key
        attrs["keys"] = np.array(keys).astype("S")

        return data, attrs
    elif isinstance(arrayData, JaggedArray):
        attrs["jagged"] = True
        attrs["offsets"] = arrayData.offsets
        attrs["shapes"] = arrayData.shapes
        attrs["noneLocations"] = arrayData.nones
        return data, attrs

    # conform non-numpy arrays to numpy
    for i, val in enumerate(data):
        if isinstance(val, (list, tuple)):
            data[i] = np.array(val)

    if not any(isinstance(d, np.ndarray) for d in data):
        # looks like 1-D plain-old-data
        data = replaceNonesWithNonsense(data, paramName, nones)
        return data, attrs
    elif any(isinstance(d, (tuple, list, np.ndarray)) for d in data):
        data = replaceNonesWithNonsense(data, paramName, nones)
        return data, attrs

    if len(nones) == 0:
        raise TypeError(f"Cannot write {paramName} to the database, it did not resolve to a numpy/HDF5 type.")

    runLog.error(f"Data unable to find special none value: {data}")
    raise TypeError(f"Failed to process special data for {paramName}")


def unpackSpecialData(data: np.ndarray, attrs, paramName: str) -> np.ndarray:
    """
    Extract data from a specially-formatted HDF5 dataset into a numpy array.

    This should invert the operations performed by :py:func:`packSpecialData`.

    Parameters
    ----------
    data
        Specially-formatted data array straight from the database.
    attrs
        The attributes associated with the dataset that contained the data.
    paramName
        The name of the parameter that is being unpacked. Only used for diagnostics.

    Returns
    -------
    np.ndarray
        An ndarray containing the closest possible representation of the data that was originally written to the
        database.

    See Also
    --------
    packSpecialData
    """
    if not attrs.get("specialFormatting", False):
        # The data were not subjected to any special formatting; short circuit.
        assert data.dtype != "O"
        return data

    unpackedData: List[Any]
    if attrs.get("nones", False) and not attrs.get("jagged", False):
        data = replaceNonsenseWithNones(data, paramName)
        return data
    if attrs.get("jagged", False):
        offsets = attrs["offsets"]
        shapes = attrs["shapes"]
        nones = attrs["noneLocations"]
        data = JaggedArray.fromH5(data, offsets, shapes, nones, data.dtype, paramName)
        return data
    if attrs.get("dict", False):
        keys = np.char.decode(attrs["keys"])
        unpackedData = []
        assert data.ndim == 2
        for d in data:
            unpackedData.append({key: value for key, value in zip(keys, d) if not np.isnan(value)})
        return np.array(unpackedData)

    raise ValueError(
        "Do not recognize the type of special formatting that was applied to {}. Attrs: {}".format(
            paramName, {k: v for k, v in attrs.items()}
        )
    )


def collectBlockNumberDensities(blocks) -> Dict[str, np.ndarray]:
    """
    Collect block-by-block homogenized number densities for each nuclide.

    Homogenize the component-level to the block level. These are written to the database and useful for visualization.
    """
    # find the NuclidesBases object on the Reactor
    nuclideBases = None
    for b in blocks:
        if b.nuclideBases is not None:
            nuclideBases = b.nuclideBases
            break

    if not nuclideBases:
        return {}

    nucNames = sorted(list(set(nucName for b in blocks for nucName in b.getNuclides())))
    nucBases = [nuclideBases.byName[nn] for nn in nucNames]
    # It's faster to loop over blocks first and get all number densities from each than it is to get one nuclide at a
    # time from each block because of area fraction calculations. So we use some RAM here instead.
    nucDensityMatrix = []
    for block in blocks:
        nucDensityMatrix.append(block.getNuclideNumberDensities(nucNames))
    nucDensityMatrix = np.array(nucDensityMatrix)

    dataDict = dict()
    for ni, nb in enumerate(nucBases):
        # the nth column is a vector of nuclide densities for this nuclide across all blocks
        dataDict[nb.getDatabaseName()] = nucDensityMatrix[:, ni]

    return dataDict


================================================
FILE: armi/bookkeeping/db/databaseInterface.py
================================================
# Copyright 2022 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
The database interface provides a way to save the reactor state to a file, throughout
a simulation.
"""

import copy
import os
import pathlib
import time
from typing import (
    MutableSequence,
    Optional,
    Sequence,
    Tuple,
)

from armi import context, interfaces, runLog
from armi.bookkeeping.db.database import Database, getH5GroupName
from armi.bookkeeping.db.typedefs import Histories, History
from armi.reactor.composites import ArmiObject
from armi.reactor.parameters import parameterDefinitions
from armi.settings.fwSettings.databaseSettings import (
    CONF_FORCE_DB_PARAMS,
    CONF_SYNC_AFTER_WRITE,
)
from armi.utils import getPreviousTimeNode, getStepLengths

ORDER = interfaces.STACK_ORDER.BOOKKEEPING


def describeInterfaces(cs):
    """Function for exposing interface(s) to other code."""
    return (DatabaseInterface, {"enabled": cs["db"]})


class DatabaseInterface(interfaces.Interface):
    """
    Handles interactions between the ARMI data model and the persistent data storage
    system.

    This reads/writes the ARMI state to/from the database and helps derive state
    information that can be derived.
    """

    name = "database"

    def __init__(self, r, cs):
        interfaces.Interface.__init__(self, r, cs)
        self._db = None
        self._dbPath: Optional[pathlib.Path] = None

        if cs[CONF_FORCE_DB_PARAMS]:
            toSet = {paramName: set() for paramName in cs[CONF_FORCE_DB_PARAMS]}
            for (name, _), pDef in parameterDefinitions.ALL_DEFINITIONS.items():
                if name in toSet.keys():
                    toSet[name].add(pDef)

            for name, pDefs in toSet.items():
                runLog.info("Forcing parameter {} to be written to the database, per user input".format(name))
                for pDef in pDefs:
                    pDef.saveToDB = True

    def __repr__(self):
        return "<{} '{}' {} >".format(self.__class__.__name__, self.name, repr(self._db))

    @property
    def database(self):
        """Presents the internal database object, if it exists."""
        if self._db is not None:
            return self._db
        else:
            raise RuntimeError(
                "The Database interface has not yet created a database "
                "object. InteractBOL or loadState must be called first."
            )

    def interactBOL(self):
        """Initialize the database if the main interface was not available. (Beginning of Life)."""
        if not self._db:
            self.initDB()

    def initDB(self, fName: Optional[os.PathLike] = None):
        """
        Open the underlying database to be written to, and write input files to DB.

        Notes
        -----
        Main Interface calls this so that the database is available as early as possible in the run.
        The database interface interacts near the end of the interface stack (so that all the
        parameters have been updated) while the Main Interface interacts first.
        """
        if fName is None:
            self._dbPath = pathlib.Path(self.cs.caseTitle + ".h5")
        else:
            self._dbPath = pathlib.Path(fName)

        if self.cs["reloadDBName"].lower() == str(self._dbPath).lower():
            raise ValueError(
                "It appears that reloadDBName is the same as the case title. "
                "This could lead to data loss! Rename the reload DB or the case."
            )
        self._db = Database(self._dbPath, "w")
        self._db.open()
        self._db.writeInputsToDB(self.cs)

    def interactEveryNode(self, cycle, node):
        """
        Write to database.

        DBs should receive the state information of the run at each node.

        Notes
        -----
        - If tight coupling is enabled, the DB will be written in ``Operator::_timeNodeLoop`` via
          writeDBEveryNode.
        """
        if self.o.cs["tightCoupling"]:
            # h5 can't handle overwriting so we skip here and write once the tight coupling loop has completed
            return
        self.writeDBEveryNode()

    def writeDBEveryNode(self):
        """Write the database at the end of the time node."""
        self.r.core.p.minutesSinceStart = (time.time() - self.r.core.timeOfStart) / 60.0
        self._db.writeToDB(self.r)
        if self.cs[CONF_SYNC_AFTER_WRITE]:
            self._db.syncToSharedFolder()

    def interactEOC(self, cycle=None):
        """
        Do not write; this state doesn't tend to be important since its decay only step.

        Notes
        -----
        The same time is available at start of next cycle.
        """
        return

    def interactEOL(self):
        """DB's should be closed at run's end. (End of Life)."""
        # minutesSinceStarts should include as much of the ARMI run as possible so EOL is necessary, too.
        self.r.core.p.minutesSinceStart = (time.time() - self.r.core.timeOfStart) / 60.0
        self._db.writeToDB(self.r, "EOL")
        self.closeDB()

    def closeDB(self):
        """Close the DB, writing to file."""
        self._db.close(True)

    def interactError(self):
        """Get shutdown state information even if the run encounters an error."""
        try:
            self.r.core.p.minutesSinceStart = (time.time() - self.r.core.timeOfStart) / 60.0

            # this can result in a double-error if the error occurred in the database
            # writing
            self._db.writeToDB(self.r, "error")
            self._db.close(False)
        except Exception:  # we're already responding to an error
            pass

    def interactDistributeState(self) -> None:
        """
        Reconnect to pre-existing database.

        DB is created and managed by the primary node only but we can still connect to it
        from workers to enable things like history tracking.
        """
        if context.MPI_RANK > 0:
            # DB may not exist if distribute state is called early.
            if self._dbPath is not None and os.path.exists(self._dbPath):
                self._db = Database(self._dbPath, "r")
                self._db.open()

    def distributable(self):
        return self.Distribute.SKIP

    def prepRestartRun(self):
        """
        Load the data history from the database requested in the case setting
        `reloadDBName`.

        Reactor state is put at the cycle/node requested in the case settings
        `startCycle` and `startNode`, having loaded the state from all cycles prior
        to that in the requested database.

        .. impl:: Runs at a particular timenode can be re-instantiated for a snapshot.
            :id: I_ARMI_SNAPSHOT_RESTART
            :implements: R_ARMI_SNAPSHOT_RESTART

            This method loads the state of a reactor from a particular point in time
            from a standard ARMI
            :py:class:`Database <armi.bookkeeping.db.database.Database>`. This is a
            major use-case for having ARMI databases in the first case. And restarting
            from such a database is easy, you just need to set a few settings::

            * reloadDBName - Path to existing H5 file to rel
Download .txt
gitextract_528z7ijz/

├── .github/
│   ├── .codecov.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── coverage.yaml
│       ├── docs.yaml
│       ├── find_test_crumbs.py
│       ├── licensechecker.yaml
│       ├── linting.yaml
│       ├── mac_tests.yaml
│       ├── stale.yaml
│       ├── unittests.yaml
│       ├── validatemanifest.py
│       ├── validatemanifest.yaml
│       ├── wheels.yaml
│       └── wintests.yaml
├── .gitignore
├── .gitmodules
├── .licenserc.json
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE.md
├── README.rst
├── armi/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _bootstrap.py
│   ├── apps.py
│   ├── bookkeeping/
│   │   ├── __init__.py
│   │   ├── db/
│   │   │   ├── __init__.py
│   │   │   ├── compareDB3.py
│   │   │   ├── database.py
│   │   │   ├── databaseInterface.py
│   │   │   ├── factory.py
│   │   │   ├── jaggedArray.py
│   │   │   ├── layout.py
│   │   │   ├── passiveDBLoadPlugin.py
│   │   │   ├── permissions.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_comparedb3.py
│   │   │   │   ├── test_database.py
│   │   │   │   ├── test_databaseInterface.py
│   │   │   │   ├── test_jaggedArray.py
│   │   │   │   ├── test_layout.py
│   │   │   │   └── test_passiveDBLoadPlugin.py
│   │   │   └── typedefs.py
│   │   ├── historyTracker.py
│   │   ├── mainInterface.py
│   │   ├── memoryProfiler.py
│   │   ├── report/
│   │   │   ├── __init__.py
│   │   │   ├── data.py
│   │   │   ├── reportInterface.py
│   │   │   ├── reportingUtils.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       └── test_report.py
│   │   ├── snapshotInterface.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── _constants.py
│   │   │   ├── test_historyTracker.py
│   │   │   ├── test_memoryProfiler.py
│   │   │   └── test_snapshot.py
│   │   └── visualization/
│   │       ├── __init__.py
│   │       ├── dumper.py
│   │       ├── entryPoint.py
│   │       ├── tests/
│   │       │   ├── __init__.py
│   │       │   ├── test_vis.py
│   │       │   └── test_xdmf.py
│   │       ├── utils.py
│   │       ├── vtk.py
│   │       └── xdmf.py
│   ├── cases/
│   │   ├── __init__.py
│   │   ├── case.py
│   │   ├── inputModifiers/
│   │   │   ├── __init__.py
│   │   │   ├── inputModifiers.py
│   │   │   ├── neutronicsModifiers.py
│   │   │   ├── pinTypeInputModifiers.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── test_inputModifiers.py
│   │   │       └── test_pinTypeInputModifiers.py
│   │   ├── suite.py
│   │   ├── suiteBuilder.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_cases.py
│   │       └── test_suiteBuilder.py
│   ├── cli/
│   │   ├── __init__.py
│   │   ├── checkInputs.py
│   │   ├── cleanTemps.py
│   │   ├── clone.py
│   │   ├── compareCases.py
│   │   ├── database.py
│   │   ├── entryPoint.py
│   │   ├── gridGui.py
│   │   ├── migrateInputs.py
│   │   ├── modify.py
│   │   ├── reportsEntryPoint.py
│   │   ├── run.py
│   │   ├── runSuite.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_runEntryPoint.py
│   │       └── test_runSuite.py
│   ├── conftest.py
│   ├── context.py
│   ├── interfaces.py
│   ├── matProps/
│   │   ├── __init__.py
│   │   ├── constituent.py
│   │   ├── function.py
│   │   ├── interpolationFunctions.py
│   │   ├── material.py
│   │   ├── materialType.py
│   │   ├── piecewiseFunction.py
│   │   ├── point.py
│   │   ├── prop.py
│   │   ├── reference.py
│   │   ├── symbolicFunction.py
│   │   ├── tableFunction.py
│   │   ├── tableFunction1D.py
│   │   ├── tableFunction2D.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── invalidTestFiles/
│   │       │   ├── badFileFormat.YAML
│   │       │   ├── badProperty.yaml
│   │       │   └── duplicateComposition.yaml
│   │       ├── testDir1/
│   │       │   ├── a.yaml
│   │       │   └── b.yaml
│   │       ├── testDir2/
│   │       │   ├── c.yml
│   │       │   └── d.yaml
│   │       ├── testDir3/
│   │       │   ├── a.yaml
│   │       │   └── e.yaml
│   │       ├── testDir4/
│   │       │   └── sampleProperty.yaml
│   │       ├── testMaterialsData/
│   │       │   ├── materialA.yaml
│   │       │   ├── materialB.yaml
│   │       │   └── materialsSubDir/
│   │       │       ├── materialC.yaml
│   │       │       └── materialD.yaml
│   │       ├── test_1DSymbolicFunction.py
│   │       ├── test_composition.py
│   │       ├── test_constituent.py
│   │       ├── test_functions.py
│   │       ├── test_hashing.py
│   │       ├── test_interpolationFunctions.py
│   │       ├── test_material.py
│   │       ├── test_materialType.py
│   │       ├── test_parsing.py
│   │       ├── test_performance.py
│   │       ├── test_piecewiseFunction.py
│   │       ├── test_point.py
│   │       ├── test_property.py
│   │       ├── test_references.py
│   │       ├── test_symbolicFunction.py
│   │       └── test_tableFunctions.py
│   ├── materials/
│   │   ├── __init__.py
│   │   ├── air.py
│   │   ├── alloy200.py
│   │   ├── b4c.py
│   │   ├── be9.py
│   │   ├── caH2.py
│   │   ├── californium.py
│   │   ├── concrete.py
│   │   ├── copper.py
│   │   ├── cs.py
│   │   ├── custom.py
│   │   ├── graphite.py
│   │   ├── hafnium.py
│   │   ├── hastelloyN.py
│   │   ├── ht9.py
│   │   ├── inconel.py
│   │   ├── inconel600.py
│   │   ├── inconel625.py
│   │   ├── inconel800.py
│   │   ├── inconelPE16.py
│   │   ├── inconelX750.py
│   │   ├── lead.py
│   │   ├── leadBismuth.py
│   │   ├── lithium.py
│   │   ├── magnesium.py
│   │   ├── material.py
│   │   ├── mgO.py
│   │   ├── mixture.py
│   │   ├── molybdenum.py
│   │   ├── mox.py
│   │   ├── nZ.py
│   │   ├── potassium.py
│   │   ├── scandiumOxide.py
│   │   ├── siC.py
│   │   ├── sodium.py
│   │   ├── sodiumChloride.py
│   │   ├── sulfur.py
│   │   ├── tZM.py
│   │   ├── tantalum.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test__init__.py
│   │   │   ├── test_air.py
│   │   │   ├── test_b4c.py
│   │   │   ├── test_be9.py
│   │   │   ├── test_fluids.py
│   │   │   ├── test_graphite.py
│   │   │   ├── test_lithium.py
│   │   │   ├── test_materials.py
│   │   │   ├── test_sic.py
│   │   │   ├── test_sulfur.py
│   │   │   ├── test_thoriumOxide.py
│   │   │   ├── test_uZr.py
│   │   │   └── test_water.py
│   │   ├── thU.py
│   │   ├── thorium.py
│   │   ├── thoriumOxide.py
│   │   ├── uZr.py
│   │   ├── uranium.py
│   │   ├── uraniumOxide.py
│   │   ├── void.py
│   │   ├── water.py
│   │   ├── yttriumOxide.py
│   │   ├── zincOxide.py
│   │   └── zr.py
│   ├── meta.py
│   ├── migration/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── m0_1_3.py
│   │   ├── m0_1_6.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_m0_1_6.py
│   │       └── test_migration_base.py
│   ├── mpiActions.py
│   ├── nucDirectory/
│   │   ├── __init__.py
│   │   ├── elements.py
│   │   ├── nucDir.py
│   │   ├── nuclideBases.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test_elements.py
│   │   │   ├── test_nucDirectory.py
│   │   │   ├── test_nuclideBases.py
│   │   │   ├── test_thermalScattering.py
│   │   │   └── test_transmutations.py
│   │   ├── thermalScattering.py
│   │   └── transmutations.py
│   ├── nuclearDataIO/
│   │   ├── __init__.py
│   │   ├── cccc/
│   │   │   ├── __init__.py
│   │   │   ├── cccc.py
│   │   │   ├── compxs.py
│   │   │   ├── dif3d.py
│   │   │   ├── fixsrc.py
│   │   │   ├── gamiso.py
│   │   │   ├── geodst.py
│   │   │   ├── isotxs.py
│   │   │   ├── labels.py
│   │   │   ├── nhflux.py
│   │   │   ├── pmatrx.py
│   │   │   ├── pwdint.py
│   │   │   ├── rtflux.py
│   │   │   ├── rzflux.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── fixtures/
│   │   │       │   ├── labels.binary
│   │   │       │   ├── simple_cartesian.pwdint
│   │   │       │   ├── simple_cartesian.rtflux
│   │   │       │   ├── simple_cartesian.rzflux
│   │   │       │   ├── simple_hexz.dif3d
│   │   │       │   ├── simple_hexz.geodst
│   │   │       │   ├── simple_hexz.nhflux
│   │   │       │   └── simple_hexz.nhflux.variant
│   │   │       ├── test_cccc.py
│   │   │       ├── test_compxs.py
│   │   │       ├── test_dif3d.py
│   │   │       ├── test_fixsrc.py
│   │   │       ├── test_gamiso.py
│   │   │       ├── test_geodst.py
│   │   │       ├── test_isotxs.py
│   │   │       ├── test_labels.py
│   │   │       ├── test_nhflux.py
│   │   │       ├── test_pmatrx.py
│   │   │       ├── test_pwdint.py
│   │   │       ├── test_rtflux.py
│   │   │       └── test_rzflux.py
│   │   ├── nuclearFileMetadata.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── fixtures/
│   │   │   │   ├── AA.gamiso
│   │   │   │   ├── AA.pmatrx
│   │   │   │   ├── AB.gamiso
│   │   │   │   ├── AB.pmatrx
│   │   │   │   ├── ISOAA
│   │   │   │   ├── ISOAB
│   │   │   │   ├── combined-AA-AB.gamiso
│   │   │   │   ├── combined-AA-AB.isotxs
│   │   │   │   ├── combined-AA-AB.pmatrx
│   │   │   │   ├── combined-and-lumped-AA-AB.gamiso
│   │   │   │   ├── combined-and-lumped-AA-AB.isotxs
│   │   │   │   ├── combined-and-lumped-AA-AB.pmatrx
│   │   │   │   ├── mc2v3-AA.gamiso
│   │   │   │   ├── mc2v3-AA.isotxs
│   │   │   │   ├── mc2v3-AA.pmatrx
│   │   │   │   ├── mc2v3-AB.gamiso
│   │   │   │   ├── mc2v3-AB.isotxs
│   │   │   │   └── mc2v3-AB.pmatrx
│   │   │   ├── library-file-generation/
│   │   │   │   ├── combine-AA-AB.inp
│   │   │   │   ├── combine-and-lump-AA-AB.inp
│   │   │   │   ├── mc2v3-AA.inp
│   │   │   │   └── mc2v3-AB.inp
│   │   │   ├── simple_hexz.inp
│   │   │   ├── test_xsCollections.py
│   │   │   ├── test_xsLibraries.py
│   │   │   └── test_xsNuclides.py
│   │   ├── xsCollections.py
│   │   ├── xsLibraries.py
│   │   └── xsNuclides.py
│   ├── operators/
│   │   ├── __init__.py
│   │   ├── operator.py
│   │   ├── operatorMPI.py
│   │   ├── runTypes.py
│   │   ├── snapshots.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_operatorSnapshots.py
│   │       └── test_operators.py
│   ├── physics/
│   │   ├── __init__.py
│   │   ├── constants.py
│   │   ├── executers.py
│   │   ├── fuelCycle/
│   │   │   ├── __init__.py
│   │   │   ├── assemblyRotationAlgorithms.py
│   │   │   ├── fuelHandlerFactory.py
│   │   │   ├── fuelHandlerInterface.py
│   │   │   ├── fuelHandlers.py
│   │   │   ├── hexAssemblyFuelMgmtUtils.py
│   │   │   ├── settings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── _customFuelHandlerModule.py
│   │   │   │   ├── test_assemblyRotationAlgorithms.py
│   │   │   │   ├── test_fuelHandlerFactory.py
│   │   │   │   ├── test_fuelHandlers.py
│   │   │   │   ├── test_hexAssemblyFuelMgmtUtils.py
│   │   │   │   └── test_utils.py
│   │   │   └── utils.py
│   │   ├── fuelPerformance/
│   │   │   ├── __init__.py
│   │   │   ├── executers.py
│   │   │   ├── parameters.py
│   │   │   ├── plugin.py
│   │   │   ├── settings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_executers.py
│   │   │   │   ├── test_fuelPerformancePlugin.py
│   │   │   │   ├── test_fuelPerformanceSymmetry.py
│   │   │   │   └── test_fuelPerformanceUtils.py
│   │   │   └── utils.py
│   │   ├── neutronics/
│   │   │   ├── __init__.py
│   │   │   ├── const.py
│   │   │   ├── crossSectionGroupManager.py
│   │   │   ├── crossSectionSettings.py
│   │   │   ├── diffIsotxs.py
│   │   │   ├── energyGroups.py
│   │   │   ├── fissionProductModel/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── fissionProductModel.py
│   │   │   │   ├── fissionProductModelSettings.py
│   │   │   │   ├── lumpedFissionProduct.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_fissionProductModel.py
│   │   │   │       └── test_lumpedFissionProduct.py
│   │   │   ├── globalFlux/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── globalFluxInterface.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       └── test_globalFluxInterface.py
│   │   │   ├── isotopicDepletion/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── crossSectionTable.py
│   │   │   │   └── isotopicDepletionInterface.py
│   │   │   ├── latticePhysics/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── latticePhysicsInterface.py
│   │   │   │   ├── latticePhysicsWriter.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       ├── test_latticeInterface.py
│   │   │   │       └── test_latticeWriter.py
│   │   │   ├── macroXSGenerationInterface.py
│   │   │   ├── parameters.py
│   │   │   ├── plugin.py
│   │   │   ├── settings.py
│   │   │   └── tests/
│   │   │       ├── ISOXA
│   │   │       ├── __init__.py
│   │   │       ├── rzmflxYA
│   │   │       ├── test_crossSectionManager.py
│   │   │       ├── test_crossSectionSettings.py
│   │   │       ├── test_crossSectionTable.py
│   │   │       ├── test_energyGroups.py
│   │   │       ├── test_macroXSGenerationInterface.py
│   │   │       ├── test_neutronicsPlugin.py
│   │   │       └── test_neutronicsSymmetry.py
│   │   ├── safety/
│   │   │   └── __init__.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   └── test_executers.py
│   │   └── thermalHydraulics/
│   │       ├── __init__.py
│   │       ├── const.py
│   │       ├── parameters.py
│   │       ├── plugin.py
│   │       └── tests/
│   │           ├── __init__.py
│   │           └── test_thermalHydraulicsSymmetry.py
│   ├── pluginManager.py
│   ├── plugins.py
│   ├── reactor/
│   │   ├── __init__.py
│   │   ├── assemblies.py
│   │   ├── assemblyParameters.py
│   │   ├── blockParameters.py
│   │   ├── blocks/
│   │   │   ├── __init__.py
│   │   │   ├── block.py
│   │   │   ├── cartesianBlock.py
│   │   │   ├── hexBlock.py
│   │   │   └── thRZBlock.py
│   │   ├── blueprints/
│   │   │   ├── __init__.py
│   │   │   ├── assemblyBlueprint.py
│   │   │   ├── blockBlueprint.py
│   │   │   ├── componentBlueprint.py
│   │   │   ├── gridBlueprint.py
│   │   │   ├── isotopicOptions.py
│   │   │   ├── reactorBlueprint.py
│   │   │   └── tests/
│   │   │       ├── __init__.py
│   │   │       ├── test_assemblyBlueprints.py
│   │   │       ├── test_blockBlueprints.py
│   │   │       ├── test_blueprints.py
│   │   │       ├── test_componentBlueprint.py
│   │   │       ├── test_customIsotopics.py
│   │   │       ├── test_gridBlueprints.py
│   │   │       ├── test_materialModifications.py
│   │   │       └── test_reactorBlueprints.py
│   │   ├── components/
│   │   │   ├── __init__.py
│   │   │   ├── basicShapes.py
│   │   │   ├── complexShapes.py
│   │   │   ├── component.py
│   │   │   ├── componentParameters.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_basicShapes.py
│   │   │   │   └── test_complexShapes.py
│   │   │   └── volumetricShapes.py
│   │   ├── composites.py
│   │   ├── converters/
│   │   │   ├── __init__.py
│   │   │   ├── axialExpansionChanger/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── assemblyAxialLinkage.py
│   │   │   │   ├── axialExpansionChanger.py
│   │   │   │   ├── expansionData.py
│   │   │   │   └── redistributeMass.py
│   │   │   ├── blockConverters.py
│   │   │   ├── geometryConverters.py
│   │   │   ├── meshConverters.py
│   │   │   ├── parameterSweeps/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── generalParameterSweepConverters.py
│   │   │   │   └── tests/
│   │   │   │       ├── __init__.py
│   │   │   │       └── test_paramSweepConverters.py
│   │   │   ├── pinTypeBlockConverters.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_assemblyAxialLinkage.py
│   │   │   │   ├── test_axialExpansionChanger.py
│   │   │   │   ├── test_axialExpansionChanger_MultiPin.py
│   │   │   │   ├── test_blockConverter.py
│   │   │   │   ├── test_geometryConverters.py
│   │   │   │   ├── test_meshConverters.py
│   │   │   │   ├── test_pinTypeBlockConverters.py
│   │   │   │   └── test_uniformMesh.py
│   │   │   └── uniformMesh.py
│   │   ├── cores.py
│   │   ├── excoreStructure.py
│   │   ├── flags.py
│   │   ├── geometry.py
│   │   ├── grids/
│   │   │   ├── __init__.py
│   │   │   ├── axial.py
│   │   │   ├── cartesian.py
│   │   │   ├── constants.py
│   │   │   ├── grid.py
│   │   │   ├── hexagonal.py
│   │   │   ├── locations.py
│   │   │   ├── structuredGrid.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   └── test_grids.py
│   │   │   └── thetarz.py
│   │   ├── parameters/
│   │   │   ├── __init__.py
│   │   │   ├── exceptions.py
│   │   │   ├── parameterCollections.py
│   │   │   ├── parameterDefinitions.py
│   │   │   └── resolveCollections.py
│   │   ├── reactorParameters.py
│   │   ├── reactors.py
│   │   ├── spentFuelPool.py
│   │   ├── tests/
│   │   │   ├── __init__.py
│   │   │   ├── test_assemblies.py
│   │   │   ├── test_blocks.py
│   │   │   ├── test_components.py
│   │   │   ├── test_composites.py
│   │   │   ├── test_cores.py
│   │   │   ├── test_excoreStructures.py
│   │   │   ├── test_flags.py
│   │   │   ├── test_geometry.py
│   │   │   ├── test_hexBlockRotate.py
│   │   │   ├── test_parameters.py
│   │   │   ├── test_reactors.py
│   │   │   ├── test_rz_reactors.py
│   │   │   ├── test_zones.py
│   │   │   └── zonesFile.yaml
│   │   └── zones.py
│   ├── resources/
│   │   ├── burn-chain.yaml
│   │   └── mcc-nuclides.yaml
│   ├── runLog.py
│   ├── settings/
│   │   ├── __init__.py
│   │   ├── caseSettings.py
│   │   ├── fwSettings/
│   │   │   ├── __init__.py
│   │   │   ├── databaseSettings.py
│   │   │   ├── globalSettings.py
│   │   │   ├── reportSettings.py
│   │   │   ├── tests/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── test_fwSettings.py
│   │   │   │   └── test_tightCouplingSettings.py
│   │   │   └── tightCouplingSettings.py
│   │   ├── setting.py
│   │   ├── settingsIO.py
│   │   ├── settingsValidation.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       ├── test_inspectors.py
│   │       ├── test_settings.py
│   │       └── test_settingsIO.py
│   ├── testing/
│   │   ├── __init__.py
│   │   ├── reactors/
│   │   │   ├── anl-afci-177/
│   │   │   │   ├── anl-afci-177-blueprints.yaml
│   │   │   │   ├── anl-afci-177-coreMap.yaml
│   │   │   │   ├── anl-afci-177-fuelManagement.py
│   │   │   │   └── anl-afci-177.yaml
│   │   │   ├── c5g7/
│   │   │   │   ├── c5g7-blueprints.yaml
│   │   │   │   └── c5g7-settings.yaml
│   │   │   ├── godiva/
│   │   │   │   ├── godiva-blueprints.yaml
│   │   │   │   └── godiva.armi.unittest.yaml
│   │   │   ├── smallHexReactor/
│   │   │   │   ├── smallHexReactor-bp.yaml
│   │   │   │   └── smallHexReactor.yaml
│   │   │   └── thirdSmallHexReactor/
│   │   │       ├── thirdSmallHexReactor-bp.yaml
│   │   │       └── thirdSmallHexReactor.yaml
│   │   ├── resources/
│   │   │   └── armiRun-SHUFFLES.yaml
│   │   ├── singleMixedAssembly.py
│   │   ├── symmetryTesting.py
│   │   └── tests/
│   │       ├── __init__.py
│   │       └── test_symmetryTesting.py
│   ├── tests/
│   │   ├── 1DslabXSByCompTest.yaml
│   │   ├── ISOAA
│   │   ├── __init__.py
│   │   ├── armiRun.yaml
│   │   ├── detailedAxialExpansion/
│   │   │   ├── armiRun.yaml
│   │   │   ├── refSmallCoreGrid.yaml
│   │   │   ├── refSmallReactor.yaml
│   │   │   └── refSmallReactorBase.yaml
│   │   ├── mockRunLogs.py
│   │   ├── refSmallCartesian.yaml
│   │   ├── refSmallCoreGrid.yaml
│   │   ├── refSmallReactor.yaml
│   │   ├── refSmallReactorBase.yaml
│   │   ├── refSmallReactorShuffleLogic.py
│   │   ├── refSmallSfpGrid.yaml
│   │   ├── refTestCartesian.yaml
│   │   ├── smallestTestReactor/
│   │   │   ├── armiRunSmallest.yaml
│   │   │   ├── refOneBlockReactor.yaml
│   │   │   └── refSmallestReactor.yaml
│   │   ├── test_apps.py
│   │   ├── test_armiTestHelper.py
│   │   ├── test_cartesian.py
│   │   ├── test_context.py
│   │   ├── test_interfaces.py
│   │   ├── test_lwrInputs.py
│   │   ├── test_mpiActions.py
│   │   ├── test_mpiFeatures.py
│   │   ├── test_mpiParameters.py
│   │   ├── test_plugins.py
│   │   ├── test_runLog.py
│   │   ├── test_symmetry.py
│   │   ├── test_tests.py
│   │   ├── test_user_plugins.py
│   │   ├── tutorials/
│   │   │   ├── data_model.ipynb
│   │   │   ├── param_sweep.ipynb
│   │   │   └── pin-rotations.ipynb
│   │   ├── zpprTest.yaml
│   │   └── zpprTestGeom.yaml
│   └── utils/
│       ├── __init__.py
│       ├── asciimaps.py
│       ├── codeTiming.py
│       ├── customExceptions.py
│       ├── densityTools.py
│       ├── directoryChangers.py
│       ├── directoryChangersMpi.py
│       ├── dynamicImporter.py
│       ├── flags.py
│       ├── gridEditor.py
│       ├── hexagon.py
│       ├── iterables.py
│       ├── mathematics.py
│       ├── outputCache.py
│       ├── parsing.py
│       ├── pathTools.py
│       ├── plotting.py
│       ├── properties.py
│       ├── reportPlotting.py
│       ├── tabulate.py
│       ├── tests/
│       │   ├── __init__.py
│       │   ├── resources/
│       │   │   ├── lower/
│       │   │   │   ├── includeA.yaml
│       │   │   │   └── includeB.yaml
│       │   │   └── root.yaml
│       │   ├── test_asciimaps.py
│       │   ├── test_codeTiming.py
│       │   ├── test_custom_exceptions.py
│       │   ├── test_densityTools.py
│       │   ├── test_directoryChangers.py
│       │   ├── test_directoryChangersMpi.py
│       │   ├── test_flags.py
│       │   ├── test_hexagon.py
│       │   ├── test_iterables.py
│       │   ├── test_mathematics.py
│       │   ├── test_outputCache.py
│       │   ├── test_parsing.py
│       │   ├── test_pathTools.py
│       │   ├── test_plotting.py
│       │   ├── test_properties.py
│       │   ├── test_reportPlotting.py
│       │   ├── test_tabulate.py
│       │   ├── test_textProcessors.py
│       │   ├── test_triangle.py
│       │   ├── test_units.py
│       │   └── test_utils.py
│       ├── textProcessors.py
│       ├── triangle.py
│       └── units.py
├── doc/
│   ├── .static/
│   │   ├── __init__.py
│   │   ├── automateScr.py
│   │   ├── cleanup_test_results.py
│   │   ├── css/
│   │   │   └── theme_fixes.css
│   │   ├── dochelpers.py
│   │   ├── looseCouplingIllustration.dot
│   │   └── tightCouplingIllustration.dot
│   ├── Makefile
│   ├── __init__.py
│   ├── conf.py
│   ├── developer/
│   │   ├── documenting.rst
│   │   ├── entrypoints.rst
│   │   ├── first_time_contributors.rst
│   │   ├── guide.rst
│   │   ├── index.rst
│   │   ├── making_armi_based_apps.rst
│   │   ├── parallel_coding.rst
│   │   ├── profiling.rst
│   │   ├── standards_and_practices.rst
│   │   ├── testing.rst
│   │   └── tooling.rst
│   ├── gallery-src/
│   │   ├── README.rst
│   │   ├── analysis/
│   │   │   ├── README.rst
│   │   │   ├── run_blockMcnpMaterialCard.py
│   │   │   ├── run_hexBlockToRZConversion.py
│   │   │   └── run_hexReactorToRZ.py
│   │   └── framework/
│   │       ├── README.rst
│   │       ├── run_blockVolumeFractions.py
│   │       ├── run_chartOfNuclides.py
│   │       ├── run_computeReactionRates.py
│   │       ├── run_fuelManagement.py
│   │       ├── run_grids1_hex.py
│   │       ├── run_grids2_cartesian.py
│   │       ├── run_grids3_rzt.py
│   │       ├── run_isotxs.py
│   │       ├── run_isotxs2_matrix.py
│   │       ├── run_materials.py
│   │       ├── run_programmaticReactorDefinition.py
│   │       ├── run_reactorFacemap.py
│   │       └── run_transmutationMatrix.py
│   ├── getTestResults.py
│   ├── glossary.rst
│   ├── index.rst
│   ├── installation.rst
│   ├── make.bat
│   ├── qa_docs/
│   │   ├── index.rst
│   │   ├── scr/
│   │   │   ├── 0.1.rst
│   │   │   ├── 0.2.rst
│   │   │   ├── 0.3.rst
│   │   │   ├── 0.4.rst
│   │   │   ├── 0.5.rst
│   │   │   ├── 0.6.rst
│   │   │   ├── index.rst
│   │   │   └── latest_scr.rst
│   │   ├── sdid.rst
│   │   ├── srsd/
│   │   │   ├── bookkeeping_reqs.rst
│   │   │   ├── cases_reqs.rst
│   │   │   ├── cli_reqs.rst
│   │   │   ├── framework_reqs.rst
│   │   │   ├── materials_reqs.rst
│   │   │   ├── nucDirectory_reqs.rst
│   │   │   ├── nuclearDataIO_reqs.rst
│   │   │   ├── physics_reqs.rst
│   │   │   ├── reactors_reqs.rst
│   │   │   ├── runLog_reqs.rst
│   │   │   ├── settings_reqs.rst
│   │   │   └── utils_reqs.rst
│   │   ├── srsd.rst
│   │   └── str.rst
│   ├── readme.rst
│   ├── release/
│   │   └── index.rst
│   ├── skip_str.py
│   ├── tutorials/
│   │   ├── data_model.nblink
│   │   ├── index.rst
│   │   ├── making_your_first_app.rst
│   │   ├── materials_demo.ipynb
│   │   ├── nuclide_demo.ipynb
│   │   ├── param_sweep.nblink
│   │   ├── pin-rotations.nblink
│   │   ├── walkthrough_inputs.rst
│   │   └── walkthrough_lwr_inputs.rst
│   └── user/
│       ├── _gallery/
│       │   └── index.rst
│       ├── accessingEntryPoints.rst
│       ├── index.rst
│       ├── inputs.rst
│       ├── manual_data_access.rst
│       ├── outputs.rst
│       ├── params_report.rst
│       ├── physics_coupling.rst
│       ├── radial_and_axial_expansion.rst
│       ├── settings_report.rst
│       ├── spatial_block_data.rst
│       ├── symmetry_handling.rst
│       └── user_install.rst
└── pyproject.toml
Download .txt
Showing preview only (626K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (7732 symbols across 457 files)

FILE: .github/workflows/find_test_crumbs.py
  function main (line 29) | def main():

FILE: .github/workflows/validatemanifest.py
  function main (line 31) | def main():

FILE: armi/__init__.py
  function disableFutureConfigures (line 95) | def disableFutureConfigures():
  function isStableReleaseVersion (line 101) | def isStableReleaseVersion(version=None):
  function init (line 107) | def init(fName=None, cs=None, skipInspection=False, choice=None):
  function getDefaultPlugins (line 155) | def getDefaultPlugins() -> List[Type[plugins.ArmiPlugin]]:
  function getDefaultPluginManager (line 176) | def getDefaultPluginManager() -> pluginManager.ArmiPluginManager:
  function isConfigured (line 189) | def isConfigured():
  function getPluginManager (line 194) | def getPluginManager() -> Optional[pluginManager.ArmiPluginManager]:
  function getPluginManagerOrFail (line 202) | def getPluginManagerOrFail() -> pluginManager.ArmiPluginManager:
  function getApp (line 213) | def getApp() -> Optional[apps.App]:
  function _cleanupOnCancel (line 218) | def _cleanupOnCancel(signum, _frame):
  function _liveInterpreter (line 227) | def _liveInterpreter():
  function configure (line 232) | def configure(app: Optional[apps.App] = None, permissive=False):
  function applyAsyncioWindowsWorkaround (line 294) | def applyAsyncioWindowsWorkaround() -> None:

FILE: armi/__main__.py
  function main (line 29) | def main():

FILE: armi/apps.py
  class App (line 35) | class App:
    method __init__ (line 64) | def __init__(self):
    method __initNewPlugins (line 78) | def __initNewPlugins(self):
    method version (line 104) | def version(self) -> str:
    method pluginManager (line 114) | def pluginManager(self) -> pluginManager.ArmiPluginManager:
    method getSettings (line 118) | def getSettings(self) -> Dict[str, Setting]:
    method getParamRenames (line 178) | def getParamRenames(self) -> Dict[str, str]:
    method registerPluginFlags (line 217) | def registerPluginFlags(self):
    method registerUserPlugins (line 233) | def registerUserPlugins(self, pluginPaths):
    method _isPluginRegistered (line 271) | def _isPluginRegistered(self, pluginPath: str):
    method __registerUserPluginsAbsPath (line 303) | def __registerUserPluginsAbsPath(self, pluginPath):
    method __registerUserPluginsInternalImport (line 327) | def __registerUserPluginsInternalImport(self, pluginPath):
    method splashText (line 346) | def splashText(self):

FILE: armi/bookkeeping/__init__.py
  class BookkeepingPlugin (line 20) | class BookkeepingPlugin(plugins.ArmiPlugin):
    method exposeInterfaces (line 23) | def exposeInterfaces(cs):
    method defineEntryPoints (line 45) | def defineEntryPoints():
    method defineCaseDependencies (line 58) | def defineCaseDependencies(case, suite):
    method mpiActionRequiresReset (line 70) | def mpiActionRequiresReset(cmd) -> bool:

FILE: armi/bookkeeping/db/__init__.py
  function loadOperator (line 81) | def loadOperator(
  function _getH5File (line 177) | def _getH5File(db):

FILE: armi/bookkeeping/db/compareDB3.py
  class OutputWriter (line 65) | class OutputWriter:
    method __init__ (line 68) | def __init__(self, fname):
    method __enter__ (line 72) | def __enter__(self):
    method __exit__ (line 76) | def __exit__(self, *args):
    method writeln (line 79) | def writeln(self, msg: str) -> None:
  class DiffResults (line 85) | class DiffResults:
    method __init__ (line 105) | def __init__(self, tolerance):
    method addDiff (line 115) | def addDiff(self, compType: str, paramName: str, absMean: float, mean:...
    method addStructureDiffs (line 126) | def addStructureDiffs(self, nDiffs: int) -> None:
    method addTimeStep (line 132) | def addTimeStep(self, tsName: str) -> None:
    method _getDefault (line 136) | def _getDefault(self) -> list:
    method reportDiffs (line 139) | def reportDiffs(self, stream: OutputWriter) -> None:
    method nDiffs (line 150) | def nDiffs(self) -> int:
  function compareDatabases (line 157) | def compareDatabases(
  function _compareH5Groups (line 210) | def _compareH5Groups(out: OutputWriter, ref: h5py.Group, src: h5py.Group...
  function _compareTimeStep (line 219) | def _compareTimeStep(
  function _compareAuxData (line 243) | def _compareAuxData(
  function _compareSets (line 276) | def _compareSets(src: set, ref: set, out: OutputWriter, name: Optional[s...
  function _diffSpecialData (line 290) | def _diffSpecialData(
  function _diffSimpleData (line 416) | def _diffSimpleData(ref: h5py.Dataset, src: h5py.Dataset, diffResults: D...
  function _compareComponentData (line 451) | def _compareComponentData(

FILE: armi/bookkeeping/db/database.py
  function getH5GroupName (line 90) | def getH5GroupName(cycle: int, timeNode: int, statePointName: str = None...
  class Database (line 100) | class Database:
    method __init__ (line 125) | def __init__(self, fileName: os.PathLike, permission: str = "r"):
    method version (line 156) | def version(self) -> str:
    method version (line 160) | def version(self, value: str):
    method versionMajor (line 167) | def versionMajor(self):
    method versionMinor (line 171) | def versionMinor(self):
    method __repr__ (line 174) | def __repr__(self):
    method open (line 177) | def open(self):
    method isOpen (line 216) | def isOpen(self):
    method writeSystemAttributes (line 220) | def writeSystemAttributes(h5db):
    method grabLocalCommitHash (line 247) | def grabLocalCommitHash():
    method close (line 286) | def close(self, completedSuccessfully=False):
    method splitDatabase (line 305) | def splitDatabase(self, keepTimeSteps: Sequence[Tuple[int, int]], labe...
    method fileName (line 366) | def fileName(self):
    method fileName (line 370) | def fileName(self, fName):
    method loadCS (line 375) | def loadCS(self, handleInvalids=True):
    method loadBlueprints (line 395) | def loadBlueprints(self, cs=None):
    method writeInputsToDB (line 429) | def writeInputsToDB(self, cs, csString=None, bpString=None):
    method readInputsFromDB (line 490) | def readInputsFromDB(self):
    method mergeHistory (line 496) | def mergeHistory(self, inputDB, startCycle, startNode):
    method __enter__ (line 518) | def __enter__(self):
    method __exit__ (line 528) | def __exit__(self, type, value, traceback):
    method __del__ (line 535) | def __del__(self):
    method __delitem__ (line 539) | def __delitem__(self, tn: Tuple[int, int, Optional[str]]):
    method genTimeStepGroups (line 545) | def genTimeStepGroups(
    method getLayout (line 559) | def getLayout(self, cycle, node):
    method genTimeSteps (line 566) | def genTimeSteps(self) -> Generator[Tuple[int, int], None, None]:
    method genAuxiliaryData (line 576) | def genAuxiliaryData(self, ts: Tuple[int, int]) -> Generator[str, None...
    method getAuxiliaryDataPath (line 587) | def getAuxiliaryDataPath(ts: Tuple[int, int], name: str) -> str:
    method keys (line 590) | def keys(self):
    method getH5Group (line 593) | def getH5Group(self, r, statePointName=None):
    method hasTimeStep (line 608) | def hasTimeStep(self, cycle, timeNode, statePointName=""):
    method writeToDB (line 612) | def writeToDB(self, reactor, statePointName=None):
    method syncToSharedFolder (line 624) | def syncToSharedFolder(self):
    method load (line 650) | def load(
    method loadReadOnly (line 752) | def loadReadOnly(self, cycle, node, statePointName=None):
    method _setParamsBeforeFreezing (line 775) | def _setParamsBeforeFreezing(r: Reactor):
    method _assignBlueprintsParams (line 782) | def _assignBlueprintsParams(blueprints, groupedComps):
    method _compose (line 796) | def _compose(self, comps, cs, parent=None):
    method _getArrayShape (line 857) | def _getArrayShape(arr: Union[np.ndarray, List, Tuple]):
    method _writeParams (line 867) | def _writeParams(self, h5group, comps) -> tuple:
    method _addHomogenizedNumberDensityParams (line 962) | def _addHomogenizedNumberDensityParams(blocks, h5group):
    method _readParams (line 976) | def _readParams(h5group, compTypeName, comps, allowMissing=False):
    method getHistoryByLocation (line 1059) | def getHistoryByLocation(
    method getHistoriesByLocation (line 1068) | def getHistoriesByLocation(
    method getHistory (line 1207) | def getHistory(
    method getHistories (line 1230) | def getHistories(
    method _writeAttrs (line 1363) | def _writeAttrs(obj, group, attrs):
    method _resolveAttrs (line 1399) | def _resolveAttrs(attrs, group):
    method _applyComponentNumberDensitiesMigration (line 1430) | def _applyComponentNumberDensitiesMigration(comps, unpackedData):
    method getCycleNodeAtTime (line 1446) | def getCycleNodeAtTime(dbPath, startTime, endTime, errorIfNotExactlyOn...
  function packSpecialData (line 1495) | def packSpecialData(
  function unpackSpecialData (line 1599) | def unpackSpecialData(data: np.ndarray, attrs, paramName: str) -> np.nda...
  function collectBlockNumberDensities (line 1654) | def collectBlockNumberDensities(blocks) -> Dict[str, np.ndarray]:

FILE: armi/bookkeeping/db/databaseInterface.py
  function describeInterfaces (line 45) | def describeInterfaces(cs):
  class DatabaseInterface (line 50) | class DatabaseInterface(interfaces.Interface):
    method __init__ (line 61) | def __init__(self, r, cs):
    method __repr__ (line 77) | def __repr__(self):
    method database (line 81) | def database(self):
    method interactBOL (line 91) | def interactBOL(self):
    method initDB (line 96) | def initDB(self, fName: Optional[os.PathLike] = None):
    method interactEveryNode (line 120) | def interactEveryNode(self, cycle, node):
    method writeDBEveryNode (line 136) | def writeDBEveryNode(self):
    method interactEOC (line 143) | def interactEOC(self, cycle=None):
    method interactEOL (line 153) | def interactEOL(self):
    method closeDB (line 160) | def closeDB(self):
    method interactError (line 164) | def interactError(self):
    method interactDistributeState (line 176) | def interactDistributeState(self) -> None:
    method distributable (line 189) | def distributable(self):
    method prepRestartRun (line 192) | def prepRestartRun(self):
    method _checkThatCyclesHistoriesAreEquivalentUpToRestartTime (line 244) | def _checkThatCyclesHistoriesAreEquivalentUpToRestartTime(self, loadDb...
    method _getLoadDB (line 266) | def _getLoadDB(self, fileName):
    method loadState (line 286) | def loadState(self, cycle, timeNode, timeStepName="", fileName=None):
    method getHistory (line 326) | def getHistory(
    method getHistories (line 366) | def getHistories(

FILE: armi/bookkeeping/db/factory.py
  function databaseFactory (line 24) | def databaseFactory(dbName: str, permission: str, version: Optional[str]...

FILE: armi/bookkeeping/db/jaggedArray.py
  class JaggedArray (line 27) | class JaggedArray:
    method __init__ (line 41) | def __init__(self, jaggedData, paramName):
    method __iter__ (line 101) | def __iter__(self):
    method __contains__ (line 105) | def __contains__(self, other):
    method flatten (line 109) | def flatten(x):
    method fromH5 (line 126) | def fromH5(cls, data, offsets, shapes, nones, dtype, paramName):
    method tolist (line 162) | def tolist(self):
    method unpack (line 166) | def unpack(self):

FILE: armi/bookkeeping/db/layout.py
  class Layout (line 93) | class Layout:
    method __init__ (line 123) | def __init__(self, version: Tuple[int, int], h5group=None, comp=None):
    method __getitem__ (line 177) | def __getitem__(self, sn):
    method _createLayout (line 191) | def _createLayout(self, comp):
    method _readLayout (line 249) | def _readLayout(self, h5group):
    method _initComps (line 312) | def _initComps(self, caseTitle, bp):
    method writeToDB (line 366) | def writeToDB(self, h5group):
    method computeAncestors (line 465) | def computeAncestors(serialNum, numChildren, depth=1) -> List[Optional...
    method allSubclasses (line 529) | def allSubclasses(cls) -> set:
  function _packLocations (line 534) | def _packLocations(
  function _packLocationsV1 (line 563) | def _packLocationsV1(
  function _packLocationsV2 (line 585) | def _packLocationsV2(
  function _packLocationsV3 (line 612) | def _packLocationsV3(
  function _unpackLocations (line 642) | def _unpackLocations(locationTypes, locData, minorVersion: int = DB_MINOR):
  function _unpackLocationsV1 (line 655) | def _unpackLocationsV1(locationTypes, locData):
  function _unpackLocationsV2 (line 673) | def _unpackLocationsV2(locationTypes, locData):
  function replaceNonesWithNonsense (line 703) | def replaceNonesWithNonsense(data: np.ndarray, paramName: str, nones: np...
  function replaceNonsenseWithNones (line 804) | def replaceNonsenseWithNones(data: np.ndarray, paramName: str) -> np.nda...

FILE: armi/bookkeeping/db/passiveDBLoadPlugin.py
  class PassThroughYamlize (line 32) | class PassThroughYamlize(yamlize.Object):
    method from_yaml (line 36) | def from_yaml(cls, loader, node, round_trip_data=None):
  class PassiveDBLoadPlugin (line 41) | class PassiveDBLoadPlugin(plugins.ArmiPlugin):
    method defineBlueprintsSections (line 67) | def defineBlueprintsSections():
    method defineParameters (line 83) | def defineParameters():
    method buildParamColl (line 94) | def buildParamColl(names):

FILE: armi/bookkeeping/db/permissions.py
  class Permissions (line 16) | class Permissions:

FILE: armi/bookkeeping/db/tests/test_comparedb3.py
  class TestCompareDB3 (line 39) | class TestCompareDB3(unittest.TestCase):
    method setUp (line 42) | def setUp(self):
    method tearDown (line 46) | def tearDown(self):
    method test_outputWriter (line 49) | def test_outputWriter(self):
    method test_compareSets (line 57) | def test_compareSets(self):
    method test_diffResultsBasic (line 67) | def test_diffResultsBasic(self):
    method test_compareDatabaseDuplicate (line 99) | def test_compareDatabaseDuplicate(self):
    method test_compareDatabaseSim (line 130) | def test_compareDatabaseSim(self):
    method test_diffSpecialData (line 197) | def test_diffSpecialData(self):
    method test_diffSimpleData (line 262) | def test_diffSimpleData(self):
    method test_compareAuxData (line 296) | def test_compareAuxData(self):
    method test_differentlySizedSpecialData (line 320) | def test_differentlySizedSpecialData(self):
    method test_nothingForDictionaries (line 337) | def test_nothingForDictionaries(self):

FILE: armi/bookkeeping/db/tests/test_database.py
  class TestDatabase (line 54) | class TestDatabase(unittest.TestCase):
    method setUp (line 57) | def setUp(self):
    method tearDown (line 75) | def tearDown(self):
    method makeShuffleHistory (line 80) | def makeShuffleHistory(self):
    method test_load (line 120) | def test_load(self):
    method test_loadSortSetting (line 156) | def test_loadSortSetting(self):
    method test_history (line 171) | def test_history(self):
    method test_fullCoreOnDbLoad (line 208) | def test_fullCoreOnDbLoad(self):
    method test_dontExpandIfFullCoreInDB (line 217) | def test_dontExpandIfFullCoreInDB(self):
    method test_getCycleNodeAtTime (line 231) | def test_getCycleNodeAtTime(self):
  class TestDatabaseSmaller (line 265) | class TestDatabaseSmaller(unittest.TestCase):
    method setUp (line 268) | def setUp(self):
    method tearDown (line 282) | def tearDown(self):
    method makeHistory (line 287) | def makeHistory(self):
    method test_loadOperator (line 298) | def test_loadOperator(self):
    method _compareArrays (line 333) | def _compareArrays(self, ref, src):
    method _compareRoundTrip (line 353) | def _compareRoundTrip(self, data):
    method test_getArrayShape (line 359) | def test_getArrayShape(self):
    method test_writeToDB (line 372) | def test_writeToDB(self):
    method test_getH5File (line 418) | def test_getH5File(self):
    method test_auxData (line 432) | def test_auxData(self):
    method test_replaceNones (line 439) | def test_replaceNones(self):
    method test_mergeHistory (line 461) | def test_mergeHistory(self):
    method test_splitDatabase (line 504) | def test_splitDatabase(self):
    method test_grabLocalCommitHash (line 547) | def test_grabLocalCommitHash(self):
    method test_fileName (line 601) | def test_fileName(self):
    method test_readInputsFromDB (line 610) | def test_readInputsFromDB(self):
    method test_deleting (line 632) | def test_deleting(self):
    method test_open (line 638) | def test_open(self):
    method test_loadCS (line 643) | def test_loadCS(self):
    method test_loadBlueprints (line 648) | def test_loadBlueprints(self):
    method test_prepRestartRun (line 653) | def test_prepRestartRun(self):
    method test_computeParents (line 747) | def test_computeParents(self):
  class TestWriteReadDatabase (line 806) | class TestWriteReadDatabase(unittest.TestCase):
    method setUp (line 845) | def setUp(self):
    method tearDown (line 864) | def tearDown(self):
    method test_readWriteRoundTrip (line 868) | def test_readWriteRoundTrip(self):
    method test_badData (line 953) | def test_badData(self):
  class TestSimplestDatabaseItems (line 971) | class TestSimplestDatabaseItems(unittest.TestCase):
    method setUp (line 974) | def setUp(self):
    method tearDown (line 978) | def tearDown(self):
    method test_open (line 981) | def test_open(self):
  class TestStaticDatabaseItems (line 991) | class TestStaticDatabaseItems(unittest.TestCase):
    method test_applyComponentNumberDensitiesMigration (line 992) | def test_applyComponentNumberDensitiesMigration(self):

FILE: armi/bookkeeping/db/tests/test_databaseInterface.py
  function getSimpleDBOperator (line 40) | def getSimpleDBOperator(cs):
  class MockInterface (line 65) | class MockInterface(interfaces.Interface):
    method __init__ (line 68) | def __init__(self, r, cs, action=None):
    method interactEveryNode (line 72) | def interactEveryNode(self, cycle, node):
  class TestDatabaseInterfaceBOL (line 76) | class TestDatabaseInterfaceBOL(unittest.TestCase):
    method test_interactBOL (line 79) | def test_interactBOL(self):
  class TestDatabaseInterface (line 99) | class TestDatabaseInterface(unittest.TestCase):
    method setUp (line 102) | def setUp(self):
    method tearDown (line 111) | def tearDown(self):
    method test_distributable (line 125) | def test_distributable(self):
    method test_demonstrateWritingInteractions (line 130) | def test_demonstrateWritingInteractions(self):
    method test_interactEveryNodeReturnTightCoupling (line 174) | def test_interactEveryNodeReturnTightCoupling(self):
    method test_timeNodeLoop_tightCoupling (line 180) | def test_timeNodeLoop_tightCoupling(self):
    method test_syncDbAfterWrite (line 189) | def test_syncDbAfterWrite(self):
    method test_noSyncDbAfterWrite (line 224) | def test_noSyncDbAfterWrite(self):
    method test_writeDBFromDBLoadSameDir (line 238) | def test_writeDBFromDBLoadSameDir(self):
    method test_writeDBFromDBLoadDifDir (line 275) | def test_writeDBFromDBLoadDifDir(self):
  class TestDatabaseWriter (line 317) | class TestDatabaseWriter(unittest.TestCase):
    method setUp (line 318) | def setUp(self):
    method tearDown (line 327) | def tearDown(self):
    method test_writeSystemAttributes (line 331) | def test_writeSystemAttributes(self):
    method test_metaData_endSuccessfully (line 353) | def test_metaData_endSuccessfully(self):
    method test_metaDataEndFail (line 396) | def test_metaDataEndFail(self):
    method test_getHistory (line 415) | def test_getHistory(self):
    method test_getHistoryByLocation (line 451) | def test_getHistoryByLocation(self):
  class TestDatabaseReading (line 477) | class TestDatabaseReading(unittest.TestCase):
    method setUpClass (line 479) | def setUpClass(cls):
    method tearDownClass (line 519) | def tearDownClass(cls):
    method _fullCoreSizeChecker (line 524) | def _fullCoreSizeChecker(self, r):
    method test_loadReadOnly (line 531) | def test_loadReadOnly(self):
    method test_growToFullCore (line 546) | def test_growToFullCore(self):
    method test_growToFullCoreWithCS (line 560) | def test_growToFullCoreWithCS(self):
    method test_growToFullCoreFromFactory (line 567) | def test_growToFullCoreFromFactory(self):
    method test_growToFullCoreFromFactoryWithCS (line 577) | def test_growToFullCoreFromFactoryWithCS(self):
    method test_readWritten (line 587) | def test_readWritten(self):
    method test_readWithoutInputs (line 626) | def test_readWithoutInputs(self):
    method test_variousTypesWork (line 637) | def test_variousTypesWork(self):
    method test_timesteps (line 654) | def test_timesteps(self):
  class TestBadName (line 667) | class TestBadName(unittest.TestCase):
    method test_badDBName (line 668) | def test_badDBName(self):
  class TestStandardFollowOn (line 679) | class TestStandardFollowOn(unittest.TestCase):
    method setUpClass (line 683) | def setUpClass(cls):
    method tearDownClass (line 698) | def tearDownClass(cls):
    method _getOperatorThatChangesVariables (line 702) | def _getOperatorThatChangesVariables(cs):
    method test_standardRestart (line 726) | def test_standardRestart(self):
    method _getRestartOperator (line 740) | def _getRestartOperator(self):

FILE: armi/bookkeeping/db/tests/test_jaggedArray.py
  class TestJaggedArray (line 25) | class TestJaggedArray(unittest.TestCase):
    method setUp (line 28) | def setUp(self):
    method tearDown (line 32) | def tearDown(self):
    method test_roundTrip (line 35) | def test_roundTrip(self):
    method test_roundTripBool (line 40) | def test_roundTripBool(self):
    method test_flatten (line 45) | def test_flatten(self):
    method test_backwardsCompatible (line 51) | def test_backwardsCompatible(self):
    method _compareRoundTrip (line 93) | def _compareRoundTrip(self, data, paramName):
    method _compareArrays (line 126) | def _compareArrays(self, ref, src):

FILE: armi/bookkeeping/db/tests/test_layout.py
  class TestLocationPacking (line 25) | class TestLocationPacking(unittest.TestCase):
    method setUp (line 28) | def setUp(self):
    method tearDown (line 32) | def tearDown(self):
    method test_locationPacking (line 35) | def test_locationPacking(self):
    method test_locationPackingOlderVersions (line 55) | def test_locationPackingOlderVersions(self):
    method test_locationPackingOldVersion (line 77) | def test_locationPackingOldVersion(self):
    method test_close (line 100) | def test_close(self):

FILE: armi/bookkeeping/db/tests/test_passiveDBLoadPlugin.py
  class TestPassiveDBLoadPlugin (line 32) | class TestPassiveDBLoadPlugin(unittest.TestCase):
    method setUp (line 33) | def setUp(self):
    method tearDown (line 45) | def tearDown(self):
    method test_passiveDBLoadPlugin (line 54) | def test_passiveDBLoadPlugin(self):
  class TestPassThroughYamlize (line 77) | class TestPassThroughYamlize(unittest.TestCase):
    method test_passThroughYamlizeExample1 (line 78) | def test_passThroughYamlizeExample1(self):

FILE: armi/bookkeeping/historyTracker.py
  function describeInterfaces (line 84) | def describeInterfaces(cs):
  class HistoryTrackerInterface (line 93) | class HistoryTrackerInterface(interfaces.Interface):
    method __init__ (line 123) | def __init__(self, r, cs):
    method interactBOL (line 138) | def interactBOL(self):
    method interactBOC (line 141) | def interactBOC(self, cycle=None):
    method interactEOL (line 147) | def interactEOL(self):
    method addDetailAssembliesBOL (line 151) | def addDetailAssembliesBOL(self):
    method addAllDetailedAssems (line 174) | def addAllDetailedAssems(self):
    method addDetailAssemsByAssemNums (line 180) | def addDetailAssemsByAssemNums(self):
    method _writeDetailAssemblyHistories (line 199) | def _writeDetailAssemblyHistories(self):
    method _getAssemHistoryFileName (line 210) | def _getAssemHistoryFileName(self, assem):
    method _getHistoryFileName (line 213) | def _getHistoryFileName(self, label, letter):
    method getTrackedParams (line 216) | def getTrackedParams(self):
    method addDetailAssembly (line 227) | def addDetailAssembly(self, a: "Assembly"):
    method getDetailAssemblies (line 233) | def getDetailAssemblies(self) -> list["Assembly"]:
    method getDetailBlocks (line 251) | def getDetailBlocks(self) -> list["Block"]:
    method nonStationaryBlocks (line 255) | def nonStationaryBlocks(self, a: "Assembly"):
    method getAssemHistories (line 258) | def getAssemHistories(self, assemList: List["Assembly"]):
    method writeAssemHistories (line 265) | def writeAssemHistories(self, detailAssems, allBlockHistories, assemLo...
    method preloadBlockHistoryVals (line 309) | def preloadBlockHistoryVals(self, names, keys, timesteps):
    method unloadBlockHistoryVals (line 332) | def unloadBlockHistoryVals(self):
    method getBlockHistoryVal (line 336) | def getBlockHistoryVal(self, name: str, paramName: str, ts: tuple[int,...
    method _isCurrentTimeStep (line 380) | def _isCurrentTimeStep(self, ts: tuple[int, int]) -> bool:
    method _databaseHasDataForTimeStep (line 384) | def _databaseHasDataForTimeStep(self, ts) -> bool:
    method getTimeSteps (line 389) | def getTimeSteps(self, a: "Assembly" = None) -> list[float]:
    method _getBlockInAssembly (line 420) | def _getBlockInAssembly(a: "Assembly") -> "Block":

FILE: armi/bookkeeping/mainInterface.py
  function describeInterfaces (line 40) | def describeInterfaces(_cs):
  class MainInterface (line 45) | class MainInterface(interfaces.Interface):
    method specifyInputs (line 58) | def specifyInputs(cs):
    method interactBOL (line 61) | def interactBOL(self):
    method _moveFiles (line 65) | def _moveFiles(self):
    method interactBOC (line 111) | def interactBOC(self, cycle=None):
    method interactEveryNode (line 119) | def interactEveryNode(self, cycle, node):
    method interactEOL (line 134) | def interactEOL(self):
    method cleanARMIFiles (line 140) | def cleanARMIFiles(self):
    method cleanLastCycleFiles (line 183) | def cleanLastCycleFiles(self):

FILE: armi/bookkeeping/memoryProfiler.py
  function describeInterfaces (line 64) | def describeInterfaces(cs):
  function getTotalJobMemory (line 69) | def getTotalJobMemory(nTasks, cpusPerTask):
  function getCurrentMemoryUsage (line 77) | def getCurrentMemoryUsage():
  class MemoryProfiler (line 88) | class MemoryProfiler(interfaces.Interface):
    method __init__ (line 91) | def __init__(self, r, cs):
    method interactBOL (line 95) | def interactBOL(self):
    method interactEveryNode (line 107) | def interactEveryNode(self, cycle, node):
    method interactEOL (line 122) | def interactEOL(self):
    method printCurrentMemoryState (line 128) | def printCurrentMemoryState(self):
    method displayMemoryUsage (line 148) | def displayMemoryUsage(self, timeDescription):
    method _reactorAssemblyTrackingBreakdown (line 161) | def _reactorAssemblyTrackingBreakdown(self):
    method checkForDuplicateObjectsOnArmiModel (line 176) | def checkForDuplicateObjectsOnArmiModel(self, attrName, refObject):
    method _printFullMemoryBreakdown (line 219) | def _printFullMemoryBreakdown(self, reportSize=True, printReferrers=Fa...
    method getReferrers (line 273) | def getReferrers(obj):
  class KlassCounter (line 280) | class KlassCounter:
    method __init__ (line 288) | def __init__(self, reportSize):
    method __getitem__ (line 293) | def __getitem__(self, classType):
    method countObjects (line 298) | def countObjects(self, ao):
  class InstanceCounter (line 320) | class InstanceCounter:
    method __init__ (line 321) | def __init__(self, classType, reportSize):
    method add (line 333) | def add(self, item):
    method __cmp__ (line 344) | def __cmp__(self, that):
    method __ls__ (line 347) | def __ls__(self, that):
    method __gt__ (line 350) | def __gt__(self, that):
  class ProfileMemoryUsageAction (line 354) | class ProfileMemoryUsageAction(mpiActions.MpiAction):
    method __init__ (line 355) | def __init__(self, timeDescription):
    method invokeHook (line 359) | def invokeHook(self):
  class SystemAndProcessMemoryUsage (line 364) | class SystemAndProcessMemoryUsage:
    method __init__ (line 365) | def __init__(self):
    method __isub__ (line 376) | def __isub__(self, other):
  class PrintSystemMemoryUsageAction (line 384) | class PrintSystemMemoryUsageAction(mpiActions.MpiAction):
    method __init__ (line 385) | def __init__(self):
    method __iter__ (line 390) | def __iter__(self):
    method __isub__ (line 393) | def __isub__(self, other):
    method minProcessMemoryInMB (line 401) | def minProcessMemoryInMB(self):
    method maxProcessMemoryInMB (line 407) | def maxProcessMemoryInMB(self):
    method invokeHook (line 412) | def invokeHook(self):
    method printUsage (line 417) | def printUsage(self, description=None):

FILE: armi/bookkeeping/report/__init__.py
  function setData (line 20) | def setData(name, value, group=None, reports=None):

FILE: armi/bookkeeping/report/data.py
  class Report (line 24) | class Report:
    method __init__ (line 31) | def __init__(self, title, description):
    method _groupRenderOrder (line 37) | def _groupRenderOrder(self):
    method __str__ (line 46) | def __str__(self):
    method addToReport (line 52) | def addToReport(self, group, name, value):
    method __getitem__ (line 58) | def __getitem__(self, group):
  class Group (line 66) | class Group:
    method __init__ (line 72) | def __init__(self, title, description=""):
    method __str__ (line 79) | def __str__(self):
    method __getitem__ (line 85) | def __getitem__(self, name):
    method __setitem__ (line 93) | def __setitem__(self, name, value):
  class Table (line 97) | class Table(Group):
    method __init__ (line 98) | def __init__(self, title, description="", header=None):
    method __str__ (line 102) | def __str__(self):
    method _lowerCaseSortForTuples (line 132) | def _lowerCaseSortForTuples(nameValPair):
    method __setitem__ (line 136) | def __setitem__(self, name, value):
  class Image (line 143) | class Image(Group):
    method __init__ (line 144) | def __init__(self, title, description=""):

FILE: armi/bookkeeping/report/reportInterface.py
  function describeInterfaces (line 35) | def describeInterfaces(cs):
  class ReportInterface (line 42) | class ReportInterface(interfaces.Interface):
    method __init__ (line 49) | def __init__(self, r, cs):
    method distributable (line 53) | def distributable(self):
    method interactBOL (line 57) | def interactBOL(self):
    method interactEveryNode (line 68) | def interactEveryNode(self, cycle, node):
    method interactBOC (line 94) | def interactBOC(self, cycle=None):
    method interactEOC (line 97) | def interactEOC(self, cycle=None):
    method generateDesignReport (line 101) | def generateDesignReport(self, generateFullCoreMap, showBlockAxMesh):
    method interactEOL (line 106) | def interactEOL(self):
    method printReports (line 129) | def printReports(self):
    method writeRunSummary (line 137) | def writeRunSummary(self):
    method reportSFP (line 145) | def reportSFP(sfp):
    method countAssembliesSFP (line 170) | def countAssembliesSFP(sfp):

FILE: armi/bookkeeping/report/reportingUtils.py
  function writeWelcomeHeaders (line 60) | def writeWelcomeHeaders(o, cs):
  function getNodeName (line 226) | def getNodeName():
  function _getSystemInfoWindows (line 250) | def _getSystemInfoWindows():
  function _getSystemInfoMac (line 273) | def _getSystemInfoMac():
  function _getSystemInfoLinux (line 298) | def _getSystemInfoLinux():
  function getSystemInfo (line 363) | def getSystemInfo():
  function getInterfaceStackSummary (line 390) | def getInterfaceStackSummary(o):
  function writeTightCouplingConvergenceSummary (line 421) | def writeTightCouplingConvergenceSummary(convergenceSummary):
  function writeAssemblyMassSummary (line 426) | def writeAssemblyMassSummary(r):
  function _makeBOLAssemblyMassSummary (line 522) | def _makeBOLAssemblyMassSummary(massSum):
  function _makeTotalAssemblyMassSummary (line 547) | def _makeTotalAssemblyMassSummary(massSum):
  function writeCycleSummary (line 563) | def writeCycleSummary(core):
  function setNeutronBalancesReport (line 582) | def setNeutronBalancesReport(core):
  function summarizePinDesign (line 638) | def summarizePinDesign(core):
  function summarizePowerPeaking (line 713) | def summarizePowerPeaking(core):
  function makeCoreDesignReport (line 743) | def makeCoreDesignReport(core, cs):
  function _setGeneralCoreDesignData (line 763) | def _setGeneralCoreDesignData(cs, coreDesignTable):
  function _setGeneralCoreParametersData (line 808) | def _setGeneralCoreParametersData(core, cs, coreDesignTable):
  function _setGeneralSimulationData (line 903) | def _setGeneralSimulationData(core, cs, coreDesignTable):
  function makeBlockDesignReport (line 928) | def makeBlockDesignReport(r):
  function _getComponentInputDimensions (line 958) | def _getComponentInputDimensions(cDesign):
  function makeCoreAndAssemblyMaps (line 979) | def makeCoreAndAssemblyMaps(r, cs, generateFullCoreMap=False, showBlockA...

FILE: armi/bookkeeping/report/tests/test_report.py
  class _MockReturnResult (line 48) | class _MockReturnResult:
    method __init__ (line 51) | def __init__(self, stdout):
  class TestReportingUtils (line 55) | class TestReportingUtils(unittest.TestCase):
    method test_getSystemInfoLinux (line 56) | def test_getSystemInfoLinux(self):
    method test_getSystemInfoWindows (line 86) | def test_getSystemInfoWindows(self, mockSubprocess):
    method test_getSystemInfoMac (line 99) | def test_getSystemInfoMac(self, mockSubprocess):
    method test_getSystemInfo (line 115) | def test_getSystemInfo(self):
    method test_getNodeName (line 133) | def test_getNodeName(self):
  class TestReport (line 143) | class TestReport(unittest.TestCase):
    method setUp (line 144) | def setUp(self):
    method test_setData (line 147) | def test_setData(self):
    method test_getData (line 164) | def test_getData(self):
    method test_reactorSpecificReporting (line 177) | def test_reactorSpecificReporting(self):
    method test_writeWelcomeHeaders (line 231) | def test_writeWelcomeHeaders(self):
  class TestReportInterface (line 257) | class TestReportInterface(unittest.TestCase):
    method setUpClass (line 259) | def setUpClass(cls):
    method tearDownClass (line 264) | def tearDownClass(cls):
    method test_printReports (line 267) | def test_printReports(self):
    method test_distributableReportInt (line 275) | def test_distributableReportInt(self):
    method test_interactBOLReportInt (line 279) | def test_interactBOLReportInt(self):
    method test_interactEveryNode (line 289) | def test_interactEveryNode(self):
    method test_interactBOC (line 299) | def test_interactBOC(self):
    method test_interactEOC (line 307) | def test_interactEOC(self):
    method test_interactEOL (line 316) | def test_interactEOL(self):

FILE: armi/bookkeeping/snapshotInterface.py
  function describeInterfaces (line 37) | def describeInterfaces(cs):
  class SnapshotInterface (line 42) | class SnapshotInterface(interfaces.Interface):
    method interactBOL (line 61) | def interactBOL(self):
    method interactEveryNode (line 67) | def interactEveryNode(self, cycle, node):
    method interactCoupled (line 73) | def interactCoupled(self, iteration):
    method activateDefaultSnapshots (line 79) | def activateDefaultSnapshots(self):
    method _getSnapTimesEquilibrium (line 94) | def _getSnapTimesEquilibrium(self):
    method _getSnapTimesNormal (line 100) | def _getSnapTimesNormal(self):
  function extractCycleNodeFromStamp (line 123) | def extractCycleNodeFromStamp(stamp):
  function getCycleNodeStamp (line 136) | def getCycleNodeStamp(cycle, node):

FILE: armi/bookkeeping/tests/test_historyTracker.py
  class TestHistoryTracker (line 37) | class TestHistoryTracker(ArmiTestHelper):
    method setUpClass (line 41) | def setUpClass(cls):
    method tearDownClass (line 87) | def tearDownClass(cls):
    method test_calcMGFluence (line 96) | def test_calcMGFluence(self):
    method test_historyParameters (line 133) | def test_historyParameters(self):
    method test_historyReport (line 178) | def test_historyReport(self):
    method test_getAssemHistories (line 204) | def test_getAssemHistories(self):
    method test_getBlockInAssembly (line 217) | def test_getBlockInAssembly(self):

FILE: armi/bookkeeping/tests/test_memoryProfiler.py
  class TestMemoryProfiler (line 31) | class TestMemoryProfiler(unittest.TestCase):
    method setUp (line 32) | def setUp(self):
    method tearDown (line 40) | def tearDown(self):
    method test_fullBreakdown (line 43) | def test_fullBreakdown(self):
    method test_displayMemoryUsage (line 58) | def test_displayMemoryUsage(self):
    method test_printFullMemoryBreakdown (line 72) | def test_printFullMemoryBreakdown(self):
    method test_getReferrers (line 87) | def test_getReferrers(self):
    method test_checkForDuplicateObjectsOnArmiModel (line 106) | def test_checkForDuplicateObjectsOnArmiModel(self):
    method test_profileMemoryUsageAction (line 126) | def test_profileMemoryUsageAction(self):
    method test_getTotalJobMemory (line 132) | def test_getTotalJobMemory(self, mockCpuCount, mockVMem):
    method test_getCurrentMemoryUsage (line 154) | def test_getCurrentMemoryUsage(self, mockSysAndProcMemUse, mockPrintSy...
    method test_printCurrentMemoryState (line 163) | def test_printCurrentMemoryState(self, mockCpuCount, mockVMem, mock1, ...
    method test_printCurrentMemoryState_noSetting (line 186) | def test_printCurrentMemoryState_noSetting(self):
    method _setMemUseMock (line 196) | def _setMemUseMock(self, mockPrintSysMemUseAction):
  class KlassCounterTests (line 209) | class KlassCounterTests(unittest.TestCase):
    method get_containers (line 210) | def get_containers(self):
    method test_expandContainer (line 223) | def test_expandContainer(self):
    method test_countHandlesRecursion (line 235) | def test_countHandlesRecursion(self):

FILE: armi/bookkeeping/tests/test_snapshot.py
  class MockReactorParams (line 25) | class MockReactorParams:
    method __init__ (line 26) | def __init__(self):
  class MockReactor (line 31) | class MockReactor:
    method __init__ (line 32) | def __init__(self, cs):
  class TestSnapshotInterface (line 37) | class TestSnapshotInterface(unittest.TestCase):
    method setUpClass (line 39) | def setUpClass(self):
    method setUp (line 42) | def setUp(self):
    method test_interactEveryNode (line 47) | def test_interactEveryNode(self, mockSnapshotRequest):
    method test_interactCoupled (line 55) | def test_interactCoupled(self, mockSnapshotRequest):
    method test_activateDefSnapshots_30cyc2burns (line 62) | def test_activateDefSnapshots_30cyc2burns(self):
    method test_activateDeftSnapshots_17cyc5surns (line 82) | def test_activateDeftSnapshots_17cyc5surns(self):

FILE: armi/bookkeeping/visualization/dumper.py
  class VisFileDumper (line 21) | class VisFileDumper(ABC):
    method dumpState (line 23) | def dumpState(self, r: reactors.Reactor):
    method __enter__ (line 27) | def __enter__(self):
    method __exit__ (line 31) | def __exit__(self, type, value, traceback):

FILE: armi/bookkeeping/visualization/entryPoint.py
  class VisFileEntryPoint (line 24) | class VisFileEntryPoint(entryPoint.EntryPoint):
    method __init__ (line 34) | def __init__(self):
    method addOptions (line 37) | def addOptions(self):
    method parse (line 71) | def parse(self, args):
    method invoke (line 114) | def invoke(self):

FILE: armi/bookkeeping/visualization/tests/test_vis.py
  class TestVtkMesh (line 30) | class TestVtkMesh(unittest.TestCase):
    method test_testVtkMesh (line 33) | def test_testVtkMesh(self):
  class TestVisDump (line 60) | class TestVisDump(unittest.TestCase):
    method setUpClass (line 64) | def setUpClass(cls):
    method test_dumpReactorVtk (line 83) | def test_dumpReactorVtk(self):
    method test_dumpReactorXdmf (line 90) | def test_dumpReactorXdmf(self):
    method test_hexMesh (line 100) | def test_hexMesh(self):
    method test_cartesianMesh (line 106) | def test_cartesianMesh(self):

FILE: armi/bookkeeping/visualization/tests/test_xdmf.py
  class TestXdmf (line 20) | class TestXdmf(unittest.TestCase):
    method test_dedupTimes (line 29) | def test_dedupTimes(self):

FILE: armi/bookkeeping/visualization/utils.py
  class VtkMesh (line 37) | class VtkMesh:
    method __init__ (line 50) | def __init__(self, vertices, connectivity, offsets, cellTypes):
    method empty (line 69) | def empty():
    method x (line 78) | def x(self):
    method y (line 82) | def y(self):
    method z (line 86) | def z(self):
    method append (line 89) | def append(self, other):
    method write (line 99) | def write(self, path, data) -> str:
  function createReactorBlockMesh (line 117) | def createReactorBlockMesh(r: reactors.Reactor) -> VtkMesh:
  function createReactorAssemMesh (line 126) | def createReactorAssemMesh(r: reactors.Reactor) -> VtkMesh:
  function createBlockMesh (line 135) | def createBlockMesh(b: blocks.Block) -> VtkMesh:
  function createAssemMesh (line 151) | def createAssemMesh(a: assemblies.Assembly) -> VtkMesh:
  function _createHexBlockMesh (line 179) | def _createHexBlockMesh(b: blocks.HexBlock) -> VtkMesh:
  function _createCartesianBlockMesh (line 206) | def _createCartesianBlockMesh(b: blocks.CartesianBlock) -> VtkMesh:
  function _createTRZBlockMesh (line 243) | def _createTRZBlockMesh(b: blocks.ThRZBlock) -> VtkMesh:

FILE: armi/bookkeeping/visualization/vtk.py
  class VtkDumper (line 43) | class VtkDumper(dumper.VisFileDumper):
    method __init__ (line 52) | def __init__(self, baseName: str, inputName: str):
    method dumpState (line 57) | def dumpState(
    method __enter__ (line 114) | def __enter__(self):
    method __exit__ (line 118) | def __exit__(self, type, value, traceback):
  function _collectObjectData (line 135) | def _collectObjectData(

FILE: armi/bookkeeping/visualization/xdmf.py
  function _getAttributesFromDataset (line 90) | def _getAttributesFromDataset(d: h5py.Dataset) -> Dict[str, str]:
  class XdmfDumper (line 113) | class XdmfDumper(dumper.VisFileDumper):
    method __init__ (line 125) | def __init__(self, baseName: str, inputName: Optional[str] = None):
    method __enter__ (line 144) | def __enter__(self):
    method __exit__ (line 170) | def __exit__(self, type, value, traceback):
    method _dedupTimes (line 219) | def _dedupTimes(times: List[float]) -> List[float]:
    method dumpState (line 254) | def dumpState(
    method _collectObjectData (line 293) | def _collectObjectData(self, objs: List[composites.ArmiObject], timeGr...
    method _makeBlockMesh (line 330) | def _makeBlockMesh(self, r: reactors.Reactor, indexMap) -> ET.Element:
    method _makeAssemblyMesh (line 361) | def _makeAssemblyMesh(self, r: reactors.Reactor, indexMap) -> ET.Element:
    method _makeGenericMesh (line 392) | def _makeGenericMesh(name: str, nCells: int, vertexData: h5py.Dataset,...
  function _getTopologyFromShape (line 429) | def _getTopologyFromShape(b: blocks.Block, offset: int) -> Tuple[int, Li...

FILE: armi/cases/case.py
  class Case (line 60) | class Case:
    method __init__ (line 69) | def __init__(self, cs, caseSuite=None, bp=None):
    method independentVariables (line 106) | def independentVariables(self):
    method __repr__ (line 123) | def __repr__(self):
    method bp (line 127) | def bp(self):
    method bp (line 140) | def bp(self, bp):
    method dependencies (line 144) | def dependencies(self):
    method addExplicitDependency (line 177) | def addExplicitDependency(self, case):
    method getPotentialParentFromSettingValue (line 191) | def getPotentialParentFromSettingValue(self, settingValue, filePattern):
    method _getPotentialDependencies (line 215) | def _getPotentialDependencies(self, dirName, title):
    method title (line 231) | def title(self):
    method title (line 236) | def title(self, name):
    method dbName (line 240) | def dbName(self):
    method directory (line 245) | def directory(self):
    method __eq__ (line 249) | def __eq__(self, that):
    method __hash__ (line 263) | def __hash__(self):
    method setUpTaskDependence (line 270) | def setUpTaskDependence(self):
    method run (line 283) | def run(self):
    method _startCoverage (line 330) | def _startCoverage(self):
    method _endCoverage (line 354) | def _endCoverage(userCovFile, cov=None):
    method _getCoverageRcFile (line 385) | def _getCoverageRcFile(userCovFile, makeCopy=False):
    method _startProfiling (line 412) | def _startProfiling(self):
    method _endProfiling (line 428) | def _endProfiling(profiler=None):
    method initializeOperator (line 457) | def initializeOperator(self, r=None):
    method _initBurnChain (line 470) | def _initBurnChain(self):
    method checkInputs (line 494) | def checkInputs(self):
    method clone (line 548) | def clone(
    method compare (line 637) | def compare(
    method writeInputs (line 665) | def writeInputs(self, sourceDir: Optional[str] = None, writeStyle: Opt...
  function _copyInputsHelper (line 720) | def _copyInputsHelper(fileDescription: str, sourcePath: str, destPath: s...
  function copyInterfaceInputs (line 756) | def copyInterfaceInputs(cs, destination: str, sourceDir: Optional[str] =...

FILE: armi/cases/inputModifiers/inputModifiers.py
  class InputModifier (line 17) | class InputModifier:
    method __init__ (line 38) | def __init__(self, independentVariable=None):
    method __call__ (line 52) | def __call__(self, cs, bp):
  class SamplingInputModifier (line 57) | class SamplingInputModifier(InputModifier):
    method __init__ (line 72) | def __init__(self, name: str, paramType: str, bounds: list, independen...
    method __call__ (line 94) | def __call__(self, cs, blueprints):
  class FullCoreModifier (line 99) | class FullCoreModifier(InputModifier):
    method __call__ (line 112) | def __call__(self, cs, bp):
  class SettingsModifier (line 119) | class SettingsModifier(InputModifier):
    method __init__ (line 122) | def __init__(self, settingName, value):
    method __call__ (line 127) | def __call__(self, cs, bp):
  class MultiSettingModifier (line 132) | class MultiSettingModifier(InputModifier):
    method __init__ (line 142) | def __init__(self, settingVals: dict):
    method __call__ (line 146) | def __call__(self, cs, bp):
  class BluePrintBlockModifier (line 155) | class BluePrintBlockModifier(InputModifier):
    method __init__ (line 158) | def __init__(self, block, component, dimension, value):
    method __call__ (line 165) | def __call__(self, cs, bp):

FILE: armi/cases/inputModifiers/neutronicsModifiers.py
  class NeutronicConvergenceModifier (line 30) | class NeutronicConvergenceModifier(inputModifiers.InputModifier):
    method __init__ (line 41) | def __init__(self, value):
    method __call__ (line 49) | def __call__(self, cs, bp):
  class NeutronicMeshsSizeModifier (line 59) | class NeutronicMeshsSizeModifier(inputModifiers.InputModifier):
    method __init__ (line 72) | def __init__(self, multFactor):
    method __call__ (line 78) | def __call__(self, cs, bp):

FILE: armi/cases/inputModifiers/pinTypeInputModifiers.py
  class _PinTypeAssemblyModifier (line 20) | class _PinTypeAssemblyModifier(inputModifiers.InputModifier):
    method __init__ (line 31) | def __init__(self, value):
    method __call__ (line 35) | def __call__(self, cs, bp):
    method _getBlockTypesToModify (line 81) | def _getBlockTypesToModify(self):
    method _adjustBlock (line 85) | def _adjustBlock(self, b):
  class SmearDensityModifier (line 90) | class SmearDensityModifier(_PinTypeAssemblyModifier):
    method _getBlockTypesToModify (line 98) | def _getBlockTypesToModify(self):
    method _adjustBlock (line 102) | def _adjustBlock(self, b):
  class CladThicknessByODModifier (line 107) | class CladThicknessByODModifier(_PinTypeAssemblyModifier):
    method _getBlockTypesToModify (line 112) | def _getBlockTypesToModify(self):
    method _adjustBlock (line 116) | def _adjustBlock(self, b):
  class CladThicknessByIDModifier (line 120) | class CladThicknessByIDModifier(_PinTypeAssemblyModifier):
    method _getBlockTypesToModify (line 125) | def _getBlockTypesToModify(self):
    method _adjustBlock (line 129) | def _adjustBlock(self, b):

FILE: armi/cases/inputModifiers/tests/test_inputModifiers.py
  class TestsuiteBuilderIntegrations (line 124) | class TestsuiteBuilderIntegrations(unittest.TestCase):
    method setUpClass (line 126) | def setUpClass(cls):
    method test_smearDensityFail (line 132) | def test_smearDensityFail(self):
    method test_settingsModifier (line 142) | def test_settingsModifier(self):
    method test_bluePrintBlockModifier (line 165) | def test_bluePrintBlockModifier(self):
  class TestSettingsModifiers (line 201) | class TestSettingsModifiers(unittest.TestCase):
    method test_NeutronicConvergenceModifier (line 202) | def test_NeutronicConvergenceModifier(self):
  class NeutronicsKernelOpts (line 217) | class NeutronicsKernelOpts(inputModifiers.InputModifier):
    method __init__ (line 218) | def __init__(self, neutronicsKernelOpts):
    method __call__ (line 222) | def __call__(self, cs, bp):
  class TestFullCoreModifier (line 227) | class TestFullCoreModifier(unittest.TestCase):
    method test_fullCoreConversion (line 230) | def test_fullCoreConversion(self):
    method test_fullCoreConversionWithOrientation (line 238) | def test_fullCoreConversionWithOrientation(self):

FILE: armi/cases/inputModifiers/tests/test_pinTypeInputModifiers.py
  class TestBlueprintModifiers (line 25) | class TestBlueprintModifiers(unittest.TestCase):
    method setUp (line 26) | def setUp(self):
    method test_AdjustSmearDensity (line 30) | def test_AdjustSmearDensity(self):
    method test_CladThickenessByODModifier (line 60) | def test_CladThickenessByODModifier(self):
    method test_CladThickenessByIDModifier (line 91) | def test_CladThickenessByIDModifier(self):

FILE: armi/cases/suite.py
  class CaseSuite (line 40) | class CaseSuite:
    method __init__ (line 56) | def __init__(self, cs):
    method add (line 60) | def add(self, case):
    method remove (line 77) | def remove(self, case):
    method __iter__ (line 82) | def __iter__(self):
    method __len__ (line 85) | def __len__(self):
    method discover (line 88) | def discover(
    method echoConfiguration (line 129) | def echoConfiguration(self):
    method clone (line 157) | def clone(self, oldRoot=None, writeStyle="short"):
    method run (line 198) | def run(self):
    method compare (line 217) | def compare(
    method writeInputs (line 275) | def writeInputs(self, writeStyle="short"):
    method writeTable (line 292) | def writeTable(tableResults):

FILE: armi/cases/suiteBuilder.py
  function getInputModifiers (line 37) | def getInputModifiers(cls):
  class SuiteBuilder (line 41) | class SuiteBuilder:
    method __init__ (line 73) | def __init__(self, baseCase):
    method __len__ (line 83) | def __len__(self):
    method __repr__ (line 86) | def __repr__(self):
    method addDegreeOfFreedom (line 89) | def addDegreeOfFreedom(self, inputModifiers):
    method addModifierSet (line 104) | def addModifierSet(self, inputModifierSet: List):
    method buildSuite (line 112) | def buildSuite(self, namingFunc=None):
  class FullFactorialSuiteBuilder (line 181) | class FullFactorialSuiteBuilder(SuiteBuilder):
    method __init__ (line 184) | def __init__(self, baseCase):
    method addDegreeOfFreedom (line 189) | def addDegreeOfFreedom(self, inputModifiers):
  class FullFactorialSuiteBuilderNoisy (line 241) | class FullFactorialSuiteBuilderNoisy(FullFactorialSuiteBuilder):
    method __init__ (line 250) | def __init__(self, baseCase, noiseFraction):
    method addDegreeOfFreedom (line 254) | def addDegreeOfFreedom(self, inputModifiers):
    method _perturb (line 268) | def _perturb(self, mod):
  class SeparateEffectsSuiteBuilder (line 277) | class SeparateEffectsSuiteBuilder(SuiteBuilder):
    method addDegreeOfFreedom (line 280) | def addDegreeOfFreedom(self, inputModifiers):

FILE: armi/cases/tests/test_cases.py
  class TestArmiCase (line 84) | class TestArmiCase(unittest.TestCase):
    method test_independentVariables (line 87) | def test_independentVariables(self):
    method test_setUpTaskDependence (line 103) | def test_setUpTaskDependence(self):
    method test_getCoverageRcFile (line 113) | def test_getCoverageRcFile(self):
    method test_startCoverage (line 124) | def test_startCoverage(self):
    method test_endCoverage (line 136) | def test_endCoverage(self):
    method test_startProfiling (line 150) | def test_startProfiling(self):
    method test_endProfiling (line 167) | def test_endProfiling(self):
    method test_run (line 178) | def test_run(self):
    method test_clone (line 216) | def test_clone(self):
  class TestCaseSuiteDependencies (line 253) | class TestCaseSuiteDependencies(unittest.TestCase):
    method setUp (line 256) | def setUp(self):
    method test_clone (line 269) | def test_clone(self):
    method test_checkInputs (line 274) | def test_checkInputs(self):
    method test_dependenciesWithObscurePaths (line 285) | def test_dependenciesWithObscurePaths(self):
    method test_dependencyFromDBName (line 366) | def test_dependencyFromDBName(self):
    method test_dependencyFromExplictRepeatShuffles (line 381) | def test_dependencyFromExplictRepeatShuffles(self):
    method test_explicitDependency (line 387) | def test_explicitDependency(self):
    method test_titleSetterGetter (line 399) | def test_titleSetterGetter(self):
  class TestCaseSuiteComparison (line 405) | class TestCaseSuiteComparison(unittest.TestCase):
    method setUp (line 408) | def setUp(self):
    method tearDown (line 412) | def tearDown(self):
    method test_compareNoDiffs (line 415) | def test_compareNoDiffs(self):
  class TestExtraInputWriting (line 470) | class TestExtraInputWriting(unittest.TestCase):
    method test_writeInput (line 473) | def test_writeInput(self):
  class MultiFilesInterfaces (line 496) | class MultiFilesInterfaces(interfaces.Interface):
    method specifyInputs (line 505) | def specifyInputs(cs):
  class TestPluginWithDuplicateSetting (line 510) | class TestPluginWithDuplicateSetting(plugins.ArmiPlugin):
    method defineSettings (line 513) | def defineSettings():
  class TestPluginCopyInterfaceFiles (line 525) | class TestPluginCopyInterfaceFiles(plugins.ArmiPlugin):
    method defineSettings (line 528) | def defineSettings():
    method exposeInterfaces (line 541) | def exposeInterfaces(cs):
  class TestCopyInterfaceInputs (line 552) | class TestCopyInterfaceInputs(unittest.TestCase):
    method setUp (line 555) | def setUp(self):
    method tearDown (line 562) | def tearDown(self):
    method test_copyInputsHelper (line 569) | def test_copyInputsHelper(self):
    method test_copyInterfaceInputsSingleFile (line 600) | def test_copyInterfaceInputsSingleFile(self):
    method test_copyInterfaceInputsNonFilePath (line 612) | def test_copyInterfaceInputsNonFilePath(self):
    method test_copyInterfaceInputs_emptyFilePath (line 624) | def test_copyInterfaceInputs_emptyFilePath(self):
    method test_failOnDuplicateSetting (line 637) | def test_failOnDuplicateSetting(self):
    method test_copyInterfaceInputsMultipleFiles (line 646) | def test_copyInterfaceInputsMultipleFiles(self):
    method test_copyInterfaceInputsOneFile (line 671) | def test_copyInterfaceInputsOneFile(self):
    method test_copyInterfaceInputsWildcardFile (line 696) | def test_copyInterfaceInputsWildcardFile(self):
    method test_copyInterfaceInputsRelPath (line 718) | def test_copyInterfaceInputsRelPath(self):
    method test_copyInterfaceInputsAbsPath (line 732) | def test_copyInterfaceInputsAbsPath(self):

FILE: armi/cases/tests/test_suiteBuilder.py
  class SettingModifier (line 28) | class SettingModifier(InputModifier):
    method __init__ (line 29) | def __init__(self, settingName, value):
    method __call__ (line 33) | def __call__(self, cs, bp):
  class TestFullFactorialSuiteBuilder (line 38) | class TestFullFactorialSuiteBuilder(unittest.TestCase):
    method test_buildSuite (line 41) | def test_buildSuite(self):
  class TestSeparateEffectsBuilder (line 75) | class TestSeparateEffectsBuilder(unittest.TestCase):
    method test_buildSuite (line 78) | def test_buildSuite(self):

FILE: armi/cli/__init__.py
  class EntryPointsPlugin (line 51) | class EntryPointsPlugin(plugins.ArmiPlugin):
    method defineEntryPoints (line 54) | def defineEntryPoints():
  class ArmiParser (line 90) | class ArmiParser(argparse.ArgumentParser):
    method print_help (line 93) | def print_help(self, file=None):
  class ArmiCLI (line 98) | class ArmiCLI:
    method __init__ (line 113) | def __init__(self):
    method showVersion (line 146) | def showVersion():
    method listCommands (line 157) | def listCommands(self):
    method run (line 183) | def run(self) -> Optional[int]:
    method executeCommand (line 198) | def executeCommand(self, command, args) -> Optional[int]:
  function splash (line 224) | def splash():

FILE: armi/cli/checkInputs.py
  class ExpandBlueprints (line 25) | class ExpandBlueprints(EntryPoint):
    method addOptions (line 36) | def addOptions(self):
    method invoke (line 39) | def invoke(self):
  class CheckInputEntryPoint (line 50) | class CheckInputEntryPoint(EntryPoint):
    method addOptions (line 60) | def addOptions(self):
    method invoke (line 83) | def invoke(self):

FILE: armi/cli/cleanTemps.py
  class CleanTemps (line 19) | class CleanTemps(EntryPoint):
    method invoke (line 30) | def invoke(self):

FILE: armi/cli/clone.py
  class CloneArmiRunCommandBatch (line 20) | class CloneArmiRunCommandBatch(EntryPoint):
    method addOptions (line 30) | def addOptions(self):
    method invoke (line 49) | def invoke(self):
  class CloneArmiRunCommandInteractive (line 60) | class CloneArmiRunCommandInteractive(CloneArmiRunCommandBatch):
  class CloneSuiteCommand (line 70) | class CloneSuiteCommand(EntryPoint):
    method addOptions (line 75) | def addOptions(self):
    method invoke (line 116) | def invoke(self):

FILE: armi/cli/compareCases.py
  class CompareCases (line 39) | class CompareCases(EntryPoint):
    method _addComparisonOptions (line 44) | def _addComparisonOptions(self):
    method addOptions (line 82) | def addOptions(self):
    method parse (line 97) | def parse(self, args):
    method invoke (line 106) | def invoke(self):
  class CompareSuites (line 119) | class CompareSuites(CompareCases):
    method addOptions (line 124) | def addOptions(self):
    method invoke (line 171) | def invoke(self):

FILE: armi/cli/database.py
  class ExtractInputs (line 25) | class ExtractInputs(EntryPoint):
    method addOptions (line 37) | def addOptions(self):
    method parse_args (line 47) | def parse_args(self, args):
    method invoke (line 53) | def invoke(self):
  class InjectInputs (line 85) | class InjectInputs(EntryPoint):
    method addOptions (line 95) | def addOptions(self):
    method invoke (line 100) | def invoke(self):

FILE: armi/cli/entryPoint.py
  class _EntryPointEnforcer (line 26) | class _EntryPointEnforcer(type):
    method __new__ (line 32) | def __new__(mcs, name, bases, attrs):
  class EntryPoint (line 43) | class EntryPoint(metaclass=_EntryPointEnforcer):
    method __init__ (line 98) | def __init__(self):
    method _initSettings (line 148) | def _initSettings():
    method addOptions (line 157) | def addOptions(self):
    method parse_args (line 174) | def parse_args(self, args):
    method parse (line 178) | def parse(self, args):
    method invoke (line 183) | def invoke(self) -> Optional[int]:
    method createOptionFromSetting (line 197) | def createOptionFromSetting(self, settingName: str, additionalAlias: s...
    method _createToggleFromSetting (line 251) | def _createToggleFromSetting(self, settingName, helpMessage, additiona...
  function storeBool (line 275) | def storeBool(boolDefault, ep):
  function setSetting (line 296) | def setSetting(ep):
  function setCaseTitle (line 314) | def setCaseTitle(cs):
  function loadSettings (line 327) | def loadSettings(cs):

FILE: armi/cli/gridGui.py
  class GridGuiEntryPoint (line 23) | class GridGuiEntryPoint(entryPoint.EntryPoint):
    method addOptions (line 28) | def addOptions(self):
    method invoke (line 37) | def invoke(self):

FILE: armi/cli/migrateInputs.py
  class MigrateInputs (line 24) | class MigrateInputs(EntryPoint):
    method addOptions (line 29) | def addOptions(self):
    method invoke (line 43) | def invoke(self):
    method _migrate (line 53) | def _migrate(settingsPath, dbPath):

FILE: armi/cli/modify.py
  class ModifyCaseSettingsCommand (line 24) | class ModifyCaseSettingsCommand(EntryPoint):
    method addOptions (line 37) | def addOptions(self):
    method invoke (line 76) | def invoke(self):

FILE: armi/cli/reportsEntryPoint.py
  class ReportsEntryPoint (line 18) | class ReportsEntryPoint(entryPoint.EntryPoint):
    method __init__ (line 28) | def __init__(self):
    method invoke (line 31) | def invoke(self):

FILE: armi/cli/run.py
  class RunEntryPoint (line 20) | class RunEntryPoint(EntryPoint):
    method invoke (line 26) | def invoke(self):

FILE: armi/cli/runSuite.py
  class RunSuiteCommand (line 24) | class RunSuiteCommand(RunEntryPoint):
    method addOptions (line 33) | def addOptions(self):
    method invoke (line 64) | def invoke(self):

FILE: armi/cli/tests/test_runEntryPoint.py
  function buildTestDB (line 43) | def buildTestDB(fileName, numNodes=1, numCycles=1):
  class TestInitializationEntryPoints (line 87) | class TestInitializationEntryPoints(unittest.TestCase):
    method test_entryPointInitialization (line 88) | def test_entryPointInitialization(self):
  class TestCheckInputEntryPoint (line 119) | class TestCheckInputEntryPoint(unittest.TestCase):
    method test_checkInputEntryPointBasics (line 120) | def test_checkInputEntryPointBasics(self):
    method test_checkInputEntryPointInvoke (line 129) | def test_checkInputEntryPointInvoke(self):
  class TestCloneArmiRunCommandBatch (line 151) | class TestCloneArmiRunCommandBatch(unittest.TestCase):
    method test_cloneArmiRunCommandBatchBasics (line 152) | def test_cloneArmiRunCommandBatchBasics(self):
    method test_cloneArmiRunCommandBatchInvokeShort (line 170) | def test_cloneArmiRunCommandBatchInvokeShort(self):
    method test_cloneArmiRunCommandBatchInvokeMedium (line 187) | def test_cloneArmiRunCommandBatchInvokeMedium(self):
  class TestCloneSuiteCommand (line 211) | class TestCloneSuiteCommand(unittest.TestCase):
    method test_cloneSuiteCommandBasics (line 212) | def test_cloneSuiteCommandBasics(self):
  class TestCompareCases (line 222) | class TestCompareCases(unittest.TestCase):
    method test_compareCasesBasics (line 223) | def test_compareCasesBasics(self):
  class TestCompareSuites (line 238) | class TestCompareSuites(unittest.TestCase):
    method test_compareSuitesBasics (line 239) | def test_compareSuitesBasics(self):
  class TestExpandBlueprints (line 251) | class TestExpandBlueprints(unittest.TestCase):
    method test_expandBlueprintsBasics (line 252) | def test_expandBlueprintsBasics(self):
  class TestExtractInputs (line 269) | class TestExtractInputs(unittest.TestCase):
    method test_extractInputsBasics (line 270) | def test_extractInputsBasics(self):
  class TestInjectInputs (line 301) | class TestInjectInputs(unittest.TestCase):
    method test_injectInputsBasics (line 302) | def test_injectInputsBasics(self):
    method test_injectInputsInvokeIgnore (line 310) | def test_injectInputsInvokeIgnore(self):
    method test_injectInputsInvokeNoData (line 322) | def test_injectInputsInvokeNoData(self):
  class TestMigrateInputs (line 337) | class TestMigrateInputs(unittest.TestCase):
    method test_migrateInputsBasics (line 338) | def test_migrateInputsBasics(self):
  class TestModifyCaseSettingsCommand (line 347) | class TestModifyCaseSettingsCommand(unittest.TestCase):
    method test_modifyCaseSettingsCommandBasics (line 348) | def test_modifyCaseSettingsCommandBasics(self):
    method test_modifyCaseSettingsCommandInvoke (line 358) | def test_modifyCaseSettingsCommandInvoke(self):
  class MockFakeReportsEntryPoint (line 382) | class MockFakeReportsEntryPoint(ReportsEntryPoint):
    method invoke (line 385) | def invoke(self):
  class TestReportsEntryPoint (line 389) | class TestReportsEntryPoint(unittest.TestCase):
    method test_cleanArgs (line 390) | def test_cleanArgs(self):
  class TestCompareIsotxsLibsEntryPoint (line 396) | class TestCompareIsotxsLibsEntryPoint(unittest.TestCase):
    method test_compareIsotxsLibsBasics (line 397) | def test_compareIsotxsLibsBasics(self):
  class TestRunEntryPoint (line 410) | class TestRunEntryPoint(unittest.TestCase):
    method test_runEntryPointBasics (line 411) | def test_runEntryPointBasics(self):
    method test_runCommandHelp (line 419) | def test_runCommandHelp(self):
    method test_executeCommand (line 427) | def test_executeCommand(self):
  class TestRunSuiteCommand (line 439) | class TestRunSuiteCommand(unittest.TestCase):
    method test_runSuiteCommandBasics (line 440) | def test_runSuiteCommandBasics(self):
  class TestVisFileEntryPointCommand (line 459) | class TestVisFileEntryPointCommand(unittest.TestCase):
    method test_visFileEntryPointBasics (line 460) | def test_visFileEntryPointBasics(self):

FILE: armi/cli/tests/test_runSuite.py
  class TestRunSuiteSuite (line 25) | class TestRunSuiteSuite(unittest.TestCase):
    method test_listCommand (line 26) | def test_listCommand(self):
    method test_showVersion (line 45) | def test_showVersion(self):
    method test_run (line 64) | def test_run(self, mockExeCmd):

FILE: armi/conftest.py
  function pytest_sessionstart (line 36) | def pytest_sessionstart(session):
  function bootstrapArmiTestEnv (line 42) | def bootstrapArmiTestEnv():

FILE: armi/context.py
  class Mode (line 53) | class Mode(enum.Enum):
    method setMode (line 67) | def setMode(cls, mode):
  function activateLocalFastPath (line 156) | def activateLocalFastPath() -> None:
  function getFastPath (line 189) | def getFastPath() -> str:
  function cleanFastPathAfterSimulation (line 201) | def cleanFastPathAfterSimulation():
  function disconnectAllHdfDBs (line 234) | def disconnectAllHdfDBs() -> None:

FILE: armi/interfaces.py
  class STACK_ORDER (line 38) | class STACK_ORDER:  # noqa: N801
  class TightCoupler (line 82) | class TightCoupler:
    method __init__ (line 120) | def __init__(self, param, tolerance, maxIters):
    method __repr__ (line 128) | def __repr__(self):
    method storePreviousIterationValue (line 134) | def storePreviousIterationValue(self, val: _SUPPORTED_TYPES):
    method isConverged (line 156) | def isConverged(self, val: _SUPPORTED_TYPES) -> bool:
    method getListDimension (line 229) | def getListDimension(listToCheck: list, dim: int = 1) -> int:
  class Interface (line 252) | class Interface:
    method getDependencies (line 275) | def getDependencies(cls, cs):
    method getInputFiles (line 279) | def getInputFiles(cls, cs):
    class Distribute (line 295) | class Distribute:
    method __init__ (line 302) | def __init__(self, r, cs):
    method __repr__ (line 333) | def __repr__(self):
    method _checkSettings (line 336) | def _checkSettings(self):
    method nameContains (line 340) | def nameContains(self, name):
    method distributable (line 343) | def distributable(self):
    method preDistributeState (line 354) | def preDistributeState(self):
    method postDistributeState (line 364) | def postDistributeState(self, toRestore):
    method attachReactor (line 368) | def attachReactor(self, o, r):
    method detachReactor (line 387) | def detachReactor(self):
    method duplicate (line 393) | def duplicate(self):
    method getHistoryParams (line 426) | def getHistoryParams(self):
    method getInterface (line 434) | def getInterface(self, *args, **kwargs):
    method interactInit (line 437) | def interactInit(self):
    method interactBOL (line 447) | def interactBOL(self):
    method _initializeParams (line 452) | def _initializeParams(self):
    method interactEOL (line 466) | def interactEOL(self):
    method interactBOC (line 470) | def interactBOC(self, cycle=None):
    method interactEOC (line 474) | def interactEOC(self, cycle=None):
    method interactEveryNode (line 478) | def interactEveryNode(self, cycle, node):
    method interactCoupled (line 482) | def interactCoupled(self, iteration):
    method getTightCouplingValue (line 486) | def getTightCouplingValue(self):
    method interactError (line 490) | def interactError(self):
    method interactDistributeState (line 494) | def interactDistributeState(self):
    method interactRestart (line 498) | def interactRestart(self, startNode: Tuple[int, int], previousNode: Tu...
    method isRequestedDetailPoint (line 515) | def isRequestedDetailPoint(self, cycle=None, node=None):
    method workerOperate (line 559) | def workerOperate(self, _cmd):
    method enabled (line 570) | def enabled(self, flag=None):
    method bolForce (line 588) | def bolForce(self, flag=None):
    method writeInput (line 610) | def writeInput(self, inName):
    method readOutput (line 614) | def readOutput(self, outName):
    method specifyInputs (line 619) | def specifyInputs(cs) -> Dict[Union[str, settings.Setting], List[str]]:
    method updatePhysicsCouplingControl (line 653) | def updatePhysicsCouplingControl(self):
  class InputWriter (line 658) | class InputWriter:
    method __init__ (line 661) | def __init__(self, r=None, externalCodeInterface=None, cs=None):
    method getInterface (line 667) | def getInterface(self, name):
    method write (line 673) | def write(self, fName):
  class OutputReader (line 678) | class OutputReader:
    method __init__ (line 692) | def __init__(self, r=None, externalCodeInterface=None, fName=None, cs=...
    method getInterface (line 704) | def getInterface(self, name):
    method read (line 710) | def read(self, fileName):
    method apply (line 714) | def apply(self, reactor):
  function _setTightCouplerByInterfaceFunction (line 725) | def _setTightCouplerByInterfaceFunction(interfaceClass, cs):
  function getActiveInterfaceInfo (line 751) | def getActiveInterfaceInfo(cs):
  function isInterfaceActive (line 774) | def isInterfaceActive(klass, cs):
  class InterfaceInfo (line 779) | class InterfaceInfo(NamedTuple):

FILE: armi/matProps/__init__.py
  function getPaths (line 93) | def getPaths(rootDir: str) -> list:
  function addMaterial (line 108) | def addMaterial(yamlPath: str, mat):
  function loadAll (line 128) | def loadAll(rootDir: str = None) -> None:
  function clear (line 164) | def clear() -> None:
  function loadSafe (line 172) | def loadSafe(rootDir: str = None) -> None:
  function getHashes (line 194) | def getHashes() -> dict:
  function getMaterial (line 204) | def getMaterial(name: str) -> Material:
  function loadMaterial (line 226) | def loadMaterial(yamlPath: str, saveMaterial: bool = False) -> Material:
  function loadedMaterials (line 259) | def loadedMaterials() -> list:
  function getLoadedRootDirs (line 276) | def getLoadedRootDirs() -> list:
  function load_all (line 289) | def load_all(rootDir: str = None) -> None:
  function load_safe (line 295) | def load_safe(rootDir: str = None) -> None:
  function get_material (line 301) | def get_material(name: str) -> Material:
  function load_material (line 307) | def load_material(yamlPath: str, saveMaterial: bool = False) -> Material:
  function loaded_materials (line 313) | def loaded_materials() -> list:
  function get_loaded_root_dirs (line 319) | def get_loaded_root_dirs() -> list:

FILE: armi/matProps/constituent.py
  class Constituent (line 18) | class Constituent:
    method __init__ (line 21) | def __init__(self, name: str, minValue: float, maxValue: float, isBala...
    method __repr__ (line 55) | def __repr__(self):
    method parseComposition (line 64) | def parseComposition(node):

FILE: armi/matProps/function.py
  class Function (line 18) | class Function:
    method __init__ (line 36) | def __init__(self, mat, prop):
    method clear (line 65) | def clear(self):
    method isTable (line 69) | def isTable():
    method getReferenceTemperature (line 73) | def getReferenceTemperature(self):
    method getIndependentVariables (line 89) | def getIndependentVariables(self):
    method getMinBound (line 100) | def getMinBound(self, var) -> float:
    method getMaxBound (line 111) | def getMaxBound(self, var) -> float:
    method references (line 123) | def references(self) -> list:
    method calc (line 126) | def calc(self, point: dict = None, **kwargs):
    method inRange (line 166) | def inRange(self, point: dict) -> bool:
    method __repr__ (line 185) | def __repr__(self):
    method _factory (line 190) | def _factory(mat, node, prop):
    method _setBounds (line 228) | def _setBounds(self, node: dict, var: str):
    method _parse (line 252) | def _parse(self, node):
    method _parseSpecific (line 298) | def _parseSpecific(self, node):
    method _calcSpecific (line 309) | def _calcSpecific(self, point: dict) -> float:

FILE: armi/matProps/interpolationFunctions.py
  function findIndex (line 20) | def findIndex(val: float, x: list) -> int:
  function linearLinear (line 48) | def linearLinear(Tc: float, x: list, y: list) -> float:
  function logLinear (line 72) | def logLinear(Tc: float, x: list, y: list) -> float:

FILE: armi/matProps/material.py
  class Material (line 28) | class Material:
    method __init__ (line 38) | def __init__(self):
    method __repr__ (line 55) | def __repr__(self):
    method hash (line 59) | def hash(self) -> str:
    method saved (line 63) | def saved(self) -> bool:
    method save (line 70) | def save(self):
    method dataCheckMaterialFile (line 75) | def dataCheckMaterialFile(filePath, rootNode):
    method getValidFileFormatVersions (line 102) | def getValidFileFormatVersions():
    method getNode (line 107) | def getNode(node: dict, subnodeName: str):
    method loadNode (line 124) | def loadNode(self, node: dict):
    method loadFile (line 143) | def loadFile(self, filePath: str):

FILE: armi/matProps/materialType.py
  class MaterialType (line 18) | class MaterialType:
    method __init__ (line 37) | def __init__(self, value: int = 0):
    method fromString (line 50) | def fromString(name: str) -> "MaterialType":
    method __repr__ (line 71) | def __repr__(self):
    method __eq__ (line 81) | def __eq__(self, other) -> bool:

FILE: armi/matProps/piecewiseFunction.py
  class PiecewiseFunction (line 26) | class PiecewiseFunction(Function):
    method __init__ (line 63) | def __init__(self, mat, prop):
    method __repr__ (line 79) | def __repr__(self):
    method clear (line 88) | def clear(self) -> None:
    method _parseSpecific (line 93) | def _parseSpecific(self, node):
    method _calcSpecific (line 137) | def _calcSpecific(self, point: dict) -> float:

FILE: armi/matProps/point.py
  class Point (line 18) | class Point:
    method __init__ (line 21) | def __init__(self, var1, var2, val):
    method __repr__ (line 43) | def __repr__(self):

FILE: armi/matProps/prop.py
  class Property (line 74) | class Property:
    method __init__ (line 77) | def __init__(self, name: str, symbol: str, units: str, tex: str = None):
    method __repr__ (line 104) | def __repr__(self):
  function contains (line 109) | def contains(name: str):
  function defProp (line 127) | def defProp(symbol: str, name: str, units: str, tex: str = None):
  function initialize (line 153) | def initialize():

FILE: armi/matProps/reference.py
  class Reference (line 20) | class Reference:
    method __init__ (line 26) | def __init__(self):
    method __repr__ (line 33) | def __repr__(self):
    method _factory (line 42) | def _factory(node):
    method getRef (line 68) | def getRef(self):
    method getType (line 72) | def getType(self):

FILE: armi/matProps/symbolicFunction.py
  class SymbolicFunction (line 28) | class SymbolicFunction(Function):
    method __init__ (line 46) | def __init__(self, mat, prop):
    method _parseSpecific (line 61) | def _parseSpecific(self, node):
    method _calcSpecific (line 95) | def _calcSpecific(self, point: dict) -> float:
    method __repr__ (line 112) | def __repr__(self):
    method __getstate__ (line 116) | def __getstate__(self):
    method __setstate__ (line 121) | def __setstate__(self, s):

FILE: armi/matProps/tableFunction.py
  class TableFunction (line 20) | class TableFunction(Function):
    method isTable (line 24) | def isTable():
    method _setBounds (line 27) | def _setBounds(self, node: dict):

FILE: armi/matProps/tableFunction1D.py
  class TableFunction1D (line 21) | class TableFunction1D(TableFunction):
    method __init__ (line 38) | def __init__(
    method __repr__ (line 61) | def __repr__(self):
    method _setBounds (line 65) | def _setBounds(self, node: dict, var: str):
    method _parseSpecific (line 78) | def _parseSpecific(self, prop):
    method _calcSpecific (line 92) | def _calcSpecific(self, point: dict) -> float:

FILE: armi/matProps/tableFunction2D.py
  class TableFunction2D (line 23) | class TableFunction2D(TableFunction):
    method __init__ (line 43) | def __init__(self, mat, prop):
    method __repr__ (line 65) | def __repr__(self):
    method _setBounds (line 69) | def _setBounds(self, node: int, var: str):
    method _parseSpecific (line 104) | def _parseSpecific(self, prop):
    method _calcSpecific (line 133) | def _calcSpecific(self, point: dict) -> float:

FILE: armi/matProps/tests/__init__.py
  class MatPropsFunTestBase (line 23) | class MatPropsFunTestBase(unittest.TestCase):
    method setUp (line 26) | def setUp(self):
    method polynomialEvaluation (line 33) | def polynomialEvaluation(powerMap, value):
    method powerLawEvaluation (line 52) | def powerLawEvaluation(coefficients, value):
    method hyperbolicEvaluation (line 62) | def hyperbolicEvaluation(coefficients, value):
    method createEqnPoly (line 72) | def createEqnPoly(coefficients):
    method createEqnPower (line 84) | def createEqnPower(coefficients):
    method createEqnHyper (line 95) | def createEqnHyper(coefficients):
    method _createFunctionWithoutTable (line 104) | def _createFunctionWithoutTable(self, data=None):
    method _createFunction (line 127) | def _createFunction(self, data=None, tableData=None, minT=-100.0, maxT...
    method belowMinimumCheck (line 156) | def belowMinimumCheck(self, yamlData, tableData=None):
    method aboveMaximumCheck (line 163) | def aboveMaximumCheck(self, yamlData, tableData=None):

FILE: armi/matProps/tests/test_1DSymbolicFunction.py
  class Test1DSymbolicFunction (line 22) | class Test1DSymbolicFunction(MatPropsFunTestBase):
    method setUpClass (line 26) | def setUpClass(cls):
    method test_polynomialEqnIntInt (line 62) | def test_polynomialEqnIntInt(self):
    method test_polynomialEqnFloatInt (line 87) | def test_polynomialEqnFloatInt(self):
    method test_polynomialEqnFloatFloat (line 107) | def test_polynomialEqnFloatFloat(self):
    method test_polynomialDiffFloatTypes (line 121) | def test_polynomialDiffFloatTypes(self):
    method test_symbolicEqnError (line 131) | def test_symbolicEqnError(self):
    method test_powerEqn (line 143) | def test_powerEqn(self):
    method test_powerEqnAllInt (line 154) | def test_powerEqnAllInt(self):
    method test_powerEqnFloatInt (line 175) | def test_powerEqnFloatInt(self):
    method test_powerEqnNoInter (line 196) | def test_powerEqnNoInter(self):
    method test_powerEqnNoOuter (line 209) | def test_powerEqnNoOuter(self):
    method test_powerEqnNoOuterInter (line 223) | def test_powerEqnNoOuterInter(self):
    method test_constantsEval (line 236) | def test_constantsEval(self):
    method test_hyperbolicEqnEval (line 245) | def test_hyperbolicEqnEval(self):
    method test_hyperbolicEqnEval2 (line 261) | def test_hyperbolicEqnEval2(self):

FILE: armi/matProps/tests/test_composition.py
  class TestComposition (line 26) | class TestComposition(unittest.TestCase):
    method setUp (line 27) | def setUp(self):
    method _createFunction (line 33) | def _createFunction(self, compMap=None):
    method test_compositionMissing (line 55) | def test_compositionMissing(self):
    method test_compositionInvTuple (line 67) | def test_compositionInvTuple(self):
    method test_compositionInvStr (line 76) | def test_compositionInvStr(self):
    method test_compositionMissBalance (line 84) | def test_compositionMissBalance(self):
    method test_compositionBalanceNum (line 89) | def test_compositionBalanceNum(self):
    method test_compositionBalance (line 94) | def test_compositionBalance(self):
    method test_compositionBalance2 (line 118) | def test_compositionBalance2(self):
    method test_compositionMinValue (line 147) | def test_compositionMinValue(self):
    method test_compositionMaxValue (line 152) | def test_compositionMaxValue(self):
    method test_compositionMaxValue2 (line 157) | def test_compositionMaxValue2(self):
    method test_compositionMinSum (line 162) | def test_compositionMinSum(self):
    method test_compositionDuplicate (line 172) | def test_compositionDuplicate(self):

FILE: armi/matProps/tests/test_constituent.py
  class TestConstituent (line 22) | class TestConstituent(unittest.TestCase):
    method test_errorHandling (line 23) | def test_errorHandling(self):
    method test_parseComposition (line 39) | def test_parseComposition(self):

FILE: armi/matProps/tests/test_functions.py
  class TestFunctions (line 21) | class TestFunctions(MatPropsFunTestBase):
    method setUpClass (line 25) | def setUpClass(cls):
    method test_getReferences (line 30) | def test_getReferences(self):
    method test_datafilesVarVals (line 36) | def test_datafilesVarVals(self):
    method test_datafilesMaxVar (line 48) | def test_datafilesMaxVar(self):
    method test_datafilesInvType (line 53) | def test_datafilesInvType(self):
    method test_refTempEval (line 59) | def test_refTempEval(self):
    method test_refTempMissing (line 67) | def test_refTempMissing(self):
    method test_refTempInvalid (line 74) | def test_refTempInvalid(self):
    method test_independentVars (line 83) | def test_independentVars(self):
    method test_calcEdgeCases (line 98) | def test_calcEdgeCases(self):
    method test_references (line 123) | def test_references(self):
    method test_tabulatedData (line 143) | def test_tabulatedData(self):

FILE: armi/matProps/tests/test_hashing.py
  class TestHashValues (line 23) | class TestHashValues(unittest.TestCase):
    method setUpClass (line 27) | def setUpClass(cls):
    method test_hash (line 30) | def test_hash(self):

FILE: armi/matProps/tests/test_interpolationFunctions.py
  class TestInterpolationFunctions (line 25) | class TestInterpolationFunctions(unittest.TestCase):
    method test_findIndex (line 28) | def test_findIndex(self):
    method test_linearLinear (line 44) | def test_linearLinear(self):
    method test_linearLinearInterpolation (line 56) | def test_linearLinearInterpolation(self):
    method test_linearLinearExtrapolation (line 68) | def test_linearLinearExtrapolation(self):
    method test_logLinear (line 75) | def test_logLinear(self):
    method test_logLinearExtrapolation (line 86) | def test_logLinearExtrapolation(self):

FILE: armi/matProps/tests/test_material.py
  class TestMapPropsMaterial (line 27) | class TestMapPropsMaterial(unittest.TestCase):
    method _createFunction (line 31) | def _createFunction(materialType):
    method test_getValidFileFormatVersions (line 63) | def test_getValidFileFormatVersions(self):
    method test_loadFile (line 70) | def test_loadFile(self):
    method test_datafilesType (line 78) | def test_datafilesType(self):
    method test_invalidFileFormat (line 95) | def test_invalidFileFormat(self):
    method test_datafilesInvType (line 102) | def test_datafilesInvType(self):
    method test_saveLogic (line 106) | def test_saveLogic(self):

FILE: armi/matProps/tests/test_materialType.py
  class TestMaterialType (line 22) | class TestMaterialType(unittest.TestCase):
    method test_fromString (line 23) | def test_fromString(self):
    method test_repr (line 33) | def test_repr(self):
    method test_equality (line 43) | def test_equality(self):

FILE: armi/matProps/tests/test_parsing.py
  class TestParsing (line 25) | class TestParsing(unittest.TestCase):
    method dirname (line 29) | def dirname(self):
    method setUpClass (line 34) | def setUpClass(cls):
    method tearDown (line 44) | def tearDown(self):
    method test_datafilesMatOwner (line 47) | def test_datafilesMatOwner(self):
    method test_multiDataLoadingLoadingAll (line 66) | def test_multiDataLoadingLoadingAll(self):
    method test_loadSafe (line 73) | def test_loadSafe(self):
    method test_dataLoadingPrioSameDir (line 88) | def test_dataLoadingPrioSameDir(self):
    method test_datafilesBadPath (line 100) | def test_datafilesBadPath(self):
    method test_multiDataLoadingMultidir (line 111) | def test_multiDataLoadingMultidir(self):
    method test_dataLoadingPrioDiffDir (line 143) | def test_dataLoadingPrioDiffDir(self):
    method test_datafilesGetMat (line 164) | def test_datafilesGetMat(self):

FILE: armi/matProps/tests/test_performance.py
  class TestPerformance (line 29) | class TestPerformance(unittest.TestCase):
    method test_load (line 35) | def test_load(self):
    method test_pickle (line 45) | def test_pickle(self):
    method test_calc (line 58) | def test_calc(self):
    method test_deepcopy (line 72) | def test_deepcopy(self):

FILE: armi/matProps/tests/test_piecewiseFunction.py
  class TestPiecewiseFunction (line 21) | class TestPiecewiseFunction(MatPropsFunTestBase):
    method setUpClass (line 25) | def setUpClass(cls):
    method test_piecewiseEqnEval (line 62) | def test_piecewiseEqnEval(self):
    method test_piecewiseEqnGap (line 78) | def test_piecewiseEqnGap(self):
    method test_piecewiseEqnPoly (line 130) | def test_piecewiseEqnPoly(self):
    method test_piecewiseEqnPolyTable (line 175) | def test_piecewiseEqnPolyTable(self):
    method test_inputCheckPiecewiseMinTemp (line 221) | def test_inputCheckPiecewiseMinTemp(self):
    method test_inputCheckPiecewiseMaxTemp (line 225) | def test_inputCheckPiecewiseMaxTemp(self):
    method _createFunction2D (line 229) | def _createFunction2D(self, data=None):
    method test_piecewiseEqn2d (line 252) | def test_piecewiseEqn2d(self):
    method test_piecewiseEqnOverlap (line 326) | def test_piecewiseEqnOverlap(self):
    method test_piecewiseEqnDiffVars (line 373) | def test_piecewiseEqnDiffVars(self):

FILE: armi/matProps/tests/test_point.py
  class TestPoint (line 28) | class TestPoint(unittest.TestCase):
    method test_string (line 31) | def test_string(self):

FILE: armi/matProps/tests/test_property.py
  class PropertyTests (line 25) | class PropertyTests(unittest.TestCase):
    method setUpClass (line 29) | def setUpClass(cls):
    method test_propertiesUnique (line 82) | def test_propertiesUnique(self):
    method test_propertiesNames (line 88) | def test_propertiesNames(self):
    method test_propertiesInvName (line 94) | def test_propertiesInvName(self):
    method test_propertiesDefinitions (line 101) | def test_propertiesDefinitions(self):
    method test_spotCheckAllPropsDict (line 119) | def test_spotCheckAllPropsDict(self):
    method test_spotCheckAllPropsKwargs (line 171) | def test_spotCheckAllPropsKwargs(self):
    method test_defPropDup (line 223) | def test_defPropDup(self):

FILE: armi/matProps/tests/test_references.py
  class TestReference (line 22) | class TestReference(unittest.TestCase):
    method test_str (line 25) | def test_str(self):
    method test_getRef (line 32) | def test_getRef(self):
    method test_getType (line 38) | def test_getType(self):
    method test_factory (line 44) | def test_factory(self):

FILE: armi/matProps/tests/test_symbolicFunction.py
  class TestSymbolicFunction (line 28) | class TestSymbolicFunction(unittest.TestCase):
    method setUp (line 31) | def setUp(self):
    method loadMaterial (line 47) | def loadMaterial(self, num=1):
    method functionTest (line 53) | def functionTest(self, func, num=1):
    method setEqnField (line 77) | def setEqnField(self, eqn):
    method test_symbolicMult (line 80) | def test_symbolicMult(self):
    method test_symbolicExponent (line 114) | def test_symbolicExponent(self):
    method test_symbolicDiv (line 148) | def test_symbolicDiv(self):
    method test_symbolicAdd (line 182) | def test_symbolicAdd(self):
    method test_symbolicSub (line 216) | def test_symbolicSub(self):
    method test_symbolicParens (line 250) | def test_symbolicParens(self):
    method test_symbolicSine (line 285) | def test_symbolicSine(self):
    method test_symbolicCosine (line 305) | def test_symbolicCosine(self):
    method test_symbolicTan (line 325) | def test_symbolicTan(self):
    method test_symbolicSinh (line 345) | def test_symbolicSinh(self):
    method test_symbolicCosh (line 365) | def test_symbolicCosh(self):
    method test_symbolicTanh (line 385) | def test_symbolicTanh(self):
    method test_symbolicNatLog (line 405) | def test_symbolicNatLog(self):
    method test_symbolicLog10 (line 438) | def test_symbolicLog10(self):
    method test_symbolicExp (line 458) | def test_symbolicExp(self):
    method test_symbolicComposition (line 478) | def test_symbolicComposition(self):
    method test_symbolicOrdop (line 505) | def test_symbolicOrdop(self):
    method test_symbolicWhitespace (line 536) | def test_symbolicWhitespace(self):
    method test_symbolicIntFloat (line 570) | def test_symbolicIntFloat(self):
    method test_symbolicBadParens (line 592) | def test_symbolicBadParens(self):
    method test_symbolicUndefined (line 630) | def test_symbolicUndefined(self):
    method test_symbolicCaps (line 648) | def test_symbolicCaps(self):
    method test_symbolicImpmult (line 671) | def test_symbolicImpmult(self):
    method test_symbolicVarVar (line 706) | def test_symbolicVarVar(self):
    method test_symbolicScientific (line 722) | def test_symbolicScientific(self):
    method test_symbolicExamples (line 748) | def test_symbolicExamples(self):
    method test_symbolicBadparse (line 767) | def test_symbolicBadparse(self):
    method test_pickleSymbolicFunction (line 789) | def test_pickleSymbolicFunction(self):
    method test_numpyEvals (line 806) | def test_numpyEvals(self):
    method test_largeExponentials (line 816) | def test_largeExponentials(self):
    method test_symbolicOutofbounds (line 828) | def test_symbolicOutofbounds(self):
  class TestBrokenSymbolicFunctions (line 848) | class TestBrokenSymbolicFunctions(unittest.TestCase):
    method test_complexNumbers (line 849) | def test_complexNumbers(self):
    method test_isNan (line 874) | def test_isNan(self):

FILE: armi/matProps/tests/test_tableFunctions.py
  class TestTableFunctions (line 23) | class TestTableFunctions(MatPropsFunTestBase):
    method setUpClass (line 27) | def setUpClass(cls):
    method test_interpolation1Dtable (line 45) | def test_interpolation1Dtable(self):
    method test_interpolation1DtableMissnode (line 61) | def test_interpolation1DtableMissnode(self):
    method test_interpolation1Dtable2 (line 66) | def test_interpolation1Dtable2(self):
    method test_interpolation1DtableInt (line 99) | def test_interpolation1DtableInt(self):
    method test_interpolationTable2D (line 118) | def test_interpolationTable2D(self):
    method test_interpolationTable2DMissNode (line 142) | def test_interpolationTable2DMissNode(self):
    method test_inputCheckTable2Doutbounds (line 147) | def test_inputCheckTable2Doutbounds(self):
    method test_inputCheckTableMinVar (line 163) | def test_inputCheckTableMinVar(self):
    method test_inputCheckTableMaxVar (line 167) | def test_inputCheckTableMaxVar(self):
    method test_inputCheckTable2DMinVar1 (line 171) | def test_inputCheckTable2DMinVar1(self):
    method test_inputCheckTable2DMaxVar1 (line 178) | def test_inputCheckTable2DMaxVar1(self):
    method test_inputCheckTable2DMinVar2 (line 185) | def test_inputCheckTable2DMinVar2(self):
    method test_table2DsetBounds (line 192) | def test_table2DsetBounds(self):
    method test_inputCheckTable2DMaxVar2 (line 224) | def test_inputCheckTable2DMaxVar2(self):
    method test_calcSpec2dEdgeCase (line 231) | def test_calcSpec2dEdgeCase(self):

FILE: armi/materials/__init__.py
  function setMaterialNamespaceOrder (line 48) | def setMaterialNamespaceOrder(order):
  function importMaterialsIntoModuleNamespace (line 74) | def importMaterialsIntoModuleNamespace(path, name, namespace, updateSour...
  function iterAllMaterialClassesInNamespace (line 116) | def iterAllMaterialClassesInNamespace(namespace):
  function resolveMaterialClassByName (line 130) | def resolveMaterialClassByName(name: str, namespaceOrder: List[str] = No...

FILE: armi/materials/air.py
  class Air (line 26) | class Air(material.Fluid):
    method setDefaultMassFracs (line 46) | def setDefaultMassFracs(self):
    method pseudoDensity (line 64) | def pseudoDensity(
    method specificVolumeLiquid (line 97) | def specificVolumeLiquid(self, Tk=None, Tc=None):
    method thermalConductivity (line 101) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 125) | def heatCapacity(self, Tk=None, Tc=None):

FILE: armi/materials/alloy200.py
  class Alloy200 (line 28) | class Alloy200(Material):
    method linearExpansion (line 87) | def linearExpansion(self, Tk=None, Tc=None):
    method setDefaultMassFracs (line 108) | def setDefaultMassFracs(self):

FILE: armi/materials/b4c.py
  class B4C (line 32) | class B4C(material.Material):
    method __init__ (line 39) | def __init__(self):
    method applyInputParams (line 43) | def applyInputParams(self, B10_wt_frac=None, theoretical_density=None,...
    method updateTD (line 63) | def updateTD(self, td: float) -> None:
    method setNewMassFracsFromMassEnrich (line 67) | def setNewMassFracsFromMassEnrich(self, massEnrichment):
    method setDefaultMassFracs (line 128) | def setDefaultMassFracs(self) -> None:
    method getMassEnrichmentFromNumEnrich (line 162) | def getMassEnrichmentFromNumEnrich(
    method pseudoDensity (line 173) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
    method density (line 183) | def density(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansionPercent (line 193) | def linearExpansionPercent(self, Tk: float = None, Tc: float = None) -...

FILE: armi/materials/be9.py
  class Be9 (line 30) | class Be9(Material):
    method setDefaultMassFracs (line 36) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 40) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/caH2.py
  class CaH2 (line 25) | class CaH2(SimpleSolid):
    method setDefaultMassFracs (line 28) | def setDefaultMassFracs(self):
    method density (line 54) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/californium.py
  class Californium (line 29) | class Californium(SimpleSolid):
    method setDefaultMassFracs (line 30) | def setDefaultMassFracs(self):
    method density (line 33) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/concrete.py
  class Concrete (line 28) | class Concrete(Material):
    method setDefaultMassFracs (line 34) | def setDefaultMassFracs(self):
    method density (line 46) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/copper.py
  class Cu (line 26) | class Cu(Material):
    method setDefaultMassFracs (line 29) | def setDefaultMassFracs(self):
    method density (line 33) | def density(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 36) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/cs.py
  class Cs (line 26) | class Cs(Fluid):
    method setDefaultMassFracs (line 29) | def setDefaultMassFracs(self):
    method pseudoDensity (line 32) | def pseudoDensity(self, Tk=None, Tc=None):
    method meltingPoint (line 47) | def meltingPoint(self):

FILE: armi/materials/custom.py
  class Custom (line 28) | class Custom(Material):
    method __init__ (line 33) | def __init__(self):
    method pseudoDensity (line 41) | def pseudoDensity(self, Tk=None, Tc=None):
    method setMassFrac (line 50) | def setMassFrac(self, *args, **kwargs):

FILE: armi/materials/graphite.py
  class Graphite (line 27) | class Graphite(Material):
    method setDefaultMassFracs (line 38) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 47) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/hafnium.py
  class Hafnium (line 26) | class Hafnium(SimpleSolid):
    method setDefaultMassFracs (line 27) | def setDefaultMassFracs(self):
    method density (line 31) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/hastelloyN.py
  class HastelloyN (line 26) | class HastelloyN(Material):
    method setDefaultMassFracs (line 53) | def setDefaultMassFracs(self):
    method thermalConductivity (line 75) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 97) | def heatCapacity(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 127) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method meanCoefficientThermalExpansion (line 146) | def meanCoefficientThermalExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/ht9.py
  class HT9 (line 29) | class HT9(materials.Material):
    method setDefaultMassFracs (line 46) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 65) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method thermalConductivity (line 75) | def thermalConductivity(self, Tk=None, Tc=None):

FILE: armi/materials/inconel.py
  class Inconel (line 25) | class Inconel(SimpleSolid):
    method setDefaultMassFracs (line 31) | def setDefaultMassFracs(self):
    method density (line 46) | def density(self, Tk=None, Tc=None):
  class Inconel617 (line 50) | class Inconel617(Inconel):

FILE: armi/materials/inconel600.py
  class Inconel600 (line 26) | class Inconel600(Material):
    method __init__ (line 43) | def __init__(self):
    method setDefaultMassFracs (line 49) | def setDefaultMassFracs(self):
    method thermalConductivity (line 63) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 84) | def heatCapacity(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 105) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method linearExpansion (line 125) | def linearExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/inconel625.py
  class Inconel625 (line 26) | class Inconel625(Material):
    method __init__ (line 43) | def __init__(self):
    method setDefaultMassFracs (line 49) | def setDefaultMassFracs(self):
    method thermalConductivity (line 68) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 89) | def heatCapacity(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 110) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method linearExpansion (line 130) | def linearExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/inconel800.py
  class Inconel800 (line 26) | class Inconel800(Material):
    method setDefaultMassFracs (line 37) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 56) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method meanCoefficientThermalExpansion (line 75) | def meanCoefficientThermalExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/inconelPE16.py
  class InconelPE16 (line 26) | class InconelPE16(SimpleSolid):
    method setDefaultMassFracs (line 32) | def setDefaultMassFracs(self):
    method density (line 73) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/inconelX750.py
  class InconelX750 (line 26) | class InconelX750(Material):
    method __init__ (line 43) | def __init__(self):
    method setDefaultMassFracs (line 50) | def setDefaultMassFracs(self):
    method thermalConductivity (line 68) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 89) | def heatCapacity(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 110) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method linearExpansion (line 130) | def linearExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/lead.py
  class Lead (line 26) | class Lead(material.Fluid):
    method volumetricExpansion (line 35) | def volumetricExpansion(self, Tk=None, Tc=None):
    method setDefaultMassFracs (line 46) | def setDefaultMassFracs(self):
    method pseudoDensity (line 50) | def pseudoDensity(self, Tk=None, Tc=None):
    method heatCapacity (line 57) | def heatCapacity(self, Tk=None, Tc=None):

FILE: armi/materials/leadBismuth.py
  class LeadBismuth (line 31) | class LeadBismuth(material.Fluid):
    method setDefaultMassFracs (line 42) | def setDefaultMassFracs(self):
    method pseudoDensity (line 47) | def pseudoDensity(self, Tk=None, Tc=None):
    method dynamicVisc (line 54) | def dynamicVisc(self, Tk=None, Tc=None):
    method heatCapacity (line 65) | def heatCapacity(self, Tk=None, Tc=None):
    method thermalConductivity (line 72) | def thermalConductivity(self, Tk=None, Tc=None):
    method volumetricExpansion (line 83) | def volumetricExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/lithium.py
  class Lithium (line 32) | class Lithium(material.Fluid):
    method applyInputParams (line 36) | def applyInputParams(self, LI_wt_frac=None, LI6_wt_frac=None, *args, *...
    method pseudoDensity (line 58) | def pseudoDensity(self, Tk=None, Tc=None):
    method setDefaultMassFracs (line 69) | def setDefaultMassFracs(self):
    method meltingPoint (line 81) | def meltingPoint(self):
    method boilingPoint (line 84) | def boilingPoint(self):
    method thermalConductivity (line 87) | def thermalConductivity(self, Tk=None, Tc=None):
    method heatCapacity (line 91) | def heatCapacity(self, Tk=None, Tc=None):

FILE: armi/materials/magnesium.py
  class Magnesium (line 26) | class Magnesium(material.Fluid):
    method setDefaultMassFracs (line 29) | def setDefaultMassFracs(self):
    method pseudoDensity (line 32) | def pseudoDensity(self, Tk=None, Tc=None):

FILE: armi/materials/material.py
  function parentAwareDensityRedirect (line 38) | def parentAwareDensityRedirect(f):
  class Material (line 65) | class Material:
    method __init_subclass__ (line 108) | def __init_subclass__(cls) -> None:
    method __init__ (line 133) | def __init__(self):
    method __repr__ (line 145) | def __repr__(self):
    method name (line 149) | def name(self):
    method name (line 154) | def name(self, nomen):
    method getName (line 168) | def getName(self):
    method getChildren (line 172) | def getChildren(self, deep=False, generationNum=1, includeMaterials=Fa...
    method getChildrenWithFlags (line 176) | def getChildrenWithFlags(self, typeSpec: TypeSpec, exactMatch=True):
    method backUp (line 180) | def backUp(self):
    method restoreBackup (line 185) | def restoreBackup(self, paramsToApply):
    method clearCache (line 189) | def clearCache(self):
    method _getCached (line 193) | def _getCached(self, name):
    method _setCache (line 197) | def _setCache(self, name, val):
    method duplicate (line 207) | def duplicate(self):
    method linearExpansion (line 221) | def linearExpansion(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansionPercent (line 233) | def linearExpansionPercent(self, Tk: float = None, Tc: float = None) -...
    method linearExpansionFactor (line 256) | def linearExpansionFactor(self, Tc: float, T0: float) -> float:
    method getThermalExpansionDensityReduction (line 285) | def getThermalExpansionDensityReduction(self, prevTempInC: float, newT...
    method setDefaultMassFracs (line 290) | def setDefaultMassFracs(self):
    method setMassFrac (line 294) | def setMassFrac(self, nucName: str, massFrac: float) -> None:
    method applyInputParams (line 317) | def applyInputParams(self):
    method adjustMassEnrichment (line 321) | def adjustMassEnrichment(self, massEnrichment: float) -> None:
    method adjustMassFrac (line 331) | def adjustMassFrac(self, nuclideName: str, massFraction: float) -> None:
    method volumetricExpansion (line 416) | def volumetricExpansion(self, Tk=None, Tc=None):
    method getTemperatureAtDensity (line 419) | def getTemperatureAtDensity(self, targetDensity: float, tempGuessInC: ...
    method liquidPorosity (line 428) | def liquidPorosity(self) -> float:
    method gasPorosity (line 433) | def gasPorosity(self) -> float:
    method pseudoDensity (line 437) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
    method pseudoDensityKgM3 (line 470) | def pseudoDensityKgM3(self, Tk: float = None, Tc: float = None) -> float:
    method density (line 481) | def density(self, Tk: float = None, Tc: float = None) -> float:
    method densityKgM3 (line 505) | def densityKgM3(self, Tk: float = None, Tc: float = None) -> float:
    method getCorrosionRate (line 515) | def getCorrosionRate(self, Tk: float = None, Tc: float = None) -> float:
    method yieldStrength (line 519) | def yieldStrength(self, Tk: float = None, Tc: float = None) -> float:
    method thermalConductivity (line 523) | def thermalConductivity(self, Tk: float = None, Tc: float = None) -> f...
    method getProperty (line 527) | def getProperty(self, propName: str, Tk: float = None, Tc: float = Non...
    method getMassFrac (line 542) | def getMassFrac(
    method clearMassFrac (line 577) | def clearMassFrac(self) -> None:
    method removeNucMassFrac (line 581) | def removeNucMassFrac(self, nuc: str) -> None:
    method checkPropertyTempRange (line 589) | def checkPropertyTempRange(self, label, val):
    method checkTempRange (line 608) | def checkTempRange(self, minT, maxT, val, label=""):
    method densityTimesHeatCapacity (line 638) | def densityTimesHeatCapacity(self, Tk: float = None, Tc: float = None)...
    method getNuclides (line 661) | def getNuclides(self):
    method getTempChangeForDensityChange (line 676) | def getTempChangeForDensityChange(self, Tc: float, densityFrac: float,...
    method heatCapacity (line 690) | def heatCapacity(self, Tk=None, Tc=None):
    method getTD (line 694) | def getTD(self):
    method adjustTD (line 698) | def adjustTD(self, val):
  class Fluid (line 704) | class Fluid(Material):
    method __init_subclass__ (line 707) | def __init_subclass__(cls):
    method getThermalExpansionDensityReduction (line 713) | def getThermalExpansionDensityReduction(self, prevTempInC, newTempInC):
    method linearExpansion (line 723) | def linearExpansion(self, Tk=None, Tc=None):
    method getTempChangeForDensityChange (line 738) | def getTempChangeForDensityChange(self, Tc: float, densityFrac: float,...
    method density (line 754) | def density(self, Tk=None, Tc=None):
  class SimpleSolid (line 765) | class SimpleSolid(Material):
    method __init__ (line 777) | def __init__(self):
    method linearExpansionPercent (line 781) | def linearExpansionPercent(self, Tk: float = None, Tc: float = None) -...
    method density (line 811) | def density(self, Tk: float = None, Tc: float = None) -> float:
    method pseudoDensity (line 815) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
  class FuelMaterial (line 823) | class FuelMaterial(Material):
    method applyInputParams (line 834) | def applyInputParams(
    method _applyIsotopicsMixFromCustomIsotopicsInput (line 877) | def _applyIsotopicsMixFromCustomIsotopicsInput(self, customIsotopics):
    method duplicate (line 890) | def duplicate(self):

FILE: armi/materials/mgO.py
  class MgO (line 26) | class MgO(Material):
    method __init__ (line 34) | def __init__(self):
    method setDefaultMassFracs (line 42) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 47) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/mixture.py
  class _Mixture (line 20) | class _Mixture(materials.Material):

FILE: armi/materials/molybdenum.py
  class Molybdenum (line 25) | class Molybdenum(SimpleSolid):
    method setDefaultMassFracs (line 26) | def setDefaultMassFracs(self):
    method density (line 30) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/mox.py
  class MOX (line 35) | class MOX(UraniumOxide):
    method __init__ (line 47) | def __init__(self):
    method applyInputParams (line 50) | def applyInputParams(self, U235_wt_frac=None, TD_frac=None, mass_frac_...
    method getMassFracPuO2 (line 74) | def getMassFracPuO2(self):
    method setMassFracPuO2 (line 79) | def setMassFracPuO2(self, massFracPuO2):
    method getMolFracPuO2 (line 90) | def getMolFracPuO2(self):
    method setDefaultMassFracs (line 98) | def setDefaultMassFracs(self):
    method meltingPoint (line 152) | def meltingPoint(self):

FILE: armi/materials/nZ.py
  class NZ (line 25) | class NZ(SimpleSolid):
    method setDefaultMassFracs (line 26) | def setDefaultMassFracs(self):
    method density (line 30) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/potassium.py
  class Potassium (line 26) | class Potassium(material.Fluid):
    method pseudoDensity (line 35) | def pseudoDensity(self, Tk=None, Tc=None):

FILE: armi/materials/scandiumOxide.py
  class Sc2O3 (line 26) | class Sc2O3(Material):
    method __init__ (line 29) | def __init__(self):
    method setDefaultMassFracs (line 36) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 40) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/siC.py
  class SiC (line 29) | class SiC(Material):
    method setDefaultMassFracs (line 68) | def setDefaultMassFracs(self):
    method meltingPoint (line 74) | def meltingPoint(self):
    method heatCapacity (line 77) | def heatCapacity(self, Tc=None, Tk=None):
    method cumulativeLinearExpansion (line 82) | def cumulativeLinearExpansion(self, Tk=None, Tc=None):
    method pseudoDensity (line 87) | def pseudoDensity(self, Tc=None, Tk=None):
    method thermalConductivity (line 95) | def thermalConductivity(self, Tc=None, Tk=None):

FILE: armi/materials/sodium.py
  class Sodium (line 27) | class Sodium(material.Fluid):
    method setDefaultMassFracs (line 47) | def setDefaultMassFracs(self):
    method pseudoDensity (line 52) | def pseudoDensity(self, Tk=None, Tc=None):
    method specificVolumeLiquid (line 89) | def specificVolumeLiquid(self, Tk=None, Tc=None):
    method enthalpy (line 93) | def enthalpy(self, Tk=None, Tc=None):
    method thermalConductivity (line 105) | def thermalConductivity(self, Tk=None, Tc=None):

FILE: armi/materials/sodiumChloride.py
  class NaCl (line 31) | class NaCl(SimpleSolid):
    method setDefaultMassFracs (line 32) | def setDefaultMassFracs(self):
    method density (line 37) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/sulfur.py
  class Sulfur (line 28) | class Sulfur(material.Fluid):
    method applyInputParams (line 34) | def applyInputParams(self, sulfur_density_frac=None, TD_frac=None):
    method updateTD (line 50) | def updateTD(self, TD):
    method setDefaultMassFracs (line 53) | def setDefaultMassFracs(self):
    method pseudoDensity (line 61) | def pseudoDensity(self, Tk=None, Tc=None):
    method volumetricExpansion (line 75) | def volumetricExpansion(self, Tk=None, Tc=None):

FILE: armi/materials/tZM.py
  class TZM (line 28) | class TZM(Material):
    method __init__ (line 64) | def __init__(self):
    method setDefaultMassFracs (line 68) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 74) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/tantalum.py
  class Tantalum (line 25) | class Tantalum(SimpleSolid):
    method setDefaultMassFracs (line 26) | def setDefaultMassFracs(self):
    method density (line 29) | def density(self, Tk=None, Tc=None):

FILE: armi/materials/tests/test__init__.py
  function betterSubClassCheck (line 22) | def betterSubClassCheck(item, superClass):
  class Materials__init__Tests (line 29) | class Materials__init__Tests(unittest.TestCase):
    method test_canAccessClassesFromPackage (line 30) | def test_canAccessClassesFromPackage(self):
    method test_packageClassesEqualModuleClasses (line 34) | def test_packageClassesEqualModuleClasses(self):

FILE: armi/materials/tests/test_air.py
  class TestAir (line 181) | class TestAir(unittest.TestCase):
    method test_pseudoDensity (line 189) | def test_pseudoDensity(self):
    method test_heatCapacity (line 203) | def test_heatCapacity(self):
    method test_thermalConductivity (line 215) | def test_thermalConductivity(self):
    method test_massFrac (line 229) | def test_massFrac(self):
    method test_validRanges (line 255) | def test_validRanges(self):

FILE: armi/materials/tests/test_b4c.py
  class B4C_TestCase (line 22) | class B4C_TestCase(AbstractMaterialTest, unittest.TestCase):
    method setUp (line 25) | def setUp(self):
    method test_theoretical_pseudoDensity (line 38) | def test_theoretical_pseudoDensity(self):
    method test_propertyValidTemperature (line 50) | def test_propertyValidTemperature(self):
    method test_variousEdgeCases (line 53) | def test_variousEdgeCases(self):

FILE: armi/materials/tests/test_be9.py
  class TestBe9 (line 22) | class TestBe9(test_materials.AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 27) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 33) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_fluids.py
  class TestFluids (line 28) | class TestFluids(TestCase):
    class MyFluid (line 29) | class MyFluid(Fluid):
    class MySolid (line 32) | class MySolid(Material):
    method test_fluidDensityWrapperNoWarning (line 35) | def test_fluidDensityWrapperNoWarning(self):
    method _checkCompDensityLogs (line 59) | def _checkCompDensityLogs(self, mat: Material, nExpectedWarnings: int,...

FILE: armi/materials/tests/test_graphite.py
  class Graphite_TestCase (line 22) | class Graphite_TestCase(unittest.TestCase):
    method setUp (line 25) | def setUp(self):
    method test_linearExpansionPercent (line 28) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 43) | def test_propertyValidTemperature(self):
    method test_density (line 46) | def test_density(self):

FILE: armi/materials/tests/test_lithium.py
  class Lithium_TestCase (line 22) | class Lithium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method setUp (line 25) | def setUp(self):
    method test_Lithium_material_modifications (line 38) | def test_Lithium_material_modifications(self):
    method test_pseudoDensity (line 44) | def test_pseudoDensity(self):
    method test_meltingPoint (line 51) | def test_meltingPoint(self):
    method test_boilingPoint (line 56) | def test_boilingPoint(self):
    method test_heatCapacity (line 61) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 70) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_materials.py
  class AbstractMaterialTest (line 29) | class AbstractMaterialTest:
    method setUp (line 35) | def setUp(self):
    method test_isPicklable (line 38) | def test_isPicklable(self):
    method test_density (line 46) | def test_density(self):
    method test_TD (line 50) | def test_TD(self):
    method test_duplicate (line 61) | def test_duplicate(self):
    method test_cache (line 73) | def test_cache(self):
    method test_densityKgM3 (line 84) | def test_densityKgM3(self):
    method test_pseudoDensityKgM3 (line 90) | def test_pseudoDensityKgM3(self):
    method test_wrappedDensity (line 96) | def test_wrappedDensity(self):
  class MaterialConstructionTests (line 105) | class MaterialConstructionTests(unittest.TestCase):
    method test_material_initialization (line 106) | def test_material_initialization(self):
  class MaterialFindingTests (line 112) | class MaterialFindingTests(unittest.TestCase):
    method test_findMaterial (line 115) | def test_findMaterial(self):
    method __validateMaterialNamespace (line 139) | def __validateMaterialNamespace(self):
    method test_namespacing (line 147) | def test_namespacing(self):
  class Californium_TestCase (line 184) | class Californium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 187) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 196) | def test_propertyValidTemperature(self):
    method test_porosities (line 199) | def test_porosities(self):
    method test_getCorrosionRate (line 204) | def test_getCorrosionRate(self):
  class Cesium_TestCase (line 208) | class Cesium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 211) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 220) | def test_propertyValidTemperature(self):
  class Magnesium_TestCase (line 224) | class Magnesium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 228) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 239) | def test_propertyValidTemperature(self):
  class MagnesiumOxide_TestCase (line 243) | class MagnesiumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 246) | def test_pseudoDensity(self):
    method test_linearExpansionPercent (line 257) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 266) | def test_propertyValidTemperature(self):
  class Molybdenum_TestCase (line 270) | class Molybdenum_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 273) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 284) | def test_propertyValidTemperature(self):
  class MOX_TestCase (line 288) | class MOX_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_density (line 291) | def test_density(self):
    method test_getMassFracPuO2 (line 297) | def test_getMassFracPuO2(self):
    method test_getMolFracPuO2 (line 301) | def test_getMolFracPuO2(self):
    method test_getMeltingPoint (line 305) | def test_getMeltingPoint(self):
    method test_applyInputParams (line 309) | def test_applyInputParams(self):
  class NaCl_TestCase (line 348) | class NaCl_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_density (line 351) | def test_density(self):
    method test_propertyValidTemperature (line 360) | def test_propertyValidTemperature(self):
  class NiobiumZirconium_TestCase (line 364) | class NiobiumZirconium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 367) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 376) | def test_propertyValidTemperature(self):
  class Potassium_TestCase (line 380) | class Potassium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 383) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 409) | def test_propertyValidTemperature(self):
  class ScandiumOxide_TestCase (line 413) | class ScandiumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 416) | def test_pseudoDensity(self):
    method test_linearExpansionPercent (line 421) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 430) | def test_propertyValidTemperature(self):
  class Sodium_TestCase (line 434) | class Sodium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 437) | def test_pseudoDensity(self):
    method test_specificVolumeLiquid (line 448) | def test_specificVolumeLiquid(self):
    method test_enthalpy (line 459) | def test_enthalpy(self):
    method test_thermalConductivity (line 470) | def test_thermalConductivity(self):
    method test_propertyValidTemperature (line 481) | def test_propertyValidTemperature(self):
  class Tantalum_TestCase (line 485) | class Tantalum_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 488) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 497) | def test_propertyValidTemperature(self):
  class ThoriumUraniumMetal_TestCase (line 501) | class ThoriumUraniumMetal_TestCase(AbstractMaterialTest, unittest.TestCa...
    method test_pseudoDensity (line 504) | def test_pseudoDensity(self):
    method test_meltingPoint (line 513) | def test_meltingPoint(self):
    method test_thermalConductivity (line 518) | def test_thermalConductivity(self):
    method test_linearExpansion (line 527) | def test_linearExpansion(self):
    method test_propertyValidTemperature (line 536) | def test_propertyValidTemperature(self):
  class Uranium_TestCase (line 540) | class Uranium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_applyInputParams (line 543) | def test_applyInputParams(self):
    method test_thermalConductivity (line 560) | def test_thermalConductivity(self):
    method test_propertyValidTemperature (line 581) | def test_propertyValidTemperature(self):
    method test_pseudoDensity (line 611) | def test_pseudoDensity(self):
  class UraniumOxide_TestCase (line 621) | class UraniumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_adjustMassEnrichment (line 624) | def test_adjustMassEnrichment(self):
    method test_meltingPoint (line 645) | def test_meltingPoint(self):
    method test_density (line 649) | def test_density(self):
    method test_thermalConductivity (line 664) | def test_thermalConductivity(self):
    method test_linearExpansion (line 680) | def test_linearExpansion(self):
    method test_linearExpansionPercent (line 696) | def test_linearExpansionPercent(self):
    method test_heatCapacity (line 705) | def test_heatCapacity(self):
    method test_getTemperatureAtDensity (line 711) | def test_getTemperatureAtDensity(self):
    method test_getDensityExpansion3D (line 716) | def test_getDensityExpansion3D(self):
    method test_removeNucMassFrac (line 724) | def test_removeNucMassFrac(self):
    method test_densityTimesHeatCapactiy (line 729) | def test_densityTimesHeatCapactiy(self):
    method test_getTempChangeForDensityChange (line 734) | def test_getTempChangeForDensityChange(self):
    method test_duplicate (line 743) | def test_duplicate(self):
    method test_propertyValidTemperature (line 759) | def test_propertyValidTemperature(self):
    method test_applyInputParams (line 762) | def test_applyInputParams(self):
  class Thorium_TestCase (line 778) | class Thorium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_setDefaultMassFracs (line 781) | def test_setDefaultMassFracs(self):
    method test_pseudoDensity (line 794) | def test_pseudoDensity(self):
    method test_linearExpansion (line 800) | def test_linearExpansion(self):
    method test_thermalConductivity (line 806) | def test_thermalConductivity(self):
    method test_meltingPoint (line 812) | def test_meltingPoint(self):
    method test_propertyValidTemperature (line 818) | def test_propertyValidTemperature(self):
  class ThoriumOxide_TestCase (line 822) | class ThoriumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_density (line 825) | def test_density(self):
    method test_linearExpansion (line 836) | def test_linearExpansion(self):
    method test_thermalConductivity (line 842) | def test_thermalConductivity(self):
    method test_meltingPoint (line 848) | def test_meltingPoint(self):
    method test_propertyValidTemperature (line 854) | def test_propertyValidTemperature(self):
  class Void_TestCase (line 858) | class Void_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 861) | def test_pseudoDensity(self):
    method test_density (line 867) | def test_density(self):
    method test_linearExpansion (line 875) | def test_linearExpansion(self):
    method test_propertyValidTemperature (line 881) | def test_propertyValidTemperature(self):
  class Mixture_TestCase (line 886) | class Mixture_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_density (line 889) | def test_density(self):
    method test_setDefaultMassFracs (line 893) | def test_setDefaultMassFracs(self):
    method test_linearExpansion (line 905) | def test_linearExpansion(self):
    method test_propertyValidTemperature (line 909) | def test_propertyValidTemperature(self):
  class Lead_TestCase (line 913) | class Lead_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_volumetricExpansion (line 917) | def test_volumetricExpansion(self):
    method test_linearExpansion (line 935) | def test_linearExpansion(self):
    method test_setDefaultMassFracs (line 946) | def test_setDefaultMassFracs(self):
    method test_pseudoDensity (line 959) | def test_pseudoDensity(self):
    method test_heatCapacity (line 970) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 976) | def test_propertyValidTemperature(self):
  class LeadBismuth_TestCase (line 980) | class LeadBismuth_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_setDefaultMassFracs (line 983) | def test_setDefaultMassFracs(self):
    method test_pseudoDensity (line 996) | def test_pseudoDensity(self):
    method test_volumetricExpansion (line 1007) | def test_volumetricExpansion(self):
    method test_heatCapacity (line 1018) | def test_heatCapacity(self):
    method test_getTempChangeForDensityChange (line 1029) | def test_getTempChangeForDensityChange(self):
    method test_dynamicVisc (line 1039) | def test_dynamicVisc(self):
    method test_propertyValidTemperature (line 1048) | def test_propertyValidTemperature(self):
  class Copper_TestCase (line 1052) | class Copper_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_setDefaultMassFracs (line 1055) | def test_setDefaultMassFracs(self):
    method test_densityNeverChanges (line 1060) | def test_densityNeverChanges(self):
    method test_linearExpansionPercent (line 1065) | def test_linearExpansionPercent(self):
    method test_getChildren (line 1072) | def test_getChildren(self):
    method test_getChildrenWithFlags (line 1075) | def test_getChildrenWithFlags(self):
  class Sulfur_TestCase (line 1079) | class Sulfur_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_setDefaultMassFracs (line 1083) | def test_setDefaultMassFracs(self):
    method test_pseudoDensity (line 1088) | def test_pseudoDensity(self):
    method test_volumetricExpansion (line 1094) | def test_volumetricExpansion(self):
    method test_propertyValidTemperature (line 1100) | def test_propertyValidTemperature(self):
  class Zr_TestCase (line 1104) | class Zr_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_thermalConductivity (line 1107) | def test_thermalConductivity(self):
    method test_linearExpansion (line 1116) | def test_linearExpansion(self):
    method test_linearExpansionPercent (line 1127) | def test_linearExpansionPercent(self):
    method test_pseudoDensity (line 1166) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 1207) | def test_propertyValidTemperature(self):
  class Inconel_TestCase (line 1211) | class Inconel_TestCase(AbstractMaterialTest, unittest.TestCase):
    method setUp (line 1212) | def setUp(self):
    method tearDown (line 1218) | def tearDown(self):
    method test_setDefaultMassFracs (line 1223) | def test_setDefaultMassFracs(self):
    method test_pseudoDensity (line 1232) | def test_pseudoDensity(self):
    method test_Iconel800_linearExpansion (line 1237) | def test_Iconel800_linearExpansion(self):
    method test_propertyValidTemperature (line 1256) | def test_propertyValidTemperature(self):
  class Inconel600_TestCase (line 1263) | class Inconel600_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_00_setDefaultMassFracs (line 1266) | def test_00_setDefaultMassFracs(self):
    method test_01_linearExpansionPercent (line 1284) | def test_01_linearExpansionPercent(self):
    method test_02_linearExpansion (line 1307) | def test_02_linearExpansion(self):
    method test_03_pseudoDensity (line 1328) | def test_03_pseudoDensity(self):
    method test_heatCapacity (line 1349) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 1358) | def test_propertyValidTemperature(self):
  class Inconel625_TestCase (line 1362) | class Inconel625_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_00_setDefaultMassFracs (line 1365) | def test_00_setDefaultMassFracs(self):
    method test_01_linearExpansionPercent (line 1402) | def test_01_linearExpansionPercent(self):
    method test_02_linearExpansion (line 1425) | def test_02_linearExpansion(self):
    method test_03_pseudoDensity (line 1446) | def test_03_pseudoDensity(self):
    method test_heatCapacity (line 1467) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 1476) | def test_propertyValidTemperature(self):
  class InconelX750_TestCase (line 1480) | class InconelX750_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_00_setDefaultMassFracs (line 1483) | def test_00_setDefaultMassFracs(self):
    method test_01_linearExpansionPercent (line 1518) | def test_01_linearExpansionPercent(self):
    method test_02_linearExpansion (line 1541) | def test_02_linearExpansion(self):
    method test_03_pseudoDensity (line 1562) | def test_03_pseudoDensity(self):
    method test_heatCapacity (line 1583) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 1592) | def test_propertyValidTemperature(self):
  class Alloy200_TestCase (line 1596) | class Alloy200_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_nickleContent (line 1599) | def test_nickleContent(self):
    method test_linearExpansion (line 1603) | def test_linearExpansion(self):
    method test_linearExpansionHotter (line 1608) | def test_linearExpansionHotter(self):
    method test_propertyValidTemperature (line 1613) | def test_propertyValidTemperature(self):
  class CaH2_TestCase (line 1617) | class CaH2_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 1620) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 1629) | def test_propertyValidTemperature(self):
  class Hafnium_TestCase (line 1633) | class Hafnium_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 1636) | def test_pseudoDensity(self):
    method test_propertyValidTemperature (line 1645) | def test_propertyValidTemperature(self):
  class HastelloyN_TestCase (line 1649) | class HastelloyN_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_thermalConductivity (line 1652) | def test_thermalConductivity(self):
    method test_heatCapacity (line 1669) | def test_heatCapacity(self):
    method test_linearExpansionPercent (line 1687) | def test_linearExpansionPercent(self):
    method test_meanCoefficientThermalExpansion (line 1706) | def test_meanCoefficientThermalExpansion(self):
    method test_propertyValidTemperature (line 1727) | def test_propertyValidTemperature(self):
  class TZM_TestCase (line 1731) | class TZM_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_00_applyInputParams (line 1734) | def test_00_applyInputParams(self):
    method test_01_pseudoDensity (line 1745) | def test_01_pseudoDensity(self):
    method test_02_linearExpansionPercent (line 1750) | def test_02_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 1786) | def test_propertyValidTemperature(self):
  class YttriumOxide_TestCase (line 1790) | class YttriumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 1793) | def test_pseudoDensity(self):
    method test_linearExpansionPercent (line 1799) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 1808) | def test_propertyValidTemperature(self):
  class ZincOxide_TestCase (line 1812) | class ZincOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method test_density (line 1815) | def test_density(self):
    method test_linearExpansionPercent (line 1821) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 1830) | def test_propertyValidTemperature(self):
  class FuelMaterial_TestCase (line 1834) | class FuelMaterial_TestCase(unittest.TestCase):
    method loadAssembly (line 1875) | def loadAssembly(self, materialModifications):
    method test_class1Class2_class1_wt_frac (line 1881) | def test_class1Class2_class1_wt_frac(self):
    method test_class1Class2_classX_custom_isotopics (line 1893) | def test_class1Class2_classX_custom_isotopics(self):

FILE: armi/materials/tests/test_sic.py
  class TestSiC (line 22) | class TestSiC(test_materials.AbstractMaterialTest, unittest.TestCase):
    method test_pseudoDensity (line 27) | def test_pseudoDensity(self):
    method test_meltingPoint (line 33) | def test_meltingPoint(self):
    method test_heatCapacity (line 39) | def test_heatCapacity(self):
    method test_propertyValidTemperature (line 50) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_sulfur.py
  class Sulfur_TestCase (line 22) | class Sulfur_TestCase(AbstractMaterialTest, unittest.TestCase):
    method setUp (line 26) | def setUp(self):
    method test_sulfur_density_frac (line 39) | def test_sulfur_density_frac(self):
    method test_propertyValidTemperature (line 52) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_thoriumOxide.py
  class ThoriumOxide_TestCase (line 22) | class ThoriumOxide_TestCase(AbstractMaterialTest, unittest.TestCase):
    method setUp (line 25) | def setUp(self):
    method test_theoretical_pseudoDensity (line 32) | def test_theoretical_pseudoDensity(self):
    method test_linearExpansionPercent (line 38) | def test_linearExpansionPercent(self):
    method test_propertyValidTemperature (line 41) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_uZr.py
  class UZR_TestCase (line 23) | class UZR_TestCase(TestCase):
    method setUp (line 26) | def setUp(self):
    method test_isPicklable (line 29) | def test_isPicklable(self):
    method test_TD (line 42) | def test_TD(self):
    method test_duplicate (line 53) | def test_duplicate(self):
    method test_cache (line 70) | def test_cache(self):
    method test_densityKgM3 (line 81) | def test_densityKgM3(self):
    method test_pseudoDensityKgM3 (line 92) | def test_pseudoDensityKgM3(self):
    method test_density (line 103) | def test_density(self):
    method test_propertyValidTemperature (line 117) | def test_propertyValidTemperature(self):

FILE: armi/materials/tests/test_water.py
  class TestWater (line 22) | class TestWater(unittest.TestCase):
    method test_waterAtFreezing (line 25) | def test_waterAtFreezing(self):
    method test_waterAtBoiling (line 71) | def test_waterAtBoiling(self):
    method test_waterAtCritcalPoint (line 113) | def test_waterAtCritcalPoint(self):
    method test_massFrac (line 155) | def test_massFrac(self):
    method test_propertyValidTemperature (line 162) | def test_propertyValidTemperature(self):
    method test_validateNames (line 169) | def test_validateNames(self):

FILE: armi/materials/thU.py
  class ThU (line 30) | class ThU(FuelMaterial):
    method __init__ (line 34) | def __init__(self):
    method getEnrichment (line 39) | def getEnrichment(self):
    method applyInputParams (line 42) | def applyInputParams(self, U233_wt_frac=None, *args, **kwargs):
    method setDefaultMassFracs (line 54) | def setDefaultMassFracs(self):
    method linearExpansion (line 58) | def linearExpansion(self, Tk=None, Tc=None):
    method thermalConductivity (line 64) | def thermalConductivity(self, Tk=None, Tc=None):
    method meltingPoint (line 69) | def meltingPoint(self):

FILE: armi/materials/thorium.py
  class Thorium (line 29) | class Thorium(FuelMaterial):
    method __init__ (line 32) | def __init__(self):
    method setDefaultMassFracs (line 36) | def setDefaultMassFracs(self):
    method linearExpansion (line 39) | def linearExpansion(self, Tk=None, Tc=None):
    method thermalConductivity (line 46) | def thermalConductivity(self, Tk=None, Tc=None):
    method meltingPoint (line 50) | def meltingPoint(self):

FILE: armi/materials/thoriumOxide.py
  class ThoriumOxide (line 33) | class ThoriumOxide(FuelMaterial, SimpleSolid):
    method __init__ (line 36) | def __init__(self):
    method applyInputParams (line 40) | def applyInputParams(self, TD_frac=None, *args, **kwargs):
    method setDefaultMassFracs (line 64) | def setDefaultMassFracs(self):
    method linearExpansion (line 80) | def linearExpansion(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 87) | def linearExpansionPercent(self, Tk=None, Tc=None):
    method thermalConductivity (line 97) | def thermalConductivity(self, Tk=None, Tc=None):
    method meltingPoint (line 101) | def meltingPoint(self):
    method density (line 105) | def density(self, Tk=None, Tc=None):
  class ThO2 (line 109) | class ThO2(ThoriumOxide):

FILE: armi/materials/uZr.py
  class UZr (line 29) | class UZr(material.FuelMaterial):
    method __init__ (line 52) | def __init__(self):
    method setDefaultMassFracs (line 55) | def setDefaultMassFracs(self):
    method applyInputParams (line 63) | def applyInputParams(self, U235_wt_frac=None, ZR_wt_frac=None, *args, ...
    method _calculateReferenceDensity (line 76) | def _calculateReferenceDensity(self, zrFrac, uFrac):
    method linearExpansionPercent (line 84) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/uranium.py
  class Uranium (line 34) | class Uranium(FuelMaterial):
    method thermalConductivity (line 214) | def thermalConductivity(self, Tk: float = None, Tc: float = None) -> f...
    method heatCapacity (line 222) | def heatCapacity(self, Tk: float = None, Tc: float = None) -> float:
    method setDefaultMassFracs (line 229) | def setDefaultMassFracs(self) -> None:
    method applyInputParams (line 248) | def applyInputParams(self, U235_wt_frac: float = None, TD_frac: float ...
    method meltingPoint (line 270) | def meltingPoint(self):
    method density (line 274) | def density(self, Tk: float = None, Tc: float = None) -> float:
    method pseudoDensity (line 281) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansion (line 285) | def linearExpansion(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansionPercent (line 292) | def linearExpansionPercent(self, Tk: float = None, Tc: float = None) -...

FILE: armi/materials/uraniumOxide.py
  class UraniumOxide (line 42) | class UraniumOxide(material.FuelMaterial, material.SimpleSolid):
    method __init__ (line 101) | def __init__(self):
    method applyInputParams (line 105) | def applyInputParams(self, U235_wt_frac: float = None, TD_frac: float ...
    method setDefaultMassFracs (line 127) | def setDefaultMassFracs(self) -> None:
    method meltingPoint (line 148) | def meltingPoint(self):
    method density (line 156) | def density(self, Tk: float = None, Tc: float = None) -> float:
    method heatCapacity (line 167) | def heatCapacity(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansion (line 185) | def linearExpansion(self, Tk: float = None, Tc: float = None) -> float:
    method linearExpansionPercent (line 196) | def linearExpansionPercent(self, Tk: float = None, Tc: float = None) -...
    method thermalConductivity (line 210) | def thermalConductivity(self, Tk: float = None, Tc: float = None) -> f...
  class UO2 (line 223) | class UO2(UraniumOxide):
    method __init__ (line 226) | def __init__(self):

FILE: armi/materials/void.py
  class Void (line 24) | class Void(material.Fluid):
    method pseudoDensity (line 27) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
    method density (line 30) | def density(self, Tk: float = None, Tc: float = None) -> float:

FILE: armi/materials/water.py
  class Water (line 32) | class Water(Fluid):
    method setDefaultMassFracs (line 78) | def setDefaultMassFracs(self) -> None:
    method theta (line 92) | def theta(self, Tk: float = None, Tc: float = None) -> float:
    method tau (line 96) | def tau(self, Tc: float = None, Tk: float = None) -> float:
    method vaporPressure (line 106) | def vaporPressure(self, Tk: float = None, Tc: float = None) -> float:
    method vaporPressurePrime (line 145) | def vaporPressurePrime(self, Tk: float = None, Tc: float = None, dT: f...
    method auxiliaryQuantitySpecificEnthalpy (line 166) | def auxiliaryQuantitySpecificEnthalpy(self, Tk: float = None, Tc: floa...
    method auxiliaryQuantitySpecificEntropy (line 206) | def auxiliaryQuantitySpecificEntropy(self, Tk: float = None, Tc: float...
    method enthalpy (line 246) | def enthalpy(self, Tk: float = None, Tc: float = None) -> float:
    method entropy (line 276) | def entropy(self, Tk: float = None, Tc: float = None) -> float:
    method pseudoDensity (line 305) | def pseudoDensity(self, Tk=None, Tc=None):
  class SaturatedWater (line 316) | class SaturatedWater(Water):
    method pseudoDensity (line 328) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:
  class SaturatedSteam (line 374) | class SaturatedSteam(Water):
    method pseudoDensity (line 386) | def pseudoDensity(self, Tk: float = None, Tc: float = None) -> float:

FILE: armi/materials/yttriumOxide.py
  class Y2O3 (line 26) | class Y2O3(Material):
    method __init__ (line 29) | def __init__(self):
    method setDefaultMassFracs (line 33) | def setDefaultMassFracs(self):
    method linearExpansionPercent (line 37) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/zincOxide.py
  class ZnO (line 26) | class ZnO(Material):
    method setDefaultMassFracs (line 29) | def setDefaultMassFracs(self):
    method density (line 33) | def density(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 36) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/materials/zr.py
  class Zr (line 28) | class Zr(Material):
    method __init__ (line 85) | def __init__(self):
    method setDefaultMassFracs (line 89) | def setDefaultMassFracs(self):
    method _computeReferenceDensity (line 92) | def _computeReferenceDensity(self, Tk=None, Tc=None):
    method thermalConductivity (line 102) | def thermalConductivity(self, Tk=None, Tc=None):
    method linearExpansion (line 112) | def linearExpansion(self, Tk=None, Tc=None):
    method linearExpansionPercent (line 124) | def linearExpansionPercent(self, Tk=None, Tc=None):

FILE: armi/migration/base.py
  class Migration (line 32) | class Migration:
    method __init__ (line 42) | def __init__(self, stream=None, path=None):
    method __repr__ (line 49) | def __repr__(self):
    method apply (line 52) | def apply(self):
    method _loadStreamFromPath (line 67) | def _loadStreamFromPath(self):
    method _applyToStream (line 75) | def _applyToStream(self):
    method _backupOriginal (line 79) | def _backupOriginal(self):
    method _writeNewFile (line 84) | def _writeNewFile(self, newStream):
  class BlueprintsMigration (line 96) | class BlueprintsMigration(Migration):
    method _loadStreamFromPath (line 99) | def _loadStreamFromPath(self):
  class SettingsMigration (line 108) | class SettingsMigration(Migration):
    method _loadStreamFromPath (line 111) | def _loadStreamFromPath(self):
  class DatabaseMigration (line 116) | class DatabaseMigration(Migration):

FILE: armi/migration/m0_1_3.py
  class RemoveCentersFromBlueprints (line 23) | class RemoveCentersFromBlueprints(BlueprintsMigration):
    method _applyToStream (line 29) | def _applyToStream(self):
  class UpdateElementalNuclides (line 40) | class UpdateElementalNuclides(BlueprintsMigration):
    method _applyToStream (line 58) | def _applyToStream(self):

FILE: armi/migration/m0_1_6.py
  class ConvertAlphanumLocationSettingsToNum (line 35) | class ConvertAlphanumLocationSettingsToNum(SettingsMigration):
    method _applyToStream (line 41) | def _applyToStream(self):
  function _modify_settings (line 61) | def _modify_settings(cs):
  function getIndicesFromDIF3DStyleLocatorLabel (line 78) | def getIndicesFromDIF3DStyleLocatorLabel(label):

FILE: armi/migration/tests/test_m0_1_6.py
  class TestMigration (line 24) | class TestMigration(unittest.TestCase):
    method test_locationLabelMigration (line 25) | def test_locationLabelMigration(self):

FILE: armi/migration/tests/test_migration_base.py
  class TestMigrationBases (line 23) | class TestMigrationBases(unittest.TestCase):
    method test_basic_validation (line 24) | def test_basic_validation(self):
  class TestSettingsMigration (line 37) | class TestSettingsMigration(unittest.TestCase):
    method test_loadStreamFromPath (line 38) | def test_loadStreamFromPath(self):

FILE: armi/mpiActions.py
  class MpiAction (line 69) | class MpiAction:
    method __init__ (line 77) | def __init__(self):
    method parallel (line 91) | def parallel(self):
    method invokeAsMaster (line 95) | def invokeAsMaster(cls, o, r, cs):
    method _mpiOperationHelper (line 126) | def _mpiOperationHelper(self, obj, mpiFunction):
    method broadcast (line 144) | def broadcast(self, obj=None):
    method gather (line 179) | def gather(self, obj=None):
    method invoke (line 207) | def invoke(self, o, r, cs):
    method mpiFlatten (line 232) | def mpiFlatten(allCPUResults):
    method mpiIter (line 243) | def mpiIter(objectsForAllCoresToIter):
    method invokeHook (line 273) | def invokeHook(self):
  function runActions (line 288) | def runActions(o, r, cs, actions, numPerNode=None, serial=False):
  function runBatchedActions (line 327) | def runBatchedActions(o, r, cs, actionsByNode, serial=False):
  function distributeActions (line 384) | def distributeActions(actionsThisRound, useForComputation):
  function _disableForExclusiveTasks (line 394) | def _disableForExclusiveTasks(actionsThisRound, useForComputation):
  function _makeQueue (line 404) | def _makeQueue(actions, useForComputation):
  function runActionsInSerial (line 440) | def runActionsInSerial(o, r, cs, actions):
  class DistributionAction (line 462) | class DistributionAction(MpiAction):
    method __init__ (line 478) | def __init__(self, actions):
    method __reduce__ (line 482) | def __reduce__(self):
    method invokeHook (line 489) | def invokeHook(self):
  class MpiActionError (line 534) | class MpiActionError(Exception):
  class DistributeStateAction (line 538) | class DistributeStateAction(MpiAction):
    method __init__ (line 539) | def __init__(self, skipInterfaces=False):
    method invokeHook (line 543) | def invokeHook(self):
    method _distributeSettings (line 604) | def _distributeSettings(self):
    method _distributeReactor (line 618) | def _distributeReactor(self, cs):
    method _distributeParamAssignments (line 642) | def _distributeParamAssignments():
    method _distributeInterfaces (line 659) | def _distributeInterfaces(self):

FILE: armi/nucDirectory/elements.py
  class ChemicalPhase (line 149) | class ChemicalPhase(Enum):
  class ChemicalGroup (line 156) | class ChemicalGroup(Enum):
  class Element (line 170) | class Element:
    method __init__ (line 173) | def __init__(self, z, symbol, name, phase="UNKNOWN", group="UNKNOWN"):
    method __repr__ (line 211) | def __repr__(self):
    method __hash__ (line 214) | def __hash__(self):
    method __lt__ (line 217) | def __lt__(self, other):
    method __eq__ (line 220) | def __eq__(self, other):
    method __iter__ (line 223) | def __iter__(self):
    method append (line 227) | def append(self, nuclide):
    method isNaturallyOccurring (line 234) | def isNaturallyOccurring(self):
    method getNaturalIsotopics (line 238) | def getNaturalIsotopics(self):
    method isHeavyMetal (line 248) | def isHeavyMetal(self):
  function getElementsByChemicalPhase (line 261) | def getElementsByChemicalPhase(phase: ChemicalPhase) -> List[Element]:
  function getElementsByChemicalGroup (line 267) | def getElementsByChemicalGroup(group: ChemicalGroup) -> List[Element]:
  function getName (line 273) | def getName(z: int = None, symbol: str = None) -> str:
  function getSymbol (line 279) | def getSymbol(z: int = None, name: str = None) -> str:
  function getElementZ (line 285) | def getElementZ(symbol: str = None, name: str = None) -> int:
  function factory (line 291) | def factory(elementsFile: str = None):
  function addGlobalElement (line 306) | def addGlobalElement(element: Element):
  function destroyGlobalElements (line 312) | def destroyGlobalElements():
  class Elements (line 318) | class Elements:
    method __init__ (line 338) | def __init__(self, elementsFile: str = None):
    method clear (line 344) | def clear(self):
    method addElement (line 350) | def addElement(self, element: Element):
    method factory (line 365) | def factory(self, elementsFile: str = None):
    method getElementsByChemicalPhase (line 391) | def getElementsByChemicalPhase(self, phase: ChemicalPhase) -> List[Ele...
    method getElementsByChemicalGroup (line 415) | def getElementsByChemicalGroup(self, group: ChemicalGroup) -> List[Ele...
    method getName (line 439) | def getName(self, z: int = None, symbol: str = None) -> str:
    method getSymbol (line 465) | def getSymbol(self, z: int = None, name: str = None) -> str:
    method getElementZ (line 492) | def getElementZ(self, symbol: str = None, name: str = None) -> int:

FILE: armi/nucDirectory/nucDir.py
  function getNuclideFromName (line 59) | def getNuclideFromName(name):
  function getNaturalIsotopics (line 69) | def getNaturalIsotopics(elementSymbol=None, z=None):
  function getNaturalMassIsotopics (line 93) | def getNaturalMassIsotopics(elementSymbol=None, z=None):
  function getMc2Label (line 111) | def getMc2Label(name):
  function getElementName (line 150) | def getElementName(z=None, symbol=None):
  function getElementSymbol (line 177) | def getElementSymbol(z=None, name=None):
  function getNuclide (line 204) | def getNuclide(nucName):
  function getNuclides (line 226) | def getNuclides(nucName=None, elementSymbol=None):
  function getNuclideNames (line 253) | def getNuclideNames(nucName=None, elementSymbol=None):
  function getAtomicWeight (line 272) | def getAtomicWeight(lab=None, z=None, a=None):
  function isHeavyMetal (line 324) | def isHeavyMetal(name):
  function isFissile (line 331) | def isFissile(name):
  function getThresholdDisplacementEnergy (line 338) | def getThresholdDisplacementEnergy(nuc):

FILE: armi/nucDirectory/nuclideBases.py
  class NuclideInterface (line 136) | class NuclideInterface:
    method getDatabaseName (line 139) | def getDatabaseName(self):
    method getDecay (line 143) | def getDecay(self, decayType):
    method getMcc2Id (line 158) | def getMcc2Id(self):
    method getMcc3Id (line 162) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 166) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 170) | def getMcc3IdEndfbVII1(self):
    method getSerpentId (line 174) | def getSerpentId(self):
    method getNaturalIsotopics (line 178) | def getNaturalIsotopics(self):
    method isFissile (line 182) | def isFissile(self):
    method isHeavyMetal (line 186) | def isHeavyMetal(self):
  class NuclideWrapper (line 191) | class NuclideWrapper(NuclideInterface):
    method __init__ (line 194) | def __init__(self, container, key):
    method __repr__ (line 200) | def __repr__(self):
    method __format__ (line 203) | def __format__(self, format_spec):
    method name (line 207) | def name(self):
    method weight (line 218) | def weight(self):
    method getDatabaseName (line 222) | def getDatabaseName(self):
    method getDecay (line 226) | def getDecay(self, decayType):
    method getMcc2Id (line 241) | def getMcc2Id(self):
    method getMcc3Id (line 245) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 249) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 253) | def getMcc3IdEndfbVII1(self):
    method getNaturalIsotopics (line 257) | def getNaturalIsotopics(self):
    method isFissile (line 261) | def isFissile(self):
    method isHeavyMetal (line 265) | def isHeavyMetal(self):
  class INuclide (line 270) | class INuclide(NuclideInterface):
    method __init__ (line 301) | def __init__(
    method __hash__ (line 347) | def __hash__(self):
    method __reduce__ (line 350) | def __reduce__(self):
    method __lt__ (line 353) | def __lt__(self, other):
    method __eq__ (line 356) | def __eq__(self, other):
    method _processBurnData (line 359) | def _processBurnData(self, burnInfo):
    method getDecay (line 403) | def getDecay(self, decayType):
    method isFissile (line 423) | def isFissile(self):
    method getNaturalIsotopics (line 433) | def getNaturalIsotopics(self):
    method getDatabaseName (line 452) | def getDatabaseName(self):
    method isHeavyMetal (line 456) | def isHeavyMetal(self):
  class IMcnpNuclide (line 460) | class IMcnpNuclide:
    method getMcnpId (line 463) | def getMcnpId(self):
    method getAAAZZZSId (line 467) | def getAAAZZZSId(self):
  class NuclideBase (line 472) | class NuclideBase(INuclide, IMcnpNuclide):
    method __init__ (line 487) | def __init__(self, element, a, weight, abundance, state, halflife):
    method __repr__ (line 501) | def __repr__(self):
    method _createName (line 509) | def _createName(element, a, state):
    method _createLabel (line 517) | def _createLabel(element, a, state):
    method getNaturalIsotopics (line 533) | def getNaturalIsotopics(self):
    method getMcc2Id (line 549) | def getMcc2Id(self):
    method getMcc3Id (line 562) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 566) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 580) | def getMcc3IdEndfbVII1(self):
    method getMcnpId (line 594) | def getMcnpId(self):
    method getAAAZZZSId (line 629) | def getAAAZZZSId(self):
    method getSerpentId (line 648) | def getSerpentId(self):
    method getEndfMatNum (line 661) | def getEndfMatNum(self):
  class NaturalNuclideBase (line 691) | class NaturalNuclideBase(INuclide, IMcnpNuclide):
    method __init__ (line 701) | def __init__(self, name, element):
    method __repr__ (line 714) | def __repr__(self):
    method getNaturalIsotopics (line 717) | def getNaturalIsotopics(self):
    method getMcnpId (line 733) | def getMcnpId(self):
    method getMcc2Id (line 743) | def getMcc2Id(self):
    method getMcc3Id (line 747) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 751) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 755) | def getMcc3IdEndfbVII1(self):
    method getSerpentId (line 759) | def getSerpentId(self):
    method getEndfMatNum (line 769) | def getEndfMatNum(self):
  class DummyNuclideBase (line 780) | class DummyNuclideBase(INuclide):
    method __init__ (line 790) | def __init__(self, element, name, weight):
    method __repr__ (line 803) | def __repr__(self):
    method __hash__ (line 806) | def __hash__(self):
    method __lt__ (line 809) | def __lt__(self, other):
    method getNaturalIsotopics (line 817) | def getNaturalIsotopics(self):
    method isHeavyMetal (line 834) | def isHeavyMetal(self):
    method getMcc2Id (line 837) | def getMcc2Id(self):
    method getMcc3Id (line 841) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 845) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 849) | def getMcc3IdEndfbVII1(self):
  class LumpNuclideBase (line 854) | class LumpNuclideBase(INuclide):
    method __init__ (line 864) | def __init__(self, element, name, weight):
    method __repr__ (line 877) | def __repr__(self):
    method __hash__ (line 880) | def __hash__(self):
    method __lt__ (line 883) | def __lt__(self, other):
    method getNaturalIsotopics (line 891) | def getNaturalIsotopics(self):
    method isHeavyMetal (line 908) | def isHeavyMetal(self):
    method getMcc2Id (line 911) | def getMcc2Id(self):
    method getMcc3Id (line 915) | def getMcc3Id(self):
    method getMcc3IdEndfbVII0 (line 919) | def getMcc3IdEndfbVII0(self):
    method getMcc3IdEndfbVII1 (line 923) | def getMcc3IdEndfbVII1(self):
  function initReachableActiveNuclidesThroughBurnChain (line 928) | def initReachableActiveNuclidesThroughBurnChain(nuclides, numberDensitie...
  function getIsotopics (line 934) | def getIsotopics(nucName):
  function fromName (line 940) | def fromName(name):
  function isMonoIsotopicElement (line 946) | def isMonoIsotopicElement(name):
  function where (line 952) | def where(predicate):
  function single (line 958) | def single(predicate):
  function changeLabel (line 964) | def changeLabel(nuclideBase, newLabel):
  function getDepletableNuclides (line 970) | def getDepletableNuclides(activeNuclides, obj):
  function imposeBurnChain (line 975) | def imposeBurnChain(burnChainStream):
  function factory (line 981) | def factory():
  function addNuclideBases (line 1011) | def addNuclideBases():
  function readMCCNuclideData (line 1017) | def readMCCNuclideData():
  function updateNuclideBasesForSpecialCases (line 1023) | def updateNuclideBasesForSpecialCases():
  function addGlobalNuclide (line 1029) | def addGlobalNuclide(nuclide: NuclideBase):
  function destroyGlobalNuclides (line 1035) | def destroyGlobalNuclides():
  class NuclideBases (line 1041) | class NuclideBases:
    method __init__ (line 1085) | def __init__(self, nuclidesFile=None, mccNuclidesFile=None):
    method clear (line 1102) | def clear(self):
    method addNuclide (line 1144) | def addNuclide(self, nuclide: INuclide):
    method factory (line 1163) | def factory(self, nuclidesFile: str = None, mccNuclidesFile: str = Non...
    method initReachableActiveNuclidesThroughBurnChain (line 1215) | def initReachableActiveNuclidesThroughBurnChain(self, nuclides, number...
    method _failOnMissingActiveNuclides (line 1271) | def _failOnMissingActiveNuclides(self, missingActiveNuclides):
    method getIsotopics (line 1282) | def getIsotopics(self, nucName):
    method fromName (line 1295) | def fromName(self, name):
    method isMonoIsotopicElement (line 1303) | def isMonoIsotopicElement(self, name):
    method where (line 1308) | def where(self, predicate):
    method single (line 1337) | def single(self, predicate):
    method changeLabel (line 1363) | def changeLabel(self, nuclideBase, newLabel):
    method imposeBurnChain (line 1374) | def imposeBurnChain(self, burnChainStream):
    method addNuclideBases (line 1408) | def addNuclideBases(self, nuclidesFile: str):
    method __addNaturalNuclideBases (line 1455) | def __addNaturalNuclideBases(self):
    method __addDummyNuclideBases (line 1462) | def __addDummyNuclideBases(self):
    method __addLumpedFissionProductNuclideBases (line 1473) | def __addLumpedFissionProductNuclideBases(self):
    method readMCCNuclideData (line 1492) | def readMCCNuclideData(self, mccNuclidesFile):
    method updateNuclideBasesForSpecialCases (line 1528) | def updateNuclideBasesForSpecialCases(self):
    method __renormalizeNuclideToElementRelationship (line 1559) | def __renormalizeNuclideToElementRelationship(self):
    method __deriveElementalWeightsByNaturalNuclideAbundances (line 1566) | def __deriveElementalWeightsByNaturalNuclideAbundances(self):

FILE: armi/nucDirectory/tests/test_elements.py
  class TestElements (line 21) | class TestElements(unittest.TestCase):
    method setUp (line 22) | def setUp(self):
    method test_elements_elementBulkProperties (line 25) | def test_elements_elementBulkProperties(self):
    method test_element_elementByNameReturnsElement (line 31) | def test_element_elementByNameReturnsElement(self):
    method test_element_elementByZReturnsElement (line 41) | def test_element_elementByZReturnsElement(self):
    method test_element_elementBySymbolReturnsElement (line 51) | def test_element_elementBySymbolReturnsElement(self):
    method test_element_addExistingElementFails (line 61) | def test_element_addExistingElementFails(self):
    method test_addedElementAppearsInElementList (line 66) | def test_addedElementAppearsInElementList(self):
    method test_elementGetNatIsosOnlyRetrievesAbund (line 75) | def test_elementGetNatIsosOnlyRetrievesAbund(self):
    method test_elementIsNatOccurring (line 84) | def test_elementIsNatOccurring(self):
    method test_abundancesAddToOne (line 102) | def test_abundancesAddToOne(self):
    method test_isHeavyMetal (line 114) | def test_isHeavyMetal(self):

FILE: armi/nucDirectory/tests/test_nucDirectory.py
  class TestNucDirectory (line 23) | class TestNucDirectory(unittest.TestCase):
    method test_nucDir_getNameForOldDashedNames (line 24) | def test_nucDir_getNameForOldDashedNames(self):
    method test_nucDir_getNucFromNucNameReturnsNuc (line 48) | def test_nucDir_getNucFromNucNameReturnsNuc(self):
    method test_nucDir_getNuclidesFromForBadName (line 53) | def test_nucDir_getNuclidesFromForBadName(self):
    method test_getDisplacementEnergy (line 57) | def test_getDisplacementEnergy(self):

FILE: armi/nucDirectory/tests/test_nuclideBases.py
  class TestNuclideBases (line 35) | class TestNuclideBases(unittest.TestCase):
    method setUpClass (line 37) | def setUpClass(cls):
    method test_nucBases_fromNameBadNameRaisesException (line 46) | def test_nucBases_fromNameBadNameRaisesException(self):
    method test_nucBase_AllAbundancesAddToOne (line 50) | def test_nucBase_AllAbundancesAddToOne(self):
    method test_nucBases_AllLabelsAreUnique (line 65) | def test_nucBases_AllLabelsAreUnique(self):
    method test_nucBases_NegativeZRaisesException (line 71) | def test_nucBases_NegativeZRaisesException(self):
    method test_nucBases_Z295RaisesException (line 76) | def test_nucBases_Z295RaisesException(self):
    method test_nucBases_Mc2Elementals (line 80) | def test_nucBases_Mc2Elementals(self):
    method test_LumpNucBaseGetNatIsotopDoesNotFail (line 98) | def test_LumpNucBaseGetNatIsotopDoesNotFail(self):
    method test_NaturalNuclideBase_getNatrualIsotpics (line 102) | def test_NaturalNuclideBase_getNatrualIsotpics(self):
    method test_nucBases_singleFailsWithMultipleMatches (line 107) | def test_nucBases_singleFailsWithMultipleMatches(self):
    method test_nucBases_singleFailsWithNoMatches (line 111) | def test_nucBases_singleFailsWithNoMatches(self):
    method test_nucBases_singleIsPrettySpecific (line 115) | def test_nucBases_singleIsPrettySpecific(self):
    method test_natNucStomicWgtIsAvgOfNatIsotopes (line 120) | def test_natNucStomicWgtIsAvgOfNatIsotopes(self):
    method test_nucBasesLabelAndNameCollsAreForSameNuc (line 127) | def test_nucBasesLabelAndNameCollsAreForSameNuc(self):
    method test_nucBases_imposeBurnChainDecayBulkStats (line 142) | def test_nucBases_imposeBurnChainDecayBulkStats(self):
    method test_nucBasesImposeBurnChainTransmBulkStats (line 160) | def test_nucBasesImposeBurnChainTransmBulkStats(self):
    method test_nucBases_imposeBurn_nuSF (line 180) | def test_nucBases_imposeBurn_nuSF(self):
    method test_nucBases_databaseNamesStartWith_n (line 224) | def test_nucBases_databaseNamesStartWith_n(self):
    method test_nucBases_AllDatabaseNamesAreUnique (line 228) | def test_nucBases_AllDatabaseNamesAreUnique(self):
    method test_nucBases_Am242m (line 234) | def test_nucBases_Am242m(self):
    method test_nucBases_isHeavyMetal (line 252) | def test_nucBases_isHeavyMetal(self):
    method test_getDecay (line 261) | def test_getDecay(self):
    method test_getEndfMatNum (line 266) | def test_getEndfMatNum(self):
    method test_NonMc2Nuclide (line 283) | def test_NonMc2Nuclide(self):
    method test_kryptonDecayConstants (line 288) | def test_kryptonDecayConstants(self):
    method test_curieDefinitionWithRa226 (line 350) | def test_curieDefinitionWithRa226(self):
    method test_loadMcc2Data (line 367) | def test_loadMcc2Data(self):
    method test_loadMcc3EndfVII0Data (line 386) | def test_loadMcc3EndfVII0Data(self):
    method test_loadMcc3EndfVII1Data (line 410) | def test_loadMcc3EndfVII1Data(self):
  class TestAAAZZZSId (line 437) | class TestAAAZZZSId(unittest.TestCase):
    method test_AAAZZZSNameGenerator (line 438) | def test_AAAZZZSNameGenerator(self):

FILE: armi/nucDirectory/tests/test_thermalScattering.py
  class TestThermalScattering (line 22) | class TestThermalScattering(unittest.TestCase):
    method test_dataValidity (line 23) | def test_dataValidity(self):
    method test_fromNameCompInvalid (line 43) | def test_fromNameCompInvalid(self):
    method test_fromNameCompSpotCheck (line 57) | def test_fromNameCompSpotCheck(self):

FILE: armi/nucDirectory/tests/test_transmutations.py
  function randomString (line 25) | def randomString(length):
  class TransmutationTests (line 29) | class TransmutationTests(unittest.TestCase):
    method setUpClass (line 31) | def setUpClass(cls):
    method test_Transmutation_validReactionTypes (line 34) | def test_Transmutation_validReactionTypes(self):
    method test_Transmutation_productParticle (line 42) | def test_Transmutation_productParticle(self):
    method test_Transmutation_invalidReactionTypes (line 46) | def test_Transmutation_invalidReactionTypes(self):
  class DecayModeTests (line 61) | class DecayModeTests(unittest.TestCase):
    method setUpClass (line 63) | def setUpClass(cls):
    method test_DecayMode_validReactionTypes (line 66) | def test_DecayMode_validReactionTypes(self):
    method test_DecayMode_invalidReactionTypes (line 73) | def test_DecayMode_invalidReactionTypes(self):

FILE: armi/nucDirectory/thermalScattering.py
  class ThermalScatteringLabels (line 75) | class ThermalScatteringLabels:
  function fromNameAndCompound (line 96) | def fromNameAndCompound(name: str, compound: str):

FILE: armi/nucDirectory/transmutations.py
  class Transmutable (line 98) | class Transmutable:
    method __init__ (line 134) | def __init__(self, parent, dataDict):
    method getPreferredProduct (line 144) | def getPreferredProduct(self, libraryNucNames):
  class Transmutation (line 164) | class Transmutation(Transmutable):
    method __init__ (line 181) | def __init__(self, parent, dataDict):
    method __repr__ (line 186) | def __repr__(self):
  class DecayMode (line 192) | class DecayMode(Transmutable):
    method __init__ (line 211) | def __init__(self, parent, dataDict):
    method __repr__ (line 233) | def __repr__(self):

FILE: armi/nuclearDataIO/__init__.py
  function getExpectedISOTXSFileName (line 37) | def getExpectedISOTXSFileName(cycle=None, node=None, suffix=None, xsID=N...
  function getExpectedCOMPXSFileName (line 60) | def getExpectedCOMPXSFileName(cycle=None, node=None):
  function _findExpectedNeutronFileName (line 73) | def _findExpectedNeutronFileName(fileType, fileNameKeywords):
  function _getNeutronKeywords (line 77) | def _getNeutronKeywords(cycle, node, suffix, xsID):
  function getExpectedGAMISOFileName (line 97) | def getExpectedGAMISOFileName(cycle=None, node=None, suffix=None, xsID=N...
  function getExpectedPMATRXFileName (line 122) | def getExpectedPMATRXFileName(cycle=None, node=None, suffix=None, xsID=N...
  function _findExpectedGammaFileName (line 147) | def _findExpectedGammaFileName(fileType, fileNameKeywords):
  function _getGammaKeywords (line 151) | def _getGammaKeywords(cycle, node, suffix, xsID):

FILE: armi/nuclearDataIO/cccc/cccc.py
  class IORecord (line 90) | class IORecord:
    method __init__ (line 127) | def __init__(self, stream, hasRecordBoundaries=True):
    method __enter__ (line 134) | def __enter__(self):
    method __exit__ (line 144) | def __exit__(self, exc_type, exc_value, traceback):
    method open (line 159) | def open(self):
    method close (line 163) | def close(self):
    method rwInt (line 167) | def rwInt(self, val):
    method rwBool (line 178) | def rwBool(self, val):
    method rwFloat (line 183) | def rwFloat(self, val):
    method rwDouble (line 194) | def rwDouble(self, val):
    method rwString (line 205) | def rwString(self, val, length):
    method rwList (line 216) | def rwList(self, contents, containedType, length, strLength=0):
    method rwMatrix (line 245) | def rwMatrix(self, contents, *shape):
    method rwDoubleMatrix (line 261) | def rwDoubleMatrix(self, contents, *shape):
    method rwIntMatrix (line 277) | def rwIntMatrix(self, contents, *shape):
    method _rwMatrix (line 282) | def _rwMatrix(contents, func, *shape):
    method rwImplicitlyTypedMap (line 308) | def rwImplicitlyTypedMap(self, keys: List[str], contents) -> dict:
  class BinaryRecordReader (line 323) | class BinaryRecordReader(IORecord):
    method open (line 334) | def open(self):
    method close (line 343) | def close(self):
    method rwInt (line 359) | def rwInt(self, val):
    method rwBool (line 365) | def rwBool(self, val):
    method rwLong (line 369) | def rwLong(self, val):
    method rwFloat (line 375) | def rwFloat(self, val):
    method rwDouble (line 381) | def rwDouble(self, val):
    method rwString (line 387) | def rwString(self, val, length):
  class BinaryRecordWriter (line 394) | class BinaryRecordWriter(IORecord):
    method __init__ (line 401) | def __init__(self, stream, hasRecordBoundaries=True):
    method open (line 405) | def open(self):
    method close (line 408) | def close(self):
    method _getPackedNumBytes (line 419) | def _getPackedNumBytes(self):
    method _write_buffer_to_stream (line 422) | def _write_buffer_to_stream(self, i):
    method rwInt (line 425) | def rwInt(self, val):
    method rwBool (line 430) | def rwBool(self, val):
    method rwLong (line 434) | def rwLong(self, val):
    method rwFloat (line 440) | def rwFloat(self, val):
    method rwDouble (line 445) | def rwDouble(self, val):
    method rwString (line 450) | def rwString(self, val, length):
  class AsciiRecordReader (line 456) | class AsciiRecordReader(BinaryRecordReader):
    method close (line 465) | def close(self):
    method _getPackedNumBytes (line 471) | def _getPackedNumBytes(self):
    method _write_buffer_to_stream (line 474) | def _write_buffer_to_stream(self, i):
    method rwInt (line 477) | def rwInt(self, val):
    method rwFloat (line 480) | def rwFloat(self, val):
    method rwDouble (line 483) | def rwDouble(self, val):
    method rwString (line 486) | def rwString(self, val, length):
  class AsciiRecordWriter (line 492) | class AsciiRecordWriter(IORecord):
    method __init__ (line 502) | def __init__(self, stream, hasRecordBoundaries=True):
    method open (line 507) | def open(self):
    method close (line 510) | def close(self):
    method rwInt (line 517) | def rwInt(self, val):
    method rwFloat (line 522) | def rwFloat(self, val):
    method rwDouble (line 527) | def rwDouble(self, val):
    method rwString (line 532) | def rwString(self, val, length):
  class DataContainer (line 538) | class DataContainer:
    method __init__ (line 546) | def __init__(self):
  class Stream (line 551) | class Stream:
    method __init__ (line 572) | def __init__(self, fileName, fileMode):
    method __deepcopy__ (line 591) | def __deepcopy__(self, memo):
    method __repr__ (line 602) | def __repr__(self):
    method __enter__ (line 605) | def __enter__(self):
    method __exit__ (line 614) | def __exit__(self, exc_type, exc_value, traceback):
    method readWrite (line 618) | def readWrite(self):
    method createRecord (line 622) | def createRecord(self, hasRecordBoundaries=True):
    method readBinary (line 627) | def readBinary(cls, fileName: str):
    method readAscii (line 632) | def readAscii(cls, fileName: str):
    method _read (line 637) | def _read(cls, fileName, fileMode):
    method writeBinary (line 641) | def writeBinary(cls, data: DataContainer, fileName: str):
    method writeAscii (line 646) | def writeAscii(cls, data: DataContainer, fileName: str):
    method _write (line 651) | def _write(cls, lib, fileName, fileMode):
  class StreamWithDataContainer (line 655) | class StreamWithDataContainer(Stream):
    method __init__ (line 672) | def __init__(self, data: DataContainer, fileName: str, fileMode: str):
    method _getDataContainer (line 678) | def _getDataContainer() -> DataContainer:
    method _read (line 682) | def _read(cls, fileName: str, fileMode: str):
    method _write (line 691) | def _write(cls, data: DataContainer, fileName: str, fileMode: str):
    method _readWrite (line 695) | def _readWrite(cls, data: DataContainer, fileName: str, fileMode: str):
  function getBlockBandwidth (line 701) | def getBlockBandwidth(m, nintj, nblok):

FILE: armi/nuclearDataIO/cccc/compxs.py
  function _getRegionIO (line 92) | def _getRegionIO():
  function _flattenScatteringVector (line 96) | def _flattenScatteringVector(colVector, group, numUpScatter, numDownScat...
  function compare (line 101) | def compare(lib1, lib2, tolerance=0.0, verbose=False):
  function _compareRegionXS (line 141) | def _compareRegionXS(region1, region2, tolerance, verbose):
  class _CompxsIO (line 146) | class _CompxsIO(cccc.Stream):
    method __init__ (line 178) | def __init__(self, fileName, lib, fileMode, getRegionFunc):
    method _getFileMetadata (line 186) | def _getFileMetadata(self):
    method isReadingCompxs (line 189) | def isReadingCompxs(self):
    method fileMode (line 192) | def fileMode(self):
    method _read (line 196) | def _read(cls, fileName, fileMode):
    method _write (line 208) | def _write(cls, lib, fileName, fileMode):
    method _readWrite (line 212) | def _readWrite(cls, lib, fileName, fileMode, getRegionFunc):
    method readWrite (line 217) | def readWrite(self):
    method _rw1DRecord (line 240) | def _rw1DRecord(self, regNames):
    method _rw2DRecord (line 250) | def _rw2DRecord(self):
    method _rwLibraryEnergies (line 262) | def _rwLibraryEnergies(self, record):
    method _rwDelayedProperties (line 268) | def _rwDelayedProperties(self, record, numDelayedFam):
    method _rw5DRecord (line 285) | def _rw5DRecord(self):
  class _CompxsRegionIO (line 299) | class _CompxsRegionIO:
    method __init__ (line 314) | def __init__(self, region, compxsIO, lib):
    method _getRegionMetadata (line 322) | def _getRegionMetadata(self):
    method _getFileMetadata (line 325) | def _getFileMetadata(self):
    method rwRegionData (line 328) | def rwRegionData(self):
    method _rw3DRecord (line 333) | def _rw3DRecord(self):
    method _rw4DRecord (line 352) | def _rw4DRecord(self):
    method _rwGroup4DRecord (line 363) | def _rwGroup4DRecord(self, record, group, macros):
    method _rwPrimaryXS (line 381) | def _rwPrimaryXS(self, record, group, macros):
    method _rwScatteringMatrix (line 390) | def _rwScatteringMatrix(self, record, group, macros, order):
  class _CompxsScatterMatrix (line 409) | class _CompxsScatterMatrix:
    method __init__ (line 412) | def __init__(self, shape):
    method addColumnData (line 418) | def addColumnData(self, dataj, indicesj):
    method makeSparse (line 423) | def makeSparse(self, sparseFunc=csc_matrix):
  class CompxsRegion (line 430) | class CompxsRegion:
    method __init__ (line 473) | def __init__(self, lib, regionNumber):
    method __repr__ (line 480) | def __repr__(self):
    method _getFileMetadata (line 483) | def _getFileMetadata(self):
    method _getMetadata (line 486) | def _getMetadata(self):
    method initMetadata (line 499) | def initMetadata(self, groups):
    method isFissile (line 512) | def isFissile(self):
    method allocateXS (line 515) | def allocateXS(self, numGroups):
    method makeScatteringMatrices (line 553) | def makeScatteringMatrices(self):
    method getXS (line 580) | def getXS(self, interaction):
    method merge (line 590) | def merge(self, other):

FILE: armi/nuclearDataIO/cccc/dif3d.py
  class Dif3dData (line 84) | class Dif3dData(cccc.DataContainer):
    method __init__ (line 85) | def __init__(self):
  class Dif3dStream (line 94) | class Dif3dStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 98) | def _getDataContainer() -> Dif3dData:
    method _rwFileID (line 101) | def _rwFileID(self) -> None:
    method _rw1DRecord (line 112) | def _rw1DRecord(self) -> None:
    method _rw2DRecord (line 126) | def _rw2DRecord(self) -> None:
    method _rw3DRecord (line 136) | def _rw3DRecord(self) -> None:
    method _rw4DRecord (line 147) | def _rw4DRecord(self) -> None:
    method _rw5DRecord (line 167) | def _rw5DRecord(self) -> None:
    method readWrite (line 190) | def readWrite(self):

FILE: armi/nuclearDataIO/cccc/fixsrc.py
  function readBinary (line 30) | def readBinary(fileName):
  function writeBinary (line 37) | def writeBinary(fileName, fixSrcArray):
  class FIXSRC (line 43) | class FIXSRC(cccc.Stream):
    method __init__ (line 46) | def __init__(self, fileName, fileMode, fixSrc):
    method readWrite (line 93) | def readWrite(self):
    method _rwFileID (line 106) | def _rwFileID(self):
    method _rw1DRecord (line 112) | def _rw1DRecord(self):
    method _rw3DRecord (line 118) | def _rw3DRecord(self, g, z):

FILE: armi/nuclearDataIO/cccc/gamiso.py
  function compare (line 44) | def compare(lib1, lib2):
  function compareNuclideXS (line 61) | def compareNuclideXS(nuc1, nuc2):
  function addDummyNuclidesToLibrary (line 67) | def addDummyNuclidesToLibrary(lib, dummyNuclides):
  class _GamisoIO (line 120) | class _GamisoIO(isotxs.IsotxsIO):
    method _getFileMetadata (line 129) | def _getFileMetadata(self):
    method _getNuclideIO (line 132) | def _getNuclideIO(self):
    method _rwMessage (line 135) | def _rwMessage(self):
    method _rwLibraryEnergies (line 138) | def _rwLibraryEnergies(self, record):
  class _GamisoNuclideIO (line 156) | class _GamisoNuclideIO(isotxs._IsotxsNuclideIO):
    method _getFileMetadata (line 167) | def _getFileMetadata(self):
    method _getNuclideMetadata (line 170) | def _getNuclideMetadata(self):
    method _getMicros (line 173) | def _getMicros(self):

FILE: armi/nuclearDataIO/cccc/geodst.py
  class GeodstData (line 70) | class GeodstData(cccc.DataContainer):
    method __init__ (line 83) | def __init__(self):
  class GeodstStream (line 110) | class GeodstStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 126) | def _getDataContainer() -> GeodstData:
    method readWrite (line 129) | def readWrite(self):
    method _rwFileID (line 192) | def _rwFileID(self):
    method _rw1DRecord (line 204) | def _rw1DRecord(self):
    method _rw2DRecord (line 214) | def _rw2DRecord(self):
    method _rw3DRecord (line 220) | def _rw3DRecord(self):
    method _rw4DRecord (line 228) | def _rw4DRecord(self):
    method _rw5DRecord (line 238) | def _rw5DRecord(self):
    method _rw6DRecord (line 255) | def _rw6DRecord(self):
    method _rw7DRecord (line 276) | def _rw7DRecord(self):

FILE: armi/nuclearDataIO/cccc/isotxs.py
  function compareSet (line 58) | def compareSet(fileNames, tolerance=0.0, verbose=False):
  function compare (line 84) | def compare(lib1, lib2, tolerance=0.0, verbose=False):
  function compareNuclideXS (line 118) | def compareNuclideXS(nuc1, nuc2, tolerance=0.0, verbose=False, nucName=""):
  function addDummyNuclidesToLibrary (line 124) | def addDummyNuclidesToLibrary(lib, dummyNuclides):
  class IsotxsIO (line 176) | class IsotxsIO(cccc.Stream):
    method __init__ (line 191) | def __init__(self, fileName, lib, fileMode, getNuclideFunc):
    method _getFileMetadata (line 198) | def _getFileMetadata(self):
    method _getNuclideIO (line 201) | def _getNuclideIO(self):
    method _read (line 205) | def _read(cls, fileName, fileMode):
    method _write (line 215) | def _write(cls, lib, fileName, fileMode):
    method _readWrite (line 219) | def _readWrite(cls, lib, fileName, fileMode, getNuclideFunc):
    method _rwMessage (line 224) | def _rwMessage(self):
    method _updateFileLabel (line 227) | def _updateFileLabel(self):
    method readWrite (line 245) | def readWrite(self):
    method _fileID (line 315) | def _fileID(self):
    method _rw1DRecord (line 321) | def _rw1DRecord(self, numNucs):
    method _rw2DRecord (line 333) | def _rw2DRecord(self, numNucs, nucNames):
    method _rwLibraryEnergies (line 354) | def _rwLibraryEnergies(self, record):
    method _rw3DRecord (line 362) | def _rw3DRecord(self):
    method _computeNuclideRecordOffset (line 366) | def _computeNuclideRecordOffset(self):
    method _computeNumIsotxsRecords (line 379) | def _computeNumIsotxsRecords(self, nuclide):
  class _IsotxsNuclideIO (line 395) | class _IsotxsNuclideIO:
    method __init__ (line 404) | def __init__(self, nuclide, isotxsIO, lib):
    method _getFileMetadata (line 415) | def _getFileMetadata(self):
    method _getNuclideMetadata (line 418) | def _getNuclideMetadata(self):
    method _getMicros (line 421) | def _getMicros(self):
    method rwNuclide (line 424) | def rwNuclide(self):
    method _rw4DRecord (line 443) | def _rw4DRecord(self):
    method _rw5DRecord (line 498) | def _rw5DRecord(self):
    method _rw6DRecord (line 537) | def _rw6DRecord(self):
    method _rw7DRecord (line 541) | def _rw7DRecord(self, blockNumIndex, subBlock):
    method _getScatterBlockNum (line 633) | def _getScatterBlockNum(self, scatterType):
    method _getElasticScatterBlockNumIndex (line 655) | def _getElasticScatterBlockNumIndex(self, legendreOrder=0):
    method _getInelasticScatterBlockNumIndex (line 658) | def _getInelasticScatterBlockNumIndex(self):
    method _getN2nScatterBlockNumIndex (line 661) | def _getN2nScatterBlockNumIndex(self):
    method _getTotalScatterBlockNumIndex (line 664) | def _getTotalScatterBlockNumIndex(self):
    method _setScatterMatrix (line 667) | def _setScatterMatrix(self, blockNumIndex, scatterMatrix):
    method _getScatterMatrix (line 687) | def _getScatterMatrix(self, blockNumIndex):

FILE: armi/nuclearDataIO/cccc/labels.py
  class LabelsData (line 85) | class LabelsData(cccc.DataContainer):
    method __init__ (line 92) | def __init__(self):
  class LabelsStream (line 106) | class LabelsStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 121) | def _getDataContainer() -> LabelsData:
    method readWrite (line 124) | def readWrite(self):
    method _rwFileID (line 146) | def _rwFileID(self):
    method _rw1DRecord (line 152) | def _rw1DRecord(self):
    method _rw2DRecord (line 159) | def _rw2DRecord(self):
    method _rw3DRecord (line 177) | def _rw3DRecord(self):
    method _rw4DRecord (line 201) | def _rw4DRecord(self):
    method _rw5DRecord (line 211) | def _rw5DRecord(self):
    method _rw6DRecord (line 221) | def _rw6DRecord(self):
    method _rw7DRecord (line 225) | def _rw7DRecord(self):
    method _rw8DRecord (line 229) | def _rw8DRecord(self):
    method _rw9DRecord (line 233) | def _rw9DRecord(self):
    method _rw10DRecord (line 237) | def _rw10DRecord(self):
    method _rw11DRecord (line 241) | def _rw11DRecord(self):

FILE: armi/nuclearDataIO/cccc/nhflux.py
  class NHFLUX (line 60) | class NHFLUX(cccc.DataContainer):
    method __init__ (line 139) | def __init__(self, fName="NHFLUX", variant=False, numDataSetsToRead=1):
    method fluxMoments (line 170) | def fluxMoments(self):
    method partialCurrentsHex (line 181) | def partialCurrentsHex(self):
    method partialCurrentsHex_ext (line 192) | def partialCurrentsHex_ext(self):
    method partialCurrentsZ (line 203) | def partialCurrentsZ(self):
  class NhfluxStream (line 214) | class NhfluxStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 216) | def _getDataContainer() -> NHFLUX:
    method readWrite (line 219) | def readWrite(self):
    method _getNumOuterSurfacesHex (line 334) | def _getNumOuterSurfacesHex(self):
    method _rwFileID (line 353) | def _rwFileID(self):
    method _rwBasicFileData1D (line 365) | def _rwBasicFileData1D(self):
    method _rwGeodstCoordMap2D (line 377) | def _rwGeodstCoordMap2D(self):
    method _rwFluxMoments3D (line 452) | def _rwFluxMoments3D(self, contents):
    method _rwHexPartialCurrents4D (line 487) | def _rwHexPartialCurrents4D(self, surfCurrents, externalSurfCurrents):
    method _rwZPartialCurrents5D (line 543) | def _rwZPartialCurrents5D(self, surfCurrents):
    method _getEnergyGroupIndex (line 586) | def _getEnergyGroupIndex(self, g):
  class NafluxStream (line 594) | class NafluxStream(NhfluxStream):
    method _getEnergyGroupIndex (line 601) | def _getEnergyGroupIndex(self, g):
  class NhfluxStreamVariant (line 607) | class NhfluxStreamVariant(NhfluxStream):
    method _getDataContainer (line 617) | def _getDataContainer() -> NHFLUX:
  class NafluxStreamVariant (line 621) | class NafluxStreamVariant(NafluxStream):
    method _getDataContainer (line 631) | def _getDataContainer() -> NHFLUX:
  function getNhfluxReader (line 635) | def getNhfluxReader(adjointFlag, variantFlag):

FILE: armi/nuclearDataIO/cccc/pmatrx.py
  function compare (line 33) | def compare(lib1, lib2):
  function compareNuclideXS (line 53) | def compareNuclideXS(nuc1, nuc2):
  function addDummyNuclidesToLibrary (line 73) | def addDummyNuclidesToLibrary(lib, dummyNuclides):
  function readBinary (line 117) | def readBinary(fileName):
  function readAscii (line 122) | def readAscii(fileName):
  function _read (line 127) | def _read(fileName, fileMode):
  function writeBinary (line 137) | def writeBinary(lib, fileName):
  function writeAscii (line 144) | def writeAscii(lib, fileName):
  function _write (line 151) | def _write(lib, fileName, fileMode):
  function _readWrite (line 155) | def _readWrite(lib, fileName, fileMode, getNuclideFunc):
  class PmatrxIO (line 162) | class PmatrxIO(cccc.Stream):
    method __init__ (line 163) | def __init__(self, fileName, xsLib, fileMode, getNuclideFunc):
    method _rwMessage (line 171) | def _rwMessage(self):
    method readWrite (line 174) | def readWrite(self):
    method _rwFileID (line 213) | def _rwFileID(self):
    method _rwGroupStructure (line 236) | def _rwGroupStructure(self):
    method _rwDoseConversionFactor (line 249) | def _rwDoseConversionFactor(self):
    method _rwIsotopes (line 263) | def _rwIsotopes(self, numNucs):
    method _rwCompositions (line 278) | def _rwCompositions(self):
  class _PmatrxNuclideIO (line 283) | class _PmatrxNuclideIO:
    method __init__ (line 284) | def __init__(self, nuclide, pmatrixIO, numNeutronGroups, numGammaGroups):
    method rwNuclide (line 291) | def rwNuclide(self):
    method _rwNuclideHeading (line 298) | def _rwNuclideHeading(self):
    method _rwNeutronHeatingAndDamage (line 306) | def _rwNeutronHeatingAndDamage(self):
    method _rwReactionXS (line 313) | def _rwReactionXS(self):
    method _rwGammaHeating (line 325) | def _rwGammaHeating(self):
    method _rwCellAveragedProductionMatrix (line 331) | def _rwCellAveragedProductionMatrix(self):
    method _getProductionMatrix (line 338) | def _getProductionMatrix(self, order):
    method _setProductionMatrix (line 346) | def _setProductionMatrix(self, order, matrix):

FILE: armi/nuclearDataIO/cccc/pwdint.py
  class PwdintData (line 47) | class PwdintData(cccc.DataContainer):
    method __init__ (line 55) | def __init__(self):
  class PwdintStream (line 60) | class PwdintStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 76) | def _getDataContainer() -> PwdintData:
    method readWrite (line 79) | def readWrite(self):
    method _rwFileID (line 90) | def _rwFileID(self):
    method _rw1DRecord (line 98) | def _rw1DRecord(self):
    method _rw2DRecord (line 103) | def _rw2DRecord(self):

FILE: armi/nuclearDataIO/cccc/rtflux.py
  class RtfluxData (line 59) | class RtfluxData(cccc.DataContainer):
    method __init__ (line 68) | def __init__(self):
  class RtfluxStream (line 75) | class RtfluxStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 92) | def _getDataContainer() -> RtfluxData:
    method readWrite (line 95) | def readWrite(self):
    method _rwFileID (line 106) | def _rwFileID(self):
    method _rw1DRecord (line 118) | def _rw1DRecord(self):
    method _rw2DRecord (line 123) | def _rw2DRecord(self):
    method _rw3DRecord (line 127) | def _rw3DRecord(self):
    method getEnergyGroupIndex (line 158) | def getEnergyGroupIndex(self, g):
  class AtfluxStream (line 168) | class AtfluxStream(RtfluxStream):
    method getEnergyGroupIndex (line 174) | def getEnergyGroupIndex(self, g):
  function getFDFluxReader (line 184) | def getFDFluxReader(adjointFlag):

FILE: armi/nuclearDataIO/cccc/rzflux.py
  class Convergence (line 62) | class Convergence(Enum):
  class RzfluxData (line 71) | class RzfluxData(cccc.DataContainer):
    method __init__ (line 80) | def __init__(self):
  class RzfluxStream (line 86) | class RzfluxStream(cccc.StreamWithDataContainer):
    method _getDataContainer (line 102) | def _getDataContainer() -> RzfluxData:
    method readWrite (line 105) | def readWrite(self):
    method _rwFileID (line 111) | def _rwFileID(self):
    method _rw1DRecord (line 124) | def _rw1DRecord(self):
    method _rw2DRecord (line 130) | def _rw2DRecord(self):

FILE: armi/nuclearDataIO/cccc/tests/test_cccc.py
  class CcccIOStreamTests (line 22) | class CcccIOStreamTests(unittest.TestCase):
    method test_initWithFileMode (line 23) | def test_initWithFileMode(self):
  class CcccBinaryRecordTests (line 32) | class CcccBinaryRecordTests(unittest.TestCase):
    method setUpClass (line 34) | def setUpClass(cls):
    method setUp (line 38) | def setUp(self):
    method test_writeAndReadSimpleIntegerRecord (line 41) | def test_writeAndReadSimpleIntegerRecord(self):
    method test_writeAndReadSimpleFloatRecord (line 51) | def test_writeAndReadSimpleFloatRecord(self):
    method test_writeAndReadSimpleStringRecord (line 61) | def test_writeAndReadSimpleStringRecord(self):
    method test_readPartialRecord (line 72) | def test_readPartialRecord(self):
    method test_readingBeyondRecordRaisesException (line 86) | def test_readingBeyondRecordRaisesException(self):
  class CcccAsciiRecordTests (line 100) | class CcccAsciiRecordTests(CcccBinaryRecordTests):
    method setUpClass (line 104) | def setUpClass(cls):
    method setUp (line 108) | def setUp(self):

FILE: armi/nuclearDataIO/cccc/tests/test_compxs.py
  class TestCompxs (line 30) | class TestCompxs(unittest.TestCase):
    method binaryWritePath (line 34) | def binaryWritePath(self):
    method asciiWritePath (line 38) | def asciiWritePath(self):
    method setUpClass (line 42) | def setUpClass(cls):
    method test_libraryData (line 50) | def test_libraryData(self):
    method test_regionPrimaryXS (line 56) | def test_regionPrimaryXS(self):
    method test_totalScatterMatrix (line 155) | def test_totalScatterMatrix(self):
    method test_binaryRW (line 296) | def test_binaryRW(self):
    method test_asciiRW (line 302) | def test_asciiRW(self):
    method test_mergeCompxsLibraries (line 308) | def test_mergeCompxsLibraries(self):
    method test_getCOMPXSFileName (line 315) | def test_getCOMPXSFileName(self):

FILE: armi/nuclearDataIO/cccc/tests/test_dif3d.py
  class TestDif3dSimpleHexz (line 29) | class TestDif3dSimpleHexz(unittest.TestCase):
    method setUpClass (line 31) | def setUpClass(cls):
    method test__rwFileID (line 39) | def test__rwFileID(self):
    method test__rwFile1DRecord (line 51) | def test__rwFile1DRecord(self):
    method test__rw2DRecord (line 66) | def test__rw2DRecord(self):
    method test__rw3DRecord (line 120) | def test__rw3DRecord(self):
    method test__rw4DRecord (line 137) | def test__rw4DRecord(self):
    method test__rw5DRecord (line 141) | def test__rw5DRecord(self):
    method test_writeBinary (line 145) | def test_writeBinary(self):
  class TestDif3dEmptyRecords (line 161) | class TestDif3dEmptyRecords(unittest.TestCase):
    method test_empty4and5Records (line 162) | def test_empty4and5Records(self):

FILE: armi/nuclearDataIO/cccc/tests/test_fixsrc.py
  class TestFixsrc (line 35) | class TestFixsrc(unittest.TestCase):
    method test_writeReadBinaryLoop (line 36) | def test_writeReadBinaryLoop(self):

FILE: armi/nuclearDataIO/cccc/tests/test_gamiso.py
  class TestGamiso (line 31) | class TestGamiso(unittest.TestCase):
    method setUp (line 32) | def setUp(self):
    method test_compare (line 35) | def test_compare(self):
    method test_writeBinary (line 46) | def test_writeBinary(self):
    method test_addDummyNuclidesToLibrary (line 58) | def test_addDummyNuclidesToLibrary(self):
    method test_addDummyNuclidesToLibraryNumGroups (line 73) | def test_addDummyNuclidesToLibraryNumGroups(self):

FILE: armi/nuclearDataIO/cccc/tests/test_geodst.py
  class TestGeodst (line 28) | class TestGeodst(unittest.TestCase):
    method test_readGeodst (line 36) | def test_readGeodst(self):
    method test_writeGeodst (line 51) | def test_writeGeodst(self):

FILE: armi/nuclearDataIO/cccc/tests/test_isotxs.py
  class TestIsotxs (line 26) | class TestIsotxs(unittest.TestCase):
    method setUpClass (line 30) | def setUpClass(cls):
    method test_writeBinary (line 35) | def test_writeBinary(self):
    method test_isotxsGeneralData (line 62) | def test_isotxsGeneralData(self):
    method test_isotxsDetailedData (line 71) | def test_isotxsDetailedData(self):
    method test_getScatteringWeights (line 81) | def test_getScatteringWeights(self):
    method test_getNuclide (line 121) | def test_getNuclide(self):
    method test_n2nIsReactionBased (line 126) | def test_n2nIsReactionBased(self):
    method test_getScatterWeights (line 138) | def test_getScatterWeights(self):
    method test_getISOTXSFileName (line 143) | def test_getISOTXSFileName(self):
    method test_getGAMISOFileName (line 158) | def test_getGAMISOFileName(self):
  class Isotxs_merge_Tests (line 177) | class Isotxs_merge_Tests(unittest.TestCase):
    method test_mergeMccV2FilesRemovesTheFileWideChi (line 178) | def test_mergeMccV2FilesRemovesTheFileWideChi(self):

FILE: armi/nuclearDataIO/cccc/tests/test_labels.py
  class TestLabels (line 29) | class TestLabels(unittest.TestCase):
    method test_readLabelsBinary (line 32) | def test_readLabelsBinary(self):
    method test_writeLabelsAscii (line 46) | def test_writeLabelsAscii(self):

FILE: armi/nuclearDataIO/cccc/tests/test_nhflux.py
  class TestNhflux (line 32) | class TestNhflux(unittest.TestCase):
    method setUpClass (line 34) | def setUpClass(cls):
    method test_fc (line 38) | def test_fc(self):
    method test_fluxMoments (line 56) | def test_fluxMoments(self):
    method test_xyPartialCurrents (line 86) | def test_xyPartialCurrents(self):
    method test_zPartialCurrents (line 106) | def test_zPartialCurrents(self):
    method test_write (line 117) | def test_write(self):
  class TestNhfluxVariant (line 128) | class TestNhfluxVariant(unittest.TestCase):
    method setUpClass (line 130) | def setUpClass(cls):
    method test_fc (line 134) | def test_fc(self):
    method test_fluxMoments (line 149) | def test_fluxMoments(self):
    method test_write (line 174) | def test_write(self):

FILE: armi/nuclearDataIO/cccc/tests/test_pmatrx.py
  class TestPmatrxNuclides (line 26) | class TestPmatrxNuclides(unittest.TestCase):
    method setUpClass (line 28) | def setUpClass(cls):
    method _nuclideGeneralHelper (line 34) | def _nuclideGeneralHelper(self, u235):
    method test_pmatrxNuclideDataAA (line 45) | def test_pmatrxNuclideDataAA(self):
    method test_pmatrxNuclideDataAB (line 48) | def test_pmatrxNuclideDataAB(self):
    method test_nuclideDataIsDifferent (line 51) | def test_nuclideDataIsDifferent(self):
    method test_getPMATRXFileName (line 56) | def test_getPMATRXFileName(self):
  class TestPmatrx (line 71) | class TestPmatrx(unittest.TestCase):
    method setUpClass (line 75) | def setUpClass(cls):
    method setUp (line 80) | def setUp(self):
    method tearDown (line 84) | def tearDown(self):
    method test_pmatrxGammaEnergies (line 87) | def test_pmatrxGammaEnergies(self):
    method test_pmatrxNeutronEnergies (line 113) | def test_pmatrxNeutronEnergies(self):
    method test_pmatrxNuclideNames (line 151) | def test_pmatrxNuclideNames(self):
    method test_pmatrxDoesntHaveDoseConversionFactors (line 181) | def test_pmatrxDoesntHaveDoseConversionFactors(self):
  class TestProdMatrix (line 189) | class TestProdMatrix(TestPmatrx):
    method test_writtenIsIdenticalToOriginal (line 196) | def test_writtenIsIdenticalToOriginal(self):
  class TestProdMatrixFromAscii (line 212) | class TestProdMatrixFromAscii(TestPmatrx):
    method setUpClass (line 222) | def setUpClass(cls):
    method setUp (line 225) | def setUp(self):
    method tearDown (line 234) | def tearDown(self):

FILE: armi/nuclearDataIO/cccc/tests/test_pwdint.py
  class TestGeodst (line 26) | class TestGeodst(unittest.TestCase):
    method test_readGeodst (line 34) | def test_readGeodst(self):
    method test_writeGeodst (line 39) | def test_writeGeodst(self):

FILE: armi/nuclearDataIO/cccc/tests/test_rtflux.py
  class Testrtflux (line 27) | class Testrtflux(unittest.TestCase):
    method test_readrtflux (line 30) | def test_readrtflux(self):
    method test_writertflux (line 43) | def test_writertflux(self):
    method test_rwAscii (line 54) | def test_rwAscii(self):
    method test_adjoint (line 62) | def test_adjoint(self):

FILE: armi/nuclearDataIO/cccc/tests/test_rzflux.py
  class TestRzflux (line 27) | class TestRzflux(unittest.TestCase):
    method test_readRzflux (line 30) | def test_readRzflux(self):
    method test_writeRzflux (line 35) | def test_writeRzflux(self):
    method test_rwAscii (line 48) | def test_rwAscii(self):
  function binaryFilesEqual (line 57) | def binaryFilesEqual(fn1, fn2):

FILE: armi/nuclearDataIO/nuclearFileMetadata.py
  class _Metadata (line 39) | class _Metadata:
    method __init__ (line 47) | def __init__(self):
    method __getitem__ (line 50) | def __getitem__(self, key):
    method __setitem__ (line 53) | def __setitem__(self, key, value):
    method __iter__ (line 56) | def __iter__(self):
    method items (line 59) | def items(self):
    method __len__ (line 63) | def __len__(self):
    method keys (line 66) | def keys(self):
    method values (line 70) | def values(self):
    method update (line 73) | def update(self, other):
    method merge (line 77) | def merge(self, other, selfContainer, otherContainer, fileType, except...
    method _getSkippedKeys (line 130) | def _getSkippedKeys(self, other, selfContainer, otherContainer, merged...
    method _mergeLibrarySpecificData (line 133) | def _mergeLibrarySpecificData(self, other, selfContainer, otherContain...
    method compare (line 136) | def compare(self, other, selfContainer, otherContainer, tolerance=0.0):
  class FileMetadata (line 174) | class FileMetadata(_Metadata):
    method __init__ (line 184) | def __init__(self):
    method update (line 188) | def update(self, other):
    method _mergeLibrarySpecificData (line 193) | def _mergeLibrarySpecificData(self, other, selfContainer, otherContain...
  class NuclideXSMetadata (line 197) | class NuclideXSMetadata(FileMetadata):
    method _getSkippedKeys (line 200) | def _getSkippedKeys(self, other, selfContainer, otherContainer, merged...
    method _mergeLibrarySpecificData (line 218) | def _mergeLibrarySpecificData(self, other, selfContainer, otherContain...
  class RegionXSMetadata (line 223) | class RegionXSMetadata(FileMetadata):
    method _mergeLibrarySpecificData (line 226) | def _mergeLibrarySpecificData(self, other, selfContainer, 
Condensed preview — 703 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,436K chars).
[
  {
    "path": ".github/.codecov.yml",
    "chars": 181,
    "preview": "coverage:\n  status:\n    project:\n      default:\n        target: 80%    # the required coverage value\n        threshold: "
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1203,
    "preview": "## What is the change? Why is it being made?\n\n<!-- MANDATORY: Describe the change -->\n\n\n## SCR Information\n\n<!-- MANDATO"
  },
  {
    "path": ".github/workflows/coverage.yaml",
    "chars": 2116,
    "preview": "name: Coverage\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n      - 'doc/**'"
  },
  {
    "path": ".github/workflows/docs.yaml",
    "chars": 3031,
    "preview": "name: Documentation\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\nconcurrency:\n  group: ${{ github.workflow }"
  },
  {
    "path": ".github/workflows/find_test_crumbs.py",
    "chars": 1568,
    "preview": "# Copyright 2024 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": ".github/workflows/licensechecker.yaml",
    "chars": 244,
    "preview": "name: Check License Lines\n\npermissions:\n  contents: read\n\non: [push]\n\njobs:\n  check-license-lines:\n    runs-on: ubuntu-2"
  },
  {
    "path": ".github/workflows/linting.yaml",
    "chars": 404,
    "preview": "name: Linting\n\npermissions:\n  contents: read\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-24.04\n\n    steps:\n      - "
  },
  {
    "path": ".github/workflows/mac_tests.yaml",
    "chars": 745,
    "preview": "name: ARMI MacOS Tests\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n      - "
  },
  {
    "path": ".github/workflows/stale.yaml",
    "chars": 1009,
    "preview": "# This workflow warns and then closes PRs that have had no activity for a specified amount of time.\n#\n# You can adjust t"
  },
  {
    "path": ".github/workflows/unittests.yaml",
    "chars": 968,
    "preview": "name: ARMI unit tests\n\npermissions:\n  contents: read\n\non:\n  push:\n    paths-ignore:\n      - 'doc/**'\n\nconcurrency:\n  gro"
  },
  {
    "path": ".github/workflows/validatemanifest.py",
    "chars": 1774,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": ".github/workflows/validatemanifest.yaml",
    "chars": 397,
    "preview": "name: Validate Manifest\n\npermissions:\n  contents: read\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-24.04\n\n    steps"
  },
  {
    "path": ".github/workflows/wheels.yaml",
    "chars": 800,
    "preview": "name: Build Wheel\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  build:\n    if: github."
  },
  {
    "path": ".github/workflows/wintests.yaml",
    "chars": 801,
    "preview": "name: ARMI Windows tests\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n      "
  },
  {
    "path": ".gitignore",
    "chars": 1074,
    "preview": "# No non-source python resources\n*.pyc\n*.pyd\n*.pyo\n*.pyx\n\n# No build artifacts\n*.aux\n*.dll\n*.fdb_latexmk\n*.fls\n*.lib\narm"
  },
  {
    "path": ".gitmodules",
    "chars": 142,
    "preview": "[submodule \"doc/tutorials/armi-example-app\"]\n\tpath = doc/tutorials/armi-example-app\n\turl = https://github.com/terrapower"
  },
  {
    "path": ".licenserc.json",
    "chars": 32,
    "preview": "{\n  \"**/*.py\": \"# Copyright \"\n}\n"
  },
  {
    "path": "AUTHORS",
    "chars": 1507,
    "preview": "# This is the list of ARMI's contributors.\n#\n# This may not list everyone who has ever contributed code, important ideas"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 7111,
    "preview": "# Contribution License Agreement\n\nFor information on how to contribute to ARMI, see [our official documentation](https:/"
  },
  {
    "path": "LICENSE.md",
    "chars": 11345,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.rst",
    "chars": 19068,
    "preview": "\n|Build Status| |Code Coverage| |Commit Activity| |Good First Issues|\n\n#################\nARMI Introduction\n#############"
  },
  {
    "path": "armi/__init__.py",
    "chars": 11395,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/__main__.py",
    "chars": 2164,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/_bootstrap.py",
    "chars": 1103,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/apps.py",
    "chars": 15482,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/__init__.py",
    "chars": 3399,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/__init__.py",
    "chars": 7991,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/compareDB3.py",
    "chars": 18820,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/database.py",
    "chars": 72465,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/databaseInterface.py",
    "chars": 15514,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/factory.py",
    "chars": 3416,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/jaggedArray.py",
    "chars": 7058,
    "preview": "# Copyright 2024 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/layout.py",
    "chars": 32386,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/passiveDBLoadPlugin.py",
    "chars": 3928,
    "preview": "# Copyright 2024 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/permissions.py",
    "chars": 1474,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/__init__.py",
    "chars": 602,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_comparedb3.py",
    "chars": 14237,
    "preview": "# Copyright 2021 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_database.py",
    "chars": 37976,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_databaseInterface.py",
    "chars": 28277,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_jaggedArray.py",
    "chars": 5977,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_layout.py",
    "chars": 4269,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/tests/test_passiveDBLoadPlugin.py",
    "chars": 4367,
    "preview": "# Copyright 2025 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/db/typedefs.py",
    "chars": 935,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/historyTracker.py",
    "chars": 17809,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/mainInterface.py",
    "chars": 8039,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/memoryProfiler.py",
    "chars": 16832,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/__init__.py",
    "chars": 4971,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/data.py",
    "chars": 4994,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/reportInterface.py",
    "chars": 7176,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/reportingUtils.py",
    "chars": 36665,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/report/tests/test_report.py",
    "chars": 12295,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/snapshotInterface.py",
    "chars": 5898,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/tests/__init__.py",
    "chars": 1016,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/tests/_constants.py",
    "chars": 1514,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/tests/test_historyTracker.py",
    "chars": 8950,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/tests/test_memoryProfiler.py",
    "chars": 10215,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/tests/test_snapshot.py",
    "chars": 3443,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/__init__.py",
    "chars": 1254,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/dumper.py",
    "chars": 1107,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/entryPoint.py",
    "chars": 5586,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/tests/test_vis.py",
    "chars": 3966,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/tests/test_xdmf.py",
    "chars": 2236,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/utils.py",
    "chars": 8944,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/vtk.py",
    "chars": 7514,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/bookkeeping/visualization/xdmf.py",
    "chars": 17302,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/__init__.py",
    "chars": 2306,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/case.py",
    "chars": 34492,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/__init__.py",
    "chars": 859,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/inputModifiers.py",
    "chars": 6618,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/neutronicsModifiers.py",
    "chars": 2859,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/pinTypeInputModifiers.py",
    "chars": 5380,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/tests/test_inputModifiers.py",
    "chars": 8876,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/inputModifiers/tests/test_pinTypeInputModifiers.py",
    "chars": 4747,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/suite.py",
    "chars": 12986,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/suiteBuilder.py",
    "chars": 12947,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/tests/test_cases.py",
    "chars": 28801,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cases/tests/test_suiteBuilder.py",
    "chars": 4212,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/__init__.py",
    "chars": 8348,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/checkInputs.py",
    "chars": 3533,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/cleanTemps.py",
    "chars": 973,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/clone.py",
    "chars": 3993,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/compareCases.py",
    "chars": 6889,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/database.py",
    "chars": 4533,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/entryPoint.py",
    "chars": 12934,
    "preview": "\"\"\"\nEntryPoint base classes.\n\nSee :doc:`/developer/entrypoints`.\n\"\"\"\n# Copyright 2019 TerraPower, LLC\n#\n# Licensed under"
  },
  {
    "path": "armi/cli/gridGui.py",
    "chars": 1922,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/migrateInputs.py",
    "chars": 2627,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/modify.py",
    "chars": 4032,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/reportsEntryPoint.py",
    "chars": 985,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/run.py",
    "chars": 885,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/runSuite.py",
    "chars": 2350,
    "preview": "# Copyright 2020 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/tests/test_runEntryPoint.py",
    "chars": 17777,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/cli/tests/test_runSuite.py",
    "chars": 2213,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/conftest.py",
    "chars": 2514,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/context.py",
    "chars": 8441,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/interfaces.py",
    "chars": 27802,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/__init__.py",
    "chars": 10621,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/constituent.py",
    "chars": 4629,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/function.py",
    "chars": 11144,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/interpolationFunctions.py",
    "chars": 2590,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/material.py",
    "chars": 5835,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/materialType.py",
    "chars": 3001,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/piecewiseFunction.py",
    "chars": 5363,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/point.py",
    "chars": 1419,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/prop.py",
    "chars": 6239,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/reference.py",
    "chars": 2201,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/symbolicFunction.py",
    "chars": 4123,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tableFunction.py",
    "chars": 1178,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tableFunction1D.py",
    "chars": 3206,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tableFunction2D.py",
    "chars": 5835,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/__init__.py",
    "chars": 6161,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/invalidTestFiles/badFileFormat.YAML",
    "chars": 168,
    "preview": "file format: INVALID\nmaterial type: Fluid\ncomposition:\n  a: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      "
  },
  {
    "path": "armi/matProps/tests/invalidTestFiles/badProperty.yaml",
    "chars": 82,
    "preview": "file format: TESTS\nmaterial type: Metal\ncomposition:\n  Na: 1.0\n\nbad_prop: whatever"
  },
  {
    "path": "armi/matProps/tests/invalidTestFiles/duplicateComposition.yaml",
    "chars": 208,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  a: [15, 30]\n  b: [10, 15]\n  b: [11, 16]\n  c: balance\n\ndensity:\n  "
  },
  {
    "path": "armi/matProps/tests/testDir1/a.yaml",
    "chars": 251,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  a: balance\n  references:\n    - ref: ACME II.2017, Table 3 pg 182\n"
  },
  {
    "path": "armi/matProps/tests/testDir1/b.yaml",
    "chars": 166,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  b: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testDir2/c.yml",
    "chars": 166,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  c: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testDir2/d.yaml",
    "chars": 166,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  d: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testDir3/a.yaml",
    "chars": 166,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  a: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testDir3/e.yaml",
    "chars": 166,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  e: balance\n\ndensity:\n  function:\n    T:\n      min: 100.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testDir4/sampleProperty.yaml",
    "chars": 5511,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  a: balance\n\ndensity:\n  function:\n    T:\n      min: 101.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testMaterialsData/materialA.yaml",
    "chars": 176,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  a: balance\n\ndensity:\n  function:\n    T:\n      min: 201.0\n      ma"
  },
  {
    "path": "armi/matProps/tests/testMaterialsData/materialB.yaml",
    "chars": 184,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  b: balance\n\nspecific heat capacity:\n  function:\n    T: \n      min"
  },
  {
    "path": "armi/matProps/tests/testMaterialsData/materialsSubDir/materialC.yaml",
    "chars": 180,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  c: balance\n\nthermal conductivity:\n  function:\n    T: \n      min: "
  },
  {
    "path": "armi/matProps/tests/testMaterialsData/materialsSubDir/materialD.yaml",
    "chars": 180,
    "preview": "file format: TESTS\nmaterial type: Fluid\ncomposition:\n  d: balance\n\nthermal diffusivity:\n  function:\n    T:\n      min: 20"
  },
  {
    "path": "armi/matProps/tests/test_1DSymbolicFunction.py",
    "chars": 14441,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_composition.py",
    "chars": 6590,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_constituent.py",
    "chars": 2256,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_functions.py",
    "chars": 6277,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_hashing.py",
    "chars": 1407,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_interpolationFunctions.py",
    "chars": 3640,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_material.py",
    "chars": 3587,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_materialType.py",
    "chars": 1851,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_parsing.py",
    "chars": 7416,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_performance.py",
    "chars": 3360,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_piecewiseFunction.py",
    "chars": 16024,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_point.py",
    "chars": 1176,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_property.py",
    "chars": 12110,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_references.py",
    "chars": 1457,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_symbolicFunction.py",
    "chars": 31225,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/matProps/tests/test_tableFunctions.py",
    "chars": 10151,
    "preview": "# Copyright 2026 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/__init__.py",
    "chars": 8278,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/air.py",
    "chars": 5034,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/alloy200.py",
    "chars": 3561,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/b4c.py",
    "chars": 7811,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/be9.py",
    "chars": 1964,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/caH2.py",
    "chars": 2304,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/californium.py",
    "chars": 1381,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/concrete.py",
    "chars": 1761,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/copper.py",
    "chars": 1827,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/cs.py",
    "chars": 1554,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/custom.py",
    "chars": 2040,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/graphite.py",
    "chars": 1968,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/hafnium.py",
    "chars": 1372,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/hastelloyN.py",
    "chars": 5358,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/ht9.py",
    "chars": 3178,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconel.py",
    "chars": 2190,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconel600.py",
    "chars": 5201,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconel625.py",
    "chars": 5483,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconel800.py",
    "chars": 3103,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconelPE16.py",
    "chars": 2992,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/inconelX750.py",
    "chars": 5391,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/lead.py",
    "chars": 2163,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/leadBismuth.py",
    "chars": 3183,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/lithium.py",
    "chars": 3044,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/magnesium.py",
    "chars": 1621,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/material.py",
    "chars": 34516,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/mgO.py",
    "chars": 2054,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/mixture.py",
    "chars": 1373,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/molybdenum.py",
    "chars": 1163,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/mox.py",
    "chars": 6734,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/nZ.py",
    "chars": 1172,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/potassium.py",
    "chars": 1762,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/scandiumOxide.py",
    "chars": 1808,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/siC.py",
    "chars": 3672,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/sodium.py",
    "chars": 4193,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/sodiumChloride.py",
    "chars": 1570,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/sulfur.py",
    "chars": 3120,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tZM.py",
    "chars": 3077,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tantalum.py",
    "chars": 1124,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/__init__.py",
    "chars": 579,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test__init__.py",
    "chars": 1248,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_air.py",
    "chars": 5754,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_b4c.py",
    "chars": 2118,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_be9.py",
    "chars": 1128,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_fluids.py",
    "chars": 2802,
    "preview": "# Copyright 2025 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_graphite.py",
    "chars": 1959,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_lithium.py",
    "chars": 2607,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_materials.py",
    "chars": 62748,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_sic.py",
    "chars": 1585,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_sulfur.py",
    "chars": 1831,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_thoriumOxide.py",
    "chars": 1501,
    "preview": "# Copyright 2022 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_uZr.py",
    "chars": 4079,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/tests/test_water.py",
    "chars": 7505,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/thU.py",
    "chars": 2446,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  },
  {
    "path": "armi/materials/thorium.py",
    "chars": 1736,
    "preview": "# Copyright 2019 TerraPower, LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use t"
  }
]

// ... and 503 more files (download for full content)

About this extraction

This page contains the full source code of the terrapower/armi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 703 files (6.8 MB), approximately 1.8M tokens, and a symbol index with 7732 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!