OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
main_vic_petsc.cpp
1
105#include "config.h"
106
107#ifdef HAVE_PETSC
108
109//#define SE_CLASS1
110//#define PRINT_STACKTRACE
111
113
114#include "interpolation/interpolation.hpp"
115#include "Grid/grid_dist_id.hpp"
116#include "Vector/vector_dist.hpp"
117#include "Matrix/SparseMatrix.hpp"
118#include "Vector/Vector.hpp"
119#include "FiniteDifference/FDScheme.hpp"
120#include "Solvers/petsc_solver.hpp"
121#include "interpolation/mp4_kernel.hpp"
122#include "Solvers/petsc_solver_AMG_report.hpp"
123
124constexpr int x = 0;
125constexpr int y = 1;
126constexpr int z = 2;
127
128// The type of the grids
130
131// The type of the particles
133
134// radius of the torus
135float ringr1 = 1.0;
136// radius of the core of the torus
137float sigma = 1.0/3.523;
138// Reynold number (If you want to use 7500.0 you have to use a grid 1600x400x400)
139//float tgtre = 7500.0;
140float tgtre = 3000.0;
141
142// Kinematic viscosity
143float nu = 1.0/tgtre;
144
145// Time step
146// float dt = 0.0025 for Re 7500
147float dt = 0.0125;
148
149#ifdef TEST_RUN
150const unsigned int nsteps = 10;
151#else
152const unsigned int nsteps = 10001;
153#endif
154
155// All the properties by index
156constexpr unsigned int vorticity = 0;
157constexpr unsigned int velocity = 0;
158constexpr unsigned int p_vel = 1;
159constexpr int rhs_part = 2;
160constexpr unsigned int old_vort = 3;
161constexpr unsigned int old_pos = 4;
162
164
165template<typename grid> void calc_and_print_max_div_and_int(grid & g_vort)
166{
168
169 g_vort.template ghost_get<vorticity>();
170 auto it5 = g_vort.getDomainIterator();
171
172 double max_vort = 0.0;
173
174 double int_vort[3] = {0.0,0.0,0.0};
175
176 while (it5.isNext())
177 {
178 auto key = it5.get();
179
180 double tmp;
181
182 tmp = 1.0f/g_vort.spacing(x)/2.0f*(g_vort.template get<vorticity>(key.move(x,1))[x] - g_vort.template get<vorticity>(key.move(x,-1))[x] ) +
183 1.0f/g_vort.spacing(y)/2.0f*(g_vort.template get<vorticity>(key.move(y,1))[y] - g_vort.template get<vorticity>(key.move(y,-1))[y] ) +
184 1.0f/g_vort.spacing(z)/2.0f*(g_vort.template get<vorticity>(key.move(z,1))[z] - g_vort.template get<vorticity>(key.move(z,-1))[z] );
185
186 int_vort[x] += g_vort.template get<vorticity>(key)[x];
187 int_vort[y] += g_vort.template get<vorticity>(key)[y];
188 int_vort[z] += g_vort.template get<vorticity>(key)[z];
189
190 if (tmp > max_vort)
191 max_vort = tmp;
192
193 ++it5;
194 }
195
196 Vcluster<> & v_cl = create_vcluster();
197 v_cl.max(max_vort);
198 v_cl.sum(int_vort[0]);
199 v_cl.sum(int_vort[1]);
200 v_cl.sum(int_vort[2]);
201 v_cl.execute();
202
203 if (v_cl.getProcessUnitID() == 0)
204 {std::cout << "Max div for vorticity " << max_vort << " Integral: " << int_vort[0] << " " << int_vort[1] << " " << int_vort[2] << std::endl;}
205
207}
208
233
234/*
235 * gr is the grid where we are initializing the vortex ring
236 * domain is the simulation domain
237 *
238 */
239void init_ring(grid_type & gr, const Box<3,float> & domain)
240{
241 // To add some noise to the vortex ring we create two random
242 // vector
243 constexpr int nk = 32;
244
245 float ak[nk];
246 float bk[nk];
247
248 for (size_t i = 0 ; i < nk ; i++)
249 {
250 ak[i] = rand()/RAND_MAX;
251 bk[i] = rand()/RAND_MAX;
252 }
253
254 // We calculate the circuitation gamma
255 float gamma = nu * tgtre;
256 float rinv2 = 1.0f/(sigma*sigma);
257 float max_vorticity = gamma*rinv2/M_PI;
258
259 // We go through the grid to initialize the vortex
260 auto it = gr.getDomainIterator();
261
262 while (it.isNext())
263 {
264 auto key_d = it.get();
265 auto key = it.getGKey(key_d);
266
267 float tx = (key.get(x)-2)*gr.spacing(x) + domain.getLow(x);
268 float ty = (key.get(y)-2)*gr.spacing(y) + domain.getLow(y);
269 float tz = (key.get(z)-2)*gr.spacing(z) + domain.getLow(z);
270 float theta1 = atan2((ty-domain.getHigh(1)/2.0f),(tz-domain.getHigh(2)/2.0f));
271
272
273 float rad1r = sqrt((ty-domain.getHigh(1)/2.0f)*(ty-domain.getHigh(1)/2.0f) + (tz-domain.getHigh(2)/2.0f)*(tz-domain.getHigh(2)/2.0f)) - ringr1;
274 float rad1t = tx - 1.0f;
275 float rad1sq = rad1r*rad1r + rad1t*rad1t;
276 float radstr = -exp(-rad1sq*rinv2)*rinv2*gamma/M_PI;
277 gr.template get<vorticity>(key_d)[x] = 0.0f;
278 gr.template get<vorticity>(key_d)[y] = -radstr * cos(theta1);
279 gr.template get<vorticity>(key_d)[z] = radstr * sin(theta1);
280
281 // kill the axis term
282
283 float rad1r_ = sqrt((ty-domain.getHigh(1)/2.0f)*(ty-domain.getHigh(1)/2.0f) + (tz-domain.getHigh(2)/2.0f)*(tz-domain.getHigh(2)/2.0f)) + ringr1;
284 float rad1sqTILDA = rad1sq*rinv2;
285 radstr = exp(-rad1sq*rinv2)*rinv2*gamma/M_PI;
286 gr.template get<vorticity>(key_d)[x] = 0.0f;
287 gr.template get<vorticity>(key_d)[y] = -radstr * cos(theta1);
288 gr.template get<vorticity>(key_d)[z] = radstr * sin(theta1);
289
290 ++it;
291 }
292}
293
295
297
298// Specification of the poisson equation for the helmotz-hodge projection
299// 3D (dims = 3). The field is a scalar value (nvar = 1), bournary are periodic
300// type of the the space is float. The grid type that store \psi
301// The others indicate which kind of Matrix to use to construct the linear system and
302// which kind of vector to construct for the right hand side. Here we use a PETSC Sparse Matrix
303// and PETSC vector. NORMAL_GRID indicate that is a standard grid (non-staggered)
304struct poisson_nn_helm
305{
307 static const unsigned int dims = 3;
309 static const unsigned int nvar = 1;
311 static const bool boundary[];
313 typedef float stype;
321 static const int grid_type = NORMAL_GRID;
322};
323
325const bool poisson_nn_helm::boundary[] = {PERIODIC,PERIODIC,PERIODIC};
326
328
329
438/*
439 * gr vorticity grid where we apply the correction
440 * domain simulation domain
441 *
442 */
443void helmotz_hodge_projection(grid_type & gr, const Box<3,float> & domain, petsc_solver<double> & solver, petsc_solver<double>::return_type & x_ , bool init)
444{
446
448
449 // Convenient constant
450 constexpr unsigned int phi = 0;
451
452 // We define a field phi_f
453 typedef Field<phi,poisson_nn_helm> phi_f;
454
455 // We assemble the poisson equation doing the
456 // poisson of the Laplacian of phi using Laplacian
457 // central scheme (where the both derivative use central scheme, not
458 // forward composed backward like usually)
460
462
464
465 // ghost get
466 gr.template ghost_get<vorticity>();
467
468 // ghost size of the psi function
470
471 // Here we create a distributed grid to store the result of the helmotz projection
473
474 // Calculate the divergence of the vortex field
475 auto it = gr.getDomainIterator();
476
477 while (it.isNext())
478 {
479 auto key = it.get();
480
481 psi.template get<phi>(key) = 1.0f/gr.spacing(x)/2.0f*(gr.template get<vorticity>(key.move(x,1))[x] - gr.template get<vorticity>(key.move(x,-1))[x] ) +
482 1.0f/gr.spacing(y)/2.0f*(gr.template get<vorticity>(key.move(y,1))[y] - gr.template get<vorticity>(key.move(y,-1))[y] ) +
483 1.0f/gr.spacing(z)/2.0f*(gr.template get<vorticity>(key.move(z,1))[z] - gr.template get<vorticity>(key.move(z,-1))[z] );
484
485 ++it;
486 }
487
489
490
491 calc_and_print_max_div_and_int(gr);
492
493
495
496 // In order to create a matrix that represent the poisson equation we have to indicate
497 // we have to indicate the maximum extension of the stencil and we we need an extra layer
498 // of points in case we have to impose particular boundary conditions.
499 Ghost<3,long int> stencil_max(2);
500
501 // Here we define our Finite difference disctetization scheme object
502 FDScheme<poisson_nn_helm> fd(stencil_max, domain, psi);
503
504 // impose the poisson equation, using right hand side psi on the full domain (psi.getDomainIterator)
505 // the template paramereter instead define which property of phi carry the righ-hand-side
506 // in this case phi has only one property, so the property 0 carry the right hand side
507 fd.template impose_dit<0>(poisson(),psi,psi.getDomainIterator());
508
510
512
513 timer tm_solve;
514 if (init == true)
515 {
516 // Set the conjugate-gradient as method to solve the linear solver
517 solver.setSolver(KSPBCGS);
518
519 // Set the absolute tolerance to determine that the method is converged
520 solver.setAbsTol(0.0001);
521
522 // Set the maximum number of iterations
523 solver.setMaxIter(500);
524
525#ifdef USE_MULTIGRID
526
527 solver.setPreconditioner(PCHYPRE_BOOMERAMG);
528 solver.setPreconditionerAMG_nl(6);
529 solver.setPreconditionerAMG_maxit(1);
530 solver.setPreconditionerAMG_relax("SOR/Jacobi");
531 solver.setPreconditionerAMG_cycleType("V",0,4);
532 solver.setPreconditionerAMG_coarsenNodalType(0);
533 solver.setPreconditionerAMG_coarsen("HMIS");
534
535
536#endif
537
538 tm_solve.start();
539
540 // Give to the solver A and b, return x, the solution
541 solver.solve(fd.getA(),x_,fd.getB());
542
543 tm_solve.stop();
544 }
545 else
546 {
547 tm_solve.start();
548 solver.solve(x_,fd.getB());
549 tm_solve.stop();
550 }
551
552 // copy the solution x to the grid psi
553 fd.template copy<phi>(x_,psi);
554
556
558
559 psi.template ghost_get<phi>();
560
561 // Correct the vorticity to make it divergence free
562
563 auto it2 = gr.getDomainIterator();
564
565 while (it2.isNext())
566 {
567 auto key = it2.get();
568
569 gr.template get<vorticity>(key)[x] -= 1.0f/2.0f/psi.spacing(x)*(psi.template get<phi>(key.move(x,1))-psi.template get<phi>(key.move(x,-1)));
570 gr.template get<vorticity>(key)[y] -= 1.0f/2.0f/psi.spacing(y)*(psi.template get<phi>(key.move(y,1))-psi.template get<phi>(key.move(y,-1)));
571 gr.template get<vorticity>(key)[z] -= 1.0f/2.0f/psi.spacing(z)*(psi.template get<phi>(key.move(z,1))-psi.template get<phi>(key.move(z,-1)));
572
573 ++it2;
574 }
575
577
578 calc_and_print_max_div_and_int(gr);
579}
580
581
598
599void remesh(particles_type & vd, grid_type & gr,Box<3,float> & domain)
600{
601 // Remove all particles because we reinitialize in a grid like position
602 vd.clear();
603
604 // Get a grid iterator
605 auto git = vd.getGridIterator(gr.getGridInfo().getSize());
606
607 // For each grid point
608 while (git.isNext())
609 {
610 // Get the grid point in global coordinates (key). p is in local coordinates
611 auto p = git.get();
612 auto key = git.get_dist();
613
614 // Add the particle
615 vd.add();
616
617 // Assign the position to the particle in a grid like way
618 vd.getLastPos()[x] = gr.spacing(x)*p.get(x) + domain.getLow(x);
619 vd.getLastPos()[y] = gr.spacing(y)*p.get(y) + domain.getLow(y);
620 vd.getLastPos()[z] = gr.spacing(z)*p.get(z) + domain.getLow(z);
621
622 // Initialize the vorticity
623 vd.template getLastProp<vorticity>()[x] = gr.template get<vorticity>(key)[x];
624 vd.template getLastProp<vorticity>()[y] = gr.template get<vorticity>(key)[y];
625 vd.template getLastProp<vorticity>()[z] = gr.template get<vorticity>(key)[z];
626
627 // next grid point
628 ++git;
629 }
630
631 // redistribute the particles
632 vd.map();
633}
634
636
637
690void comp_vel(Box<3,float> & domain, grid_type & g_vort,grid_type & g_vel, petsc_solver<double>::return_type (& phi_s)[3],petsc_solver<double> & solver)
691{
693
694 // Convenient constant
695 constexpr unsigned int phi = 0;
696
697 // We define a field phi_f
698 typedef Field<phi,poisson_nn_helm> phi_f;
699
700 // We assemble the poisson equation doing the
701 // poisson of the Laplacian of phi using Laplacian
702 // central scheme (where the both derivative use central scheme, not
703 // forward composed backward like usually)
705
707
708 // Maximum size of the stencil
710
711 // Here we create a distributed grid to store the result
714
715 // We calculate and print the maximum divergence of the vorticity
716 // and the integral of it
717 calc_and_print_max_div_and_int(g_vort);
718
719 // For each component solve a poisson
720 for (size_t i = 0 ; i < 3 ; i++)
721 {
723
724 // Copy the vorticity component i in gr_ps
725 auto it2 = gr_ps.getDomainIterator();
726
727 // calculate the velocity from the curl of phi
728 while (it2.isNext())
729 {
730 auto key = it2.get();
731
732 // copy
733 gr_ps.get<vorticity>(key) = g_vort.template get<vorticity>(key)[i];
734
735 ++it2;
736 }
737
738 // Maximum size of the stencil
739 Ghost<3,long int> stencil_max(2);
740
741 // Finite difference scheme
742 FDScheme<poisson_nn_helm> fd(stencil_max, domain, gr_ps);
743
744 // impose the poisson equation using gr_ps = vorticity for the right-hand-side (on the full domain)
745 fd.template impose_dit<phi>(poisson(),gr_ps,gr_ps.getDomainIterator());
746
747 solver.setAbsTol(0.01);
748
749 // Get the vector that represent the right-hand-side
750 Vector<double,PETSC_BASE> & b = fd.getB();
751
752 timer tm_solve;
753 tm_solve.start();
754
755 // Give to the solver A and b in this case we are giving
756 // an intitial guess phi_s calculated in the previous
757 // time step
758 solver.solve(phi_s[i],b);
759
760 tm_solve.stop();
761
762 // Calculate the residual
763
764 solError serr;
765 serr = solver.get_residual_error(phi_s[i],b);
766
767 Vcluster<> & v_cl = create_vcluster();
768 if (v_cl.getProcessUnitID() == 0)
769 {std::cout << "Solved component " << i << " Error: " << serr.err_inf << std::endl;}
770
771 // copy the solution to grid
772 fd.template copy<phi>(phi_s[i],gr_ps);
773
775
777
778 auto it3 = gr_ps.getDomainIterator();
779
780 // calculate the velocity from the curl of phi
781 while (it3.isNext())
782 {
783 auto key = it3.get();
784
785 phi_v.get<velocity>(key)[i] = gr_ps.get<phi>(key);
786
787 ++it3;
788 }
789
791 }
792
794
795 phi_v.ghost_get<phi>();
796
797 float inv_dx = 0.5f / g_vort.spacing(0);
798 float inv_dy = 0.5f / g_vort.spacing(1);
799 float inv_dz = 0.5f / g_vort.spacing(2);
800
801 auto it3 = phi_v.getDomainIterator();
802
803 // calculate the velocity from the curl of phi
804 while (it3.isNext())
805 {
806 auto key = it3.get();
807
808 float phi_xy = (phi_v.get<phi>(key.move(y,1))[x] - phi_v.get<phi>(key.move(y,-1))[x])*inv_dy;
809 float phi_xz = (phi_v.get<phi>(key.move(z,1))[x] - phi_v.get<phi>(key.move(z,-1))[x])*inv_dz;
810 float phi_yx = (phi_v.get<phi>(key.move(x,1))[y] - phi_v.get<phi>(key.move(x,-1))[y])*inv_dx;
811 float phi_yz = (phi_v.get<phi>(key.move(z,1))[y] - phi_v.get<phi>(key.move(z,-1))[y])*inv_dz;
812 float phi_zx = (phi_v.get<phi>(key.move(x,1))[z] - phi_v.get<phi>(key.move(x,-1))[z])*inv_dx;
813 float phi_zy = (phi_v.get<phi>(key.move(y,1))[z] - phi_v.get<phi>(key.move(y,-1))[z])*inv_dy;
814
815 g_vel.template get<velocity>(key)[x] = phi_zy - phi_yz;
816 g_vel.template get<velocity>(key)[y] = phi_xz - phi_zx;
817 g_vel.template get<velocity>(key)[z] = phi_yx - phi_xy;
818
819 ++it3;
820 }
821
823}
824
825
826template<unsigned int prp> void set_zero(grid_type & gr)
827{
828 auto it = gr.getDomainGhostIterator();
829
830 // calculate the velocity from the curl of phi
831 while (it.isNext())
832 {
833 auto key = it.get();
834
835 gr.template get<prp>(key)[0] = 0.0;
836 gr.template get<prp>(key)[1] = 0.0;
837 gr.template get<prp>(key)[2] = 0.0;
838
839 ++it;
840 }
841}
842
843
844template<unsigned int prp> void set_zero(particles_type & vd)
845{
846 auto it = vd.getDomainIterator();
847
848 // calculate the velocity from the curl of phi
849 while (it.isNext())
850 {
851 auto key = it.get();
852
853 vd.template getProp<prp>(key)[0] = 0.0;
854 vd.template getProp<prp>(key)[1] = 0.0;
855 vd.template getProp<prp>(key)[2] = 0.0;
856
857 ++it;
858 }
859}
860
875
876// Calculate the right hand side of the vorticity formulation
877template<typename grid> void calc_rhs(grid & g_vort, grid & g_vel, grid & g_dwp)
878{
879 // usefull constant
880 constexpr int rhs = 0;
881
882 // calculate several pre-factors for the stencil finite
883 // difference
884 float fac1 = 2.0f*nu/(g_vort.spacing(0)*g_vort.spacing(0));
885 float fac2 = 2.0f*nu/(g_vort.spacing(1)*g_vort.spacing(1));
886 float fac3 = 2.0f*nu/(g_vort.spacing(2)*g_vort.spacing(2));
887
888 float fac4 = 0.5f/(g_vort.spacing(0));
889 float fac5 = 0.5f/(g_vort.spacing(1));
890 float fac6 = 0.5f/(g_vort.spacing(2));
891
892 auto it = g_dwp.getDomainIterator();
893
894 g_vort.template ghost_get<vorticity>();
895
896 while (it.isNext())
897 {
898 auto key = it.get();
899
900 g_dwp.template get<rhs>(key)[x] = fac1*(g_vort.template get<vorticity>(key.move(x,1))[x]+g_vort.template get<vorticity>(key.move(x,-1))[x])+
901 fac2*(g_vort.template get<vorticity>(key.move(y,1))[x]+g_vort.template get<vorticity>(key.move(y,-1))[x])+
902 fac3*(g_vort.template get<vorticity>(key.move(z,1))[x]+g_vort.template get<vorticity>(key.move(z,-1))[x])-
903 2.0f*(fac1+fac2+fac3)*g_vort.template get<vorticity>(key)[x]+
904 fac4*g_vort.template get<vorticity>(key)[x]*
905 (g_vel.template get<velocity>(key.move(x,1))[x] - g_vel.template get<velocity>(key.move(x,-1))[x])+
906 fac5*g_vort.template get<vorticity>(key)[y]*
907 (g_vel.template get<velocity>(key.move(y,1))[x] - g_vel.template get<velocity>(key.move(y,-1))[x])+
908 fac6*g_vort.template get<vorticity>(key)[z]*
909 (g_vel.template get<velocity>(key.move(z,1))[x] - g_vel.template get<velocity>(key.move(z,-1))[x]);
910
911 g_dwp.template get<rhs>(key)[y] = fac1*(g_vort.template get<vorticity>(key.move(x,1))[y]+g_vort.template get<vorticity>(key.move(x,-1))[y])+
912 fac2*(g_vort.template get<vorticity>(key.move(y,1))[y]+g_vort.template get<vorticity>(key.move(y,-1))[y])+
913 fac3*(g_vort.template get<vorticity>(key.move(z,1))[y]+g_vort.template get<vorticity>(key.move(z,-1))[y])-
914 2.0f*(fac1+fac2+fac3)*g_vort.template get<vorticity>(key)[y]+
915 fac4*g_vort.template get<vorticity>(key)[x]*
916 (g_vel.template get<velocity>(key.move(x,1))[y] - g_vel.template get<velocity>(key.move(x,-1))[y])+
917 fac5*g_vort.template get<vorticity>(key)[y]*
918 (g_vel.template get<velocity>(key.move(y,1))[y] - g_vel.template get<velocity>(key.move(y,-1))[y])+
919 fac6*g_vort.template get<vorticity>(key)[z]*
920 (g_vel.template get<velocity>(key.move(z,1))[y] - g_vel.template get<velocity>(key.move(z,-1))[y]);
921
922
923 g_dwp.template get<rhs>(key)[z] = fac1*(g_vort.template get<vorticity>(key.move(x,1))[z]+g_vort.template get<vorticity>(key.move(x,-1))[z])+
924 fac2*(g_vort.template get<vorticity>(key.move(y,1))[z]+g_vort.template get<vorticity>(key.move(y,-1))[z])+
925 fac3*(g_vort.template get<vorticity>(key.move(z,1))[z]+g_vort.template get<vorticity>(key.move(z,-1))[z])-
926 2.0f*(fac1+fac2+fac3)*g_vort.template get<vorticity>(key)[z]+
927 fac4*g_vort.template get<vorticity>(key)[x]*
928 (g_vel.template get<velocity>(key.move(x,1))[z] - g_vel.template get<velocity>(key.move(x,-1))[z])+
929 fac5*g_vort.template get<vorticity>(key)[y]*
930 (g_vel.template get<velocity>(key.move(y,1))[z] - g_vel.template get<velocity>(key.move(y,-1))[z])+
931 fac6*g_vort.template get<vorticity>(key)[z]*
932 (g_vel.template get<velocity>(key.move(z,1))[z] - g_vel.template get<velocity>(key.move(z,-1))[z]);
933
934 ++it;
935 }
936}
937
939
959
960void rk_step1(particles_type & particles)
961{
962 auto it = particles.getDomainIterator();
963
964 while (it.isNext())
965 {
966 auto key = it.get();
967
968 // Save the old vorticity
969 particles.getProp<old_vort>(key)[x] = particles.getProp<vorticity>(key)[x];
970 particles.getProp<old_vort>(key)[y] = particles.getProp<vorticity>(key)[y];
971 particles.getProp<old_vort>(key)[z] = particles.getProp<vorticity>(key)[z];
972
973 particles.getProp<vorticity>(key)[x] = particles.getProp<vorticity>(key)[x] + 0.5f * dt * particles.getProp<rhs_part>(key)[x];
974 particles.getProp<vorticity>(key)[y] = particles.getProp<vorticity>(key)[y] + 0.5f * dt * particles.getProp<rhs_part>(key)[y];
975 particles.getProp<vorticity>(key)[z] = particles.getProp<vorticity>(key)[z] + 0.5f * dt * particles.getProp<rhs_part>(key)[z];
976
977 ++it;
978 }
979
980 auto it2 = particles.getDomainIterator();
981
982 while (it2.isNext())
983 {
984 auto key = it2.get();
985
986 // Save the old position
987 particles.getProp<old_pos>(key)[x] = particles.getPos(key)[x];
988 particles.getProp<old_pos>(key)[y] = particles.getPos(key)[y];
989 particles.getProp<old_pos>(key)[z] = particles.getPos(key)[z];
990
991 particles.getPos(key)[x] = particles.getPos(key)[x] + 0.5f * dt * particles.getProp<p_vel>(key)[x];
992 particles.getPos(key)[y] = particles.getPos(key)[y] + 0.5f * dt * particles.getProp<p_vel>(key)[y];
993 particles.getPos(key)[z] = particles.getPos(key)[z] + 0.5f * dt * particles.getProp<p_vel>(key)[z];
994
995 ++it2;
996 }
997
998 particles.map();
999}
1000
1002
1022
1023void rk_step2(particles_type & particles)
1024{
1025 auto it = particles.getDomainIterator();
1026
1027 while (it.isNext())
1028 {
1029 auto key = it.get();
1030
1031 particles.getProp<vorticity>(key)[x] = particles.getProp<old_vort>(key)[x] + dt * particles.getProp<rhs_part>(key)[x];
1032 particles.getProp<vorticity>(key)[y] = particles.getProp<old_vort>(key)[y] + dt * particles.getProp<rhs_part>(key)[y];
1033 particles.getProp<vorticity>(key)[z] = particles.getProp<old_vort>(key)[z] + dt * particles.getProp<rhs_part>(key)[z];
1034
1035 ++it;
1036 }
1037
1038 auto it2 = particles.getDomainIterator();
1039
1040 while (it2.isNext())
1041 {
1042 auto key = it2.get();
1043
1044 particles.getPos(key)[x] = particles.getProp<old_pos>(key)[x] + dt * particles.getProp<p_vel>(key)[x];
1045 particles.getPos(key)[y] = particles.getProp<old_pos>(key)[y] + dt * particles.getProp<p_vel>(key)[y];
1046 particles.getPos(key)[z] = particles.getProp<old_pos>(key)[z] + dt * particles.getProp<p_vel>(key)[z];
1047
1048 ++it2;
1049 }
1050
1051 particles.map();
1052}
1053
1054
1055
1057
1078template<typename grid, typename vector> void do_step(vector & particles,
1079 grid & g_vort,
1080 grid & g_vel,
1081 grid & g_dvort,
1082 Box<3,float> & domain,
1085 petsc_solver<double> & solver)
1086{
1087 constexpr int rhs = 0;
1088
1090
1091 set_zero<vorticity>(g_vort);
1092 inte.template p2m<vorticity,vorticity>(particles,g_vort);
1093
1094 g_vort.template ghost_put<add_,vorticity>();
1095
1097
1099
1100 // Calculate velocity from vorticity
1101 comp_vel(domain,g_vort,g_vel,phi_s,solver);
1102 calc_rhs(g_vort,g_vel,g_dvort);
1103
1105
1107
1108 g_dvort.template ghost_get<rhs>();
1109 g_vel.template ghost_get<velocity>();
1112 inte.template m2p<rhs,rhs_part>(g_dvort,particles);
1113 inte.template m2p<velocity,p_vel>(g_vel,particles);
1114
1116}
1117
1118template<typename vector, typename grid> void check_point_and_save(vector & particles,
1119 grid & g_vort,
1120 grid & g_vel,
1121 grid & g_dvort,
1122 size_t i)
1123{
1124 Vcluster<> & v_cl = create_vcluster();
1125
1126 if (v_cl.getProcessingUnits() < 24)
1127 {
1128 particles.write("part_out_" + std::to_string(i),VTK_WRITER | FORMAT_BINARY);
1129 g_vort.template ghost_get<vorticity>();
1130 g_vel.template ghost_get<velocity>();
1131 g_vel.write_frame("grid_velocity",i, VTK_WRITER | FORMAT_BINARY);
1132 g_vort.write_frame("grid_vorticity",i, VTK_WRITER | FORMAT_BINARY);
1133 }
1134
1135 // In order to reduce the size of the saved data we apply a threshold.
1136 // We only save particles with vorticity higher than 0.1
1138
1139 auto it_s = particles.getDomainIterator();
1140
1141 while (it_s.isNext())
1142 {
1143 auto p = it_s.get();
1144
1145 float vort_magn = sqrt(particles.template getProp<vorticity>(p)[0] * particles.template getProp<vorticity>(p)[0] +
1146 particles.template getProp<vorticity>(p)[1] * particles.template getProp<vorticity>(p)[1] +
1147 particles.template getProp<vorticity>(p)[2] * particles.template getProp<vorticity>(p)[2]);
1148
1149 if (vort_magn < 0.1)
1150 {
1151 ++it_s;
1152 continue;
1153 }
1154
1155 part_save.add();
1156
1157 part_save.getLastPos()[0] = particles.getPos(p)[0];
1158 part_save.getLastPos()[1] = particles.getPos(p)[1];
1159 part_save.getLastPos()[2] = particles.getPos(p)[2];
1160
1161 part_save.template getLastProp<0>() = vort_magn;
1162
1163 ++it_s;
1164 }
1165
1166 part_save.map();
1167
1168 // Save and HDF5 file for checkpoint restart
1169 particles.save("check_point");
1170}
1171
1190int main(int argc, char* argv[])
1191{
1192 // Initialize
1193 openfpm_init(&argc,&argv);
1194 {
1195 // Domain, a rectangle
1196 // For the grid 1600x400x400 use
1197 // Box<3,float> domain({0.0,0.0,0.0},{22.0,5.57,5.57});
1198 Box<3,float> domain({0.0,0.0,0.0},{3.57,3.57,3.57});
1199
1200 // Ghost (Not important in this case but required)
1201 Ghost<3,long int> g(2);
1202
1203 // Grid points on x=128 y=64 z=64
1204 // if we use Re = 7500
1205 // long int sz[] = {1600,400,400};
1206 long int sz[] = {96,96,96};
1207 size_t szu[] = {(size_t)sz[0],(size_t)sz[1],(size_t)sz[2]};
1208
1209 periodicity<3> bc = {{PERIODIC,PERIODIC,PERIODIC}};
1210
1211 grid_type g_vort(szu,domain,g,bc);
1212 grid_type g_vel(g_vort.getDecomposition(),szu,g);
1213 grid_type g_dvort(g_vort.getDecomposition(),szu,g);
1214 particles_type particles(g_vort.getDecomposition(),0);
1215
1216 // It store the solution to compute velocity
1217 // It is used as initial guess every time we call the solver
1220
1221 // Parallel object
1222 Vcluster<> & v_cl = create_vcluster();
1223
1224 // print out the spacing of the grid
1225 if (v_cl.getProcessUnitID() == 0)
1226 {std::cout << "SPACING " << g_vort.spacing(0) << " " << g_vort.spacing(1) << " " << g_vort.spacing(2) << std::endl;}
1227
1228 // initialize the ring step 1
1229 init_ring(g_vort,domain);
1230
1231 x_.resize(g_vort.size(),g_vort.getLocalDomainSize());
1232 x_.setZero();
1233
1234 // Create a PETSC solver to get the solution x
1235 petsc_solver<double> solver;
1236
1237 // Do the helmotz projection step 2
1238 helmotz_hodge_projection(g_vort,domain,solver,x_,true);
1239
1240 // initialize the particle on a mesh step 3
1241 remesh(particles,g_vort,domain);
1242
1243 // Get the total number of particles
1244 size_t tot_part = particles.size_local();
1245 v_cl.sum(tot_part);
1246 v_cl.execute();
1247
1248 // Now we set the size of phi_s
1249 phi_s[0].resize(g_vort.size(),g_vort.getLocalDomainSize());
1250 phi_s[1].resize(g_vort.size(),g_vort.getLocalDomainSize());
1251 phi_s[2].resize(g_vort.size(),g_vort.getLocalDomainSize());
1252
1253 // And we initially set it to zero
1254 phi_s[0].setZero();
1255 phi_s[1].setZero();
1256 phi_s[2].setZero();
1257
1258 // We create the interpolation object outside the loop cycles
1259 // to avoid to recreate it at every cycle. Internally this object
1260 // create some data-structure to optimize the conversion particle
1261 // position to sub-domain. If there are no re-balancing it is safe
1262 // to reuse-it
1264
1265 // With more than 24 core we rely on the HDF5 checkpoint restart file
1266 if (v_cl.getProcessingUnits() < 24)
1267 {g_vort.write("grid_vorticity_init", VTK_WRITER | FORMAT_BINARY);}
1268
1269
1270 // Before entering the loop we check if we want to restart from
1271 // a previous simulation
1272 size_t i = 0;
1273
1274 // if we have an argument
1275 if (argc > 1)
1276 {
1277 // take that argument
1278 std::string restart(argv[1]);
1279
1280 // convert it into number
1281 i = std::stoi(restart);
1282
1283 // load the file
1284 particles.load("check_point_" + std::to_string(i));
1285
1286 // Print to inform that we are restarting from a
1287 // particular position
1288 if (v_cl.getProcessUnitID() == 0)
1289 {std::cout << "Restarting from " << i << std::endl;}
1290 }
1291
1292 // Time Integration
1293 for ( ; i < nsteps ; i++)
1294 {
1295 // do step 4-5-6-7
1296 do_step(particles,g_vort,g_vel,g_dvort,domain,inte,phi_s,solver);
1297
1298 // do step 8
1299 rk_step1(particles);
1300
1301 // do step 9-10-11-12
1302 do_step(particles,g_vort,g_vel,g_dvort,domain,inte,phi_s,solver);
1303
1304 // do step 13
1305 rk_step2(particles);
1306
1307 // so step 14
1308 set_zero<vorticity>(g_vort);
1309 inte.template p2m<vorticity,vorticity>(particles,g_vort);
1310 g_vort.template ghost_put<add_,vorticity>();
1311
1312 // helmotz-hodge projection
1313 helmotz_hodge_projection(g_vort,domain,solver,x_,false);
1314
1315 remesh(particles,g_vort,domain);
1316
1317 // print the step number
1318 if (v_cl.getProcessUnitID() == 0)
1319 {std::cout << "Step " << i << std::endl;}
1320
1321 // every 100 steps write the output
1322 if (i % 100 == 0) {check_point_and_save(particles,g_vort,g_vel,g_dvort,i);}
1323
1324 }
1325 }
1326
1327 openfpm_finalize();
1328}
1329
1330#else
1331
1332int main(int argc, char* argv[])
1333{
1334 return 0;
1335}
1336
1337#endif
This class represent an N-dimensional box.
Definition Box.hpp:61
Finite Differences.
Definition FDScheme.hpp:127
Definition eq.hpp:83
Laplacian second order on h (spacing)
Definition Laplacian.hpp:23
Sparse Matrix implementation.
void execute()
Execute all the requests.
void sum(T &num)
Sum the numbers across all processors and get the result.
size_t getProcessUnitID()
Get the process unit id.
size_t getProcessingUnits()
Get the total number of processors.
void max(T &num)
Get the maximum number across all processors (or reduction with infinity norm)
Implementation of VCluster class.
Definition VCluster.hpp:59
Sparse Matrix implementation stub object when OpenFPM is compiled with no linear algebra support.
Definition Vector.hpp:40
void resize(size_t row, size_t row_n)
stub resize
Definition Vector.hpp:97
This is a distributed grid.
Decomposition & getDecomposition()
Get the object that store the information about the decomposition.
const grid_sm< dim, T > & getGridInfo() const
Get an object containing the grid informations.
grid_dist_iterator< dim, device_grid, decltype(device_grid::type_of_iterator()), FIXED > getDomainGhostIterator() const
It return an iterator that span the grid domain + ghost part.
St spacing(size_t i) const
Get the spacing of the grid in direction i.
grid_dist_iterator< dim, device_grid, decltype(device_grid::type_of_subiterator()), FREE > getDomainIterator() const
It return an iterator that span the full grid domain (each processor span its local domain)
__device__ __host__ const size_t(& getSize() const)[N]
Return the size of the grid as an array.
Definition grid_sm.hpp:760
Main class for interpolation Particle to mest p2m and Mesh to particle m2p.
In case T does not match the PETSC precision compilation create a stub structure.
static Vector< T > solve(const SparseMatrix< T, impl > &A, const Vector< T > &b)
Solve the linear system.
Class for cpu time benchmarking.
Definition timer.hpp:28
void stop()
Stop the timer.
Definition timer.hpp:119
void start()
Start the timer.
Definition timer.hpp:90
vect_dist_key_dx get()
Get the actual key.
Distributed vector.
size_t size_local() const
return the local size of the vector
auto getProp(vect_dist_key_dx vec_key) -> decltype(v_prp.template get< id >(vec_key.getKey()))
Get the property of an element.
grid_dist_id_iterator_dec< Decomposition > getGridIterator(const size_t(&sz)[dim])
auto getPos(vect_dist_key_dx vec_key) -> decltype(v_pos.template get< 0 >(vec_key.getKey()))
Get the position of an element.
vector_dist_iterator getDomainIterator() const
Get an iterator that traverse the particles in the domain.
void map(size_t opt=NONE)
It move all the particles that does not belong to the local processor to the respective processor.
void clear()
remove all the elements
bool write(std::string out, int opt=VTK_WRITER)
Output particle position and properties.
auto getLastPos() -> decltype(v_pos.template get< 0 >(0))
Get the position of the last element.
void save(const std::string &filename) const
Save the distributed vector on HDF5 file.
void add()
Add local particle.
void load(const std::string &filename)
Load the distributed vector from an HDF5 file.
Decomposition & getDecomposition()
Get the decomposition.
Boundary conditions.
Definition common.hpp:22
Vector< double, PETSC_BASE > Vector_type
Vector to solve the system (PETSC)
float stype
type of the spatial coordinates
SparseMatrix< double, int, PETSC_BASE > SparseMatrix_type
Sparse matrix used to sove the linear system (we use PETSC)
static const bool boundary[]
specify the boundary conditions
static const unsigned int nvar
We have only one scalar unknown.
static const unsigned int dims
Number of dimansions of the problem.
grid_dist_id< 3, float, aggregate< float > > b_grid
grid that store \psi
Meta-function to return a compatible zero-element.
It contain statistic of the error of the calculated solution.
PetscReal err_inf
infinity norm of the error