Skip to content

Commit 7548389

Browse files
Guillaume FrauxLuthaf
Guillaume Fraux
authored andcommitted
Add access to position/velocity in Particle
1 parent 3b0a806 commit 7548389

File tree

3 files changed

+141
-11
lines changed

3 files changed

+141
-11
lines changed

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ extern crate lumol;
66
mod macros;
77
mod systems;
88

9+
py_exception!(lumol, LumolError);
10+
911
py_module_initializer!(lumol, initlumol, PyInit_lumol, |py, m| {
1012
try!(m.add(py, "__doc__", "Modern and extensible molecular simulation engine"));
11-
1213
try!(systems::register(py, m));
13-
1414
Ok(())
1515
});

src/macros.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,39 @@ macro_rules! create_instance {
88

99
macro_rules! py_run_with {
1010
($py: ident, $obj: ident; $($code: expr),+) => ({
11+
const ASSERT_RAISES_PY: &'static str = "
12+
def assert_raises(callable, *args, **kwargs):
13+
throw = True
14+
try:
15+
callable(*args, **kwargs)
16+
throw = False
17+
except LumolError:
18+
pass
19+
assert throw
20+
";
1121
use cpython::PyDict;
12-
let dict = PyDict::new($py);
13-
dict.set_item($py, stringify!($obj), $obj).unwrap();
14-
py_run!($py, dict, $($code),+);
22+
let locals = PyDict::new($py);
23+
locals.set_item($py, stringify!($obj), $obj).unwrap();
24+
25+
let globals = PyDict::new($py);
26+
let error = $py.get_type::<::LumolError>();
27+
globals.set_item($py, "LumolError", error).unwrap();
28+
29+
py_run!($py, globals, locals, ASSERT_RAISES_PY);
30+
py_run!($py, globals, locals, $($code),+);
1531
});
32+
($py: ident, $obj: ident; $($code: expr),+,) => (
33+
py_run_with!($py, $obj; $($code),+);
34+
)
1635
}
1736

1837
macro_rules! py_run {
19-
($py: ident, $dict: ident, $code: expr) => ({
20-
$py.run($code, None, Some(&$dict)).expect($code);
38+
($py: ident, $globals: ident, $locals: ident, $code: expr) => ({
39+
$py.run($code, Some(&$globals), Some(&$locals)).expect($code);
2140
});
22-
($py: ident, $dict: ident, $code: expr, $($tail: expr),+) => ({
23-
$py.run($code, None, Some(&$dict)).expect($code);
24-
py_run!($py, $dict, $($tail),+);
41+
($py: ident, $globals: ident, $locals: ident, $code: expr, $($tail: expr),+) => ({
42+
$py.run($code, Some(&$globals), Some(&$locals)).expect($code);
43+
py_run!($py, $globals, $locals, $($tail),+);
2544
});
2645
}
2746

@@ -32,3 +51,9 @@ macro_rules! register {
3251
}
3352
);
3453
}
54+
55+
macro_rules! raise {
56+
($py: ident, $args: expr) => ({
57+
Err(PyErr::new::<LumolError, _>($py, $args))
58+
});
59+
}

src/systems/particle.rs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
use cpython::{PyObject, PyResult};
1+
use cpython::{PyObject, PyErr, PyResult, PyTuple, ToPyObject, PythonObject};
22
use lumol;
3+
use lumol::Vector3D;
34
use std::cell::RefCell;
45

6+
use LumolError;
7+
58
register!(|py, m| {
69
try!(m.add_class::<Particle>(py));
710
Ok(())
@@ -39,6 +42,72 @@ py_class!(class Particle |py| {
3942
self.particle(py).borrow_mut().charge = charge;
4043
Ok(py.None())
4144
}
45+
46+
def position(&self) -> PyResult<PyTuple> {
47+
let position = &self.particle(py).borrow().position;
48+
49+
let x = position[0].to_py_object(py).into_object();
50+
let y = position[1].to_py_object(py).into_object();
51+
let z = position[2].to_py_object(py).into_object();
52+
53+
Ok(PyTuple::new(py, &[x, y, z]))
54+
}
55+
56+
def set_position(&self, position: &PyTuple) -> PyResult<PyObject> {
57+
if position.len(py) != 3 {
58+
return raise!(py, format!(
59+
"Wrong size for the position: should be a 3-dimmensional \
60+
tuple, but contains {} elements", position.len(py)
61+
));
62+
}
63+
64+
let x = try!(position.get_item(py, 0).extract::<f64>(py).or(
65+
raise!(py, "Position elements should be numbers"))
66+
);
67+
let y = try!(position.get_item(py, 1).extract::<f64>(py).or(
68+
raise!(py, "Position elements should be numbers"))
69+
);
70+
let z = try!(position.get_item(py, 2).extract::<f64>(py).or(
71+
raise!(py, "Position elements should be numbers"))
72+
);
73+
74+
self.particle(py).borrow_mut().position = Vector3D::new(x, y, z);
75+
76+
Ok(py.None())
77+
}
78+
79+
def velocity(&self) -> PyResult<PyTuple> {
80+
let velocity = &self.particle(py).borrow().velocity;
81+
82+
let x = velocity[0].to_py_object(py).into_object();
83+
let y = velocity[1].to_py_object(py).into_object();
84+
let z = velocity[2].to_py_object(py).into_object();
85+
86+
Ok(PyTuple::new(py, &[x, y, z]))
87+
}
88+
89+
def set_velocity(&self, velocity: &PyTuple) -> PyResult<PyObject> {
90+
if velocity.len(py) != 3 {
91+
return raise!(py, format!(
92+
"Wrong size for the velocity: should be a 3-dimmensional \
93+
tuple, but contains {} elements", velocity.len(py)
94+
));
95+
}
96+
97+
let x = try!(velocity.get_item(py, 0).extract::<f64>(py).or(
98+
raise!(py, "Velocity elements should be numbers"))
99+
);
100+
let y = try!(velocity.get_item(py, 1).extract::<f64>(py).or(
101+
raise!(py, "Velocity elements should be numbers"))
102+
);
103+
let z = try!(velocity.get_item(py, 2).extract::<f64>(py).or(
104+
raise!(py, "Velocity elements should be numbers"))
105+
);
106+
107+
self.particle(py).borrow_mut().velocity = Vector3D::new(x, y, z);
108+
109+
Ok(py.None())
110+
}
42111
});
43112

44113
#[cfg(test)]
@@ -120,5 +189,41 @@ mod tests {
120189
"assert particle.charge() == 2"
121190
);
122191
}
192+
193+
#[test]
194+
fn position() {
195+
let gil = Python::acquire_gil();
196+
let py = gil.python();
197+
let particle = create_instance!(py, Particle, ("He",));
198+
199+
py_run_with!(py, particle;
200+
"assert particle.position() == (0.0, 0.0, 0.0)",
201+
"particle.set_position((1, 2, 3))",
202+
"assert particle.position() == (1, 2, 3)",
203+
"assert_raises(particle.set_position, (2, 3))",
204+
"assert_raises(particle.set_position, (1, 2, 3, 4))",
205+
"assert_raises(particle.set_position, ('1', 2, 3))",
206+
"assert_raises(particle.set_position, (1, '2', 3))",
207+
"assert_raises(particle.set_position, (1, 2, '3'))",
208+
);
209+
}
210+
211+
#[test]
212+
fn velocity() {
213+
let gil = Python::acquire_gil();
214+
let py = gil.python();
215+
let particle = create_instance!(py, Particle, ("He",));
216+
217+
py_run_with!(py, particle;
218+
"assert particle.velocity() == (0.0, 0.0, 0.0)",
219+
"particle.set_velocity((1, 2, 3))",
220+
"assert particle.velocity() == (1, 2, 3)",
221+
"assert_raises(particle.set_velocity, (2, 3))",
222+
"assert_raises(particle.set_velocity, (1, 2, 3, 4))",
223+
"assert_raises(particle.set_velocity, ('1', 2, 3))",
224+
"assert_raises(particle.set_velocity, (1, '2', 3))",
225+
"assert_raises(particle.set_velocity, (1, 2, '3'))",
226+
);
227+
}
123228
}
124229
}

0 commit comments

Comments
 (0)