moonbit-plasma

A MoonBit plasma numerics toolkit for teaching, research prototypes, and lightweight engineering calculations.

plasma
simulation
pic
vlasov
numerics
moon add mohongquan0630/moonbit-plasma@0.1.4
Download zip
Version
0.1.4
License
Apache-2.0
Last updated
17 hours ago
Downloads
5
README

#moonbit-plasma

MoonBit 等离子体数值仿真工具箱,面向教学、科研原型和轻量工程计算。当前版本聚焦 1D 静电模型:常用等离子体尺度估算、周期网格场求解、简化 Vlasov-Poisson 推进、粒子-网格 PIC 内核、CSV 输出和可复现实验示例。

这个项目为 OSC2026 MoonBit 国产开源生态大赛准备,目标不是做一个大而空的“仿真平台”,而是沉淀一组可测试、可扩展、能继续演进为 MoonBit 科学计算生态组件的基础模块。

#Features

  • Debye 长度、电子等离子体频率、回旋频率、等离子体参数估算
  • 朗道阻尼弱扰动近似,用于教学和数量级判断
  • 周期 1D 网格、线性采样和零均值静电场重构
  • 周期 Poisson 迭代、残差检查、中心差分和积分工具
  • Cloud-in-cell 粒子沉积、显式推进和能量诊断
  • 1D Vlasov-Poisson 简化半拉格朗日平流
  • Maxwell/beam 分布采样、CFL 报告和仿真质量门禁
  • CSV 导出,便于接入 Python、R、Julia 或表格工具作图
  • species、边界条件、矩诊断和 PIC 运行轨迹输出
  • moon testmoon info --target all、GitHub Actions CI 和生成的 .mbti API 摘要

#Quick Start

moon check moon test moon run cmd/main

///|
test {
let lambda = debye_length(11604.51812, 1.0e18)
assert_true(lambda > 1.0e-7)
assert_true(lambda < 1.0e-4)

let omega = electron_plasma_frequency(1.0e18)
assert_true(omega > 1.0e10)
}

#PIC Example

///|
test {
let grid = Grid1D::new(32, 1.0)
let particles = two_stream_particles(64, 1.0, 1.0e5)
let state = PicState::new(grid, particles).run(1.0e-12, 4)
assert_eq(state.particles.length(), 64)
assert_eq(state.field.electric.length(), 32)
}

#Vlasov Example

///|
test {
let config = VlasovConfig::new(
Grid1D::new(16, 1.0),
velocity_min=-4.0,
velocity_max=4.0,
velocity_bins=8,
dt=0.002,
)
let state = make_landau_initial(config, density0=1.0e12, thermal_speed=1.0)
let next = state.step()
assert_true(next.time > state.time)
}

#Package Layout

  • constants.mbt: SI constants and thermal velocity helpers
  • formulas.mbt: plasma scales and damping estimates
  • grid.mbt: 1D periodic grid utilities
  • field.mbt: periodic electrostatic field reconstruction
  • numerics.mbt, poisson.mbt: periodic finite differences and Poisson iteration
  • pic.mbt: particle type, charge deposition and PIC stepping
  • vlasov.mbt: simplified Vlasov-Poisson state and advection
  • distribution.mbt, pusher.mbt, stability.mbt: distribution fixtures, particle updates and CFL reports
  • quality_gate.mbt, catalog.mbt: quality checks and reproducible benchmark catalog
  • csv.mbt: stable CSV serializers
  • bench.mbt: deterministic benchmark scenarios
  • species.mbt: electron/proton/ion descriptors
  • boundary.mbt: periodic, reflecting and absorbing boundary handling
  • moments.mbt: particle and Vlasov moment diagnostics
  • diagnostics.mbt: PIC energy and trajectory summaries
  • cmd/main: runnable demo that emits benchmark CSV

#Scope Notes

The numerical kernels are intentionally lightweight and deterministic. They are suitable for course demos, first-pass model checks, regression fixtures and small engineering prototypes. They are not positioned as a replacement for production plasma solvers with high-order field solvers, collision operators, MPI/GPU backends or validated device models.

Remaining extension points:

  • multi-species particle states
  • alternative boundary conditions
  • higher-order shape functions
  • richer diagnostics for phase-space snapshots
  • adapters for plotting and notebook pipelines

#Diagnostics Example

///|
test {
let grid = Grid1D::new(8, 1.0)
let state = PicState::new(grid, two_stream_particles(8, 1.0, 2.0))
let samples = trace_pic(state, 1.0e-12, 2)
assert_eq(samples.length(), 3)
}

#Development

Strict local checks:

moon fmt --check moon check --deny-warn moon test --deny-warn moon info --target all

The repository keeps generated pkg.generated.mbti files after moon info --target all so reviewers can inspect public API changes directly.

#Source And License

The implementation is original MoonBit code written for this repository. Physical formulas are standard textbook relations expressed in SI units. No third-party source code was copied into the project.

Licensed under Apache-2.0.

#
BenchmarkSample

pub(all) struct BenchmarkSample {
name : String
cells : Int
particles : Int
steps : Int
energy : Double
} derive(ToJson,
Debug
)

#
Boundary1D

pub(all) enum Boundary1D {
Periodic
Reflecting
Absorbing
} derive(Eq, ToJson,
Debug
)

#
BoundaryResult

pub(all) struct BoundaryResult {
x : Double
v : Double
alive : Bool
} derive(ToJson,
Debug
)

#
CflReport

pub(all) struct CflReport {
recommended_dt : Double
max_displacement : Double
stable : Bool
} derive(ToJson,
Debug
)

#
Field1D

pub(all) struct Field1D {
grid : Grid1D
charge_density : Array[Double]
electric : Array[Double]
potential : Array[Double]
} derive(ToJson,
Debug
)

#
Field1D::charge_neutrality_error

fn Field1D::charge_neutrality_error(field : Field1D) -> Double

#
Field1D::electric_energy

fn Field1D::electric_energy(field : Field1D) -> Double

#
Field1D::electric_range

fn Field1D::electric_range(field : Field1D) -> (Double, Double)

#
Field1D::new

fn Field1D::new(grid : Grid1D) -> Field1D

#
Field1D::potential_range

fn Field1D::potential_range(field : Field1D) -> (Double, Double)

#
Grid1D

pub(all) struct Grid1D {
cells : Int
length : Double
dx : Double
} derive(ToJson,
Debug
)

#
Grid1D::cell_index

fn Grid1D::cell_index(grid : Grid1D, x : Double) -> Int

#
Grid1D::cell_width

fn Grid1D::cell_width(grid : Grid1D) -> Double

#
Grid1D::cells_count

fn Grid1D::cells_count(grid : Grid1D) -> Int

#
Grid1D::domain_length

fn Grid1D::domain_length(grid : Grid1D) -> Double

#
Grid1D::is_valid

fn Grid1D::is_valid(grid : Grid1D) -> Bool

#
Grid1D::new

fn Grid1D::new(cells : Int, length : Double) -> Grid1D

#
Grid1D::position

fn Grid1D::position(grid : Grid1D, index : Int) -> Double

#
Grid1D::wrap

fn Grid1D::wrap(grid : Grid1D, x : Double) -> Double

#
Moments1D

pub(all) struct Moments1D {
density : Array[Double]
momentum : Array[Double]
temperature_like : Array[Double]
} derive(ToJson,
Debug
)

#
Particle

pub(all) struct Particle {
x : Double
v : Double
weight : Double
charge : Double
mass : Double
} derive(ToJson,
Debug
)

#
Particle::new

fn Particle::new(x~ : Double, v~ : Double, weight? : Double, charge? : Double, mass? : Double) -> Particle

#
PicDiagnostics

pub(all) struct PicDiagnostics {
time : Double
particles : Int
total_charge : Double
kinetic_energy : Double
field_energy : Double
center_of_mass : Double
mean_velocity : Double
velocity_variance : Double
} derive(ToJson,
Debug
)

#
PicDiagnostics::from_state

fn PicDiagnostics::from_state(state : PicState) -> PicDiagnostics

#
PicDiagnostics::total_energy

fn PicDiagnostics::total_energy(d : PicDiagnostics) -> Double

#
PicQuality

pub(all) struct PicQuality {
finite : Bool
nonnegative_density : Bool
energy_drift : Double
charge_error : Double
} derive(ToJson,
Debug
)

#
PicState

pub(all) struct PicState {
grid : Grid1D
particles : Array[Particle]
field : Field1D
time : Double
} derive(ToJson,
Debug
)

#
PicState::new

fn PicState::new(grid : Grid1D, particles : Array[Particle]) -> PicState

#
PicState::run

fn PicState::run(state : PicState, dt : Double, steps : Int) -> PicState

#
PicState::step

fn PicState::step(state : PicState, dt : Double) -> PicState

#
PlasmaBenchmarkCase

pub(all) struct PlasmaBenchmarkCase {
name : String
cells : Int
particles : Int
steps : Int
initial_energy : Double
final_energy : Double
charge_error : Double
} derive(ToJson,
Debug
)

#
PlasmaBenchmarkReport

pub(all) struct PlasmaBenchmarkReport {
cases : Array[PlasmaBenchmarkCase]
total_steps : Int
} derive(ToJson,
Debug
)

#
PoissonResult

pub(all) struct PoissonResult {
potential : Array[Double]
residual : Double
iterations : Int
} derive(ToJson,
Debug
)

#
Species

pub(all) struct Species {
name : String
charge : Double
mass : Double
} derive(ToJson,
Debug
)

#
Species::electron

fn Species::electron() -> Species

#
Species::gyro_frequency

fn Species::gyro_frequency(species : Species, magnetic_field_t : Double) -> Double

#
Species::ion

fn Species::ion(name : String, charge_state : Int, mass_kg : Double) -> Species

#
Species::plasma_frequency

fn Species::plasma_frequency(species : Species, density_m3 : Double) -> Double

#
Species::proton

fn Species::proton() -> Species

#
Species::thermal_velocity

fn Species::thermal_velocity(species : Species, temperature_k : Double) -> Double

#
VlasovConfig

pub(all) struct VlasovConfig {
grid : Grid1D
velocity_min : Double
velocity_max : Double
velocity_bins : Int
dt : Double
} derive(ToJson,
Debug
)

#
VlasovConfig::dv

fn VlasovConfig::dv(config : VlasovConfig) -> Double

#
VlasovConfig::new

fn VlasovConfig::new(grid : Grid1D, velocity_min~ : Double, velocity_max~ : Double, velocity_bins~ : Int, dt~ : Double) -> VlasovConfig

#
VlasovConfig::velocity

fn VlasovConfig::velocity(config : VlasovConfig, bin : Int) -> Double

#
VlasovState

pub(all) struct VlasovState {
config : VlasovConfig
distribution : Array[Double]
charge_density : Array[Double]
time : Double
} derive(ToJson,
Debug
)

#
VlasovState::step

fn VlasovState::step(state : VlasovState) -> VlasovState

#
advance_particles

fn advance_particles(grid : Grid1D, particles : ArrayView[Particle], electric : ArrayView[Double], dt : Double) -> Array[Particle]

#
apply_boundary

fn apply_boundary(grid : Grid1D, boundary : Boundary1D, x : Double, v : Double) -> BoundaryResult

#
apply_boundary_to_particle

fn apply_boundary_to_particle(grid : Grid1D, boundary : Boundary1D, particle : Particle) -> Particle?

#
assess_pic_cfl

fn assess_pic_cfl(grid : Grid1D, maximum_speed~ : Double, dt~ : Double, safety_factor~ : Double) -> CflReport

#
assess_pic_quality

fn assess_pic_quality(state : PicState) -> PicQuality

#
assess_vlasov_cfl

fn assess_vlasov_cfl(config : VlasovConfig) -> CflReport

#
benchmark_report_csv

fn benchmark_report_csv(report : PlasmaBenchmarkReport) -> String

#
benchmark_to_csv

fn benchmark_to_csv(sample : BenchmarkSample) -> String

#
boltzmann_constant

let boltzmann_constant : Double

#
center_of_mass

fn center_of_mass(grid : Grid1D, particles : ArrayView[Particle]) -> Double

#
cfl_ratio

fn cfl_ratio(report : CflReport) -> Double

#
clamp_index

fn clamp_index(index : Int, length : Int) -> Int

#
csv_header

fn csv_header(columns : ArrayView[String]) -> String

#
csv_row

fn csv_row(values : ArrayView[Double]) -> String

#
debye_length

fn debye_length(electron_temperature_k : Double, electron_density_m3 : Double) -> Double

#
deposit_charge

fn deposit_charge(grid : Grid1D, particles : ArrayView[Particle]) -> Array[Double]

#
diagnostics_to_csv

fn diagnostics_to_csv(samples : ArrayView[PicDiagnostics]) -> String

#
distribution_is_nonnegative

fn distribution_is_nonnegative(distribution : ArrayView[Double]) -> Bool

#
distribution_mass_error

fn distribution_mass_error(config : VlasovConfig, left : ArrayView[Double], right : ArrayView[Double]) -> Double

#
distribution_mean_velocity

fn distribution_mean_velocity(config : VlasovConfig, distribution : ArrayView[Double]) -> Double

#
distribution_sum

fn distribution_sum(config : VlasovConfig, distribution : ArrayView[Double]) -> Double

#
distribution_temperature_like

fn distribution_temperature_like(config : VlasovConfig, distribution : ArrayView[Double]) -> Double

#
electron_mass

let electron_mass : Double

#
electron_plasma_frequency

fn electron_plasma_frequency(electron_density_m3 : Double) -> Double

#
electron_thermal_velocity

fn electron_thermal_velocity(temperature_k : Double) -> Double

#
elementary_charge

let elementary_charge : Double

#
field_energy

fn field_energy(field : Field1D) -> Double

#
field_to_csv

fn field_to_csv(field : Field1D) -> String

#
gyro_frequency

fn gyro_frequency(charge_c : Double, magnetic_field_t : Double, mass_kg : Double) -> Double

#
interpolate_periodic

fn interpolate_periodic(grid : Grid1D, values : ArrayView[Double], x : Double) -> Double

#
kinetic_energy

fn kinetic_energy(particles : ArrayView[Particle]) -> Double

#
kinetic_temperature

fn kinetic_temperature(particles : ArrayView[Particle]) -> Double

#
l2_distance

fn l2_distance(left : ArrayView[Double], right : ArrayView[Double]) -> Double

#
l2_norm

fn l2_norm(values : ArrayView[Double]) -> Double

#
landau_damping_rate

fn landau_damping_rate(wave_number_m : Double, electron_temperature_k : Double, electron_density_m3 : Double) -> Double

#
linspace

fn linspace(start : Double, stop : Double, count : Int) -> Array[Double]

#
make_landau_initial

fn make_landau_initial(config : VlasovConfig, density0~ : Double, thermal_speed~ : Double, perturbation? : Double, mode? : Int) -> VlasovState

#
max_value

fn max_value(values : ArrayView[Double]) -> Double

#
maxwellian

fn maxwellian(v : Double, thermal_speed : Double) -> Double

#
mean

fn mean(values : ArrayView[Double]) -> Double

#
min_value

fn min_value(values : ArrayView[Double]) -> Double

#
normalize_sum

fn normalize_sum(values : ArrayView[Double]) -> Array[Double]

#
particle_current_density

fn particle_current_density(grid : Grid1D, particles : ArrayView[Particle]) -> Array[Double]

#
particle_for_species

fn particle_for_species(species : Species, x~ : Double, v~ : Double, weight? : Double) -> Particle

#
particle_number_density

fn particle_number_density(grid : Grid1D, particles : ArrayView[Particle]) -> Array[Double]

#
particle_speed_range

fn particle_speed_range(particles : ArrayView[Particle]) -> (Double, Double)

#
particles_to_csv

fn particles_to_csv(particles : ArrayView[Particle]) -> String

#
periodic_gradient

fn periodic_gradient(grid : Grid1D, values : ArrayView[Double]) -> Array[Double]

#
periodic_index

fn periodic_index(index : Int, length : Int) -> Int

#
periodic_laplacian

fn periodic_laplacian(grid : Grid1D, values : ArrayView[Double]) -> Array[Double]

let pi : Double

#
plasma_frequency

fn plasma_frequency(density_m3 : Double, charge_c? : Double, mass_kg? : Double) -> Double

#
plasma_parameter

fn plasma_parameter(electron_density_m3 : Double, debye_length_m : Double) -> Double

#
poisson_residual

fn poisson_residual(grid : Grid1D, potential : ArrayView[Double], source : ArrayView[Double]) -> Double

#
proton_mass

let proton_mass : Double

#
push_particle

fn push_particle(grid : Grid1D, particle : Particle, electric~ : Double, dt~ : Double) -> Particle

#
relative_energy_drift

fn relative_energy_drift(initial : Double, ending : Double) -> Double

#
relative_l2_error

fn relative_l2_error(reference : ArrayView[Double], actual : ArrayView[Double]) -> Double

#
rms

fn rms(values : ArrayView[Double]) -> Double

#
run_pic_benchmark

fn run_pic_benchmark(cells? : Int, particles? : Int, steps? : Int) -> BenchmarkSample

#
run_plasma_benchmark_catalog

fn run_plasma_benchmark_catalog() -> PlasmaBenchmarkReport

#
safe_grid

fn safe_grid(cells : Int, length : Double) -> Grid1D?

#
sample_linear

fn sample_linear(grid : Grid1D, values : ArrayView[Double], x : Double) -> Double

#
sampled_beam

fn sampled_beam(config : VlasovConfig, density~ : Double, center_velocity~ : Double, thermal_speed~ : Double) -> Array[Double]

#
sampled_maxwellian

fn sampled_maxwellian(config : VlasovConfig, density~ : Double, thermal_speed~ : Double) -> Array[Double]

#
solve_periodic_field

fn solve_periodic_field(grid : Grid1D, charge_density : ArrayView[Double]) -> Field1D

#
solve_periodic_poisson

fn solve_periodic_poisson(grid : Grid1D, source : ArrayView[Double], max_iterations? : Int, tolerance? : Double) -> PoissonResult

#
solve_periodic_potential_field

fn solve_periodic_potential_field(grid : Grid1D, source : ArrayView[Double], max_iterations? : Int, tolerance? : Double) -> Field1D

#
stable_pic_dt

fn stable_pic_dt(grid : Grid1D, maximum_speed : Double, safety_factor : Double) -> Double

#
thermal_velocity

fn thermal_velocity(temperature_k : Double, mass_kg~ : Double) -> Double

#
total_charge

fn total_charge(grid : Grid1D, charge_density : ArrayView[Double]) -> Double

#
total_particle_charge

fn total_particle_charge(particles : ArrayView[Particle]) -> Double

#
trace_pic

fn trace_pic(state : PicState, dt : Double, steps : Int, every? : Int) -> Array[PicDiagnostics]

#
trapezoid_integral

fn trapezoid_integral(grid : Grid1D, values : ArrayView[Double]) -> Double

#
two_stream_particles

fn two_stream_particles(count : Int, length : Double, speed : Double) -> Array[Particle]

#
vacuum_permittivity

let vacuum_permittivity : Double

#
velocity_mean

fn velocity_mean(particles : ArrayView[Particle]) -> Double

#
velocity_variance

fn velocity_variance(particles : ArrayView[Particle]) -> Double

#
vlasov_density

fn vlasov_density(config : VlasovConfig, distribution : ArrayView[Double]) -> Array[Double]

#
vlasov_moments

fn vlasov_moments(state : VlasovState) -> Moments1D

#
weighted_mean

fn weighted_mean(values : ArrayView[Double], weights : ArrayView[Double]) -> Double

#
zeros

fn zeros(n : Int) -> Array[Double]