Skip to content

Commit bfc5d94

Browse files
committed
Add working lazy FMM and generated code up to high order
1 parent eb6f350 commit bfc5d94

File tree

7 files changed

+81507
-20981
lines changed

7 files changed

+81507
-20981
lines changed

fidimag/atomistic/demag.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import fidimag.extensions.dipolar as clib
22
import numpy as np
33
from .energy import Energy
4+
import numpy as np
5+
import fidimag
6+
from fidimag.atomistic.energy import Energy
7+
import fidimag.extensions.fmm as fmm
8+
import time
9+
410

511

612
class Demag(Energy):
@@ -94,3 +100,39 @@ def compute_energy(self):
94100
self.energy /= self.scale
95101

96102
return energy / self.scale
103+
104+
105+
class DemagFMM(Energy):
106+
def __init__(self, order, ncrit, theta, name="DemagFMM"):
107+
self.name = name
108+
assert order > 0, "Order must be 1 or higher"
109+
self.order = order
110+
assert ncrit >= 2, "ncrit must be greater than 1."
111+
self.ncrit = ncrit
112+
assert theta >= 0.0, "theta must be >= 0.0"
113+
self.theta = theta
114+
115+
def setup(self, mesh, spin, mu_s, mu_s_inv):
116+
super(DemagFMM, self).setup(mesh, spin, mu_s, mu_s_inv)
117+
self.n = mesh.n
118+
print(mesh.coordinates)
119+
self.m_temp = spin.copy()
120+
self.m_temp[0::3] *= self.mu_s
121+
self.m_temp[1::3] *= self.mu_s
122+
self.m_temp[2::3] *= self.mu_s
123+
self.fmm = fmm.FMM(self.n, self.ncrit, self.theta,
124+
self.order,
125+
mesh.coordinates * mesh.unit_length,
126+
self.m_temp)
127+
128+
def compute_field(self, t=0, spin=None):
129+
self.m_temp[:] = spin if spin is not None else self.spin
130+
self.m_temp[0::3] *= self.mu_s
131+
self.m_temp[1::3] *= self.mu_s
132+
self.m_temp[2::3] *= self.mu_s
133+
134+
self.field[:] = 0.0
135+
#self.fmm.set(self.m_temp)
136+
self.fmm.compute_field(self.theta, self.field)
137+
self.field *= 1e-7
138+
return self.field

fidimag/atomistic/fmmlib/calculate.cpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <iostream>
66
#include <stack>
77
#include <cmath>
8+
#include <algorithm>
89
#include<cstdio>
910

1011
void P2P(double x, double y, double z, double mux, double muy, double muz, double *F) {
@@ -30,9 +31,10 @@ void P2P_noatomic(double x, double y, double z, double mux, double muy, double m
3031
F[2] += (3*mu_dot_r * z / R5 - muz / R3);
3132
}
3233

34+
3335
void evaluate_P2M(std::vector<Particle> &particles, std::vector<Cell> &cells,
3436
size_t cell, size_t ncrit, size_t exporder) {
35-
std::cout << "Nparticles = " << particles.size() << std::endl;
37+
// std::cout << "Nparticles = " << particles.size() << std::endl;
3638
double *M = new double[Nterms(exporder+1)]();
3739
//#pragma omp for
3840
for(size_t c = 0; c < cells.size(); c++) {
@@ -67,14 +69,14 @@ void evaluate_M2M(std::vector<Particle> &particles, std::vector<Cell> &cells,
6769
#pragma omp for
6870
for (size_t c = cells.size() - 1; c > 0; c--) {
6971
size_t p = cells[c].parent;
70-
std::cout << "M2M: " << c << " to " << p << std::endl;
72+
// std::cout << "M2M: " << c << " to " << p << std::endl;
7173
double dx = cells[p].x - cells[c].x;
7274
double dy = cells[p].y - cells[c].y;
7375
double dz = cells[p].z - cells[c].z;
7476
M2M(dx, dy, dz, cells[c].M, cells[p].M, exporder);
7577
}
7678

77-
std::cout << "evalm2m_cpp: " << cells[0].M[0] << "," << cells[0].M[1] << "," << cells[0].M[2] << "," << cells[0].M[3] << std::endl;
79+
// std::cout << "evalm2m_cpp: " << cells[0].M[0] << "," << cells[0].M[1] << "," << cells[0].M[2] << "," << cells[0].M[3] << std::endl;
7880
}
7981

8082

@@ -210,12 +212,12 @@ void evaluate_M2L_lazy(std::vector<Cell> &cells,
210212
}
211213

212214
void evaluate_P2P_lazy(std::vector<Cell> &cells, std::vector<Particle> &particles,
213-
std::vector<std::pair<size_t, size_t>> &P2P_list, std::vector<double> &F) {
215+
std::vector<std::pair<size_t, size_t>> &P2P_list, double *F) {
214216
#pragma omp for
215217
for(size_t i = 0; i < P2P_list.size(); i++) {
216218
size_t A = P2P_list[i].first;
217219
size_t B = P2P_list[i].second;
218-
P2P_Cells(A, B, cells, particles, F.data());
220+
P2P_Cells(A, B, cells, particles, F);
219221
}
220222
}
221223

@@ -274,3 +276,54 @@ void evaluate_direct(std::vector<Particle> &particles, double *F, size_t n) {
274276
}
275277
}
276278
}
279+
280+
281+
void evaluate_approx(std::vector<Particle> &particles, std::vector<Cell> &cells,
282+
size_t ncrit, double theta, size_t order, double *F) {
283+
evaluate_P2M(particles, cells, 0, ncrit, order);
284+
evaluate_M2M(particles, cells, order);
285+
interact_dehnen(0, 0, cells, particles, theta, order, ncrit, F);
286+
evaluate_L2L(cells, order);
287+
evaluate_L2P(particles, cells, F, ncrit, order);
288+
}
289+
290+
void evaluate_approx_lazy(std::vector<Particle> &particles, std::vector<Cell> &cells,
291+
size_t ncrit, size_t order, double *F,
292+
std::vector<std::pair<size_t, size_t>> &M2L_list,
293+
std::vector<std::pair<size_t, size_t>> &P2P_list) {
294+
#pragma omp parallel
295+
evaluate_P2M(particles, cells, 0, ncrit, order);
296+
297+
evaluate_M2M(particles, cells, order);
298+
#pragma omp barrier
299+
#pragma omp parallel
300+
{
301+
evaluate_M2L_lazy(cells,M2L_list,order);
302+
evaluate_P2P_lazy(cells, particles, P2P_list, F);
303+
#pragma omp barrier
304+
evaluate_L2L(cells, order);
305+
#pragma omp barrier
306+
evaluate_L2P(particles, cells, F, ncrit, order);
307+
}
308+
309+
}
310+
311+
312+
void build_interaction_lists(std::vector<std::pair<size_t, size_t>> &M2L_list,
313+
std::vector<std::pair<size_t, size_t>> &P2P_list,
314+
std::vector<Cell> &cells,
315+
std::vector<Particle> &particles,
316+
double theta,
317+
size_t order,
318+
size_t ncrit
319+
) {
320+
321+
std::sort(M2L_list.begin(), M2L_list.end(),
322+
[](std::pair<size_t, size_t> &left, std::pair<size_t, size_t> &right) {
323+
return left.first < right.first;
324+
}
325+
);
326+
327+
std::cout << "M2L_list size = " << M2L_list.size() << std::endl;
328+
std::cout << "P2P_list size = " << P2P_list.size() << std::endl;
329+
}

fidimag/atomistic/fmmlib/calculate.hpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616

1717
void P2P(double x, double y, double z, double mux, double muy, double muz, double *F);
1818

19+
void evaluate_approx(std::vector<Particle> &particles, std::vector<Cell> &cells,
20+
size_t ncrit, double theta, size_t order, double *F);
21+
22+
void evaluate_approx_lazy(std::vector<Particle> &particles, std::vector<Cell> &cells,
23+
size_t ncrit, size_t order, double *F,
24+
std::vector<std::pair<size_t, size_t>> &M2L_list,
25+
std::vector<std::pair<size_t, size_t>> &P2P_list);
26+
1927
void evaluate_P2M(std::vector<Particle> &particles, std::vector<Cell> &cells,
2028
size_t cell, size_t ncrit, size_t exporder);
2129

@@ -42,8 +50,6 @@ void interact_dehnen_lazy(const size_t A, const size_t B, const std::vector<Cell
4250
void P2P_Cells(size_t A, size_t B, std::vector<Cell> &cells,
4351
std::vector<Particle> &particles, double *F);
4452

45-
void evaluate_P2P_lazy(std::vector<Cell> &cells,
46-
std::vector<std::pair<size_t, size_t>> &P2P_list);
4753

4854
void evaluate_M2L_lazy(std::vector<Cell> &cells,
4955
std::vector<std::pair<size_t, size_t>> &M2L_list,
@@ -53,4 +59,13 @@ void evaluate_M2L_lazy(std::vector<Cell> &cells,
5359
std::vector<std::pair<size_t, size_t>> &M2L_list, size_t order);
5460

5561
void evaluate_P2P_lazy(std::vector<Cell> &cells, std::vector<Particle> &particles,
56-
std::vector<std::pair<size_t, size_t>> &P2P_list, std::vector<double> &F);
62+
std::vector<std::pair<size_t, size_t>> &P2P_list, double *F);
63+
64+
void build_interaction_lists(std::vector<std::pair<size_t, size_t>> &M2L_list,
65+
std::vector<std::pair<size_t, size_t>> &P2P_list,
66+
std::vector<Cell> &cells,
67+
std::vector<Particle> &particles,
68+
double theta,
69+
size_t order,
70+
size_t ncrit
71+
);

fidimag/atomistic/fmmlib/fmm.pyx

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from fidimag.atomistic.energy import Energy
44
from libcpp.vector cimport vector
55
from libcpp.utility cimport pair
6-
6+
from libcpp.algorithm cimport sort
77
cimport numpy as np
88
import numpy as np
99

@@ -31,6 +31,14 @@ cdef extern from "tree.hpp":
3131

3232

3333
cdef extern from "calculate.hpp":
34+
void evaluate_approx(vector[Particle] particles, vector[Cell] cells,
35+
size_t ncrit, double theta, size_t order, double *F)
36+
37+
void evaluate_approx_lazy(vector[Particle] particles, vector[Cell] cells,
38+
size_t ncrit, size_t order, double *F,
39+
vector[pair[size_t, size_t]] M2L_list,
40+
vector[pair[size_t, size_t]] P2P_list)
41+
3442
void evaluate_P2M(vector[Particle] particles,
3543
vector[Cell] cells,
3644
size_t cell,
@@ -62,8 +70,23 @@ cdef extern from "calculate.hpp":
6270
double *F,
6371
size_t n)
6472

73+
void interact_dehnen_lazy(size_t A, size_t B,
74+
vector[Cell] cells,
75+
vector[Particle] particles,
76+
double theta, size_t order,
77+
const size_t ncrit,
78+
vector[pair[size_t, size_t]] M2L_list,
79+
vector[pair[size_t, size_t]] P2P_list)
6580

6681

82+
void build_interaction_lists(vector[pair[size_t, size_t]] M2L_list,
83+
vector[pair[size_t, size_t]]P2P_list,
84+
vector[Cell] cells,
85+
vector[Particle] particles,
86+
double theta,
87+
size_t order,
88+
size_t ncrit
89+
)
6790

6891

6992
cdef class FMM:
@@ -75,18 +98,23 @@ cdef class FMM:
7598
cdef Cell root
7699
cdef vector[double] M
77100
cdef vector[double] L
101+
cdef vector[pair[size_t, size_t]] M2L_list
102+
cdef vector[pair[size_t, size_t]] P2P_list
78103
cdef size_t Msize
79104
cdef size_t Lsize
80105
cdef public double [:, :] coords
106+
cdef double theta
81107

82-
def __cinit__(self, size_t n, size_t ncrit, size_t order, double [:, :] coords, double [:] mu):
108+
def __cinit__(self, size_t n, size_t ncrit, double theta, size_t order, double [:, :] coords, double [:] mu):
109+
if order > 11:
110+
raise ValueError("Order needs to be < 12")
83111
# self.particles = vector[Particle]
84-
112+
self.theta = theta
85113
# Don't remove this line, or the memory goes out of scope!
86114
self.coords = coords
87115
self.ncrit = ncrit
88116
self.order = order
89-
print('FMM Order = {}'.format(order))
117+
# print('FMM Order = {}'.format(order))
90118
xs = np.asarray(self.coords[:, 0])
91119
ys = np.asarray(self.coords[:, 1])
92120
zs = np.asarray(self.coords[:, 2])
@@ -108,16 +136,7 @@ cdef class FMM:
108136
&mu[3*i])
109137
self.particles.push_back(self.p)
110138
self.cells = build_tree(self.particles, self.root, ncrit, order)
111-
print(f"Cython: cells.size() {self.cells.size()}")
112-
113-
114-
print(f"r[0] = {self.particles[0].r[0]}, {self.particles[0].r[1]}, {self.particles[0].r[2]}")
115-
116-
print(f"mu[0] = {self.particles[0].mu[0]}, {self.particles[0].mu[1]}, {self.particles[0].mu[2]}")
117-
118-
# Need to allocate memory for the M and L arrays.
119-
#vector[double] M(cells.size() * (Nterms(order) - Nterms(0)), 0.0)
120-
#vector[double] L(cells.size() * Nterms(order - 1), 0.0)
139+
print(f"DemagFMM tree built with {self.cells.size()} cells")
121140

122141
self.Msize = Nterms(order) - Nterms(0)
123142
self.Lsize = Nterms(order - 1)
@@ -128,6 +147,12 @@ cdef class FMM:
128147
self.cells[i].M = &self.M[i*self.Msize]
129148
self.cells[i].L = &self.L[i*self.Lsize]
130149

150+
# vector[pair[size_t, size_t]] M2L_list
151+
# vector[pair[size_t, size_t]] P2P_list
152+
print("Setting up interaction list")
153+
# interact_dehnen_lazy(0, 0, self.cells, self.particles, theta, order, ncrit, self.M2L_list, self.P2P_list)
154+
build_interaction_lists(self.M2L_list, self.P2P_list, self.cells, self.particles, self.theta, order, ncrit)
155+
print("Done")
131156

132157
def P2M(self):
133158
evaluate_P2M(self.particles, self.cells, 0, self.ncrit, self.order)
@@ -137,24 +162,31 @@ cdef class FMM:
137162

138163

139164
def compute_field(self, double theta, double [:] F):
140-
F[:] = 0
141-
print('compute field')
142-
print("P2M starting")
143-
evaluate_P2M(self.particles, self.cells, 0, self.ncrit, self.order)
144-
print("M2M starting")
145-
evaluate_M2M(self.particles, self.cells, self.order)
146-
147-
print(f"mu[0] = {self.particles[0].mu[0]}, {self.particles[0].mu[1]}, {self.particles[0].mu[2]}")
148-
149-
print(np.max(self.M))
150-
151-
print("interact_dehnen starting")
152-
interact_dehnen(0, 0, self.cells, self.particles, theta, self.order, self.ncrit, &F[0])
153-
print("L2L starting")
154-
evaluate_L2L(self.cells, self.order)
155-
print("L2P starting")
156-
evaluate_L2P(self.particles, self.cells, &F[0], self.ncrit, self.order)
157-
print(F[0])
165+
#print("Computing field...")
166+
for i in range(self.Msize * self.cells.size()):
167+
self.M[i] = 0.0
168+
for i in range(self.Lsize * self.cells.size()):
169+
self.L[i] = 0.0
170+
for i in range(3*self.n):
171+
F[i] = 0.0
172+
#print('compute field')
173+
#print("P2M starting")
174+
# evaluate_P2M(self.particles, self.cells, 0, self.ncrit, self.order)
175+
# #print("M2M starting")
176+
# evaluate_M2M(self.particles, self.cells, self.order)
177+
178+
# #print(f"mu[0] = {self.particles[0].mu[0]}, {self.particles[0].mu[1]}, {self.particles[0].mu[2]}")
179+
180+
# #print(np.max(self.M))
181+
182+
# #print("interact_dehnen starting")
183+
# interact_dehnen(0, 0, self.cells, self.particles, theta, self.order, self.ncrit, &F[0])
184+
# #print("L2L starting")
185+
# evaluate_L2L(self.cells, self.order)
186+
# #print("L2P starting")
187+
# evaluate_L2P(self.particles, self.cells, &F[0], self.ncrit, self.order)
188+
# evaluate_approx(self.particles, self.cells, self.ncrit, theta, self.order, &F[0])
189+
evaluate_approx_lazy(self.particles, self.cells, self.ncrit, self.order, &F[0], self.M2L_list, self.P2P_list)
158190

159191
def compute_field_exact(self, double [:] F_exact):
160192
evaluate_direct(self.particles, &F_exact[0], self.n)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import fmmgen
22

3-
order = 5
3+
order = 13
44

55
fmmgen.generate_code(order, "operators", CSE=True, cython_wrapper=False, potential=False, field=True)
66

0 commit comments

Comments
 (0)