Skip to content

Commit 5268274

Browse files
Added new micromagnetic Anisotropy and DMI energy classes
1 parent 2f19fcf commit 5268274

File tree

4 files changed

+204
-17
lines changed

4 files changed

+204
-17
lines changed

fidimag/common/c_clib.pyx

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,17 @@ cdef extern from "c_energy.h":
266266

267267
cdef cppclass ExchangeEnergy(Energy):
268268
ExchangeEnergy() except +
269-
270269
void setup(double * A, MicroSim * sim)
271270
# double *A
272271

272+
cdef cppclass AnisotropyEnergy(Energy):
273+
AnisotropyEnergy() except +
274+
void setup(double * Ku, double * axis, MicroSim * sim)
275+
276+
cdef cppclass DMIEnergy(Energy):
277+
ExchangeEnergy() except +
278+
void setup(double * D, double * dmi_vector, int n_dmis, MicroSim * sim)
279+
273280
# cdef extern from "c_energy.cpp":
274281
# pass
275282

@@ -311,7 +318,6 @@ cdef class PyExchangeEnergy(PyEnergy):
311318
cdef ExchangeEnergy *_thisptr
312319
# Try cinit:
313320
def __cinit__(self, double [:] A, PyMicroSim sim):
314-
print("In Python B")
315321

316322
self._thisptr = self.thisptr = new ExchangeEnergy()
317323
self._thisptr.setup(&A[0], sim.thisptr)
@@ -323,6 +329,37 @@ cdef class PyExchangeEnergy(PyEnergy):
323329
del self._thisptr
324330

325331

332+
cdef class PyAnisotropyEnergy(PyEnergy):
333+
cdef AnisotropyEnergy *_thisptr
334+
# Try cinit:
335+
def __cinit__(self, double [:] Ku, double [:] axis, PyMicroSim sim):
336+
337+
self._thisptr = self.thisptr = new AnisotropyEnergy()
338+
self._thisptr.setup(&Ku[0], &axis[0], sim.thisptr)
339+
340+
def setup(self, double [:] Ku, double [:] axis, PyMicroSim sim):
341+
self._thisptr.setup(&Ku[0], &axis[0], sim.thisptr)
342+
343+
def __dealloc__(self):
344+
del self._thisptr
345+
346+
347+
cdef class PyDMIEnergy(PyEnergy):
348+
cdef DMIEnergy *_thisptr
349+
# Try cinit:
350+
def __cinit__(self, double [:] D, double [:] dmi_vector, n_dmis,
351+
PyMicroSim sim):
352+
353+
self._thisptr = self.thisptr = new DMIEnergy()
354+
self._thisptr.setup(&D[0], &dmi_vector[0], n_dmis, sim.thisptr)
355+
356+
def setup(self, double [:] D, double [:] dmi_vector, n_dmis, PyMicroSim sim):
357+
self._thisptr.setup(&D[0], &dmi_vector[0], n_dmis, sim.thisptr)
358+
359+
def __dealloc__(self):
360+
del self._thisptr
361+
362+
326363
# Simulation class ------------------------------------------------------------
327364

328365
cdef extern from "c_micro_sim.h":

native/include/c_energy.h

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,48 @@ class ExchangeEnergy : public Energy {
3333
this->interaction_id = 1;
3434
};
3535
~ExchangeEnergy() {std::cout << "Killing Exchange\n";};
36+
double *A;
3637
void setup(double *A, MicroSim * sim) {
3738
_setup(sim);
3839
this->A = A;
3940
}
40-
double *A;
4141
void compute_field(double t);
4242
};
4343

4444

45-
// class AnisotropyEnergy : public Energy {
46-
// public:
47-
// AnisotropyEnergy() {
48-
// std::cout << "Instatiating AnisotropyEnergy class; at " << this << "\n";
49-
// this->interaction_id = 1;
50-
// };
51-
// ~AnisotropyEnergy() {std::cout << "Killing Anisotropy\n";};
52-
// void init(double *Ku) {
53-
// this->set_up = false;
54-
// this->Ku = Ku;
55-
// }
56-
// double *A;
57-
// void compute_field(double t);
58-
// };
45+
class AnisotropyEnergy : public Energy {
46+
public:
47+
AnisotropyEnergy() {
48+
std::cout << "Instatiating AnisotropyEnergy class; at " << this << "\n";
49+
this->interaction_id = 1;
50+
};
51+
~AnisotropyEnergy() {std::cout << "Killing Anisotropy\n";};
52+
double *Ku;
53+
double *axis;
54+
void setup(double *Ku, double *axis, MicroSim * sim) {
55+
_setup(sim);
56+
this->Ku = Ku;
57+
this->axis = axis;
58+
}
59+
void compute_field(double t);
60+
};
61+
62+
63+
class DMIEnergy : public Energy {
64+
public:
65+
DMIEnergy() {
66+
std::cout << "Instatiating DMIEnergy class; at " << this << "\n";
67+
this->interaction_id = 1;
68+
};
69+
~DMIEnergy() {std::cout << "Killing DMI\n";};
70+
double *D;
71+
double *dmi_vector;
72+
int n_dmis;
73+
void setup(double * D, double *dmi_vector, int n_dmis, MicroSim * sim) {
74+
_setup(sim);
75+
this->D = D;
76+
this->dmi_vector = dmi_vector;
77+
this->n_dmis = n_dmis;
78+
}
79+
void compute_field(double t);
80+
};

native/src/m_anis.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
#include "m_clib.h"
2+
#include "c_energy.h"
3+
#include "c_constants.h"
4+
5+
// TO BE DEPRECATED::
26

37
void compute_uniaxial_anis(double * m, double * field, double * energy, double * Ms_inv,
48
double * Ku, double * axis, int nx, int ny, int nz) {
@@ -27,3 +31,28 @@ void compute_uniaxial_anis(double * m, double * field, double * energy, double *
2731
}
2832
}
2933

34+
// ----------------------------------------------------------------------------
35+
36+
void AnisotropyEnergy::compute_field(double t) {
37+
38+
for (int i = 0; i < n; i++) {
39+
40+
int j = 3 * i;
41+
42+
if (Ms_inv[i] == 0.0){
43+
field[j] = 0;
44+
field[j + 1] = 0;
45+
field[j + 2] = 0;
46+
energy[i] = 0;
47+
continue;
48+
}
49+
50+
double m_u = spin[j] * axis[j] + spin[j + 1] * axis[j + 1] + spin[j + 2] * axis[j + 2];
51+
52+
field[j] = 2 * Ku[i] * m_u * Ms_inv[i] * MU0_INV * axis[j];
53+
field[j + 1] = 2 * Ku[i] * m_u * Ms_inv[i] * MU0_INV * axis[j + 1];
54+
field[j + 2] = 2 * Ku[i] * m_u * Ms_inv[i] * MU0_INV * axis[j + 2];
55+
56+
energy[i] = Ku[i] * (1 - m_u * m_u);
57+
}
58+
}

native/src/m_dmi.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <stdlib.h>
44
#include <stdio.h>
55
#include <math.h>
6+
#include "c_energy.h"
7+
#include "c_constants.h"
68

79
/* Functions to Compute the micromagnetic Dzyaloshinskii Moriya interaction
810
* field and energy using the
@@ -364,3 +366,100 @@ void dmi_field(double * m, double * field,
364366
field[3 * i + 2] = fz * Ms_inv[i] * MU0_INV;
365367
}
366368
}
369+
370+
// ----------------------------------------------------------------------------
371+
// Using the new Energy class::
372+
373+
374+
void DMIEnergy::compute_field(double t) {
375+
376+
/* These are for the DMI prefactor or coefficient */
377+
double dxs[6] = {dx, dx, dy, dy, dz, dz};
378+
379+
/* Here we iterate through every mesh node */
380+
for (int i = 0; i < n; i++) {
381+
double DMIc;
382+
double fx = 0, fy = 0, fz = 0;
383+
int idnm; // Index for the magnetisation matrix
384+
int idn = 6 * i; // index for the neighbours
385+
/* Set a zero field for sites without magnetic material */
386+
if (Ms_inv[i] == 0.0){
387+
field[3 * i] = 0;
388+
field[3 * i + 1] = 0;
389+
field[3 * i + 2] = 0;
390+
energy[i] = 0;
391+
continue;
392+
}
393+
394+
/* Here we iterate through the neighbours. Remember:
395+
* j = 0, 1, 2, 3, 4, 5 --> -x, +x, -y, +y, -z, +z
396+
Previously we had n_dmi_neighbours as a parameter,
397+
but now we just skip if the vector entries are zero
398+
instead, because we can have cases such as in D_n
399+
where the D1 component has -x,+x,-y,+y,0,0
400+
and the D2 component has 0,0,0,0,-z,+z.
401+
*/
402+
for (int j = 0; j < 6; j++) {
403+
/* Add the DMI field x times for every DMI constant */
404+
for (int k = 0; k < n_dmis; k++) {
405+
406+
// starting index of the DMI vector for this neighbour (j)
407+
// (remember we have 18 comps of dmi_vector per DMI constant)
408+
int ngbr_idx_D = k * 18 + 3 * j;
409+
410+
/* We skip the neighbour if
411+
(a) it doesn't exist (ngbs[idn + j] = -1)
412+
(b) there is no material there
413+
(c) DMI value is zero there
414+
*/
415+
if ((ngbs[idn + j] != -1) && (Ms_inv[ngbs[idn + j]] != 0)) {
416+
/* We do here: -(D / dx_i) * ( r_{ij} X M_{j} )
417+
* The cross_i function gives the i component of the
418+
* cross product. The coefficient is computed according
419+
* to the DMI strength of the current lattice site.
420+
* For the denominator, for example, if j=2 or 3, then
421+
* dxs[j] = dy
422+
*/
423+
424+
/* check the DMI vector exists */
425+
if (dmi_vector[ngbr_idx_D ] != 0 ||
426+
dmi_vector[ngbr_idx_D + 1] != 0 ||
427+
dmi_vector[ngbr_idx_D + 2] != 0 ) {
428+
/* Notice the x component of the cross product of +-x
429+
* times anything is zero (similar for the other comps) */
430+
431+
// Get DMI constant from neighbour and scale
432+
// DMI components are in consecutive order per neighbour,
433+
// i.e. if 2 DMI consts: [D0 D1 D0 D1 .... ]
434+
DMIc = -D[n_dmis * ngbs[idn + j] + k] / dxs[j];
435+
436+
idnm = 3 * ngbs[idn + j]; // index for magnetisation
437+
438+
fx += DMIc * cross_x(dmi_vector[ngbr_idx_D],
439+
dmi_vector[ngbr_idx_D + 1],
440+
dmi_vector[ngbr_idx_D + 2],
441+
spin[idnm], spin[idnm + 1], spin[idnm + 2]);
442+
fy += DMIc * cross_y(dmi_vector[ngbr_idx_D],
443+
dmi_vector[ngbr_idx_D + 1],
444+
dmi_vector[ngbr_idx_D + 2],
445+
spin[idnm], spin[idnm + 1], spin[idnm + 2]);
446+
fz += DMIc * cross_z(dmi_vector[ngbr_idx_D],
447+
dmi_vector[ngbr_idx_D + 1],
448+
dmi_vector[ngbr_idx_D + 2],
449+
spin[idnm], spin[idnm + 1], spin[idnm + 2]);
450+
451+
}
452+
}
453+
} // Close for loop through n of DMI constants
454+
} // Close for loop through neighbours per mesh site
455+
456+
/* Energy as: (-mu0 * Ms / 2) * [ H_dmi * m ] */
457+
energy[i] = -0.5 * (fx * spin[3 * i] + fy * spin[3 * i + 1]
458+
+ fz * spin[3 * i + 2]);
459+
460+
/* Update the field H_dmi which has the same structure than *m */
461+
field[3 * i] = fx * Ms_inv[i] * MU0_INV;
462+
field[3 * i + 1] = fy * Ms_inv[i] * MU0_INV;
463+
field[3 * i + 2] = fz * Ms_inv[i] * MU0_INV;
464+
}
465+
}

0 commit comments

Comments
 (0)