A modular 2D reactor core simulator and optimizer designed to evolve fuel assembly layouts over time. It supports configurable rules, logging, and future integration with optimization algorithms (e.g., PSO, GA).
-
Grid-based simulator
- 15Γ15 grid of assemblies, categorized into
Fuel,ControlRod,Moderator, andBlank - Only
Fuelassemblies are movable/optimizable
- 15Γ15 grid of assemblies, categorized into
-
Time evolution engine
- Deterministic timestep loop (up to configurable
TIMESTEPS) - Each assembly updates attributes like
temperature,energy_output,life
- Deterministic timestep loop (up to configurable
-
Flexible initialization
- Load predefined layouts via JSON
- Generate random or uniform configurations with seeded RNG
-
Modular physics & penalty system
- Swappable models (neighbor influence rules, fitness scoring)
- Stubbed fitness/penalty functions for plugin integration
-
Extensible architecture
- Organized into core modules (
core_sim/,optimizer/,utils/,visualisation/) - Clean separation between simulation, logging, and optimization
- Organized into core modules (
-
Data logging & export
- Built-in recorder/logger outputs:
- Per-timestep grid states
- Total energy & fitness
- Penalty tracking
- Built-in recorder/logger outputs:
-
Branch-based development
- The
almost-therebranch holds the latest working version - Stable branching strategy for collaboration & integration
- The
-
Clone the repo
git clone https://github.com/ThomasKarpinski/reactor-fuel-optimizer.git cd reactor-fuel-optimizer git checkout almost-there -
Install dependencies
pip install -r requirements.txt
-
Run a quick simulation
python main.py
Use the visual layout editor (layout_editor.py) to design your own reactor core layouts. You can place any combination of:
- F β Fuel
- C β Control Rod
- M β Moderator
- B β Blank
Export your layout to a JSON file and run it in the simulator.
Demo:
The project now includes a powerful Genetic Algorithm (GA) module that automatically optimizes fuel placement in the reactor core. The GA evolves populations of reactor configurations to maximize energy output while maintaining safe operating temperatures.
python scripts/create_base_layout.pypython main_ga.pypython visualisation/visualize_simulation.py output/ga_optimized_[timestamp].jsonThe GA progressively improves reactor configurations over generations:
Example evolution showing fitness improvement over 100 generations. The blue line shows the best fitness in each generation, while the red dashed line shows the population average.
Each reactor configuration is encoded as a binary string:
1= Fuel assembly present0= Empty position (Blank)
Only positions marked as Fuel or Blank in the base layout are optimized. Fixed elements (ControlRod, Moderator) remain unchanged.
The fitness function evaluates each configuration based on:
fitness = total_energy - temperature_penalties - fuel_ratio_penalties + safety_bonuses
Components:
- β Total energy production over the simulation period
- β Temperature penalties:
- Quadratic penalty for exceeding optimal temperature (800Β°C)
- Disqualification for critical temperature (1000Β°C)
- β Fuel ratio penalties:
- Too much fuel (>80%): overheating risk
- Too little fuel (<40%): insufficient energy
- β
Safety bonuses:
- Maintaining temperature below 90% of limit
- Optimal fuel ratio (60-70%)
Selects parents by running small tournaments between random individuals.
Parent1: [1,1,0,0,1,1,0,0]
Parent2: [0,0,1,1,0,0,1,1]
----^^^^----
Child1: [1,1,1,1,1,1,0,0]
Child2: [0,0,0,0,0,0,1,1]
- Standard: bit flip (0β1 or 1β0)
- Smart mutation adjusts based on fuel ratio:
- Too much fuel (>75%): bias towards removal
- Too little fuel (<50%): bias towards addition
The best 5 individuals are preserved unchanged in the next generation.
Standard mode (balanced optimization):
python main_ga.pyQuick mode (for testing):
python main_ga.py --quickSafe mode (conservative temperature limits):
python main_ga.py --safeNo simulation (GA only):
python main_ga.py --no-sim| Parameter | Standard | Quick | Safe | Description |
|---|---|---|---|---|
population_size |
50 | 20 | 40 | Number of individuals |
generations |
100 | 30 | 80 | Number of evolution cycles |
mutation_rate |
0.02 | 0.02 | 0.025 | Mutation probability per gene |
crossover_rate |
0.85 | 0.85 | 0.80 | Crossover probability |
temp_limit |
800Β°C | 800Β°C | 700Β°C | Optimal temperature limit |
critical_temp |
1000Β°C | 1000Β°C | 900Β°C | Critical temperature |
After optimization completes, you'll find:
layouts/ga_optimized/run_[timestamp]/
βββ best_layout.json # Optimized reactor configuration
βββ evolution_plot.png # Fitness evolution graph
βββ optimization_report.json # Detailed statistics
output/
βββ ga_optimized_[timestamp].json # Full simulation results
Every 10 generations, a checkpoint is saved:
layouts/ga_optimized/checkpoints/checkpoint_gen10.json
layouts/ga_optimized/checkpoints/checkpoint_gen20.json
...
A successful optimization typically shows:
Generation 1/100
Best fitness: 125,432.50
Fuel ratio: 85/120 (70.8%)
Max temperature: 856Β°C
Generation 50/100
π― NEW RECORD! Fitness: 458,721.33
Fuel ratio: 78/120 (65.0%)
Max temperature: 792Β°C
Generation 100/100
Best fitness: 512,847.22
Fuel ratio: 76/120 (63.3%)
Max temperature: 745Β°C
β
Safe and efficient configuration found!
Create your own base layout for optimization:
python layout_editor.py
# Save as: layouts/ga_base_layouts/custom_base.json
python main_ga.py --layout layouts/ga_base_layouts/custom_base.jsonRun multiple optimizations with different parameters:
# batch_optimize.py
configs = [
{'population_size': 30, 'mutation_rate': 0.01},
{'population_size': 50, 'mutation_rate': 0.02},
{'population_size': 100, 'mutation_rate': 0.03},
]
for i, config in enumerate(configs):
print(f"Running optimization {i+1}/{len(configs)}")
run_optimization(config=config)To run a longer simulation on an optimized layout:
python scripts/run_best_layout_simulation.py layouts/ga_optimized/run_[timestamp]/best_layout.json 2000Reduce population size or simulation timesteps:
config = {
'population_size': 20,
'timesteps': 50
}- Increase population size
- Adjust mutation rate (try 0.01-0.05)
- Check if base layout has enough optimizable positions
- Use
--safemode - Reduce
optimal_fuel_ratio - Lower
temp_limitin configuration
- Cache Efficiency: The GA caches fitness evaluations. Expect faster later generations.
- Parallel Evaluation: Future versions will support parallel fitness evaluation.
- Early Stopping: Monitor evolution plot - if fitness plateaus, you can stop early.
optimization_ga/
βββ ga_optimizer.py # Main GA orchestrator
βββ chromosome.py # Chromosome representation
βββ fitness_evaluator.py # Fitness calculation with simulation
βββ genetic_operators.py # Selection, crossover, mutation
βββ run_ga.py # High-level runner with plotting
The GA integrates with the existing simulator through:
CoreGrid.initialize_from_layout()- loads configurationsSimulator.step()- runs physics simulationSimulator.meta_history- extracts energy and temperature data
Edit simulation parameters in utils/config.py (e.g., TIMESTEPS).
Implement your logic inside core_sim/core_grid.py (for neighbor interactions).
Modify optimization_ga/fitness_evaluator.py to change optimization objectives.
Contributors: Bartosz Janikula and Tomasz KarpiΕski
License: MIT


