Skip to content

Commit 09ad07e

Browse files
Implementing a Cython wrapper for the C++ energy class, only Exchange for now; ignored error in Makefile clean
1 parent 3f1d3a8 commit 09ad07e

File tree

5 files changed

+104
-24
lines changed

5 files changed

+104
-24
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ clean:
4949
touch ${EXTENSIONS_DIR}/__init__.py
5050
rm -rf build
5151
rm -rf $(OBJECTS) $(TARGET) *.dSYM
52-
find fidimag/ "*.cpp" -exec echo {} \;
52+
-find fidimag/ "*.cpp" -exec echo {};
5353

5454

5555
docker:

fidimag/common/c_clib.pyx

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
cimport numpy as np
44
import numpy as np
55

6+
# C++ modules
7+
from libcpp cimport bool
8+
69
# -----------------------------------------------------------------------------
710

811
cdef extern from "c_clib.h":
@@ -198,17 +201,15 @@ def init_vector(m0, mesh, dim=3, norm=False, *args):
198201

199202
def init_vector_func_fast(m0, mesh, double[:] field, norm=False, *args):
200203
"""
201-
An unsafe method of setting the field. Depends on
202-
the setter code being memory safe.
203-
204-
m0 must be a Python function that takes the mesh
205-
and field as arguments. Within that, the user
206-
must handle evaluating the function at different
207-
coordinate points. It needs to be able to handle
208-
the spatial dependence itself, and write the
209-
field valuse into the field array. This can
210-
be written with Cython which will give much
211-
better performance. For example:
204+
205+
An unsafe method of setting the field. Depends on the setter code being
206+
memory safe.
207+
208+
m0 must be a Python function that takes the mesh and field as arguments.
209+
Within that, the user must handle evaluating the function at different
210+
coordinate points. It needs to be able to handle the spatial dependence
211+
itself, and write the field valuse into the field array. This can be
212+
written with Cython which will give much better performance. For example:
212213
213214
from libc.math cimport sin
214215
@@ -224,3 +225,83 @@ def init_vector_func_fast(m0, mesh, double[:] field, norm=False, *args):
224225
if norm:
225226
normalise(field)
226227
return field
228+
229+
# -----------------------------------------------------------------------------
230+
# -----------------------------------------------------------------------------
231+
# CLASSES
232+
233+
# -----------------------------------------------------------------------------
234+
# C++ definitions
235+
236+
# See:
237+
# https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html
238+
#
239+
# - Methods that are redefined in inherited classes are only specified in the
240+
# base class
241+
# - These can be declared in a .pxd file:
242+
243+
cdef extern from "c_energy.h":
244+
245+
cdef cppclass Energy:
246+
# except +: Without this declaration, C++ exceptions originating from
247+
# the constructor will not be handled by Cython.
248+
Energy() except +
249+
250+
void compute_field(double t)
251+
double compute_energy()
252+
void setup(int nx, int ny, int nz, double dx, double dy, double dz,
253+
double unit_length, double *spin,
254+
double *Ms, double *Ms_inv)
255+
256+
bool set_up
257+
int nx, ny, nz, n
258+
double dx, dy, dz
259+
double unit_length
260+
double *spin
261+
double *Ms
262+
double *Ms_inv
263+
double *field
264+
double *energy
265+
double *coordinates
266+
int *ngbs
267+
268+
cdef cppclass ExchangeEnergy(Energy):
269+
ExchangeEnergy() except +
270+
271+
void init(double *A)
272+
273+
double *A
274+
275+
# -----------------------------------------------------------------------------
276+
# Python definitions
277+
278+
# Cython initializes C++ class attributes of a cdef class using the nullary
279+
# constructor. If the class you’re wrapping does not have a nullary
280+
# constructor, you must store a pointer to the wrapped class and manually
281+
# allocate and deallocate it. A convenient and safe place to do so is in the
282+
# __cinit__ and __dealloc__ methods which are guaranteed to be called exactly
283+
# once upon creation and deletion of the Python instance.
284+
285+
cdef class PyExchangeEnergy:
286+
cdef ExchangeEnergy thisptr
287+
# Try cinit:
288+
def __init__(self, double [:] A):
289+
self.thisptr.init(&A[0])
290+
# cdef ExchangeEnergy *thisptr
291+
# We could use another constructor if we use this method:
292+
# def __cinit__(self):
293+
# if type(self) is PyEnergy:
294+
# self.thisptr = new Energy()
295+
# def __dealloc__(self):
296+
# if type(self) is PyEnergy:
297+
# del self.thisptr
298+
# Necessary?
299+
def compute_field(self, t):
300+
self.thisptr.compute_field(t)
301+
def compute_energy(self, time):
302+
return self.thisptr.compute_energy()
303+
def setup(self, nx, ny, nz, dx, dy, dz, unit_length,
304+
double [:] spin, double [:] Ms, double [:] Ms_inv):
305+
return self.thisptr.setup(nx, ny, nz, dx, dy, dz, unit_length,
306+
&spin[0], &Ms[0], &Ms_inv[0])
307+

fidimag/micro/energ.pyx

Lines changed: 0 additions & 4 deletions
This file was deleted.

native/include/c_energy.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
class Energy {
44
public:
5-
bool set_up;
65
Energy();
6+
bool set_up;
77
int nx, ny, nz, n;
88
double dx, dy, dz;
99
double unit_length;
@@ -14,15 +14,17 @@ class Energy {
1414
double *energy;
1515
double *coordinates;
1616
int *ngbs;
17-
virtual void compute_field(double t) = 0;
1817
double compute_energy();
1918
void setup(int nx, int ny, int nz, double dx, double dy, double dz, double unit_length, double *spin, double *Ms, double *Ms_inv);
19+
virtual void compute_field(double t) = 0;
2020
};
2121

22-
class Exchange : public Energy {
22+
class ExchangeEnergy : public Energy {
2323
public:
24-
Exchange(double *A) : A(A) {
24+
ExchangeEnergy() {};
25+
void init(double *A) {
2526
set_up = false;
27+
this->A = A;
2628
}
2729
double *A;
2830
void compute_field(double t);

native/src/c_energy.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "c_energy.h"
2+
#include "c_constants.h"
23

34
double Energy::compute_energy() {
45
double sum = 0;
@@ -27,7 +28,7 @@ void Energy::setup(int nx, int ny, int nz,
2728
set_up = true;
2829
}
2930

30-
void Exchange::compute_field(double t) {
31+
void ExchangeEnergy::compute_field(double t) {
3132
/* Compute the micromagnetic exchange field and energy using the
3233
* matrix of neighbouring spins and a second order approximation
3334
* for the derivative
@@ -179,8 +180,8 @@ void Exchange::compute_field(double t) {
179180
+ fz * spin[3 * i + 2]);
180181

181182
/* Update the field H_ex which has the same structure than *m */
182-
field[3 * i] = fx * Ms_inv[i] * MU0_INV;
183-
field[3 * i + 1] = fy * Ms_inv[i] * MU0_INV;
184-
field[3 * i + 2] = fz * Ms_inv[i] * MU0_INV;
183+
field[3 * i] = fx * Ms_inv[i] * MU_0_INV;
184+
field[3 * i + 1] = fy * Ms_inv[i] * MU_0_INV;
185+
field[3 * i + 2] = fz * Ms_inv[i] * MU_0_INV;
185186
}
186187
}

0 commit comments

Comments
 (0)