This guide explains how to migrate from global variables to the new Config, SimulationContext, and RandomContext classes.
Holds all configuration parameters that are set at the start of a simulation and don't change during execution:
- Star properties (mass, luminosity, temperature, spectral type)
- Companion star properties (for binary systems)
- Simulation options (do_gases, do_moons, do_migration)
- Filtering options (filter_earthlike, filter_habitable)
- Output configuration (format, paths, filenames)
- Random seed and system count
- Accretion parameters
Holds all runtime state that changes during simulation execution:
- Current sun being simulated
- Statistics counters (total_earthlike, total_habitable, etc.)
- Min/max statistics for breathable planets
- Min/max statistics for potentially habitable planets
Holds random number generator state:
- seed, jseed, ifrst, nextn
- Each instance provides an independent RNG stream
- New classes exist alongside old globals
- Old code continues to work unchanged
- New code can optionally use the classes
Migrate functions one subsystem at a time:
- Pick a subsystem (e.g.,
enviro.cpp) - Update function signatures to accept Config/Context parameters
- Update function bodies to use the class members instead of globals
- Update callers to pass the Config/Context objects
Once all code uses the classes:
- Remove global variable declarations from
stargen.h - Remove global variable definitions from implementation files
- Verify compilation succeeds
// stargen.h
extern int flag_verbose;
extern long double max_age;
// somefile.cpp
void some_function() {
if (flag_verbose & 0x0001) {
std::cout << "Max age: " << max_age << std::endl;
}
}// somefile.cpp
void some_function(const Config& config) {
if (config.isVerbose(0x0001)) {
std::cout << "Max age: " << config.max_age << std::endl;
}
}Each thread can have its own Config/Context/RandomContext:
// Thread-safe parallel generation
void generate_system_thread(int thread_id, Config config, RandomContext rng) {
rng.setSeed(config.random_seed + thread_id);
SimulationContext context;
// Generate system using thread-local objects
}Easy to create test configurations:
void test_earthlike_detection() {
Config config;
config.filter_earthlike = true;
config.stellar_mass = 1.0;
SimulationContext context;
// Run test with known configuration
}Run multiple simulations simultaneously:
Config config1, config2;
config1.stellar_mass = 0.5; // Red dwarf
config2.stellar_mass = 2.0; // Blue giant
SimulationContext ctx1, ctx2;
// Generate both systems without interferenceFunction signatures document what they need:
// Old way - hidden dependencies on globals
void calculate_orbit(planet* p);
// New way - explicit dependencies
void calculate_orbit(planet* p, const Config& config, SimulationContext& ctx);Functions that are called frequently and modify state:
generate_planet()- should accept Config and SimulationContextcalculate_gases()- should accept Configcheck_planet()- should accept Config and SimulationContext
Subsystem entry points:
accrete::dist_planetary_masses()- should accept Configgenerate_stellar_system()- should accept Config and SimulationContext- Display functions - should accept Config for formatting options
Simple utility functions with few dependencies:
- Math utilities in
enviro.cpp - Radius calculation functions
- Type checking predicates
// Before
auto calculate_value() -> long double;
// After
auto calculate_value(const Config& config) -> long double;// Before
void record_planet(planet* p);
// After
void record_planet(planet* p, const Config& config, SimulationContext& ctx);// Before
auto generate_random() -> long double;
// After
auto generate_random(RandomContext& rng) -> long double;// Before
void generate_system();
// After
void generate_system(const Config& config, SimulationContext& ctx, RandomContext& rng);To maintain compilation during migration, we can use global instances:
// Temporary global instances (to be removed later)
Config g_config;
SimulationContext g_context;
RandomContext g_rng;
// Old function (unchanged)
void old_function() {
if (flag_verbose) { // Still uses old global
// ...
}
}
// Migrated function (uses classes)
void new_function(const Config& config) {
if (config.isVerbose()) { // Uses new class
// ...
}
}
// Wrapper for gradual migration
void old_caller() {
new_function(g_config); // Pass global instance
}TEST(ConfigTest, DefaultValues) {
Config config;
EXPECT_EQ(config.stellar_mass, 0.0);
EXPECT_FALSE(config.do_moons);
}
TEST(SimulationContextTest, Statistics) {
SimulationContext ctx;
ctx.recordEarthlike();
EXPECT_EQ(ctx.total_earthlike, 1);
}TEST(SystemGenerationTest, WithConfig) {
Config config;
config.stellar_mass = 1.0;
config.do_gases = true;
SimulationContext ctx;
RandomContext rng(12345);
auto planets = generate_system(config, ctx, rng);
EXPECT_GT(planets.size(), 0);
}- Create global instances (g_config, g_context, g_rng) in stargen.cpp
- Migrate main.cpp to populate Config from command-line arguments
- Migrate one subsystem (suggest: enviro.cpp) as proof-of-concept
- Update callers to pass Config/Context objects
- Repeat for other subsystems
- Remove globals once all code migrated
See also:
ARCHITECTURAL_ANALYSIS.md- Overall architecture recommendationsConfig.h,SimulationContext.h,RandomContext.h- Class definitionsstargen.h- Current global variables (to be removed)