Files
GridFire/docs/index.html

431 lines
22 KiB
HTML
Raw Permalink Normal View History

2025-06-30 07:54:31 -04:00
<!DOCTYPE html>
<html lang="en" class="scroll-smooth">
2025-06-29 14:55:49 -04:00
<head>
2025-06-30 07:54:31 -04:00
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GridFire</title>
<!-- Tailwind CSS for styling -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Fonts: Inter -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* Define color variables for light and dark themes */
:root {
--bg-color: #f0f4f8;
--text-color: #1a202c;
--header-bg: transparent;
--card-bg: #ffffff;
--border-color: rgba(0, 0, 0, 0.1);
--link-color: #2b6cb0;
--link-hover-color: #2c5282;
--modal-bg: #ffffff;
--mobile-menu-bg: rgba(240, 248, 255, 0.95);
}
html.dark {
--bg-color: #0d1117;
--text-color: #e2e8f0;
--header-bg: transparent;
--card-bg: #1e293b;
--border-color: rgba(255, 255, 255, 0.1);
--link-color: #63b3ed;
--link-hover-color: #90cdf4;
--modal-bg: #1e293b;
--mobile-menu-bg: rgba(13, 17, 23, 0.95);
}
body {
background-color: var(--bg-color);
color: var(--text-color);
font-family: 'Inter', sans-serif;
transition: background-color 0.3s ease, color 0.3s ease;
}
/* Styling for header, cards, and modal to use CSS variables */
.main-header {
background-color: var(--header-bg);
transition: background-color 0.3s ease;
}
.content-card {
background-color: var(--card-bg);
border: 1px solid var(--border-color);
}
.modal-card {
background-color: var(--modal-bg);
}
.mobile-menu-overlay {
background-color: var(--mobile-menu-bg);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
</style>
2025-06-29 14:55:49 -04:00
</head>
2025-06-30 07:54:31 -04:00
<body class="min-h-screen">
<!-- Hero Section with Canvas Background -->
<div id="hero-section" class="relative h-[60vh] min-h-[400px] max-h-[600px] w-full overflow-hidden">
<!-- The canvas element for the fusion simulation background -->
<canvas id="fusionCanvas" class="absolute top-0 left-0 w-full h-full z-0"></canvas>
<!-- Header and Navigation -->
<header class="absolute top-0 left-0 right-0 z-20 main-header">
<nav class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<div class="flex items-center">
<a href="#home" class="font-bold text-xl">GridFire</a>
</div>
<div class="hidden sm:flex items-center space-x-6">
<a href="#home" class="nav-link text-sm font-medium hover:text-[var(--link-hover-color)] transition-colors">Home</a>
<a href="#intro" class="nav-link text-sm font-medium hover:text-[var(--link-hover-color)] transition-colors">About</a>
2025-06-30 07:54:31 -04:00
<a href="https://github.com/4D-STAR/GridFire" target="_blank" class="text-sm font-medium hover:text-[var(--link-hover-color)] transition-colors">GitHub</a>
<button id="funding-btn" class="text-sm font-medium hover:text-[var(--link-hover-color)] transition-colors">Funding</button>
</div>
<!-- Mobile Menu Button -->
<div class="sm:hidden">
<button id="mobile-menu-btn" class="p-2 rounded-md focus:outline-none">
<svg class="h-6 w-6" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16m-7 6h7"></path>
</svg>
</button>
</div>
</div>
</nav>
</header>
2025-06-29 14:55:49 -04:00
</div>
2025-06-30 07:54:31 -04:00
<!-- Mobile Menu, hidden by default -->
<div id="mobile-menu" class="hidden sm:hidden fixed inset-0 z-40">
<div class="mobile-menu-overlay absolute inset-0"></div>
<div class="relative flex flex-col items-center justify-center h-full space-y-8">
<button id="close-mobile-menu-btn" class="absolute top-5 right-5 p-2">
<svg class="h-8 w-8" stroke="currentColor" fill="none" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
<a href="#home" class="mobile-nav-link text-2xl font-bold">Home</a>
<a href="#intro" class="mobile-nav-link text-2xl font-bold">About</a>
2025-06-30 07:54:31 -04:00
<a href="https://github.com/4D-STAR/GridFire" target="_blank" class="mobile-nav-link text-2xl font-bold">GitHub</a>
<button id="mobile-funding-btn" class="mobile-nav-link text-2xl font-bold">Funding</button>
</div>
</div>
<!-- Main Content Area -->
<main class="container mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12 space-y-12">
<!-- Home Section -->
<section id="home" class="pt-8 -mt-8">
<div class="content-card rounded-xl p-8 max-w-3xl mx-auto shadow-lg">
<h1 class="text-3xl sm:text-4xl font-bold mb-4">GridFire</h1>
<h2 class="text-xl sm:text-lg font-bold mb-5">C++ Nuclear Network Evolution Library</h2>
<p class="mb-6 text-lg">A C++ library designed to perform general nuclear network evolution as part of the 4D-STAR collaboration. GridFire focuses on modeling the most relevant burning stages for stellar evolution with a balanced approach to physical fidelity, computational efficiency, and extensibility.</p>
2025-06-30 07:54:31 -04:00
<div class="flex space-x-4">
<a href="html/index.html" class="nav-link-btn bg-[var(--link-color)] text-white px-5 py-2 rounded-lg font-semibold hover:bg-[var(--link-hover-color)] transition-colors">Read the Docs</a>
2025-08-01 05:19:00 -04:00
<a href="workflow.html" class="nav-link-btn bg-[var(--link-color)] text-white px-5 py-2 rounded-lg font-semibold hover:bg-[var(--link-hover-color)] transition-colors">Workflow Chart</a>
<a href="https://github.com/4D-STAR/GridFire" target="_blank" class="nav-link-btn border border-[var(--link-color)] text-[var(--link-color)] px-5 py-2 rounded-lg font-semibold hover:bg-[var(--link-color)] hover:text-white transition-colors">View on GitHub</a>
2025-06-30 07:54:31 -04:00
</div>
</div>
</section>
<section id="intro" class="pt-8 -mt-8">
<div class="content-card rounded-xl p-8 max-w-4xl mx-auto shadow-lg">
<h1 class="text-3xl font-bold mb-6">About GridFire</h1>
<h2 class="text-2xl font-semibold mb-3">Design Philosophy</h2>
<p class="mb-4">GridFire is architected to balance physical fidelity, computational efficiency, and extensibility when simulating complex nuclear reaction networks. Users begin by defining a composition, which is used to construct a full GraphEngine representation of the reaction network. A GraphNetwork uses <a href="https://reaclib.jinaweb.org/index.php" class="text-[var(--link-color)] hover:text-[var(--link-hover-color)]">JINA Reaclib</a> reaction rates along with a dynamically constructed network topology.</p>
<h2 class="text-2xl font-semibold mb-3">Architecture Overview</h2>
<p class="mb-4">GridFire is organized into composable modules, each responsible for a specific aspect of nuclear reaction network modeling:</p>
<ul class="mb-6 list-disc list-inside space-y-2">
<li><b>Engine Module:</b> Core interfaces and implementations (e.g., GraphEngine) that evaluate reaction network rate equations and energy generation.</li>
<li><b>Engine Views Module:</b> Composable engine optimization and modification (e.g., MultiscalePartitioningEngineView) which can be used to make problems more tractable.</li>
<li><b>Screening Module:</b> Implements nuclear reaction screening corrections affecting reaction rates.</li>
<li><b>Reaction Module:</b> Parses and manages Reaclib reaction rate data, providing temperature- and density-dependent rate evaluations.</li>
<li><b>Partition Module:</b> Implements partition functions to weight reaction rates based on nuclear properties.</li>
<li><b>Solver Module:</b> Defines numerical integration strategies for solving stiff ODE systems arising from reaction networks.</li>
<li><b>Python Interface:</b> Exposes almost all C++ functionality to Python for ease of use.</li>
2025-06-30 07:54:31 -04:00
</ul>
<h2 class="text-2xl font-semibold mb-3">Installation</h2>
<p class="mb-4">The easiest way to install GridFire is through pip, which will install pre-compiled wheels or build locally if needed:</p>
<pre class="bg-gray-800 dark:bg-gray-900 text-white p-4 rounded-md text-sm overflow-x-auto mb-4"><code>pip install gridfire</code></pre>
<p class="mb-4">GridFire can also be built from source using the provided installation scripts or manual build instructions. The library requires a C++ compiler supporting C++23, Meson build system, and Boost libraries (≥1.83.0).</p>
<h2 class="text-2xl font-semibold mb-3">Key Features</h2>
<ul class="mb-6 list-disc list-inside space-y-2">
<li><b>Graph-based Network Construction:</b> GraphEngine recursively constructs reaction networks from seed compositions following JINA Reaclib pathways.</li>
<li><b>Layered View Strategy:</b> Partitioning algorithms isolate fast and slow processes, adaptive culling removes negligible reactions, and implicit solvers handle stiff systems.</li>
<li><b>Multiple Engine Views:</b> Including adaptive culling, multiscale partitioning, and network priming for different simulation needs.</li>
<li><b>Automatic Differentiation:</b> Uses CppAD to generate analytic Jacobian matrices efficiently for improved solver performance.</li>
<li><b>Python Extensibility:</b> Users can subclass engine views directly in Python and pass instances back to C++ solvers.</li>
</ul>
<h2 class="text-2xl font-semibold mb-3">Simple Python Example</h2>
<pre class="bg-gray-800 dark:bg-gray-900 text-white p-4 rounded-md text-sm overflow-x-auto"><code>import gridfire
from fourdst.composition import Composition
# Create initial composition
comp = Composition()
symbols = ["H-1", "He-4", "C-12"]
massFractions = [0.7, 0.29, 0.01]
comp.registerSymbols(symbols)
comp.setMassFraction(symbols, massFractions)
comp.finalize(True)
# Initialize engine and solver
baseEngine = gridfire.GraphEngine(comp, gridfire.NetworkBuildDepth.SecondOrder)
adaptiveView = gridfire.AdaptiveEngineView(baseEngine)
solver = gridfire.DirectNetworkSolver(adaptiveView)
# Set up integration parameters
netIn = gridfire.types.NetIn()
netIn.composition = comp
netIn.temperature = 1.5e7 # K
netIn.density = 1.5e2 # g/cm^3
netIn.dt0 = 1e-12 # s
netIn.tMax = 3e17 # s
# Perform integration
netOut = solver.evaluate(netIn)
print(f"Integration completed in {netOut.num_steps} steps")
2025-06-30 07:54:31 -04:00
</code></pre>
</div>
</section>
</main>
<!-- Footer -->
<footer class="border-t border-[var(--border-color)] mt-12 py-8">
<div class="container mx-auto text-center text-sm text-[var(--text-color)] opacity-70">
<p>&copy; <span id="footer-copyright-year"></span> 4D-STAR Collaboration. All Rights Reserved.</p>
</div>
</footer>
<!-- Funding Modal -->
<div id="funding-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-60 hidden">
<div class="modal-card w-full max-w-lg m-4 p-8 rounded-xl shadow-2xl relative">
<button id="close-modal-btn" class="absolute top-4 right-4 text-2xl font-bold hover:text-gray-500">&times;</button>
<h2 class="text-2xl font-bold mb-4">Funding Information</h2>
<p class="mb-6">GridFire is a part of the 4D-STAR collaboration.</p>
<p class="mb-6">4D-STAR is funded by European Research Council (ERC) under the Horizon Europe programme (Synergy Grant agreement No. 101071505: 4D-STAR). Work for this project is funded by the European Union. Views and opinions expressed are however those of the author(s) only and do not necessarily reflect those of the European Union or the European Research Council.</p>
2025-06-30 07:54:31 -04:00
<p class="mb-6">&copy; <span id="modal-copyright-year"></span> 4D-STAR Collaboration. </p>
</div>
</div>
<script>
// --- THEME SWITCHER ---
const htmlEl = document.documentElement;
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
function applyTheme(isDark) {
htmlEl.classList.toggle("dark", isDark);
}
applyTheme(prefersDarkScheme.matches);
prefersDarkScheme.addEventListener("change", (e) => applyTheme(e.matches));
// --- PAGE NAVIGATION & MODAL ---
document.addEventListener('DOMContentLoaded', () => {
const fundingBtn = document.getElementById('funding-btn');
const modal = document.getElementById('funding-modal');
const closeModalBtn = document.getElementById('close-modal-btn');
const mobileMenuBtn = document.getElementById('mobile-menu-btn');
const mobileMenu = document.getElementById('mobile-menu');
const closeMobileMenuBtn = document.getElementById('close-mobile-menu-btn');
const mobileNavLinks = document.querySelectorAll('.mobile-nav-link');
const mobileFundingBtn = document.getElementById('mobile-funding-btn');
// Dynamic Copyright Year
const currentYear = new Date().getFullYear();
document.getElementById('footer-copyright-year').textContent = currentYear;
document.getElementById('modal-copyright-year').textContent = currentYear;
function openModal() { modal.classList.remove('hidden'); }
function closeModal() { modal.classList.add('hidden'); }
function openMobileMenu() { mobileMenu.classList.remove('hidden'); }
function closeMobileMenu() { mobileMenu.classList.add('hidden'); }
// Desktop navigation
fundingBtn.addEventListener('click', openModal);
closeModalBtn.addEventListener('click', closeModal);
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
// Mobile navigation
mobileMenuBtn.addEventListener('click', openMobileMenu);
closeMobileMenuBtn.addEventListener('click', closeMobileMenu);
mobileFundingBtn.addEventListener('click', () => {
closeMobileMenu();
openModal();
});
// Smooth scrolling for all anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
if (!mobileMenu.classList.contains('hidden')) {
closeMobileMenu();
}
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
});
// --- PARTICLE SIMULATION SCRIPT ---
const canvas = document.getElementById('fusionCanvas');
const heroSection = document.getElementById('hero-section');
const ctx = canvas.getContext('2d');
const MAX_PARTICLES = 150;
const SPAWN_RATE = 2;
const PARTICLE_LIFETIME_MIN = 500;
const PARTICLE_LIFETIME_MAX = 1000;
const PARTICLE_COLORS_DARK = ['#aedff7', '#d9faff', '#ffffff', '#fff4d6', '#ffdd75', '#ffc94e'];
const PARTICLE_COLORS_LIGHT = ['#555555', '#444444', '#333333', '#222222', '#111111', '#000000'];
let particles = [];
let particleIdCounter = 0;
function resizeCanvas() {
canvas.width = heroSection.clientWidth;
canvas.height = heroSection.clientHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function random(min, max) { return Math.random() * (max - min) + min; }
function gaussianRandom(mean = 0, stdev = 1) {
let u = 1 - Math.random();
let v = Math.random();
let z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
return z * stdev + mean;
}
class Particle {
constructor() {
this.id = particleIdCounter++;
const distribution = Math.min(canvas.width, canvas.height) / 4;
this.x = gaussianRandom(0, distribution);
this.y = gaussianRandom(0, distribution / 1.5);
this.z = random(1, 6);
this.vx = random(-0.4, 0.4);
this.vy = random(-0.2, 0.2);
this.vz = random(-0.01, 0.01);
this.baseRadius = random(1.5, 3.5);
this.components = [{ id: this.id, lifetime: random(PARTICLE_LIFETIME_MIN, PARTICLE_LIFETIME_MAX) }];
}
project() {
const scale = 1 / (this.z * 0.5 + 1);
const projX = (this.x * scale) + canvas.width / 2;
const projY = (this.y * scale) + canvas.height / 2;
const radiusMultiplier = 1 + (this.components.length * 0.1);
const projRadius = this.baseRadius * scale * radiusMultiplier;
const opacity = Math.max(0, 1 - (this.z / 8));
return { projX, projY, projRadius, opacity };
}
update() {
this.components.forEach(c => c.lifetime--);
this.x += this.vx; this.y += this.vy; this.z += this.vz;
if (this.z <= 0.5 || this.z >= 7) {
this.vz *= -1;
this.z = Math.max(0.51, Math.min(6.99, this.z));
}
const pullFactor = 0.0005;
this.vx -= this.x * pullFactor;
this.vy -= this.y * pullFactor;
}
draw(ctx) {
const { projX, projY, projRadius, opacity } = this.project();
if (projRadius < 0.3 || opacity <= 0) return;
const isDark = document.documentElement.classList.contains('dark');
const colors = isDark ? PARTICLE_COLORS_DARK : PARTICLE_COLORS_LIGHT;
const colorIndex = Math.min(this.components.length - 1, colors.length - 1);
const color = colors[colorIndex];
ctx.beginPath();
ctx.arc(projX, projY, projRadius, 0, Math.PI * 2);
ctx.globalAlpha = opacity;
ctx.shadowColor = color;
ctx.shadowBlur = projRadius * 3;
ctx.fillStyle = color;
ctx.fill();
}
}
function handleSpawning() {
for (let i = 0; i < SPAWN_RATE; i++) {
if (particles.length < MAX_PARTICLES) particles.push(new Particle());
}
}
function handleCollisionsAndMerging() {
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
const p1 = particles[i]; const p2 = particles[j];
const p1Proj = p1.project(); const p2Proj = p2.project();
const dx = p1Proj.projX - p2Proj.projX; const dy = p1Proj.projY - p2Proj.projY;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < p1Proj.projRadius + p2Proj.projRadius) {
const absorber = (p1.components.length > p2.components.length || (p1.components.length === p2.components.length && p1.z < p2.z)) ? p1 : p2;
const absorbed = (absorber === p1) ? p2 : p1;
const totalMass = absorber.components.length + absorbed.components.length;
absorber.vx = (absorber.vx * absorber.components.length + absorbed.vx * absorbed.components.length) / totalMass;
absorber.vy = (absorber.vy * absorber.components.length + absorbed.vy * absorbed.components.length) / totalMass;
absorber.vz = (absorber.vz * absorber.components.length + absorbed.vz * absorbed.components.length) / totalMass;
absorber.components.push(...absorbed.components);
absorber.baseRadius += absorbed.baseRadius * 0.4;
absorbed.components.forEach(c => c.lifetime = 0);
}
}
}
}
function animate() {
requestAnimationFrame(animate);
ctx.globalAlpha = 1; ctx.shadowBlur = 0;
const bodyBgColor = getComputedStyle(document.documentElement).getPropertyValue('--bg-color').trim();
const canvasBgColor = bodyBgColor.replace('rgb', 'rgba').replace(')', ', 0.25)');
ctx.fillStyle = canvasBgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
handleSpawning();
handleCollisionsAndMerging();
const nextParticles = [];
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
p.update();
const shouldDespawn = p.components.some(c => c.lifetime <= 0);
if (!shouldDespawn) {
p.draw(ctx);
nextParticles.push(p);
}
}
particles = nextParticles;
ctx.globalAlpha = 1; ctx.shadowBlur = 0;
}
animate();
</script>
2025-06-29 14:55:49 -04:00
</body>
</html>
2025-06-30 07:54:31 -04:00