1use crate::restraint::AtomRestraint;
8use molrs::types::F;
9
10#[derive(Debug, Clone, Copy)]
12pub struct InsideCubeRestraint {
13 pub origin: [F; 3],
14 pub side: F,
15}
16
17impl InsideCubeRestraint {
18 pub fn new(origin: [F; 3], side: F) -> Self {
19 Self { origin, side }
20 }
21}
22
23impl AtomRestraint for InsideCubeRestraint {
24 fn f(&self, pos: &[F; 3], scale: F, _scale2: F) -> F {
25 let (x, y, z) = (pos[0], pos[1], pos[2]);
26 let (xmin, ymin, zmin) = (self.origin[0], self.origin[1], self.origin[2]);
27 let (xmax, ymax, zmax) = (xmin + self.side, ymin + self.side, zmin + self.side);
28 let a1 = (x - xmin).min(0.0);
29 let a2 = (y - ymin).min(0.0);
30 let a3 = (z - zmin).min(0.0);
31 let mut f = scale * (a1 * a1 + a2 * a2 + a3 * a3);
32 let a1 = (x - xmax).max(0.0);
33 let a2 = (y - ymax).max(0.0);
34 let a3 = (z - zmax).max(0.0);
35 f += scale * (a1 * a1 + a2 * a2 + a3 * a3);
36 f
37 }
38
39 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
40 let (x, y, z) = (pos[0], pos[1], pos[2]);
41 let (xmin, ymin, zmin) = (self.origin[0], self.origin[1], self.origin[2]);
42 let (xmax, ymax, zmax) = (xmin + self.side, ymin + self.side, zmin + self.side);
43 let a1 = x - xmin;
44 let a2 = y - ymin;
45 let a3 = z - zmin;
46 if a1 < 0.0 {
47 g[0] += scale * 2.0 * a1;
48 }
49 if a2 < 0.0 {
50 g[1] += scale * 2.0 * a2;
51 }
52 if a3 < 0.0 {
53 g[2] += scale * 2.0 * a3;
54 }
55 let a1 = x - xmax;
56 let a2 = y - ymax;
57 let a3 = z - zmax;
58 if a1 > 0.0 {
59 g[0] += scale * 2.0 * a1;
60 }
61 if a2 > 0.0 {
62 g[1] += scale * 2.0 * a2;
63 }
64 if a3 > 0.0 {
65 g[2] += scale * 2.0 * a3;
66 }
67 self.f(pos, scale, scale2)
68 }
69}
70
71#[derive(Debug, Clone, Copy)]
80pub struct InsideBoxRestraint {
81 pub min: [F; 3],
82 pub max: [F; 3],
83 pub periodic: [bool; 3],
84}
85
86impl InsideBoxRestraint {
87 pub fn new(min: [F; 3], max: [F; 3], periodic: [bool; 3]) -> Self {
92 Self { min, max, periodic }
93 }
94
95 pub fn cube_from_origin(origin: [F; 3], side: F, periodic: [bool; 3]) -> Self {
98 Self {
99 min: origin,
100 max: [origin[0] + side, origin[1] + side, origin[2] + side],
101 periodic,
102 }
103 }
104
105 pub fn from_simbox(simbox: &molrs::spatial::region::SimBox, periodic: [bool; 3]) -> Self {
113 let origin = simbox.origin_view();
114 let lengths = simbox.lengths();
115 let o = [origin[0], origin[1], origin[2]];
116 Self {
117 min: o,
118 max: [o[0] + lengths[0], o[1] + lengths[1], o[2] + lengths[2]],
119 periodic,
120 }
121 }
122}
123
124impl AtomRestraint for InsideBoxRestraint {
125 fn f(&self, pos: &[F; 3], scale: F, _scale2: F) -> F {
126 let (x, y, z) = (pos[0], pos[1], pos[2]);
127 let a1 = (x - self.min[0]).min(0.0);
128 let a2 = (y - self.min[1]).min(0.0);
129 let a3 = (z - self.min[2]).min(0.0);
130 let mut f = scale * (a1 * a1 + a2 * a2 + a3 * a3);
131 let a1 = (x - self.max[0]).max(0.0);
132 let a2 = (y - self.max[1]).max(0.0);
133 let a3 = (z - self.max[2]).max(0.0);
134 f += scale * (a1 * a1 + a2 * a2 + a3 * a3);
135 f
136 }
137
138 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
139 let (x, y, z) = (pos[0], pos[1], pos[2]);
140 let a1 = x - self.min[0];
141 let a2 = y - self.min[1];
142 let a3 = z - self.min[2];
143 if a1 < 0.0 {
144 g[0] += scale * 2.0 * a1;
145 }
146 if a2 < 0.0 {
147 g[1] += scale * 2.0 * a2;
148 }
149 if a3 < 0.0 {
150 g[2] += scale * 2.0 * a3;
151 }
152 let a1 = x - self.max[0];
153 let a2 = y - self.max[1];
154 let a3 = z - self.max[2];
155 if a1 > 0.0 {
156 g[0] += scale * 2.0 * a1;
157 }
158 if a2 > 0.0 {
159 g[1] += scale * 2.0 * a2;
160 }
161 if a3 > 0.0 {
162 g[2] += scale * 2.0 * a3;
163 }
164 self.f(pos, scale, scale2)
165 }
166
167 fn periodic_box(&self) -> Option<([F; 3], [F; 3], [bool; 3])> {
168 if self.periodic.iter().any(|&p| p) {
169 Some((self.min, self.max, self.periodic))
170 } else {
171 None
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy)]
178pub struct InsideSphereRestraint {
179 pub center: [F; 3],
180 pub radius: F,
181}
182
183impl InsideSphereRestraint {
184 pub fn new(center: [F; 3], radius: F) -> Self {
185 Self { center, radius }
186 }
187}
188
189impl AtomRestraint for InsideSphereRestraint {
190 fn f(&self, pos: &[F; 3], _scale: F, scale2: F) -> F {
191 let (x, y, z) = (pos[0], pos[1], pos[2]);
192 let c = self.center;
193 let w = (x - c[0]).powi(2) + (y - c[1]).powi(2) + (z - c[2]).powi(2) - self.radius.powi(2);
194 let a1 = w.max(0.0);
195 scale2 * a1 * a1
196 }
197
198 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
199 let (x, y, z) = (pos[0], pos[1], pos[2]);
200 let c = self.center;
201 let d = (x - c[0]).powi(2) + (y - c[1]).powi(2) + (z - c[2]).powi(2) - self.radius.powi(2);
202 if d > 0.0 {
203 g[0] += 4.0 * scale2 * (x - c[0]) * d;
204 g[1] += 4.0 * scale2 * (y - c[1]) * d;
205 g[2] += 4.0 * scale2 * (z - c[2]) * d;
206 }
207 self.f(pos, scale, scale2)
208 }
209}
210
211#[derive(Debug, Clone, Copy)]
213pub struct InsideEllipsoidRestraint {
214 pub center: [F; 3],
215 pub axes: [F; 3],
216 pub exponent: F,
217}
218
219impl InsideEllipsoidRestraint {
220 pub fn new(center: [F; 3], axes: [F; 3], exponent: F) -> Self {
221 debug_assert!(
224 axes.iter().all(|&a| a > 0.0),
225 "ellipsoid semi-axes must be strictly positive, got {axes:?}"
226 );
227 Self {
228 center,
229 axes,
230 exponent,
231 }
232 }
233}
234
235impl AtomRestraint for InsideEllipsoidRestraint {
236 fn f(&self, pos: &[F; 3], _scale: F, scale2: F) -> F {
237 let (x, y, z) = (pos[0], pos[1], pos[2]);
238 let c = self.center;
239 let ax = self.axes;
240 let a1 = (x - c[0]).powi(2) / ax[0].powi(2);
241 let a2 = (y - c[1]).powi(2) / ax[1].powi(2);
242 let a3 = (z - c[2]).powi(2) / ax[2].powi(2);
243 let w = a1 + a2 + a3 - self.exponent.powi(2);
244 let v = w.max(0.0);
245 scale2 * v * v
246 }
247
248 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
249 let (x, y, z) = (pos[0], pos[1], pos[2]);
250 let c = self.center;
251 let a1 = x - c[0];
252 let b1 = y - c[1];
253 let c1 = z - c[2];
254 let a2 = self.axes[0].powi(2);
255 let b2 = self.axes[1].powi(2);
256 let c2 = self.axes[2].powi(2);
257 let d = a1.powi(2) / a2 + b1.powi(2) / b2 + c1.powi(2) / c2 - self.exponent.powi(2);
258 if d > 0.0 {
259 g[0] += scale2 * 4.0 * d * a1 / a2;
260 g[1] += scale2 * 4.0 * d * b1 / b2;
261 g[2] += scale2 * 4.0 * d * c1 / c2;
262 }
263 self.f(pos, scale, scale2)
264 }
265}
266
267#[derive(Debug, Clone, Copy)]
269pub struct OutsideCubeRestraint {
270 pub origin: [F; 3],
271 pub side: F,
272}
273
274impl OutsideCubeRestraint {
275 pub fn new(origin: [F; 3], side: F) -> Self {
276 Self { origin, side }
277 }
278}
279
280impl AtomRestraint for OutsideCubeRestraint {
281 fn f(&self, pos: &[F; 3], scale: F, _scale2: F) -> F {
282 let (x, y, z) = (pos[0], pos[1], pos[2]);
283 let (xmin, ymin, zmin) = (self.origin[0], self.origin[1], self.origin[2]);
284 let (xmax, ymax, zmax) = (xmin + self.side, ymin + self.side, zmin + self.side);
285 if x > xmin && x < xmax && y > ymin && y < ymax && z > zmin && z < zmax {
286 let xmed = (xmax - xmin) / 2.0;
287 let ymed = (ymax - ymin) / 2.0;
288 let zmed = (zmax - zmin) / 2.0;
289 let a1 = if x <= xmin + xmed { x - xmin } else { xmax - x };
290 let a2 = if y <= ymin + ymed { y - ymin } else { ymax - y };
291 let a3 = if z <= zmin + zmed { z - zmin } else { zmax - z };
292 scale * (a1 + a2 + a3)
293 } else {
294 0.0
295 }
296 }
297
298 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
299 let (x, y, z) = (pos[0], pos[1], pos[2]);
300 let (xmin, ymin, zmin) = (self.origin[0], self.origin[1], self.origin[2]);
301 let (xmax, ymax, zmax) = (xmin + self.side, ymin + self.side, zmin + self.side);
302 if x > xmin && x < xmax && y > ymin && y < ymax && z > zmin && z < zmax {
303 let xmed = (xmax - xmin) / 2.0;
304 let ymed = (ymax - ymin) / 2.0;
305 let zmed = (zmax - zmin) / 2.0;
306 let (a1, a4) = if x <= xmin + xmed {
307 (1.0, 0.0)
308 } else {
309 (0.0, -1.0)
310 };
311 let (a2, a5) = if y <= ymin + ymed {
312 (1.0, 0.0)
313 } else {
314 (0.0, -1.0)
315 };
316 let (a3, a6) = if z <= zmin + zmed {
317 (1.0, 0.0)
318 } else {
319 (0.0, -1.0)
320 };
321 g[0] += scale * (a1 + a4);
322 g[1] += scale * (a2 + a5);
323 g[2] += scale * (a3 + a6);
324 }
325 self.f(pos, scale, scale2)
326 }
327}
328
329#[derive(Debug, Clone, Copy)]
331pub struct OutsideBoxRestraint {
332 pub min: [F; 3],
333 pub max: [F; 3],
334}
335
336impl OutsideBoxRestraint {
337 pub fn new(min: [F; 3], max: [F; 3]) -> Self {
338 Self { min, max }
339 }
340}
341
342impl AtomRestraint for OutsideBoxRestraint {
343 fn f(&self, pos: &[F; 3], scale: F, _scale2: F) -> F {
344 let (x, y, z) = (pos[0], pos[1], pos[2]);
345 let (xmin, ymin, zmin) = (self.min[0], self.min[1], self.min[2]);
346 let (xmax, ymax, zmax) = (self.max[0], self.max[1], self.max[2]);
347 if x > xmin && x < xmax && y > ymin && y < ymax && z > zmin && z < zmax {
348 let xmed = (xmax - xmin) / 2.0;
349 let ymed = (ymax - ymin) / 2.0;
350 let zmed = (zmax - zmin) / 2.0;
351 let a1 = if x <= xmin + xmed { x - xmin } else { xmax - x };
352 let a2 = if y <= ymin + ymed { y - ymin } else { ymax - y };
353 let a3 = if z <= zmin + zmed { z - zmin } else { zmax - z };
354 scale * (a1 + a2 + a3)
355 } else {
356 0.0
357 }
358 }
359
360 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
361 let (x, y, z) = (pos[0], pos[1], pos[2]);
362 let (xmin, ymin, zmin) = (self.min[0], self.min[1], self.min[2]);
363 let (xmax, ymax, zmax) = (self.max[0], self.max[1], self.max[2]);
364 if x > xmin && x < xmax && y > ymin && y < ymax && z > zmin && z < zmax {
365 let xmed = (xmax - xmin) / 2.0;
366 let ymed = (ymax - ymin) / 2.0;
367 let zmed = (zmax - zmin) / 2.0;
368 let (a1, a4) = if x <= xmin + xmed {
369 (1.0, 0.0)
370 } else {
371 (0.0, -1.0)
372 };
373 let (a2, a5) = if y <= ymin + ymed {
374 (1.0, 0.0)
375 } else {
376 (0.0, -1.0)
377 };
378 let (a3, a6) = if z <= zmin + zmed {
379 (1.0, 0.0)
380 } else {
381 (0.0, -1.0)
382 };
383 g[0] += scale * (a1 + a4);
384 g[1] += scale * (a2 + a5);
385 g[2] += scale * (a3 + a6);
386 }
387 self.f(pos, scale, scale2)
388 }
389}
390
391#[derive(Debug, Clone, Copy)]
393pub struct OutsideSphereRestraint {
394 pub center: [F; 3],
395 pub radius: F,
396}
397
398impl OutsideSphereRestraint {
399 pub fn new(center: [F; 3], radius: F) -> Self {
400 Self { center, radius }
401 }
402}
403
404impl AtomRestraint for OutsideSphereRestraint {
405 fn f(&self, pos: &[F; 3], _scale: F, scale2: F) -> F {
406 let (x, y, z) = (pos[0], pos[1], pos[2]);
407 let c = self.center;
408 let w = (x - c[0]).powi(2) + (y - c[1]).powi(2) + (z - c[2]).powi(2) - self.radius.powi(2);
409 let a1 = w.min(0.0);
410 scale2 * a1 * a1
411 }
412
413 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
414 let (x, y, z) = (pos[0], pos[1], pos[2]);
415 let c = self.center;
416 let d = (x - c[0]).powi(2) + (y - c[1]).powi(2) + (z - c[2]).powi(2) - self.radius.powi(2);
417 if d < 0.0 {
418 g[0] += 4.0 * scale2 * (x - c[0]) * d;
419 g[1] += 4.0 * scale2 * (y - c[1]) * d;
420 g[2] += 4.0 * scale2 * (z - c[2]) * d;
421 }
422 self.f(pos, scale, scale2)
423 }
424}
425
426#[derive(Debug, Clone, Copy)]
436pub struct OutsideEllipsoidRestraint {
437 pub center: [F; 3],
438 pub axes: [F; 3],
439 pub exponent: F,
440}
441
442impl OutsideEllipsoidRestraint {
443 pub fn new(center: [F; 3], axes: [F; 3], exponent: F) -> Self {
444 debug_assert!(
447 axes.iter().all(|&a| a > 0.0),
448 "ellipsoid semi-axes must be strictly positive, got {axes:?}"
449 );
450 Self {
451 center,
452 axes,
453 exponent,
454 }
455 }
456}
457
458impl AtomRestraint for OutsideEllipsoidRestraint {
459 fn f(&self, pos: &[F; 3], _scale: F, scale2: F) -> F {
460 let (x, y, z) = (pos[0], pos[1], pos[2]);
461 let c = self.center;
462 let ax = self.axes;
463 let a1 = (x - c[0]).powi(2) / ax[0].powi(2);
464 let a2 = (y - c[1]).powi(2) / ax[1].powi(2);
465 let a3 = (z - c[2]).powi(2) / ax[2].powi(2);
466 let w = a1 + a2 + a3 - self.exponent.powi(2);
467 let v = w.min(0.0);
468 scale2 * v * v
469 }
470
471 fn fg(&self, pos: &[F; 3], scale: F, scale2: F, g: &mut [F; 3]) -> F {
472 let (x, y, z) = (pos[0], pos[1], pos[2]);
473 let c = self.center;
474 let a1 = x - c[0];
475 let b1 = y - c[1];
476 let c1 = z - c[2];
477 let a2 = self.axes[0].powi(2);
478 let b2 = self.axes[1].powi(2);
479 let c2 = self.axes[2].powi(2);
480 let d = a1.powi(2) / a2 + b1.powi(2) / b2 + c1.powi(2) / c2 - self.exponent.powi(2);
481 if d < 0.0 {
482 let ds = scale2 * d;
483 g[0] += 4.0 * ds * a1 / a2;
484 g[1] += 4.0 * ds * b1 / b2;
485 g[2] += 4.0 * ds * c1 / c2;
486 }
487 self.f(pos, scale, scale2)
488 }
489}