///| Derivatives of intensity w.r.t. one site's fractional coordinates, occupancy,
///|
/// constant weight and B_iso. This is local sensitivity, NOT structure refinement.
pub struct Sensitivity {
dx : Double
dy : Double
dz : Double
occupancy : Double
weight : Double
b_iso : Double
} derive(Debug)
///|
pub fn Metric::sensitivity(
self : Metric,
index : Hkl,
sites : Array[Site],
selected : Int,
) -> Result[Sensitivity, Problem] {
if selected < 0 || selected >= sites.length() {
return Err(Invalid("selected site out of range"))
}
let a = match self.amplitude(index, sites) {
Ok(x) => x
Err(e) => return Err(e)
}
let s = sites[selected]
let q2 = self.q2(index)
let phase = 2.0 *
@math.PI *
wrap(
index.h.to_double() * s.x +
index.k.to_double() * s.y +
index.l.to_double() * s.z,
)
let atten = @math.exp(-s.b_iso * q2 / 4.0)
let co = @math.cos(phase)
let si = @math.sin(phase)
let projection = 2.0 * atten * (a.real * co + a.imag * si)
let rotation = 4.0 *
@math.PI *
atten *
s.weight *
s.occupancy *
(-a.real * si + a.imag * co)
Ok({
dx: rotation * index.h.to_double(),
dy: rotation * index.k.to_double(),
dz: rotation * index.l.to_double(),
occupancy: projection * s.weight,
weight: projection * s.occupancy,
b_iso: -projection * s.weight * s.occupancy * q2 / 4.0,
})
}