2.3. Fuel Management Input

Fuel management in ARMI is specified through custom Python scripts that often reside in the working directory of a run (but can be anywhere if you use full paths). During a normal run, ARMI checks for two fuel management settings:

shuffleLogic

The path to the Python source file that contains the user’s custom fuel management logic

fuelHandlerName

The name of a FuelHandler class that ARMI will look for in the Fuel Management Input file pointed to by the shuffleLogic path. Since it’s input, it’s the user’s responsibility to design and place that object in that file.

Note

We consider the limited syntax needed to express fuel management in Python code itself to be sufficiently expressive and simple for non-programmers to actually use. Indeed, this has been our experience.

The ARMI Operator will call its fuel handler’s outage method before each cycle (and, if requested, during branch search calculations). The outage() method will perform bookkeeping operations, and eventually call the user-defined chooseSwaps method (located in Fuel Management Input). chooseSwaps will generally contain calls to findAssembly(), swapAssemblies() , swapCascade(), and dischargeSwap(), which are the primary fuel management operations and can be found in the fuel management module.

Also found in the user-defined Fuel Management Input module is a getFactors method, which is used to control which shuffling routines get called and at which time.

Note

See the fuelHandlers module for more details.

2.3.1. Fuel Management Operations

In the ARMI, the assemblies can be moved as units around the reactor with swapAssemblies, dischargeSwap, and swapCascade of a FuelHandler interface.

2.3.1.1. swapAssemblies

swapAssemblies is the simplest fuel management operation. Given two assembly objects, this method will switch their locations.

self.swapAssemblies(a1,a2)

2.3.1.2. dischargeSwap

A discharge swap is a simple operation that puts a new assembly into the reactor while discharging an outgoing one.

self.dischargeSwap(newIncoming,oldOutgoing)

This operation keeps track of the outgoing assembly in a AssemblyList object that the Reactor object has access to so you can see how much of what you discharged.

2.3.1.3. swapCascade

SwapCascade is a more powerful swapping function that can swap a list of assemblies in a “daisy-chain” type of operation. These are useful for doing the main overtone shuffling operations such as convergent shuffling and/or convergent-divergent shuffling. If we load up the list of assemblies, the first one will be put in the last one’s position, and all others will shift accordingly.

As an example, consider assemblies 1 through 5 in core positions A through E.:

self.swapCascade([a1,a2,a3,a4,a5])

This table shows the positions of the assemblies before and after the swap cascade.

Assembly

Position Before Swap Cascade

Position After Swap Cascade

1

A

E

2

B

A

3

C

B

4

D

C

5

E

D

Arbitrarily complex cascades can thusly be assembled by choosing the order of the assemblies passed into swapCascade.

2.3.2. Choosing Assemblies to Move

The methods described in the previous section require known assemblies to shuffle. Choosing these assemblies is the essence of fuel shuffling design. The single method used for these purposes is the FuelHandler’s findAssembly method. This method is very general purpose, and ranks in the top 3 most important methods of the ARMI altogether.

To use it, just say:

a = self.findAssembly(param='maxPercentBu',compareTo=20)

This will return the assembly in the reactor that has a maximum burnup closest to 20%. Other inputs to findAssembly are summarized in the API docs of findAssembly().

2.3.3. Fuel Management Examples

2.3.3.1. Convergent-Divergent

Convergent-divergent shuffling is when fresh assemblies march in from the outside until they approach the jump ring, at which point they jump to the center and diverge until they reach the jump ring again, where they now jump to the outer periphery of the core, or become discharged.

If the jump ring is 6, the order of target rings is:

[6, 5, 4, 3, 2, 1, 6, 7, 8, 9, 10, 11, 12, 13]

In this case, assemblies converge from ring 13 to 12, to 11, to 10, …, to 6, and then jump to 1 and diverge until they get back to 6. In a discharging equilibrium case, the highest burned assembly in the jumpRing should get discharged and the lowest should jump by calling a dischargeSwap on cascade[0] and a fresh feed after this cascade is run.

The convergent rings in this case are 7 through 13 and the divergent ones are 1 through 5 are the divergent ones.

2.3.4. Fuel Management Tips

Some mistakes are common. Follow these tips.

  • Always make sure your assembly-level types in the settings file are up to date with the grids in your bluepints file. Otherwise you’ll be moving feeds when you want to move igniters, or something.

  • Use the exclusions list! If you move a cascade and then the next cascade tries to run, it will choose your newly-moved assemblies if they fit your criteria in findAssemblies. This leads to very confusing results. Therefore, once you move assemblies, you should default to adding them to the exclusions list.

  • Print cascades during debugging. After you’ve built a cascade to swap, print it out and check the locations and types of each assembly in it. Is it what you want?

  • Watch typeNum in the database. You can get good intuition about what is getting moved by viewing this parameter.