///|
/// Fractional point scatterer. Weight is user-supplied constant, not an element table.
pub struct Site {
x : Double
y : Double
z : Double
weight : Double
occupancy : Double
b_iso : Double
} derive(Debug)
///|
fn wrap(x : Double) -> Double {
x - @math.floor(x)
}
///|
pub fn site(
x : Double,
y : Double,
z : Double,
weight : Double,
occupancy? : Double = 1.0,
b_iso? : Double = 0.0,
) -> Result[Site, Problem] {
for v in [x, y, z] {
if !finite(v) || v.abs() > 1.0e6 {
return Err(Invalid("fractional coordinate outside +/-1e6"))
}
}
if !finite(weight) || weight.abs() > 1.0e6 {
return Err(Invalid("constant weight outside +/-1e6"))
}
if !finite(occupancy) || occupancy < 0.0 || occupancy > 1.0 {
return Err(Invalid("occupancy outside [0,1]"))
}
if !finite(b_iso) || b_iso < 0.0 || b_iso > 1.0e6 {
return Err(Invalid("B_iso outside [0,1e6] square angstrom"))
}
Ok({ x: wrap(x), y: wrap(y), z: wrap(z), weight, occupancy, b_iso, })
}
///|
/// A global fractional translation preserves intensities, not complex phase.
pub fn Site::translated(
self : Site,
dx : Double,
dy : Double,
dz : Double,
) -> Result[Site, Problem] {
site(
self.x + dx,
self.y + dy,
self.z + dz,
self.weight,
occupancy=self.occupancy,
b_iso=self.b_iso,
)
}