quadgrid 0.1
simple cartesian quad grid with particles for c++/octave
Loading...
Searching...
No Matches
grid_velocity_field_thrust.cpp
Go to the documentation of this file.
1#include <json.hpp>
2#include <particles.h>
3
4#include <fstream>
5#include <iostream>
6#include <map>
7#include <random>
8#include <vector>
9
10#include "counter.h"
11#include <timer.h>
12#include <quadgrid_config.h>
13
15
20template<typename PVAR_t>
21class
22stepper {
23private :
24 PVAR_t x;
25 PVAR_t y;
26 PVAR_t vx;
27 PVAR_t vy;
28
30 //std::function<real_t (void)> normal; DOESNT WORK ON DEVICE
31
32public :
33
34 stepper (PVAR_t x_, PVAR_t y_,
35 PVAR_t vx_, PVAR_t vy_,
36 real_t dt_, real_t D_)
37 : x(x_), y(y_), vx(vx_), vy(vy_), dt{dt_}, D{D_} { }
38
40
46 DEVICE
47 void operator() (int n) {
48 //real_t dxb, dyb;
49
50 //Brownian motion displacements
51 //dxb=std::sqrt (2*D*dt) * normal();
52 //dyb=std::sqrt (2*D*dt) * normal();
53
54 //update particles positions
55 x[n] += vx[n] * dt; //+ dxb;
56 y[n] += vy[n] * dt; //+ dyb;
57
58 // Apply boundary conditions (unelastic walls)
59 y[n] = std::min (1.999, std::max (0.001, y[n]));
60 x[n] = std::min (1.999, std::max (0.001, x[n]));
61 }
62
63};
64
65
67
68int
69main () {
70
71 cdf::timer::timer_t timer;
72
73 // read data from file
74 constexpr auto filename = "velocity.json";
75
76 nlohmann::json j;
77 std::ifstream inbuf (filename);
78
79// Declaration of host and device variables (only if thrust is used)
80 #ifdef USE_THRUST
81 inbuf >> j;
83 std::unique_ptr<quadgrid_t<vector_t<real_t>>> qg;
84 std::unique_ptr<particles_t> p;
85 qg = std::make_unique<quadgrid_t<vector_t<real_t>>> (j["grid_properties"]);
86 p = std::make_unique<particles_t> (j, *qg);
87
88 p->build_mass();
89 p->init_particle_mesh();
90
91 std::map<std::string, vector_t<real_t>> vars=
92 j["grid_vars"].get<std::map<std::string, vector_t<real_t>>> ();
93
94 //Copy from host to device
95 p->memcpy_host_to_device();
96
97 for (const auto & g : vars)
98 p->device_grid_vars[g.first] = g.second;
99
100 inbuf.close ();
101
102 // Create the callable object to be used for moving the particles
103 // capture references to the particle positions and velocities
104 stepper state (thrust::raw_pointer_cast(p->device_x.data()), thrust::raw_pointer_cast(p->device_y.data()), thrust::raw_pointer_cast(p->device_dprops["VX"].data()), thrust::raw_pointer_cast(p->device_dprops["VY"].data()), 1., 1.e-5);
105
106// Create iterator for thrust::for_each
107 thrust::counting_iterator<idx_t> first_p(0), last_p(p -> num_particles);
108
109 #else
110 inbuf >> j;
111
112 // create grid from fields in a json object
113 quadgrid_t<vector_t<real_t>> qg (j["grid_properties"]);
114
115 // create particles from properties in the json object
116 // and the above created grid
117 particles_t p (j, qg);
118
119 // as we will use the mass matrix we must initialize it manually
120 p.build_mass ();
121
122 // the variables defined on the grid are not class members
123 std::map<std::string, vector_t<real_t>> vars=
124 j["grid_vars"].get<std::map<std::string, vector_t<real_t>>> ();
125
126 inbuf.close ();
127
128 // Diffusion is modelled as a Gaussian process
129 /*std::random_device rd2; // Will be used to obtain a seed for the random number engine
130 std::mt19937 gen2;
131 std::normal_distribution<> normal;
132 std::function<real_t ()> noise = [&gen2, &rd2, &normal] () { return normal(gen2); };*/
133
134 // Create the callable object to be used for moving the particles
135 // capture references to the particle positions and velocities
136 stepper state (p.x.data(), p.y.data(), p.dprops["VX"].data(), p.dprops["VY"].data(), 1., 1.e-5);
137
138 // Create particle <-> grid connectivity
139 // must be updated explicitely
140 p.init_particle_mesh ();
141
142 #endif
143
144
145 // Time stepping
146 for (int it = 0; it < 1000; ++it) {
147
148 #ifdef USE_THRUST
149 thrust::fill(p->device_dprops["VX"].begin (), p->device_dprops["VX"].end (), 0.0);
150 thrust::fill(p->device_dprops["VX"].begin (), p->device_dprops["VY"].end (), 0.0);
151 thrust::fill(p->device_grid_vars["rho"].begin (), p->device_grid_vars["rho"].end (), 0.0);
152 #else
153 // Clean up grid variables at each step!
154 std::fill(p.dprops["VX"].begin (), p.dprops["VX"].end (), 0.0);
155 std::fill(p.dprops["VY"].begin (), p.dprops["VY"].end (), 0.0);
156 std::fill(vars["rho"].begin (), vars["rho"].end (), 0.0);
157 #endif
158
159 // G2P : interpolate velocity at particle positions
160 timer.tic("g2p");
161 #ifdef USE_THRUST
162 p->g2p(p->device_grid_vars, {"vx", "vy"}, {"VX", "VY"});
163 #else
164 p.g2p (vars, {"vx", "vy"}, {"VX", "VY"});
165 #endif
166
167 timer.toc("g2p");
168
169 // Move particles
170 timer.tic("move partcles");
171
172 // You can use a loop
173 // for (int ip = 0; ip < p.num_particles; ++ip) {
174 // state(ip);
175 // }
176
177 // Or use an STL algorithm
178 #ifdef USE_THRUST
179 thrust::for_each(thrust::device, first_p, last_p, state);
180 #else
181 // Or use an STL algorithm
182 range rng (0, p.num_particles);
183 std::for_each (rng.begin (), rng.end (), state);
184 #endif
185
186
187 timer.toc("move partcles");
188
189 // Rebuild particle <-> grid connectivity
190 // must be updated explicitely
191 timer.tic("init_particle_mesh");
192 #ifdef USE_THRUST
193 p->update_ptcl_to_grd<particles_t::update_ptcl_to_grd_device>();
194 #else
195 p.update_ptcl_to_grd<particles_t::update_ptcl_to_grd_host>();
196 #endif
197
198 timer.toc("init_particle_mesh");
199
200 // Project particle masses onto the greed and
201 // build a density field, only used for output
202 timer.tic("p2g");
203 #ifdef USE_THRUST
204 p->p2g (p->device_grid_vars, {"M"}, {"rho"}, true);
205 #else
206 p.p2g (vars, {"M"}, {"rho"}, true);
207 #endif
208
209 timer.toc("p2g");
210
211 // Don't save at every timestep
212 if (it % 50 == 0) {
213 #ifdef USE_THRUST
214 p->memcpy_device_to_host();
215 //The following copy cannot be included in the memcpy function since vars is not defined in particles.h
216 thrust::copy (p->device_grid_vars["rho"].cbegin(), p->device_grid_vars["rho"].cend(), vars.at("rho").begin());
217
218 // write particle data to file
219 const std::string ofilename = "particle";
220 const std::string ofileext = ".csv";
221 const std::string numfile = std::string(".") + std::to_string(it);
222
223 std::ofstream outbuf (ofilename + numfile + ofileext);
224 p->print<particles_t::output_format::csv> (outbuf);
225
226 outbuf.close ();
227
228 // write grid data to file
229 const std::string gfilename = std::string("grid.") + std::to_string(it) + std::string(".vts");
230 qg->vtk_export (gfilename.c_str(), vars);
231 #else
232 // write particle data to file
233 const std::string ofilename = "particle";
234 const std::string ofileext = ".csv";
235 const std::string numfile = std::string(".") + std::to_string(it);
236
237 std::ofstream outbuf (ofilename + numfile + ofileext);
238 p.print<particles_t::output_format::csv> (outbuf);
239
240 outbuf.close ();
241
242 // write grid data to file
243 const std::string gfilename = std::string("grid.") + std::to_string(it) + std::string(".vts");
244 qg.vtk_export (gfilename.c_str(), vars);
245 #endif
246
247 }
248 }
249
250 // print timing information
251 timer.print_report();
252 return 0;
253}
Functor class for moving particles.
std::vector< double > & vx
std::vector< double > & y
stepper(PVAR_t x_, PVAR_t y_, PVAR_t vx_, PVAR_t vy_, real_t dt_, real_t D_)
std::vector< double > & x
std::vector< double > & vy
int main()
main implementing the time loop.
#define DEVICE
double real_t
Class to represent particles embedded in a grid.
Definition particles.h:29
quadgrid_t< vector_t< real_t > >::idx_t idx_t
datatype for indexing into vectors of properties
Definition particles.h:32
Definition counter.h:7
iterator begin() const
Definition counter.h:33
iterator end() const
Definition counter.h:34