← Natura·Docs/Modules/Source

stellar-test.js

53 lines · in natura-src-1.0.0.zip as natura/stellar-test.js · a test

// stellar-test.js -- assertions for the Stellar system (a star's life over billions of years).
const N = require('./natura.js');
const { makeStellar, evolve } = require('./stellar.js');
const { World, UNITS } = N;
const EON = UNITS.EON;

let pass = 0, fail = 0;
const ok = (c, m) => { if (c) pass++; else { fail++; console.log('  FAIL: ' + m); } };
const L = (age, mass) => evolve(age, mass || 1, 1).L;

console.log('stellar assertions:');

// 1. MAIN-SEQUENCE BRIGHTENING: a sun-like star slowly brightens across its main-sequence life
ok(L(1) < L(8) && L(8) < 1.5, 'main sequence brightens slowly (L ' + L(1).toFixed(2) + ' at 1Gyr -> ' + L(8).toFixed(2) + ' at 8Gyr)');

// 2. RED-GIANT SPIKE: near the end the star swells and its luminosity climbs by ~1000x
{
  let maxL = 0; for (let a = 0; a < 13; a += 0.02) maxL = Math.max(maxL, L(a));
  ok(maxL > 500, 'red-giant luminosity spike (peak L ' + maxL.toFixed(0) + ' vs ~1 on the main sequence)');
  const rg = evolve(10.9, 1, 1);
  ok(rg.phase === 'red-giant' && rg.R > 50, 'the star swells into a giant near the RGB tip (R ' + rg.R.toFixed(0) + ' solar radii)');
}

// 3. WHITE-DWARF COOLING: after the giant, the ember cools for billions of years
ok(evolve(12.5, 1, 1).L < evolve(11.5, 1, 1).L && evolve(11.5, 1, 1).phase === 'white-dwarf',
  'the white dwarf cools over time (L ' + evolve(11.5, 1, 1).L.toFixed(3) + ' -> ' + evolve(12.5, 1, 1).L.toFixed(3) + ')');

// 4. HABITABLE-ZONE MARCH: a fixed planet's insolation goes frozen(early) -> temperate(now) -> scorched(giant)
{
  const early = evolve(0.5, 1, 1).insol, now = evolve(4.6, 1, 1).insol;
  let scorch = 0; for (let a = 10; a < 11; a += 0.02) scorch = Math.max(scorch, evolve(a, 1, 1).insol);
  ok(early < 0.85 && now > 0.9 && now < 1.15 && scorch > 100, 'insolation: cool birth (' + early.toFixed(2) + '), temperate now (' + now.toFixed(2) + '), scorched giant (' + scorch.toFixed(0) + ')');
}

// 5. MASS -> LIFETIME: a heavier star burns out FASTER (shorter main sequence)
ok(evolve(5, 1, 1).phase === 'main-sequence' && evolve(5, 2, 1).phase !== 'main-sequence',
  'a heavier star leaves the main sequence sooner (at 5Gyr: 1 Msun still burning, 2 Msun already dead)');

// 6. EVENTS fire over the star's life, and DETERMINISM
{
  const run = () => {
    const w = World({ seed: 1, systems: [makeStellar({ age0Gyr: 0 })] });
    const evs = [], track = [];
    for (let i = 0; i < 280; i++) { const r = w.step(0.05 * EON); for (const e of r.events) evs.push(e.kind); if (i % 40 === 0) track.push(+w.fields().stellar.luminosity.toFixed(4)); }
    return { evs, track };
  };
  const a = run(), b = run();
  ok(a.evs.includes('leaveMainSequence') && a.evs.includes('whiteDwarf'), 'the star leaves the main sequence and becomes a white dwarf (events fired)');
  ok(JSON.stringify(a.track) === JSON.stringify(b.track), 'same star -> identical life track (reproducible)');
}

console.log(`\n${pass} passed, ${fail} failed`);
process.exit(fail ? 1 : 0);