///|
pub(all) enum ElectricFieldKind {
Constant
Sinusoidal
Gaussian
Linear
Pulse
} derive(Eq, Debug, ToJson)
///|
pub(all) struct ElectricFieldModel {
kind : ElectricFieldKind
amplitude : Double
offset : Double
wave_number : Double
center : Double
width : Double
slope : Double
} derive(Debug, ToJson)
///|
pub fn constant_electric_field(value : Double) -> ElectricFieldModel {
{
kind: Constant,
amplitude: value,
offset: 0.0,
wave_number: 0.0,
center: 0.0,
width: 1.0,
slope: 0.0,
}
}
///|
pub fn sinusoidal_electric_field(
amplitude : Double,
offset : Double,
wave_number : Double,
phase : Double,
) -> ElectricFieldModel {
{
kind: Sinusoidal,
amplitude,
offset,
wave_number,
center: phase,
width: 1.0,
slope: 0.0,
}
}
///|
pub fn gaussian_electric_field(
amplitude : Double,
center : Double,
width : Double,
offset : Double,
) -> ElectricFieldModel {
{
kind: Gaussian,
amplitude,
offset,
wave_number: 0.0,
center,
width,
slope: 0.0,
}
}
///|
pub fn linear_electric_field(
offset : Double,
slope : Double,
center : Double,
) -> ElectricFieldModel {
{
kind: Linear,
amplitude: 0.0,
offset,
wave_number: 0.0,
center,
width: 1.0,
slope,
}
}
///|
pub fn pulse_electric_field(
amplitude : Double,
center : Double,
width : Double,
offset : Double,
) -> ElectricFieldModel {
{
kind: Pulse,
amplitude,
offset,
wave_number: 0.0,
center,
width,
slope: 0.0,
}
}
///|
pub fn electric_field_value(model : ElectricFieldModel, x : Double) -> Double {
match model.kind {
Constant => model.amplitude + model.offset
Sinusoidal =>
model.offset +
model.amplitude * @math.cos(model.wave_number * x + model.center)
Gaussian => {
let scale = safe_ratio(x - model.center, model.width, 0.0)
model.offset + model.amplitude * @math.exp(-0.5 * scale * scale)
}
Linear => model.offset + model.slope * (x - model.center)
Pulse =>
if (x - model.center).abs() <= model.width * 0.5 {
model.offset + model.amplitude
} else {
model.offset
}
}
}
///|
pub fn electric_field_values(
grid : Grid1D,
model : ElectricFieldModel,
) -> Array[Double] {
Array::makei(grid.cells, fn(i) {
electric_field_value(model, grid.position(i))
})
}
///|
pub fn electric_potential_value(
model : ElectricFieldModel,
x : Double,
) -> Double {
match model.kind {
Constant => -(model.amplitude + model.offset) * x
Sinusoidal =>
if model.wave_number == 0.0 {
-(model.offset + model.amplitude) * x
} else {
-model.amplitude * @math.sin(model.wave_number * x) / model.wave_number -
model.offset * x
}
Gaussian =>
model.offset * -x -
model.amplitude *
(x - model.center) *
@math.exp(
-0.5 *
safe_ratio(
(x - model.center) * (x - model.center),
model.width * model.width,
0.0,
),
)
Linear =>
-model.offset * x -
0.5 * model.slope * (x - model.center) * (x - model.center)
Pulse =>
-model.offset * x -
(if x > model.center { model.amplitude * model.width } else { 0.0 })
}
}
///|
pub fn field_model_mean(grid : Grid1D, model : ElectricFieldModel) -> Double {
mean(electric_field_values(grid, model))
}
///|
pub fn field_model_energy(grid : Grid1D, model : ElectricFieldModel) -> Double {
let values = electric_field_values(grid, model)
0.5 *
vacuum_permittivity *
grid.dx *
sum_values(values.map(fn(value) { value * value }))
}
///|
pub fn combine_electric_models(
first : ElectricFieldModel,
second : ElectricFieldModel,
) -> ElectricFieldModel {
{
kind: Linear,
amplitude: first.amplitude + second.amplitude,
offset: first.offset + second.offset,
wave_number: first.wave_number + second.wave_number,
center: first.center,
width: first.width,
slope: first.slope + second.slope,
}
}
///|
pub fn field_model_force(
model : ElectricFieldModel,
charge : Double,
x : Double,
) -> Double {
charge * electric_field_value(model, x)
}
///|
pub fn field_model_work(
model : ElectricFieldModel,
charge : Double,
start : Double,
stop : Double,
samples : Int,
) -> Double {
if samples <= 0 {
0.0
} else {
let grid = Grid1D::new(samples, (stop - start).abs())
let values = electric_field_values(grid, model)
charge * sum_values(values) * grid.dx
}
}
///|
pub fn field_model_name(model : ElectricFieldModel) -> String {
match model.kind {
Constant => "constant"
Sinusoidal => "sinusoidal"
Gaussian => "gaussian"
Linear => "linear"
Pulse => "pulse"
}
}