in rayon/rayon-demo/src/nbody/nbody.rs [334:474]
fn next_velocity_par(time: usize, prev: &Body, bodies: &[Body]) -> (Vector3<f64>, Vector3<f64>) {
let time = time as f64;
let center = Point3 {
x: (time / 22.0).cos() * -4200.0,
y: (time / 14.0).sin() * 9200.0,
z: (time / 27.0).sin() * 6000.0,
};
// pull to center
let max_distance = 3400.0;
let pull_strength = 0.042;
// zones
let zone = 400.0;
let repel = 100.0;
let align = 300.0;
let attract = 100.0;
let (speed_limit, attract_power);
if time < 500.0 {
speed_limit = 2000.0;
attract_power = 100.9;
} else {
speed_limit = 0.2;
attract_power = 20.9;
}
let zone_sqrd = 3.0 * (zone * zone);
let mut acc = Vector3::zero();
let mut acc2 = Vector3::zero();
let dir_to_center = center - prev.position;
let dist_to_center = dir_to_center.magnitude();
// orient to center
if dist_to_center > max_distance {
let velc = if time < 200.0 {
0.2
} else {
(dist_to_center - max_distance) * pull_strength
};
let diff = (dir_to_center / dist_to_center) * velc;
acc += diff;
}
let (diff, diff2) = bodies
.par_iter()
.fold(
|| (Vector3::zero(), Vector3::zero()),
|(mut diff, mut diff2), body| {
let r = body.position - prev.position;
// make sure we are not testing the particle against its own position
let are_same = r == Vector3::zero();
let dist_sqrd = r.magnitude2();
if dist_sqrd < zone_sqrd && !are_same {
let length = dist_sqrd.sqrt();
let percent = dist_sqrd / zone_sqrd;
if dist_sqrd < repel {
let f = (repel / percent - 1.0) * 0.025;
let normal = (r / length) * f;
diff += normal;
diff2 += normal;
} else if dist_sqrd < align {
let thresh_delta = align - repel;
let adjusted_percent = (percent - repel) / thresh_delta;
let q = (0.5 - (adjusted_percent * PI * 2.0).cos() * 0.5 + 0.5) * 100.9;
// normalize vel2 and multiply by factor
let vel2_length = body.velocity2.magnitude();
let vel2 = (body.velocity2 / vel2_length) * q;
// normalize own velocity
let vel_length = prev.velocity.magnitude();
let vel = (prev.velocity / vel_length) * q;
diff += vel2;
diff2 += vel;
}
if dist_sqrd > attract {
// attract
let thresh_delta2 = 1.0 - attract;
let adjusted_percent2 = (percent - attract) / thresh_delta2;
let c = (1.0 - ((adjusted_percent2 * PI * 2.0).cos() * 0.5 + 0.5))
* attract_power;
// normalize the distance vector
let d = (r / length) * c;
diff += d;
diff2 -= d;
}
}
(diff, diff2)
},
)
.reduce(
|| (Vector3::zero(), Vector3::zero()),
|(diffa, diff2a), (diffb, diff2b)| (diffa + diffb, diff2a + diff2b),
);
acc += diff;
acc2 += diff2;
// Speed limits
if time > 500.0 {
let acc_squared = acc.magnitude2();
if acc_squared > speed_limit {
acc *= 0.015;
}
let acc_squared2 = acc2.magnitude2();
if acc_squared2 > speed_limit {
acc2 *= 0.015;
}
}
let mut new = prev.velocity + acc;
let mut new2 = prev.velocity2 + acc2;
if time < 500.0 {
let acs = new2.magnitude2();
if acs > speed_limit {
new2 *= 0.15;
}
let acs2 = new.magnitude2();
if acs2 > speed_limit {
new *= 0.15;
}
}
(new, new2)
}