OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
method_of_images_cylinder_unit_test.cpp
1//
2// Created by Abhinav Singh & Justina Stark on 10.06.21.
3//
4#define BOOST_TEST_DYN_LINK
5#include <iostream>
6#include "config.h"
7#include "util/common.hpp"
8#include "util/util_debug.hpp"
9#include <boost/test/unit_test.hpp>
10
11#include "Vector/vector_dist_subset.hpp"
12#include "Operators/Vector/vector_dist_operators.hpp"
13
14// For the Neumann BCs (Method of images)
15#include "BoundaryConditions/MethodOfImages.hpp"
16
17
18constexpr int x = 0;
19constexpr int y = 1;
20constexpr int z = 2;
21constexpr size_t CONCENTRATION = 0;
22constexpr size_t NORMAL = 1;
23constexpr size_t IS_SOURCE = 2;
24constexpr size_t subset_id_real = 0;
25constexpr size_t subset_id_mirror = 1;
26
27
28
29BOOST_AUTO_TEST_SUITE(MethodOfImagesTestSuite)
30 BOOST_AUTO_TEST_CASE(mirror_cylinder_base_test) {
31 const size_t sz[3] = {18, 18, 5};
32 double boxsize = 20.0;
33 double spacing_p = 10.0 / (sz[x]-1);
34 double spacing_np = 10.0 / (sz[x]-1);
35 Box<3, double> box({-2.0, -2.0, 0}, {boxsize, boxsize, (sz[z])*spacing_p});
36 size_t bc[3] = {NON_PERIODIC, NON_PERIODIC, PERIODIC};
37// Ghost<3, double> ghost(2.9*spacing_np+spacing_np/8.0);
38 const double ghost_layer_thickness = 2.9*spacing_np+spacing_np/8.0;
39// const double ghost_layer_thickness = 5.0 - 3*spacing_np/4;
40 Ghost<3, double> ghost(ghost_layer_thickness);
41
43 vd_type Particles(0,box,bc,ghost);
44 Particles.setPropNames({"Concentration", "Normal", "is_source"});
45
46 //Grid Like Particles
47 auto it = Particles.getGridIterator(sz);
48 while (it.isNext())
49 {
50 auto key = it.get();
51 double x_coord = key.get(x) * spacing_np;
52 double y_coord = key.get(y) * spacing_np;
53 double z_coord = key.get(z) * spacing_p;
54
55 if(sqrt((5.0-x_coord)*(5.0-x_coord)+(5.0-y_coord)*(5.0-y_coord))<5.0-7*spacing_np/6.0)
56 {
57 Particles.add();
58 if (key.get(x)==sz[x]-1)
59 {
60 Particles.getLastPos()[x] = boxsize-1e-6;
61 }
62 else
63 {
64 Particles.getLastPos()[x] = x_coord;
65 }
66
67 if (key.get(y)==sz[y]-1)
68 {
69 Particles.getLastPos()[y] = boxsize-1e-6;
70 }
71 else
72 {
73 Particles.getLastPos()[y] = y_coord;
74 }
75 Particles.getLastPos()[z] = z_coord;
76 Particles.getLastProp<NORMAL>()[x] = 0;
77 Particles.getLastProp<NORMAL>()[y] = 0;
78 Particles.getLastProp<NORMAL>()[z] = 0;
79 Particles.getLastProp<CONCENTRATION>() = x_coord+y_coord+z_coord;
80
81 Particles.getLastProp<IS_SOURCE>() = 0;
82 }
83 ++it;
84 }
85
86 //Adding a layer to represent geometry better. (Mirroring should only have this layer as it is slightly inside radius and the gridlike particles have been set to 0 normal)
87 int n_b=int(sz[0])*5;
88 double radius = 5.0 - 3*spacing_np/4;
89 //double Golden_angle=M_PI * (3.0 - sqrt(5.0));
90 double Golden_angle=2.0*M_PI/double(n_b);
91 int number_of_border_particles = 0;
92 for (int j=0;j<int(sz[z]);j++)
93 {
94 for(int i=1;i<=n_b;i++)
95 {
96 double Golden_theta = Golden_angle * i;
97 double x_coord = 5.0+cos(Golden_theta) * radius;
98 double y_coord = 5.0+sin(Golden_theta) * radius;
99 double z_coord = j*spacing_p;
100 Particles.add();
101 Particles.getLastPos()[x] = x_coord;
102 Particles.getLastPos()[y] = y_coord;
103 Particles.getLastPos()[z] = z_coord;
104
105 Particles.getLastProp<NORMAL>()[x] = (x_coord-5.0)/sqrt((x_coord-5.0)*(x_coord-5.0)+(y_coord-5.0)*(y_coord-5.0));
106 Particles.getLastProp<NORMAL>()[y] = (y_coord-5.0)/sqrt((x_coord-5.0)*(x_coord-5.0)+(y_coord-5.0)*(y_coord-5.0));
107 Particles.getLastProp<NORMAL>()[z] = 0.0;
108 Particles.getLastProp<CONCENTRATION>() = x_coord+y_coord+z_coord;
109
110 Particles.getLastProp<IS_SOURCE>() = 1;
111
112 number_of_border_particles++;
113 }
114 }
115 auto &v_cl = create_vcluster();
116 v_cl.sum(number_of_border_particles);
117 v_cl.execute();
118
119 if (v_cl.rank() == 0) std::cout << "Number of particles with surface normal = " << number_of_border_particles
120 << std::endl;
121 Particles.map();
122 Particles.ghost_get<NORMAL,IS_SOURCE>();
123 //We write the particles to check if the initialization is correct.
124// Particles.write("Init");
125
126 //Here Mirror Particle and do method of Images and check if it matches property 0 mirroring (x+y+z of the mirror).
127
129
130 auto dom = Particles.getDomainIterator();
131 while(dom.isNext())
132 {
133 auto key = dom.get();
134 if (Particles.template getProp<IS_SOURCE>(key) == 1)
135 {
136 keys_source.add(key);
137 }
138 ++dom;
139 }
140 size_t number_of_source_particles = keys_source.size();
141 v_cl.sum(number_of_source_particles);
142 v_cl.execute();
143 size_t number_of_real_particle_no_ghost = Particles.size_local();
144 size_t number_of_real_particle_with_ghost = Particles.size_local_with_ghost();
145
146 /*
147 if (v_cl.rank() == 0)
148 {
149 std::cout << "number_of_source_particles = " << number_of_source_particles << std::endl;
150 std::cout << "number_of_real_particle_no_ghost = " << number_of_real_particle_no_ghost << std::endl;
151 std::cout << "number_of_real_particle_with_ghost before mirroring = " << number_of_real_particle_with_ghost << std::endl;
152 }
153 */
154
155
156 // Apply Method of images to impose noflux Neumann Boundary Conditions
157 MethodOfImages<NORMAL, vd_type> NBCs(Particles, keys_source, subset_id_real, subset_id_mirror);
158 NBCs.get_mirror_particles(Particles);
159 NBCs.apply_noflux<CONCENTRATION>(Particles);
160
161 size_t number_of_mirror_particles = Particles.size_local() - number_of_real_particle_no_ghost;
162 v_cl.sum(number_of_mirror_particles);
163 v_cl.execute();
164
165 if (v_cl.rank() == 0) std::cout << "Number of mirror particles = " << number_of_mirror_particles << std::endl;
166
167 /*
168 if (v_cl.rank() == 0)
169 {
170 std::cout << "number_of_real_particle_with_ghost + mirror particles = " << Particles.size_local_with_ghost() <<
171 std::endl;
172 std::cout << "Total number of particles expected after mirroring = " << number_of_real_particle_with_ghost +
173 keys_source.size() << std::endl;
174 }
175 */
176
177 Particles.write("Cylinder_with_mirror_particles");
178
179 BOOST_CHECK(number_of_source_particles == number_of_border_particles);
180 BOOST_CHECK(number_of_mirror_particles == number_of_source_particles);
181
182 for (int i = 0; i < NBCs.key_map_source_mirror.size(); ++i)
183 {
184 openfpm::vector<size_t> row = NBCs.key_map_source_mirror.get(i);
185 vect_dist_key_dx key_source, key_mirror;
186 key_source.setKey(row.get(0));
187 key_mirror.setKey(row.get(1));
188 BOOST_CHECK(Particles.template getProp<CONCENTRATION>(key_mirror) == Particles.template getProp<CONCENTRATION>(key_source));
189 }
190
191 }
192BOOST_AUTO_TEST_SUITE_END()
193
This class represent an N-dimensional box.
Definition Box.hpp:61
Class for getting mirror particles to impose Neumann BCs.
Implementation of 1-D std::vector like structure.
size_t size()
Stub size.
Grid key for a distributed grid.
__device__ __host__ void setKey(size_t key)
set the key
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data