quadgrid 0.1
simple cartesian quad grid with particles for c++/octave
Loading...
Searching...
No Matches
grid_velocity_field_comsol.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
14
19class
20stepper {
21private :
22 std::vector<double> &x;
23 std::vector<double> &y;
24 std::vector<double> &vx;
25 std::vector<double> &vy;
26 std::vector<double> &dist;
27 std::vector<double> &dist_dx;
28 std::vector<double> &dist_dy;
29 double hx, hy;
30
31 double D;
32 std::function<double (void)> normal;
33
34public :
35
36 double dt;
37 stepper (std::vector<double> &x_, std::vector<double> &y_,
38 std::vector<double> &vx_, std::vector<double> &vy_,
39 std::vector<double> &dist_, std::vector<double> &dist_dx_,
40 std::vector<double> &dist_dy_, const double hx_, const double hy_,
41 double dt_, double D_, std::function<double (void)> &noise_)
42 : x(x_), y(y_), vx(vx_), vy(vy_), dist(dist_), dist_dx(dist_dx_),
43 dist_dy(dist_dy_), hx{hx_}, hy{hy_}, dt{dt_}, D{D_}, normal(noise_) { }
44
46
52 void operator() (int n) {
53 double dxb, dyb;
54
55 //Brownian motion displacements
56 dxb=std::sqrt (2*D*dt) * normal();
57 dyb=std::sqrt (2*D*dt) * normal();
58
59 //update particles positions
60 double dx = vx[n] * dt + dxb;
61 double dy = vy[n] * dt + dyb;
62 // Apply boundary conditions
63 if (dist[n] <= 2*dx || dist[n] < 2*dy) {
64 double normdist = std::sqrt (dist_dx[n]*dist_dx[n] + dist_dy[n]*dist_dy[n]);
65 double verx = dist_dx[n] / normdist;
66 double very = dist_dy[n] / normdist;
67 if (dist[n] < 0) { verx = x[n] > 1.6 ? -1. : 1.; very = 0.; }
68 dx = dist_dx[n]/normdist * std::max(0., dist_dx[n]*dx/normdist);
69 dy = dist_dy[n]/normdist * std::max(0., dist_dy[n]*dy/normdist);
70 }
71
72 x[n] += dx;
73 y[n] += dy;
74
75
76 // Constrain particles within domain
77 if (x[n] > 8.9) { x[n] = .1; y[n] = 1.6; };
78 y[n] = std::min (3.1, std::max (0.1, y[n]));
79 x[n] = std::min (8.9, std::max (0.1, x[n]));
80 }
81
82};
83
84
86
87int
88main () {
89
90 cdf::timer::timer_t timer;
91
92 // read data from file
93 constexpr auto filename = "velocity_comsol.json";
94
95 nlohmann::json j;
96 std::ifstream inbuf (filename);
97 inbuf >> j;
98
99 // create grid from fields in a json object
100 quadgrid_t<std::vector<double>> qg (j["grid_properties"]);
101
102 // create particles from properties in the json object
103 // and the above created grid
104 particles_t p (j, qg);
105
106 // as we will use the mass matrix we must initialize it manually
107 p.build_mass ();
108
109 // the variables defined on the grid are not class members
110 std::map<std::string, std::vector<double>> vars=
111 j["grid_vars"].get<std::map<std::string, std::vector<double>>> ();
112
113 inbuf.close ();
114
115 // Diffusion is modelled as a Gaussian process
116 std::random_device rd2; // Will be used to obtain a seed for the random number engine
117 std::mt19937 gen2;
118 std::normal_distribution<> normal;
119 std::function<double ()> noise = [&gen2, &rd2, &normal] () { return normal(gen2); };
120
121
122 // Create particle <-> grid connectivity
123 // must be updated explicitely
125
126
127 // Create the callable object to be used for moving the particles
128 // capture references to the particle positions and velocities
129 stepper state (p.x, p.y, p.dprops["VX"], p.dprops["VY"], p.dprops["DIST"],
130 p.dprops["DIST_DX"], p.dprops["DIST_DY"], qg.hx(), qg.hy(),
131 1.e-3, 1.e-1, noise);
132
133 p.g2p (vars, {"vx", "vy", "dist"}, {"VX", "VY", "DIST"});
134
135 constexpr int nsave = 300;
136 constexpr double tmax = 2 * 8.5 / 40.;
137 constexpr double dtsave = tmax / nsave;
138 double t = 0.;
139
140 // Time stepping
141 for (int isave = 0; isave < nsave; ++isave) {
142
143 // Project particle masses onto the greed and
144 // build a density field, only used for output
145 timer.tic("p2g");
146 p.p2g (vars, {"M"}, {"rho"}, true);
147 timer.toc("p2g");
148
149 timer.tic("save particles");
150 // write particle data to file
151 const std::string ofilename = "particle";
152 const std::string ofileext = ".csv";
153 const std::string numfile = std::string(".") + std::to_string(isave);
154
155 std::ofstream outbuf (ofilename + numfile + ofileext);
157 outbuf.close ();
158 timer.toc("save particles");
159
160 // write grid data to file
161 timer.tic("save grid");
162 const std::string gfilename = std::string("grid.") + std::to_string(isave) + std::string(".vts");
163 qg.vtk_export (gfilename.c_str(), vars);
164 timer.toc("save grid");
165
166 while (t < dtsave * (isave + 1)) {
167
168 // Clean up grid variables at each step!
169
170 timer.tic("clean particle properties interpolated from grid");
171 std::fill(p.dprops["VX"].begin (), p.dprops["VX"].end (), 0.0);
172 std::fill(p.dprops["VY"].begin (), p.dprops["VY"].end (), 0.0);
173 std::fill(p.dprops["DIST"].begin (), p.dprops["DIST"].end (), 0.0);
174 std::fill(p.dprops["DIST_DX"].begin (), p.dprops["DIST_DX"].end (), 0.0);
175 std::fill(p.dprops["DIST_DY"].begin (), p.dprops["DIST_DY"].end (), 0.0);
176 timer.toc("clean particle properties interpolated from grid");
177
178 timer.tic("clean rho");
179 std::fill(vars["rho"].begin (), vars["rho"].end (), 0.0);
180 timer.toc("clean rho");
181
182 // G2P : interpolate velocity and sgd at particle positions
183 timer.tic("g2p");
184 p.g2p (vars, {"vx", "vy", "dist"}, {"VX", "VY", "DIST"});
185 timer.toc("g2p");
186
187 // Compute dt
188 timer.tic("dt");
189 auto maxvx = std::max_element (p.dprops["VX"].begin (), p.dprops["VX"].end ());
190 state.dt = .5 * qg.hx() / (*maxvx);
191 auto maxvy = std::max_element (p.dprops["VY"].begin (), p.dprops["VY"].end ());
192 state.dt = std::min (state.dt, .5 * qg.hy() / (*maxvy));
193 if (t + state.dt > dtsave * (isave + 1)) state.dt = dtsave * (isave + 1) - t;
194 std::cout << "hx = " << qg.hx() << " hy = " << qg.hy() << " vx = " << (*maxvx) << " vy = " << (*maxvy) << std::endl;
195 std::cout << "t = " << t << " dt = " << state.dt << " t + dt = " << t + state.dt << std::endl;
196 timer.toc("dt");
197
198 // G2PD : compute direction away from boundary
199 timer.tic("g2pd");
200 p.g2pd (vars, {"dist"}, {"DIST_DX"}, {"DIST_DY"});
201 timer.toc("g2pd");
202
203 // Move particles
204 timer.tic("move partcles");
205
206 // You can use a loop
207 // for (int ip = 0; ip < p.num_particles; ++ip) {
208 // state(ip);
209 // }
210
211 // Or use an STL algorithm
212 range rng (0, p.num_particles);
213 std::for_each (rng.begin (), rng.end (), state);
214
215 timer.toc("move partcles");
216
217 // Rebuild particle <-> grid connectivity
218 // must be updated explicitely
219 timer.tic("init_particle_mesh");
221 timer.toc("init_particle_mesh");
222
223 t += state.dt;
224 }
225 }
226
227 // Project particle masses onto the greed and
228 // build a density field, only used for output
229 timer.tic("p2g");
230 p.p2g (vars, {"M"}, {"rho"}, true);
231 timer.toc("p2g");
232
233 timer.tic("save particles");
234 // write particle data to file
235 const std::string ofilename = "particle";
236 const std::string ofileext = ".csv";
237 const std::string numfile = std::string(".") + std::to_string(nsave);
238
239 std::ofstream outbuf (ofilename + numfile + ofileext);
241 outbuf.close ();
242 timer.toc("save particles");
243
244 // write grid data to file
245 timer.tic("save grid");
246 const std::string gfilename = std::string("grid.") + std::to_string(nsave) + std::string(".vts");
247 qg.vtk_export (gfilename.c_str(), vars);
248 timer.toc("save grid");
249
250 // print timing information
251 timer.print_report();
252 return 0;
253}
real_t hy() const
void vtk_export(const char *filename, const std::map< std::string, distributed_vector > &f) const
real_t hx() const
Functor class for moving particles.
std::vector< double > & vx
stepper(std::vector< double > &x_, std::vector< double > &y_, std::vector< double > &vx_, std::vector< double > &vy_, std::vector< double > &dist_, std::vector< double > &dist_dx_, std::vector< double > &dist_dy_, const double hx_, const double hy_, double dt_, double D_, std::function< double(void)> &noise_)
std::vector< double > & y
std::function< double(void)> normal
std::vector< double > & dist_dy
std::vector< double > & x
std::vector< double > & vy
std::vector< double > & dist_dx
std::vector< double > & dist
int main()
main implementing the time loop.
Class to represent particles embedded in a grid.
Definition particles.h:29
void p2g(std::map< std::string, device_vector_t< real_t > > &vars, bool apply_mass=false)
Map particle variables to the grid.
Definition particles.h:331
void g2pd(const std::map< std::string, device_vector_t< real_t > > &vars, GT const &gvarnames, PT const &pxvarnames, PT const &pyvarnames, bool apply_mass=false)
void g2p(const std::map< std::string, device_vector_t< real_t > > &vars, bool apply_mass=false)
Definition particles.h:401
idx_t num_particles
number of particles.
Definition particles.h:34
void init_particle_mesh()
Build grid/particles connectivity.
void print(std::ostream &os) const
Template for export function.
Definition particles.h:109
vector_t< real_t > x
x coordinate of particle positions.
Definition particles.h:35
std::map< std::string, vector_t< real_t > > dprops
double type quantities associated with the particles.
Definition particles.h:42
vector_t< real_t > y
y coordinate of particle positions.
Definition particles.h:36
void build_mass()
Construct a mass matrix.
Definition counter.h:7
iterator begin() const
Definition counter.h:33
iterator end() const
Definition counter.h:34