From 6f55470ae2ebbd7136af84de68b9cfcd57972021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr> Date: Fri, 14 Nov 2014 09:55:00 +0000 Subject: [PATCH] Back to previous commit to (try to) fix bug in git : it loses all history in case of file/rep renaming. --- CodesEnVrac/CodeGH/CMake | 1 + CodesEnVrac/CodeGH/CMakeLists.txt | 162 + CodesEnVrac/CodeGH/Examples/C_IN.DAT | 15 + CodesEnVrac/CodeGH/INSTALL | 32 + CodesEnVrac/CodeGH/main/main.f | 418 ++ CodesEnVrac/CodeGH/main/main_burgers.f | 154 + CodesEnVrac/CodeGH/main/main_freeb.f | 434 ++ CodesEnVrac/CodeGH/main/main_freeb_full.f | 433 ++ CodesEnVrac/CodeGH/main/main_freeb_small.f | 198 + CodesEnVrac/CodeGH/main/main_full.f | 401 ++ CodesEnVrac/CodeGH/main/main_full2.f | 416 ++ CodesEnVrac/CodeGH/main/main_full_nosplit.f | 425 ++ CodesEnVrac/CodeGH/main/main_full_split.f | 401 ++ CodesEnVrac/CodeGH/main/main_old.f | 445 ++ CodesEnVrac/CodeGH/main/main_small.f | 171 + CodesEnVrac/CodeGH/main/main_small_nosplit.f | 201 + CodesEnVrac/CodeGH/main/main_small_split.f | 165 + CodesEnVrac/CodeGH/main/main_test.f | 184 + CodesEnVrac/CodeGH/src-THI/C_IN.DAT | 16 + CodesEnVrac/CodeGH/src-THI/NotUsed/bin2asc.f | 49 + CodesEnVrac/CodeGH/src-THI/NotUsed/dfftw3d.f | 151 + .../CodeGH/src-THI/NotUsed/filter_rho.f | 128 + CodesEnVrac/CodeGH/src-THI/NotUsed/init.f | 90 + .../CodeGH/src-THI/NotUsed/init_bubble.f | 73 + .../CodeGH/src-THI/NotUsed/init_burgers.f | 27 + .../CodeGH/src-THI/NotUsed/initread_GB.f | 48 + .../CodeGH/src-THI/NotUsed/initread_full.f | 78 + .../CodeGH/src-THI/NotUsed/initread_small.f | 90 + .../CodeGH/src-THI/NotUsed/interho_cic.f | 149 + .../CodeGH/src-THI/NotUsed/interho_m4.f | 165 + .../CodeGH/src-THI/NotUsed/makefile_burgers | 53 + .../src-THI/NotUsed/makefile_burgers_nolimit | 44 + .../CodeGH/src-THI/NotUsed/makefile_freeb | 112 + .../src-THI/NotUsed/makefile_freeb_small | 38 + .../CodeGH/src-THI/NotUsed/makefile_l4 | 112 + .../CodeGH/src-THI/NotUsed/remesh_l4_tag.f | 181 + .../CodeGH/src-THI/NotUsed/remesh_rhom4.f | 379 ++ .../CodeGH/src-THI/NotUsed/remesh_tag.f | 86 + .../CodeGH/src-THI/NotUsed/remeshx_l2.f | 95 + .../CodeGH/src-THI/NotUsed/remeshx_l2_limit.f | 71 + .../CodeGH/src-THI/NotUsed/remeshx_l2_tag.f | 76 + .../CodeGH/src-THI/NotUsed/remeshx_l4.f | 83 + .../CodeGH/src-THI/NotUsed/remeshx_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshx_m4.f | 75 + .../CodeGH/src-THI/NotUsed/remeshx_omx_l4.f | 70 + .../src-THI/NotUsed/remeshx_omx_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshx_omy_l4.f | 70 + .../src-THI/NotUsed/remeshx_omy_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshx_omz_l4.f | 70 + .../src-THI/NotUsed/remeshx_omz_l4_tag.f | 171 + .../src-THI/NotUsed/remeshx_tag_limit.f | 82 + .../CodeGH/src-THI/NotUsed/remeshy_l2.f | 83 + .../CodeGH/src-THI/NotUsed/remeshy_l2_limit.f | 56 + .../CodeGH/src-THI/NotUsed/remeshy_l2_tag.f | 86 + .../CodeGH/src-THI/NotUsed/remeshy_l4.f | 83 + .../CodeGH/src-THI/NotUsed/remeshy_l4_tag.f | 178 + .../CodeGH/src-THI/NotUsed/remeshy_m4.f | 61 + .../CodeGH/src-THI/NotUsed/remeshy_omx_l4.f | 70 + .../src-THI/NotUsed/remeshy_omx_l4_tag.f | 178 + .../CodeGH/src-THI/NotUsed/remeshy_omy_l4.f | 70 + .../src-THI/NotUsed/remeshy_omy_l4_tag.f | 178 + .../CodeGH/src-THI/NotUsed/remeshy_omz_l4.f | 70 + .../src-THI/NotUsed/remeshy_omz_l4_tag.f | 178 + .../src-THI/NotUsed/remeshy_tag_limit.f | 92 + .../CodeGH/src-THI/NotUsed/remeshz_l2.f | 83 + .../CodeGH/src-THI/NotUsed/remeshz_l2_limit.f | 55 + .../CodeGH/src-THI/NotUsed/remeshz_l2_tag.f | 86 + .../CodeGH/src-THI/NotUsed/remeshz_l4.f | 83 + .../CodeGH/src-THI/NotUsed/remeshz_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshz_m4.f | 62 + .../CodeGH/src-THI/NotUsed/remeshz_omx_l4.f | 70 + .../src-THI/NotUsed/remeshz_omx_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshz_omy_l4.f | 70 + .../src-THI/NotUsed/remeshz_omy_l4_tag.f | 171 + .../CodeGH/src-THI/NotUsed/remeshz_omz_l4.f | 70 + .../src-THI/NotUsed/remeshz_omz_l4_tag.f | 171 + .../src-THI/NotUsed/remeshz_tag_limit.f | 91 + CodesEnVrac/CodeGH/src-THI/NotUsed/slopes.f | 54 + CodesEnVrac/CodeGH/src-THI/NotUsed/spec.f | 106 + .../CodeGH/src-THI/NotUsed/spec_balarac.f | 115 + .../CodeGH/src-THI/NotUsed/spec_energy.f | 145 + CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho.f | 107 + .../CodeGH/src-THI/NotUsed/spec_rho_orig.f | 104 + CodesEnVrac/CodeGH/src-THI/NotUsed/stension.f | 126 + .../CodeGH/src-THI/NotUsed/stension_fourier.f | 128 + .../CodeGH/src-THI/NotUsed/stension_old.f | 126 + .../CodeGH/src-THI/NotUsed/stretch_freeb.f | 77 + .../CodeGH/src-THI/NotUsed/tag_particles_l2.f | 181 + .../CodeGH/src-THI/NotUsed/tag_particles_l4.f | 147 + .../src-THI/NotUsed/tag_particles_limit.f | 185 + .../CodeGH/src-THI/NotUsed/velox_bar.f | 119 + .../CodeGH/src-THI/NotUsed/velox_burgers.f | 70 + .../CodeGH/src-THI/NotUsed/veloxaux_full.f | 112 + .../CodeGH/src-THI/NotUsed/veloxaux_small.f | 57 + .../CodeGH/src-THI/NotUsed/veloxaux_v2.f | 140 + .../CodeGH/src-THI/NotUsed/x_advect_corec.f | 87 + .../src-THI/NotUsed/x_advect_corec_limit.f | 97 + .../CodeGH/src-THI/NotUsed/x_advect_l2.f | 79 + .../CodeGH/src-THI/NotUsed/x_advect_l4.f | 124 + .../CodeGH/src-THI/NotUsed/x_advect_omy_l4.f | 118 + .../CodeGH/src-THI/NotUsed/x_advect_omz_l4.f | 117 + .../CodeGH/src-THI/NotUsed/x_advect_orig.f | 79 + .../CodeGH/src-THI/NotUsed/y_advect_corec.f | 80 + .../src-THI/NotUsed/y_advect_corec_limit.f | 82 + .../CodeGH/src-THI/NotUsed/y_advect_l2.f | 63 + .../CodeGH/src-THI/NotUsed/y_advect_l4.f | 120 + .../CodeGH/src-THI/NotUsed/y_advect_omy_l4.f | 113 + .../CodeGH/src-THI/NotUsed/y_advect_omz_l4.f | 113 + .../CodeGH/src-THI/NotUsed/y_advect_orig.f | 63 + .../CodeGH/src-THI/NotUsed/z_advect_corec.f | 79 + .../src-THI/NotUsed/z_advect_corec_limit.f | 84 + .../CodeGH/src-THI/NotUsed/z_advect_l2.f | 63 + .../CodeGH/src-THI/NotUsed/z_advect_l4.f | 113 + .../CodeGH/src-THI/NotUsed/z_advect_omy_l4.f | 106 + .../CodeGH/src-THI/NotUsed/z_advect_omz_l4.f | 106 + .../CodeGH/src-THI/NotUsed/z_advect_orig.f | 63 + CodesEnVrac/CodeGH/src-THI/README | 54 + CodesEnVrac/CodeGH/src-THI/arrays.h | 10 + CodesEnVrac/CodeGH/src-THI/diag.f | 92 + CodesEnVrac/CodeGH/src-THI/dif.f | 154 + CodesEnVrac/CodeGH/src-THI/dif_rho.f | 40 + CodesEnVrac/CodeGH/src-THI/fftw_f77.i | 17 + CodesEnVrac/CodeGH/src-THI/fortranize.h | 50 + CodesEnVrac/CodeGH/src-THI/initjet.f | 143 + CodesEnVrac/CodeGH/src-THI/initread.f | 81 + CodesEnVrac/CodeGH/src-THI/interho.f | 149 + CodesEnVrac/CodeGH/src-THI/intersm4.f90 | 372 ++ CodesEnVrac/CodeGH/src-THI/intervm4.f90 | 375 ++ CodesEnVrac/CodeGH/src-THI/main.f | 419 ++ CodesEnVrac/CodeGH/src-THI/make | 11 + CodesEnVrac/CodeGH/src-THI/makefile | 112 + CodesEnVrac/CodeGH/src-THI/param.h | 3 + CodesEnVrac/CodeGH/src-THI/param_rho.i | 3 + CodesEnVrac/CodeGH/src-THI/remesh_om.f90 | 465 ++ CodesEnVrac/CodeGH/src-THI/remesh_rho.f | 379 ++ CodesEnVrac/CodeGH/src-THI/remeshx.f | 75 + CodesEnVrac/CodeGH/src-THI/remeshx_m6.f | 83 + CodesEnVrac/CodeGH/src-THI/remeshx_tag.f | 76 + CodesEnVrac/CodeGH/src-THI/remeshy.f | 61 + CodesEnVrac/CodeGH/src-THI/remeshy_m6.f | 83 + CodesEnVrac/CodeGH/src-THI/remeshy_tag.f | 86 + CodesEnVrac/CodeGH/src-THI/remeshz.f | 62 + CodesEnVrac/CodeGH/src-THI/remeshz_m6.f | 81 + CodesEnVrac/CodeGH/src-THI/remeshz_tag.f | 86 + CodesEnVrac/CodeGH/src-THI/sfftw3d.f90 | 142 + CodesEnVrac/CodeGH/src-THI/stretch.f | 100 + CodesEnVrac/CodeGH/src-THI/tag_particles.f | 181 + CodesEnVrac/CodeGH/src-THI/velox.f | 124 + CodesEnVrac/CodeGH/src-THI/velox_x.f | 106 + CodesEnVrac/CodeGH/src-THI/velox_y.f | 104 + CodesEnVrac/CodeGH/src-THI/velox_z.f | 105 + CodesEnVrac/CodeGH/src-THI/veloxaux.f | 159 + CodesEnVrac/CodeGH/src-THI/x_advect.f | 87 + CodesEnVrac/CodeGH/src-THI/y_advect.f | 80 + CodesEnVrac/CodeGH/src-THI/z_advect.f | 79 + CodesEnVrac/CodeGH/src-common/fftw3d.f90 | 147 + CodesEnVrac/CodeGH/src-common/param.i | 2 + CodesEnVrac/CodeGH/src-sphere/NotUsed/array.h | 6 + CodesEnVrac/CodeGH/src-sphere/NotUsed/bar.f | 55 + .../CodeGH/src-sphere/NotUsed/common4grid.h | 6 + CodesEnVrac/CodeGH/src-sphere/NotUsed/diag.f | 56 + CodesEnVrac/CodeGH/src-sphere/NotUsed/dif.f | 154 + .../CodeGH/src-sphere/NotUsed/dif_om_part.f | 154 + .../CodeGH/src-sphere/NotUsed/fftw3d_new.f | 155 + .../CodeGH/src-sphere/NotUsed/fftw_f77.i | 17 + .../CodeGH/src-sphere/NotUsed/fortranize.h | 50 + .../CodeGH/src-sphere/NotUsed/main_2ways.f | 273 + .../CodeGH/src-sphere/NotUsed/makefile | 37 + .../CodeGH/src-sphere/NotUsed/pen_expl.f | 47 + .../CodeGH/src-sphere/NotUsed/pen_impl.f | 86 + .../CodeGH/src-sphere/NotUsed/poisson.f | 4477 ++++++++++++++ CodesEnVrac/CodeGH/src-sphere/NotUsed/read.f | 71 + .../src-sphere/NotUsed/remesh_lambda3.f | 630 ++ .../CodeGH/src-sphere/NotUsed/remesh_m4.f | 629 ++ .../CodeGH/src-sphere/NotUsed/stream.f | 137 + .../src-sphere/NotUsed/velox_fft_2ways.f | 127 + .../CodeGH/src-sphere/NotUsed/velox_stream.f | 52 + CodesEnVrac/CodeGH/src-sphere/NotUsed/vhat.f | 51 + CodesEnVrac/CodeGH/src-sphere/arrays.h | 7 + CodesEnVrac/CodeGH/src-sphere/dif_om.f90 | 73 + CodesEnVrac/CodeGH/src-sphere/diff_fft.f90 | 114 + CodesEnVrac/CodeGH/src-sphere/drag.f90 | 28 + .../CodeGH/src-sphere/drag_surface.f90 | 104 + CodesEnVrac/CodeGH/src-sphere/init.f90 | 63 + CodesEnVrac/CodeGH/src-sphere/intersm4.f90 | 365 ++ CodesEnVrac/CodeGH/src-sphere/intervm4.f90 | 377 ++ CodesEnVrac/CodeGH/src-sphere/main.f90 | 300 + CodesEnVrac/CodeGH/src-sphere/param.h | 5 + CodesEnVrac/CodeGH/src-sphere/pen.f90 | 69 + CodesEnVrac/CodeGH/src-sphere/pen_dif_fft.f90 | 138 + CodesEnVrac/CodeGH/src-sphere/reinit.f90 | 68 + CodesEnVrac/CodeGH/src-sphere/remesh.f90 | 579 ++ CodesEnVrac/CodeGH/src-sphere/remesh_om.f90 | 470 ++ CodesEnVrac/CodeGH/src-sphere/stretch.f90 | 64 + CodesEnVrac/CodeGH/src-sphere/velox_dif.f90 | 144 + CodesEnVrac/CodeGH/src-sphere/velox_fft.f90 | 86 + CodesEnVrac/CodeGH/src-sphere/vfix.f90 | 46 + CodesEnVrac/CodesAdrien/split_2d/Makefile | 25 + CodesEnVrac/CodesAdrien/split_2d/Makefile_old | 27 + .../CodesAdrien/split_2d/advection_mod.f90 | 555 ++ .../split_2d/donnees_limit_mod.f90 | 5 + .../CodesAdrien/split_2d/donnees_mod.f90 | 9 + CodesEnVrac/CodesAdrien/split_2d/init_mod.f90 | 144 + .../split_2d/interpolation_mod.f90 | 634 ++ CodesEnVrac/CodesAdrien/split_2d/main.f90 | 1253 ++++ CodesEnVrac/CodesAdrien/split_2d/parameter | 8 + .../CodesAdrien/split_2d/remaillage_mod.f90 | 5365 +++++++++++++++++ .../CodesAdrien/split_2d/resultats_mod.f90 | 255 + CodesEnVrac/CodesAdrien/split_2d/tab_mod.f90 | 19 + .../CodesAdrien/split_2d/utile_mod.f90 | 758 +++ .../CodesAdrien/split_3d_rapide/Makefile | 25 + .../split_3d_rapide/advection_mod.f90 | 664 ++ .../split_3d_rapide/donnees_mod.f90 | 10 + .../CodesAdrien/split_3d_rapide/init_mod.f90 | 89 + .../split_3d_rapide/interpolation_mod.f90 | 883 +++ .../CodesAdrien/split_3d_rapide/main.f90 | 706 +++ .../CodesAdrien/split_3d_rapide/parameter | 9 + .../split_3d_rapide/remaillage_mod.f90 | 4938 +++++++++++++++ .../split_3d_rapide/resultats_mod.f90 | 90 + .../CodesAdrien/split_3d_rapide/tab_mod.f90 | 14 + .../split_3d_rapide/tps_Petros.txt | 43 + .../CodesAdrien/split_3d_rapide/utile_mod.f90 | 800 +++ CodesEnVrac/LEGI/src/cart_topology.f90 | 288 + CodesEnVrac/LEGI/src/particles/advec.f90 | 141 + CodesEnVrac/LEGI/src/particles/advecX.f90 | 379 ++ CodesEnVrac/LEGI/src/particles/advecY.f90 | 379 ++ CodesEnVrac/LEGI/src/particles/advecZ.f90 | 386 ++ .../LEGI/src/particles/advec_common.f90 | 1043 ++++ CodesEnVrac/LEGI/src/precision.F90 | 27 + CodesEnVrac/LEGI/test/CMakeLists.txt | 1 + CodesEnVrac/LEGI/test/src/CMakeLists.txt | 30 + .../LEGI/test/src/Test_advec/advec_aux.f90 | 368 ++ .../test/src/Test_advec/advec_aux_common.f90 | 905 +++ .../test/src/Test_advec/advec_aux_init.f90 | 417 ++ .../LEGI/test/src/Test_advec/advec_main.f90 | 146 + .../LEGI/test/src/Test_topo/topo_aux.f90 | 277 + .../LEGI/test/src/Test_topo/topo_main.f90 | 59 + CodesEnVrac/LEGI/test/src/test_common.f90 | 411 ++ CodesEnVrac/NavierStokes3D-Penalization/CMake | 1 + .../CMakeLists.txt | 112 + .../examples/parameter | 12 + .../NavierStokes3D-Penalization/make_test_fft | 23 + .../src/Unused/test_fft.f90 | 1609 +++++ .../src/advection_mod.f90 | 711 +++ .../src/donnees_mod.f90 | 12 + .../src/drag_mod.f90 | 279 + .../NavierStokes3D-Penalization/src/four2.f90 | 12 + .../NavierStokes3D-Penalization/src/four3.f90 | 19 + .../src/fourrow.f90 | 89 + .../src/fourrow_3d.f90 | 44 + .../src/init_mod.f90 | 179 + .../src/interpolation_mod.f90 | 365 ++ .../NavierStokes3D-Penalization/src/main.f90 | 568 ++ .../NavierStokes3D-Penalization/src/nr.f90 | 2990 +++++++++ .../src/nrtype.f90 | 114 + .../src/nrutil.f90 | 1154 ++++ .../src/old_mod.f90 | 860 +++ .../src/penal_mod.f90 | 235 + .../src/remaillage_mod.f90 | 1820 ++++++ .../src/resultats_mod.f90 | 300 + .../NavierStokes3D-Penalization/src/rlft2.f90 | 52 + .../NavierStokes3D-Penalization/src/rlft3.f90 | 70 + .../src/source_mod.f90 | 521 ++ .../src/tab_mod.f90 | 23 + .../src/utile_mod.f90 | 369 ++ CodesEnVrac/Remesh/4GB/arrays.h | 10 + CodesEnVrac/Remesh/4GB/param.h | 3 + CodesEnVrac/Remesh/4GB/param.i | 3 + CodesEnVrac/Remesh/4GB/remeshx_l2.f | 96 + CodesEnVrac/Remesh/4GB/remeshx_tag.f | 86 + CodesEnVrac/Remesh/4GB/remeshy_l2.f | 82 + CodesEnVrac/Remesh/4GB/remeshy_tag.f | 86 + CodesEnVrac/Remesh/4GB/remeshz_l2.f | 82 + CodesEnVrac/Remesh/4GB/remeshz_tag.f | 86 + CodesEnVrac/Remesh/4GB/tag_particles.f | 181 + CodesEnVrac/Remesh/4GB/velox_x.f | 106 + CodesEnVrac/Remesh/4GB/velox_y.f | 104 + CodesEnVrac/Remesh/4GB/velox_z.f | 105 + CodesEnVrac/Remesh/4GB/x_advect.f | 107 + CodesEnVrac/Remesh/FFTPAR/4GB/arrays.h | 10 + CodesEnVrac/Remesh/FFTPAR/4GB/param.h | 3 + CodesEnVrac/Remesh/FFTPAR/4GB/param.i | 3 + CodesEnVrac/Remesh/FFTPAR/4GB/remeshx_l2.f | 96 + CodesEnVrac/Remesh/FFTPAR/4GB/remeshy_l2.f | 82 + CodesEnVrac/Remesh/FFTPAR/4GB/remeshz_l2.f | 82 + CodesEnVrac/Remesh/FFTPAR/4GB/velox_x.f | 106 + CodesEnVrac/Remesh/FFTPAR/4GB/velox_y.f | 104 + CodesEnVrac/Remesh/FFTPAR/4GB/velox_z.f | 105 + CodesEnVrac/Remesh/FFTPAR/4GB/x_advect.f | 80 + CodesEnVrac/Remesh/FFTPAR/4GB/y_advect.f | 65 + CodesEnVrac/Remesh/FFTPAR/4GB/z_advect.f | 64 + CodesEnVrac/Remesh/FFTPAR/Makefile | 39 + CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/arrays.h | 10 + CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.h | 3 + CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.i | 3 + .../Remesh/FFTPAR/SRC_COTTET/remeshx_l2.f | 96 + .../Remesh/FFTPAR/SRC_COTTET/velox_x.f | 106 + .../Remesh/FFTPAR/SRC_COTTET/x_advect.f | 80 + CodesEnVrac/Remesh/FFTPAR/TAGS | 242 + CodesEnVrac/Remesh/FFTPAR/data.f90 | 605 ++ CodesEnVrac/Remesh/FFTPAR/discretisation2.f90 | 157 + CodesEnVrac/Remesh/FFTPAR/discretisation3.f90 | 222 + CodesEnVrac/Remesh/FFTPAR/fft_2 | Bin 0 -> 1313096 bytes CodesEnVrac/Remesh/FFTPAR/fftpar.tar | Bin 0 -> 219648 bytes CodesEnVrac/Remesh/FFTPAR/fileio.f90 | 59 + CodesEnVrac/Remesh/FFTPAR/forcing.f90 | 173 + CodesEnVrac/Remesh/FFTPAR/init_plane_jet.f90 | 53 + CodesEnVrac/Remesh/FFTPAR/init_test_case.f90 | 39 + CodesEnVrac/Remesh/FFTPAR/initscal.f90 | 180 + CodesEnVrac/Remesh/FFTPAR/lesmodel.f90 | 321 + CodesEnVrac/Remesh/FFTPAR/main.f90 | 107 + CodesEnVrac/Remesh/FFTPAR/mpi_init.f90 | 185 + CodesEnVrac/Remesh/FFTPAR/parinit.f90 | 602 ++ CodesEnVrac/Remesh/FFTPAR/parser.f90 | 428 ++ CodesEnVrac/Remesh/FFTPAR/postprocess.f90 | 219 + CodesEnVrac/Remesh/FFTPAR/postprocess5.f90 | 89 + CodesEnVrac/Remesh/FFTPAR/postprocess6.f90 | 56 + CodesEnVrac/Remesh/FFTPAR/postprocess7.f90 | 156 + .../Remesh/FFTPAR/postprocessparaview.f90 | 338 ++ .../Remesh/FFTPAR/postprocesstools.f90 | 1480 +++++ CodesEnVrac/Remesh/FFTPAR/precision.f90 | 11 + CodesEnVrac/Remesh/FFTPAR/random.f90 | 119 + CodesEnVrac/Remesh/FFTPAR/solver.f90 | 970 +++ CodesEnVrac/Remesh/FFTPAR/solver.f90_sav | 963 +++ CodesEnVrac/Remesh/FFTPAR/solver.f90_sav2 | 987 +++ CodesEnVrac/Remesh/FFTPAR/string.f90 | 7 + CodesEnVrac/Remesh/FFTPAR/tg_init.f90 | 48 + CodesEnVrac/Remesh/FFTPAR/tools.f90 | 668 ++ CodesEnVrac/Remesh/FFTPAR/transforms.f90 | 329 + CodesEnVrac/Remesh/FFTPAR/x_advec.f90 | 296 + CodesEnVrac/Remesh/FFTPAR/y_advec.f90 | 221 + CodesEnVrac/Remesh/FFTPAR/z_advec.f90 | 221 + CodesEnVrac/Remesh/README | 10 + Docs/Devel/CodingRules.org => CodingRules.org | 0 {Docs/Devel => DevelDocs}/HowToGrid5000.org | 0 {Docs/Devel => DevelDocs}/ParmesCD.pdf | Bin .../about_data_management_on_GPU.tex | 0 Examples/Attic/NavierStokes3d.py | 188 + Examples/Attic/NavierStokes3d_RMI.py | 219 + Examples/Attic/NavierStokes3d_penal.py | 285 + Examples/Attic/NavierStokes3d_sphere.py | 278 + Examples/Attic/NavierStokes3d_vortRing.py | 233 + Examples/Attic/driver3D.py | 61 + Examples/Attic/gaussianSheared.cl | 36 + Examples/Attic/gaussianSheared.py | 75 + Examples/Attic/input.dat | 42 + Examples/Attic/inputData.dat | 54 + Examples/Attic/inputData_TG.dat | 34 + Examples/Attic/mainED.py | 79 + Examples/Attic/main_Rotating_2D.py | 70 + Examples/Attic/main_Rotating_2D_GH.py | 81 + Examples/Attic/main_Rotating_2D_GH_kernels.cl | 51 + Examples/Attic/main_Rotating_3D_GH.py | 65 + Examples/Attic/main_Rotating_3D_GH_kernels.cl | 58 + Examples/Attic/main_Shear_2D.py | 72 + Examples/Froggy/MPI_HelloWorld.py | 9 + Examples/Froggy/launcher.sh | 8 + Examples/Froggy/oarscript_basic.sh | 23 + Examples/Froggy/oarscript_gpu.sh | 26 + Examples/Tools/plot_2D.gp | 8 + Examples/Tools/plot_3D.gp | 8 + Examples/Tools/print_volume_2D.gp | 19 + Examples/Tools/print_volume_3D.gp | 19 + HySoP/CMake/CMakeListsForTests.cmake | 26 + HySoP/CMake/InstallPackage.cmake | 62 + HySoP/CMake/TestFortranAcceptsFlag.cmake | 38 + HySoP/FroggyHowTo.org | 14 + HySoP/Froggy_BuildEnv.sh | 16 + HySoP/Froggy_Env.sh | 8 + HySoP/Global_tests/README | 3 + .../testPerfAndMemForFD_and_div.py | 305 + ...PConfig.cmake.in => ParmesConfig.cmake.in} | 0 ....cmake.in => ParmesConfigVersion.cmake.in} | 0 HySoP/ParmesToSinglePrecision.patch | 947 +++ HySoP/hysop/domain/obstacle/__init__.py | 57 + HySoP/hysop/domain/obstacle/controlBox.py | 296 + HySoP/hysop/domain/obstacle/disk.py | 64 + HySoP/hysop/domain/obstacle/obstacle.py | 96 + HySoP/hysop/domain/obstacle/planes.py | 359 ++ HySoP/hysop/domain/obstacle/sphere.py | 132 + HySoP/hysop/domain/tests/test_obstacle.py | 267 + .../advection_and_remeshing_vector_2d.cl | 83 + .../advection_and_remeshing_vector_3d.cl | 90 + .../gpu/cl_src/kernels/remeshing_vector_2d.cl | 76 + .../gpu/cl_src/kernels/remeshing_vector_3d.cl | 83 + .../cl_src/remeshing/basic_noVec_vector_2d.cl | 111 + .../cl_src/remeshing/basic_noVec_vector_3d.cl | 121 + .../gpu/cl_src/remeshing/basic_vector_2d.cl | 111 + .../gpu/cl_src/remeshing/basic_vector_3d.cl | 121 + .../gpu/cl_src/remeshing/private_vector_2d.cl | 112 + .../gpu/cl_src/remeshing/private_vector_3d.cl | 122 + HySoP/hysop/gpu/gpu_particle_advection_1k.py | 237 + HySoP/hysop/gpu/gpu_particle_advection_2k.py | 281 + HySoP/hysop/mpi/tests/test_mesh.py | 61 + HySoP/hysop/operator/discrete/analytic.py | 45 + HySoP/hysop/operator/monitors/__init__.py | 19 + .../compute_forces.py} | 0 HySoP/hysop/operator/monitors/monitoring.py | 67 + HySoP/hysop/operator/monitors/printer.py | 373 ++ HySoP/hysop/operator/monitors/reader.py | 141 + .../hysop/operator/redistribute_intercomm.py | 343 ++ HySoP/hysop/test/__init__.py | 0 HySoP/hysop/test/main_unit_tests.py | 32 + HySoP/hysop/test/test_obstacle/__init__.py | 0 .../hysop/test/test_obstacle/test_obstacle.py | 70 + HySoP/hysop/test/test_operator/__init__.py | 0 .../test/test_operator/test_CondStability.py | 145 + HySoP/hysop/test/test_operator/test_Curl.py | 122 + .../test/test_operator/test_DivProduct.py | 109 + HySoP/hysop/test/test_operator/test_Forces.py | 120 + HySoP/hysop/test/test_operator/test_Grad.py | 146 + .../test/test_operator/test_GradUomega.py | 121 + .../test/test_operator/test_Penalization.py | 76 + .../test/test_operator/test_Stretching.py | 109 + .../test/test_operator/test_transport_d.py | 122 + .../test/test_particular_solvers/__init__.py | 0 .../test_EDO_erreur.py | 171 + .../test/test_particular_solvers/test_RK.py | 154 + .../test_particular_solvers/test_euler.py | 114 + HySoP/hysop/test/test_tools/__init__.py | 0 HySoP/hysop/tools/tests/test_timers.py | 44 + HySoP/hysop/tools/timers.py | 194 + HySoP/src/Unstable/LEGI/changelog | 16 + .../doc/benchmark/Benchmark/description.tex | 49 + .../src/Unstable/LEGI/doc/benchmark/bench.pdf | Bin 0 -> 156971 bytes .../src/Unstable/LEGI/doc/benchmark/bench.tex | 131 + HySoP/src/Unstable/LEGI/doc/doxygen/Doxyfile | 1525 +++++ .../LEGI/doc/doxygen/ext_doc/main_ext.f | 140 + .../LEGI/doc/doxygen/images/datalayout.eps | 264 + .../LEGI/doc/doxygen/images/datalayout.fig | 70 + .../LEGI/doc/doxygen/images/datalayout.png | Bin 0 -> 12132 bytes .../LEGI/doc/doxygen/images/dealias.eps | 3766 ++++++++++++ .../LEGI/doc/doxygen/images/dealias.png | Bin 0 -> 16369 bytes .../LEGI/doc/doxygen/images/parallel.eps | 209 + .../LEGI/doc/doxygen/images/parallel.fig | 43 + .../LEGI/doc/doxygen/images/parallel.png | Bin 0 -> 8436 bytes .../doc/doxygen/images/xycommunicator.eps | 246 + .../doc/doxygen/images/xycommunicator.fig | 63 + .../doc/doxygen/images/xycommunicator.png | Bin 0 -> 4602 bytes .../doc/doxygen/images/yzcommunicator.eps | 230 + .../doc/doxygen/images/yzcommunicator.fig | 61 + .../doc/doxygen/images/yzcommunicator.png | Bin 0 -> 4788 bytes .../src/Unstable/LEGI/example/CMakeLists.txt | 1 + .../src/Unstable/LEGI/example/advec/shear_tag | Bin 0 -> 769936 bytes .../Unstable/LEGI/example/advec/turn_sphere | Bin 0 -> 769936 bytes .../Unstable/LEGI/example/src/CMakeLists.txt | 45 + .../LEGI/example/src/advec/shear_tag.f90 | 161 + .../LEGI/example/src/advec/turn_sphere.f90 | 186 + .../src/Unstable/LEGI/test/src/CMakeLists.txt | 53 + .../LEGI/test/src/Test_advec/advec_aux.f90 | 775 +++ .../test/src/Test_advec/advec_aux_common.f90 | 892 +++ .../test/src/Test_advec/advec_aux_init.f90 | 529 ++ .../LEGI/test/src/Test_advec/advec_main.f90 | 213 + .../Unstable/LEGI/test/src/Test_io/io_aux.f90 | 98 + .../LEGI/test/src/Test_io/io_main.f90 | 78 + .../LEGI/test/src/Test_topo/topo_aux.f90 | 274 + .../test/src/Test_topo/topo_aux_interface.f90 | 72 + .../LEGI/test/src/Test_topo/topo_main.f90 | 60 + .../Unstable/LEGI/test/src/test_common.f90 | 536 ++ HySoP/src/Unstable/Plouhmans.f90 | 132 + HySoP/src/Unstable/SetsIndicators.f90 | 516 ++ HySoP/src/Unstable/TestFunctions.f90 | 380 ++ HySoP/src/Unstable/callPPM.f90 | 98 + HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp | 10 + .../interfaces/Fortran2Cpp/WrapFortran.f90 | 35 + HySoP/src/interfaces/ppm/ppm_wrapper.hpp | 104 + .../interfaces/ppm/wrap_ppm_topologies.f95 | 54 + HySoP/src/ppmInterface/CMakeLists.txt | 21 + HySoP/src/ppmInterface/Fields.f90 | 143 + HySoP/src/ppmInterface/PPMFields.f90 | 80 + HySoP/src/ppmInterface/Particles.f90 | 1445 +++++ HySoP/src/ppmInterface/Solver.f90 | 164 + HySoP/src/ppmInterface/Topology.f90 | 225 + HySoP/src/ppmInterface/callCharFunc.f90 | 39 + HySoP/src/ppmInterface/poisson_init.f90 | 597 ++ .../DiscreteTransportProblem.py | 108 + HySoP/unusedOrObsolet/GPUParticularSolver.py | 245 + .../GPUParticularSolver_GLRender.py | 276 + HySoP/unusedOrObsolet/InterpolationDOp.py | 76 + HySoP/unusedOrObsolet/ParticleField.py | 45 + HySoP/unusedOrObsolet/TagDOp.py | 158 + HySoP/unusedOrObsolet/VelocityDOp.py | 83 + HySoP/unusedOrObsolet/VelocityOp.py | 50 + HySoP/unusedOrObsolet/VolumeDOp.py | 102 + HySoP/unusedOrObsolet/continuous.py | 77 + .../cpu_data_transfer-subarray.py | 376 ++ HySoP/unusedOrObsolet/cpu_data_transfer.py | 301 + HySoP/unusedOrObsolet/cpu_data_transfer_S.py | 307 + HySoP/unusedOrObsolet/differentialOperator.py | 683 +++ .../unusedOrObsolet/differentialOperator_d.py | 443 ++ HySoP/unusedOrObsolet/discrete.py | 121 + HySoP/unusedOrObsolet/forward_euler.py | 54 + HySoP/unusedOrObsolet/gpu_analytic.py | 114 + HySoP/unusedOrObsolet/obstacle_d_old.py | 157 + HySoP/unusedOrObsolet/obstacle_old.py | 72 + .../particular_solvers/__init__.py | 6 + .../particular_solvers/basic.py | 168 + .../unusedOrObsolet/particular_solvers/gpu.py | 638 ++ .../particular_solvers/gpu_src.cl | 604 ++ .../gpu_src/advection_2D_builtin.cl | 34 + .../gpu_src/advection_2D_opt2_builtin.cl | 49 + .../gpu_src/advection_2D_opt4_builtin.cl | 53 + .../gpu_src/advection_2D_opt8_builtin.cl | 76 + .../gpu_src/advection_3D_builtin.cl | 37 + .../gpu_src/advection_3D_opt2_builtin.cl | 50 + .../gpu_src/advection_3D_opt4_builtin.cl | 54 + .../gpu_src/advection_3D_opt8_builtin.cl | 77 + ...vection_and_remesh_2D_opt4_builtin_noBC.cl | 95 + ...vection_and_remesh_2D_opt8_builtin_noBC.cl | 157 + ...ion_and_remesh_3D_opt4_builtin_private4.cl | 101 + ...nd_remesh_3D_opt4_builtin_private4_noBC.cl | 101 + ...and_remesh_m8prime_2D_opt4_builtin_noBC.cl | 107 + ...and_remesh_m8prime_2D_opt8_builtin_noBC.cl | 177 + ...remesh_m8prime_3D_opt4_builtin_private4.cl | 115 + ...h_m8prime_3D_opt4_builtin_private4_noBC.cl | 115 + .../particular_solvers/gpu_src/copy_2D.cl | 14 + .../gpu_src/copy_2D_opt2.cl | 17 + .../gpu_src/copy_3D_locMem.cl | 21 + .../gpu_src/copy_3D_opt4.cl | 22 + .../gpu_src/remeshing_2D_opt4_noBC.cl | 90 + .../gpu_src/remeshing_2D_opt4_private4.cl | 76 + .../remeshing_2D_opt4_private4_noBC.cl | 79 + .../gpu_src/remeshing_3D_opt4_private4.cl | 81 + .../gpu_src/remeshing_m8prime_2D_opt4_noBC.cl | 102 + .../remeshing_m8prime_3D_opt4_private4.cl | 95 + ...nspose_2D_xy_coalesced_locPad_Diag_opt4.cl | 36 + ...D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl | 33 + ...D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl | 37 + ...nspose_3D_xy_coalesced_locPad_Diag_opt2.cl | 33 + ...nspose_3D_xz_coalesced_Diag_bis_3DBlock.cl | 34 + ...3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl | 34 + .../gpu_src/weights_m6prime.cl | 20 + .../gpu_src/weights_m6prime_builtin.cl | 13 + .../gpu_src/weights_m6prime_opt4.cl | 13 + .../gpu_src/weights_m6prime_opt4_builtin.cl | 13 + .../gpu_src/weights_m8_prime.cl | 31 + .../gpu_src/weights_m8prime_builtin.cl | 33 + .../gpu_src/weights_m8prime_opt4_builtin.cl | 33 + .../interpolation/__init__.py | 0 .../interpolation/interpolation.py | 36 + .../interpolation/linear.py | 193 + .../particular_solvers/remesh/__init__.py | 0 .../particular_solvers/remesh/lambda1.py | 154 + .../particular_solvers/remesh/lambda2.py | 303 + .../particular_solvers/remesh/m4p.py | 87 + .../particular_solvers/remesh/m6p.py | 75 + .../particular_solvers/remesh/method.py | 36 + .../particular_solvers/solver.py | 36 + HySoP/unusedOrObsolet/runge_kutta.py | 61 + .../unusedOrObsolet/runge_kutta2stretching.py | 69 + .../unusedOrObsolet/runge_kutta3stretching.py | 84 + .../unusedOrObsolet/runge_kutta4stretching.py | 77 + HySoP/unusedOrObsolet/splitting.py | 91 + HySoP/unusedOrObsolet/synchronizeGhosts.py | 493 ++ .../unusedOrObsolet/test_cpu_data_tranfert.py | 93 + README | 10 + SandBox/ppm_interface/README | 28 + SandBox/ppm_interface/interf2ppm.f95 | 33 + SandBox/ppm_interface/interf2ppm.pyf | 26 + SandBox/ppm_interface/interf2ppm.pyf.modif | 26 + SandBox/ppm_interface/runPPM.py | 9 + SandBox/src/Mesh.hpp | 47 + SandBox/src/MeshModule.f90 | 68 + SandBox/src/modTest.f90 | 179 + SandBox/src/ppm_wrapper.hpp | 152 + todo.org | 9 +- 566 files changed, 112412 insertions(+), 8 deletions(-) create mode 120000 CodesEnVrac/CodeGH/CMake create mode 100755 CodesEnVrac/CodeGH/CMakeLists.txt create mode 100644 CodesEnVrac/CodeGH/Examples/C_IN.DAT create mode 100755 CodesEnVrac/CodeGH/INSTALL create mode 100644 CodesEnVrac/CodeGH/main/main.f create mode 100644 CodesEnVrac/CodeGH/main/main_burgers.f create mode 100644 CodesEnVrac/CodeGH/main/main_freeb.f create mode 100644 CodesEnVrac/CodeGH/main/main_freeb_full.f create mode 100644 CodesEnVrac/CodeGH/main/main_freeb_small.f create mode 100644 CodesEnVrac/CodeGH/main/main_full.f create mode 100644 CodesEnVrac/CodeGH/main/main_full2.f create mode 100644 CodesEnVrac/CodeGH/main/main_full_nosplit.f create mode 100644 CodesEnVrac/CodeGH/main/main_full_split.f create mode 100644 CodesEnVrac/CodeGH/main/main_old.f create mode 100644 CodesEnVrac/CodeGH/main/main_small.f create mode 100644 CodesEnVrac/CodeGH/main/main_small_nosplit.f create mode 100644 CodesEnVrac/CodeGH/main/main_small_split.f create mode 100644 CodesEnVrac/CodeGH/main/main_test.f create mode 100644 CodesEnVrac/CodeGH/src-THI/C_IN.DAT create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/bin2asc.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/dfftw3d.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/filter_rho.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/init.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/init_bubble.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/init_burgers.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/initread_GB.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/initread_full.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/initread_small.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/interho_cic.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/interho_m4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers_nolimit create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb_small create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_l4 create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_rhom4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_m4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_tag_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_m4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_tag_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_m4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_tag_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/slopes.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/spec.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/spec_balarac.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/spec_energy.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho_orig.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/stension.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/stension_fourier.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/stension_old.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/stretch_freeb.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/velox_bar.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/velox_burgers.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_full.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_small.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_v2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_orig.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_orig.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec_limit.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l2.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omy_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omz_l4.f create mode 100644 CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_orig.f create mode 100644 CodesEnVrac/CodeGH/src-THI/README create mode 100644 CodesEnVrac/CodeGH/src-THI/arrays.h create mode 100644 CodesEnVrac/CodeGH/src-THI/diag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/dif.f create mode 100644 CodesEnVrac/CodeGH/src-THI/dif_rho.f create mode 100644 CodesEnVrac/CodeGH/src-THI/fftw_f77.i create mode 100644 CodesEnVrac/CodeGH/src-THI/fortranize.h create mode 100644 CodesEnVrac/CodeGH/src-THI/initjet.f create mode 100644 CodesEnVrac/CodeGH/src-THI/initread.f create mode 100644 CodesEnVrac/CodeGH/src-THI/interho.f create mode 100644 CodesEnVrac/CodeGH/src-THI/intersm4.f90 create mode 100644 CodesEnVrac/CodeGH/src-THI/intervm4.f90 create mode 100644 CodesEnVrac/CodeGH/src-THI/main.f create mode 100644 CodesEnVrac/CodeGH/src-THI/make create mode 100644 CodesEnVrac/CodeGH/src-THI/makefile create mode 100644 CodesEnVrac/CodeGH/src-THI/param.h create mode 100644 CodesEnVrac/CodeGH/src-THI/param_rho.i create mode 100644 CodesEnVrac/CodeGH/src-THI/remesh_om.f90 create mode 100644 CodesEnVrac/CodeGH/src-THI/remesh_rho.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshx.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshx_m6.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshx_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshy.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshy_m6.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshy_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshz.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshz_m6.f create mode 100644 CodesEnVrac/CodeGH/src-THI/remeshz_tag.f create mode 100644 CodesEnVrac/CodeGH/src-THI/sfftw3d.f90 create mode 100644 CodesEnVrac/CodeGH/src-THI/stretch.f create mode 100644 CodesEnVrac/CodeGH/src-THI/tag_particles.f create mode 100644 CodesEnVrac/CodeGH/src-THI/velox.f create mode 100644 CodesEnVrac/CodeGH/src-THI/velox_x.f create mode 100644 CodesEnVrac/CodeGH/src-THI/velox_y.f create mode 100644 CodesEnVrac/CodeGH/src-THI/velox_z.f create mode 100644 CodesEnVrac/CodeGH/src-THI/veloxaux.f create mode 100644 CodesEnVrac/CodeGH/src-THI/x_advect.f create mode 100644 CodesEnVrac/CodeGH/src-THI/y_advect.f create mode 100644 CodesEnVrac/CodeGH/src-THI/z_advect.f create mode 100644 CodesEnVrac/CodeGH/src-common/fftw3d.f90 create mode 100644 CodesEnVrac/CodeGH/src-common/param.i create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/array.h create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/bar.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/common4grid.h create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/diag.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/dif.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/dif_om_part.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw3d_new.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw_f77.i create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/fortranize.h create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/main_2ways.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/makefile create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_expl.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_impl.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/poisson.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/read.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_lambda3.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_m4.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/stream.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_fft_2ways.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_stream.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/NotUsed/vhat.f create mode 100644 CodesEnVrac/CodeGH/src-sphere/arrays.h create mode 100644 CodesEnVrac/CodeGH/src-sphere/dif_om.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/diff_fft.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/drag.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/drag_surface.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/init.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/intersm4.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/intervm4.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/main.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/param.h create mode 100644 CodesEnVrac/CodeGH/src-sphere/pen.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/pen_dif_fft.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/reinit.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/remesh.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/remesh_om.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/stretch.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/velox_dif.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/velox_fft.f90 create mode 100644 CodesEnVrac/CodeGH/src-sphere/vfix.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/Makefile create mode 100644 CodesEnVrac/CodesAdrien/split_2d/Makefile_old create mode 100644 CodesEnVrac/CodesAdrien/split_2d/advection_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/donnees_limit_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/donnees_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/init_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/interpolation_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/main.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/parameter create mode 100644 CodesEnVrac/CodesAdrien/split_2d/remaillage_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/resultats_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/tab_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_2d/utile_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/Makefile create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/advection_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/donnees_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/init_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/interpolation_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/main.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/parameter create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/remaillage_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/resultats_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/tab_mod.f90 create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/tps_Petros.txt create mode 100644 CodesEnVrac/CodesAdrien/split_3d_rapide/utile_mod.f90 create mode 100644 CodesEnVrac/LEGI/src/cart_topology.f90 create mode 100644 CodesEnVrac/LEGI/src/particles/advec.f90 create mode 100644 CodesEnVrac/LEGI/src/particles/advecX.f90 create mode 100644 CodesEnVrac/LEGI/src/particles/advecY.f90 create mode 100644 CodesEnVrac/LEGI/src/particles/advecZ.f90 create mode 100644 CodesEnVrac/LEGI/src/particles/advec_common.f90 create mode 100644 CodesEnVrac/LEGI/src/precision.F90 create mode 100644 CodesEnVrac/LEGI/test/CMakeLists.txt create mode 100644 CodesEnVrac/LEGI/test/src/CMakeLists.txt create mode 100644 CodesEnVrac/LEGI/test/src/Test_advec/advec_aux.f90 create mode 100644 CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_common.f90 create mode 100644 CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_init.f90 create mode 100644 CodesEnVrac/LEGI/test/src/Test_advec/advec_main.f90 create mode 100644 CodesEnVrac/LEGI/test/src/Test_topo/topo_aux.f90 create mode 100644 CodesEnVrac/LEGI/test/src/Test_topo/topo_main.f90 create mode 100644 CodesEnVrac/LEGI/test/src/test_common.f90 create mode 120000 CodesEnVrac/NavierStokes3D-Penalization/CMake create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/CMakeLists.txt create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/examples/parameter create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/make_test_fft create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/Unused/test_fft.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/advection_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/donnees_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/drag_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/four2.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/four3.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/fourrow.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/fourrow_3d.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/init_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/interpolation_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/main.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/nr.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/nrtype.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/nrutil.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/old_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/penal_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/remaillage_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/resultats_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/rlft2.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/rlft3.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/source_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/tab_mod.f90 create mode 100644 CodesEnVrac/NavierStokes3D-Penalization/src/utile_mod.f90 create mode 100644 CodesEnVrac/Remesh/4GB/arrays.h create mode 100644 CodesEnVrac/Remesh/4GB/param.h create mode 100644 CodesEnVrac/Remesh/4GB/param.i create mode 100644 CodesEnVrac/Remesh/4GB/remeshx_l2.f create mode 100644 CodesEnVrac/Remesh/4GB/remeshx_tag.f create mode 100644 CodesEnVrac/Remesh/4GB/remeshy_l2.f create mode 100644 CodesEnVrac/Remesh/4GB/remeshy_tag.f create mode 100644 CodesEnVrac/Remesh/4GB/remeshz_l2.f create mode 100644 CodesEnVrac/Remesh/4GB/remeshz_tag.f create mode 100644 CodesEnVrac/Remesh/4GB/tag_particles.f create mode 100644 CodesEnVrac/Remesh/4GB/velox_x.f create mode 100644 CodesEnVrac/Remesh/4GB/velox_y.f create mode 100644 CodesEnVrac/Remesh/4GB/velox_z.f create mode 100644 CodesEnVrac/Remesh/4GB/x_advect.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/arrays.h create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/param.h create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/param.i create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/remeshx_l2.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/remeshy_l2.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/remeshz_l2.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/velox_x.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/velox_y.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/velox_z.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/x_advect.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/y_advect.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/4GB/z_advect.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/Makefile create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/arrays.h create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.h create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.i create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/remeshx_l2.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/velox_x.f create mode 100755 CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/x_advect.f create mode 100644 CodesEnVrac/Remesh/FFTPAR/TAGS create mode 100755 CodesEnVrac/Remesh/FFTPAR/data.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/discretisation2.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/discretisation3.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/fft_2 create mode 100755 CodesEnVrac/Remesh/FFTPAR/fftpar.tar create mode 100755 CodesEnVrac/Remesh/FFTPAR/fileio.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/forcing.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/init_plane_jet.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/init_test_case.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/initscal.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/lesmodel.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/main.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/mpi_init.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/parinit.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/parser.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocess.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocess5.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocess6.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocess7.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocessparaview.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/postprocesstools.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/precision.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/random.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/solver.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/solver.f90_sav create mode 100755 CodesEnVrac/Remesh/FFTPAR/solver.f90_sav2 create mode 100755 CodesEnVrac/Remesh/FFTPAR/string.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/tg_init.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/tools.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/transforms.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/x_advec.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/y_advec.f90 create mode 100755 CodesEnVrac/Remesh/FFTPAR/z_advec.f90 create mode 100644 CodesEnVrac/Remesh/README rename Docs/Devel/CodingRules.org => CodingRules.org (100%) rename {Docs/Devel => DevelDocs}/HowToGrid5000.org (100%) rename {Docs/Devel => DevelDocs}/ParmesCD.pdf (100%) rename {Docs/Devel => DevelDocs}/about_data_management_on_GPU.tex (100%) create mode 100755 Examples/Attic/NavierStokes3d.py create mode 100755 Examples/Attic/NavierStokes3d_RMI.py create mode 100755 Examples/Attic/NavierStokes3d_penal.py create mode 100755 Examples/Attic/NavierStokes3d_sphere.py create mode 100755 Examples/Attic/NavierStokes3d_vortRing.py create mode 100755 Examples/Attic/driver3D.py create mode 100644 Examples/Attic/gaussianSheared.cl create mode 100644 Examples/Attic/gaussianSheared.py create mode 100644 Examples/Attic/input.dat create mode 100644 Examples/Attic/inputData.dat create mode 100644 Examples/Attic/inputData_TG.dat create mode 100755 Examples/Attic/mainED.py create mode 100644 Examples/Attic/main_Rotating_2D.py create mode 100644 Examples/Attic/main_Rotating_2D_GH.py create mode 100644 Examples/Attic/main_Rotating_2D_GH_kernels.cl create mode 100644 Examples/Attic/main_Rotating_3D_GH.py create mode 100644 Examples/Attic/main_Rotating_3D_GH_kernels.cl create mode 100644 Examples/Attic/main_Shear_2D.py create mode 100644 Examples/Froggy/MPI_HelloWorld.py create mode 100755 Examples/Froggy/launcher.sh create mode 100755 Examples/Froggy/oarscript_basic.sh create mode 100755 Examples/Froggy/oarscript_gpu.sh create mode 100644 Examples/Tools/plot_2D.gp create mode 100644 Examples/Tools/plot_3D.gp create mode 100644 Examples/Tools/print_volume_2D.gp create mode 100644 Examples/Tools/print_volume_3D.gp create mode 100644 HySoP/CMake/CMakeListsForTests.cmake create mode 100644 HySoP/CMake/InstallPackage.cmake create mode 100644 HySoP/CMake/TestFortranAcceptsFlag.cmake create mode 100644 HySoP/FroggyHowTo.org create mode 100644 HySoP/Froggy_BuildEnv.sh create mode 100644 HySoP/Froggy_Env.sh create mode 100644 HySoP/Global_tests/README create mode 100644 HySoP/Global_tests/testPerfAndMemForFD_and_div.py rename HySoP/{HySoPConfig.cmake.in => ParmesConfig.cmake.in} (100%) rename HySoP/{HySoPConfigVersion.cmake.in => ParmesConfigVersion.cmake.in} (100%) create mode 100644 HySoP/ParmesToSinglePrecision.patch create mode 100644 HySoP/hysop/domain/obstacle/__init__.py create mode 100644 HySoP/hysop/domain/obstacle/controlBox.py create mode 100644 HySoP/hysop/domain/obstacle/disk.py create mode 100644 HySoP/hysop/domain/obstacle/obstacle.py create mode 100644 HySoP/hysop/domain/obstacle/planes.py create mode 100644 HySoP/hysop/domain/obstacle/sphere.py create mode 100644 HySoP/hysop/domain/tests/test_obstacle.py create mode 100644 HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_2d.cl create mode 100644 HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_3d.cl create mode 100644 HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_2d.cl create mode 100644 HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_3d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_2d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_3d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/basic_vector_2d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/basic_vector_3d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/private_vector_2d.cl create mode 100644 HySoP/hysop/gpu/cl_src/remeshing/private_vector_3d.cl create mode 100644 HySoP/hysop/gpu/gpu_particle_advection_1k.py create mode 100644 HySoP/hysop/gpu/gpu_particle_advection_2k.py create mode 100644 HySoP/hysop/mpi/tests/test_mesh.py create mode 100644 HySoP/hysop/operator/discrete/analytic.py create mode 100644 HySoP/hysop/operator/monitors/__init__.py rename HySoP/hysop/operator/{drag_and_lift.py => monitors/compute_forces.py} (100%) create mode 100644 HySoP/hysop/operator/monitors/monitoring.py create mode 100644 HySoP/hysop/operator/monitors/printer.py create mode 100644 HySoP/hysop/operator/monitors/reader.py create mode 100644 HySoP/hysop/operator/redistribute_intercomm.py create mode 100644 HySoP/hysop/test/__init__.py create mode 100644 HySoP/hysop/test/main_unit_tests.py create mode 100755 HySoP/hysop/test/test_obstacle/__init__.py create mode 100644 HySoP/hysop/test/test_obstacle/test_obstacle.py create mode 100644 HySoP/hysop/test/test_operator/__init__.py create mode 100755 HySoP/hysop/test/test_operator/test_CondStability.py create mode 100755 HySoP/hysop/test/test_operator/test_Curl.py create mode 100755 HySoP/hysop/test/test_operator/test_DivProduct.py create mode 100755 HySoP/hysop/test/test_operator/test_Forces.py create mode 100755 HySoP/hysop/test/test_operator/test_Grad.py create mode 100755 HySoP/hysop/test/test_operator/test_GradUomega.py create mode 100644 HySoP/hysop/test/test_operator/test_Penalization.py create mode 100755 HySoP/hysop/test/test_operator/test_Stretching.py create mode 100644 HySoP/hysop/test/test_operator/test_transport_d.py create mode 100644 HySoP/hysop/test/test_particular_solvers/__init__.py create mode 100644 HySoP/hysop/test/test_particular_solvers/test_EDO_erreur.py create mode 100644 HySoP/hysop/test/test_particular_solvers/test_RK.py create mode 100644 HySoP/hysop/test/test_particular_solvers/test_euler.py create mode 100755 HySoP/hysop/test/test_tools/__init__.py create mode 100644 HySoP/hysop/tools/tests/test_timers.py create mode 100644 HySoP/hysop/tools/timers.py create mode 100644 HySoP/src/Unstable/LEGI/changelog create mode 100644 HySoP/src/Unstable/LEGI/doc/benchmark/Benchmark/description.tex create mode 100644 HySoP/src/Unstable/LEGI/doc/benchmark/bench.pdf create mode 100644 HySoP/src/Unstable/LEGI/doc/benchmark/bench.tex create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/Doxyfile create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/ext_doc/main_ext.f create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.eps create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.fig create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.png create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.eps create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.png create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.eps create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.fig create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.png create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.eps create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.fig create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.png create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.eps create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.fig create mode 100644 HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.png create mode 100644 HySoP/src/Unstable/LEGI/example/CMakeLists.txt create mode 100755 HySoP/src/Unstable/LEGI/example/advec/shear_tag create mode 100755 HySoP/src/Unstable/LEGI/example/advec/turn_sphere create mode 100644 HySoP/src/Unstable/LEGI/example/src/CMakeLists.txt create mode 100644 HySoP/src/Unstable/LEGI/example/src/advec/shear_tag.f90 create mode 100644 HySoP/src/Unstable/LEGI/example/src/advec/turn_sphere.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/CMakeLists.txt create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_common.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_init.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_main.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_io/io_aux.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_io/io_main.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux_interface.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_main.f90 create mode 100644 HySoP/src/Unstable/LEGI/test/src/test_common.f90 create mode 100644 HySoP/src/Unstable/Plouhmans.f90 create mode 100755 HySoP/src/Unstable/SetsIndicators.f90 create mode 100755 HySoP/src/Unstable/TestFunctions.f90 create mode 100644 HySoP/src/Unstable/callPPM.f90 create mode 100644 HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp create mode 100644 HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 create mode 100644 HySoP/src/interfaces/ppm/ppm_wrapper.hpp create mode 100644 HySoP/src/interfaces/ppm/wrap_ppm_topologies.f95 create mode 100755 HySoP/src/ppmInterface/CMakeLists.txt create mode 100755 HySoP/src/ppmInterface/Fields.f90 create mode 100755 HySoP/src/ppmInterface/PPMFields.f90 create mode 100755 HySoP/src/ppmInterface/Particles.f90 create mode 100755 HySoP/src/ppmInterface/Solver.f90 create mode 100755 HySoP/src/ppmInterface/Topology.f90 create mode 100644 HySoP/src/ppmInterface/callCharFunc.f90 create mode 100755 HySoP/src/ppmInterface/poisson_init.f90 create mode 100644 HySoP/unusedOrObsolet/DiscreteTransportProblem.py create mode 100644 HySoP/unusedOrObsolet/GPUParticularSolver.py create mode 100644 HySoP/unusedOrObsolet/GPUParticularSolver_GLRender.py create mode 100644 HySoP/unusedOrObsolet/InterpolationDOp.py create mode 100644 HySoP/unusedOrObsolet/ParticleField.py create mode 100644 HySoP/unusedOrObsolet/TagDOp.py create mode 100644 HySoP/unusedOrObsolet/VelocityDOp.py create mode 100644 HySoP/unusedOrObsolet/VelocityOp.py create mode 100644 HySoP/unusedOrObsolet/VolumeDOp.py create mode 100644 HySoP/unusedOrObsolet/continuous.py create mode 100644 HySoP/unusedOrObsolet/cpu_data_transfer-subarray.py create mode 100644 HySoP/unusedOrObsolet/cpu_data_transfer.py create mode 100644 HySoP/unusedOrObsolet/cpu_data_transfer_S.py create mode 100755 HySoP/unusedOrObsolet/differentialOperator.py create mode 100755 HySoP/unusedOrObsolet/differentialOperator_d.py create mode 100644 HySoP/unusedOrObsolet/discrete.py create mode 100644 HySoP/unusedOrObsolet/forward_euler.py create mode 100644 HySoP/unusedOrObsolet/gpu_analytic.py create mode 100644 HySoP/unusedOrObsolet/obstacle_d_old.py create mode 100644 HySoP/unusedOrObsolet/obstacle_old.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/__init__.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/basic.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt2_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt4_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt8_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt2_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt4_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt8_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt4_builtin_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt8_builtin_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt4_builtin_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt8_builtin_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D_opt2.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_locMem.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_opt4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_3D_opt4_private4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_2D_opt4_noBC.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_3D_opt4_private4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_2D_xy_coalesced_locPad_Diag_opt4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_opt2.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_Diag_bis_3DBlock.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8_prime.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_opt4_builtin.cl create mode 100644 HySoP/unusedOrObsolet/particular_solvers/interpolation/__init__.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/interpolation/interpolation.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/interpolation/linear.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/__init__.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/lambda1.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/lambda2.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/m4p.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/m6p.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/remesh/method.py create mode 100644 HySoP/unusedOrObsolet/particular_solvers/solver.py create mode 100644 HySoP/unusedOrObsolet/runge_kutta.py create mode 100755 HySoP/unusedOrObsolet/runge_kutta2stretching.py create mode 100644 HySoP/unusedOrObsolet/runge_kutta3stretching.py create mode 100755 HySoP/unusedOrObsolet/runge_kutta4stretching.py create mode 100644 HySoP/unusedOrObsolet/splitting.py create mode 100644 HySoP/unusedOrObsolet/synchronizeGhosts.py create mode 100755 HySoP/unusedOrObsolet/test_cpu_data_tranfert.py create mode 100644 README create mode 100644 SandBox/ppm_interface/README create mode 100644 SandBox/ppm_interface/interf2ppm.f95 create mode 100644 SandBox/ppm_interface/interf2ppm.pyf create mode 100644 SandBox/ppm_interface/interf2ppm.pyf.modif create mode 100644 SandBox/ppm_interface/runPPM.py create mode 100644 SandBox/src/Mesh.hpp create mode 100644 SandBox/src/MeshModule.f90 create mode 100644 SandBox/src/modTest.f90 create mode 100644 SandBox/src/ppm_wrapper.hpp diff --git a/CodesEnVrac/CodeGH/CMake b/CodesEnVrac/CodeGH/CMake new file mode 120000 index 000000000..af160f912 --- /dev/null +++ b/CodesEnVrac/CodeGH/CMake @@ -0,0 +1 @@ +../../CMake \ No newline at end of file diff --git a/CodesEnVrac/CodeGH/CMakeLists.txt b/CodesEnVrac/CodeGH/CMakeLists.txt new file mode 100755 index 000000000..4c6a676ed --- /dev/null +++ b/CodesEnVrac/CodeGH/CMakeLists.txt @@ -0,0 +1,162 @@ +#======================================================= +# cmake utility to compile and install G.H. soft +# +# F. Pérignon, dec. 2011 +# +#======================================================= + +# ============= Global cmake Settings ============= +# Set minimum version for cmake +cmake_minimum_required(VERSION 2.8) +# Set policy +cmake_policy(VERSION 2.8) +# Set cmake modules directory (i.e. the one which contains all user-defined FindXXX.cmake files among other things) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake) +# Force out-of-source build +include(OutOfSourceBuild) +# Some usefull macros +include(MyTools) + +# ============= Specific settings for PPMCore ============= +# In this file (PPMCoreSettings.cmake) we set all variables +# required to compile and install PPMCore such as the name of +# the library to be created, the place where we can find the sources, +# the version number of the current package ... + +option(BUILD_SHARED_LIBS "Enable dynamic library build, default = ON" ON) +option(VERBOSE_MODE "enable verbose mode for cmake exec" ON) + +# cmake project name +set(PROJECT_NAME vicper) + +# The list of all dirs containing sources to be compiled +# Any file in those dirs will be used to create the executable +set(${PROJECT_NAME}_SRCDIRS + src-common + src-sphere +# src-THI + ) +# Matching expr for files to be compiled. +set(EXTS *.f *.f90 *.f95) +# Matching expr for headers (install purpose) +set(EXTS_HDRS *.i *.h) + +# ============= The project ============= +# Set project name and project languages +# => this automatically defines: +# - ${PROJECT_NAME}_BINARY_DIR : where you have run cmake, i.e. the place for compilation +# - ${PROJECT_NAME}_SOURCE_DIR : where sources (.f and .h and this CMakeLists.txt) are located +# Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. +project(${PROJECT_NAME} Fortran) + +# ============= Search for libraries ============= +# We search for libraries Parmes depends on and +# set the compile/link conf (-I and -L opt) +find_package(FFTW REQUIRED) +include_directories(${FFTW_INCLUDE_DIRS}) +set(LIBS ${LIBS} ${FFTW_LIBRARIES}) +if(VERBOSE_MODE) + message(STATUS "FFTW include dirs : ${FFTW_INCLUDE_DIRS}") + message(STATUS "FFTW libraries : ${FFTW_LIBRARIES}") +endif(VERBOSE_MODE) + +# ============= Prepare compilation ============= +# Force a default build type if not provided by user +# CMAKE_BUILD_TYPE = empty, Debug, Release, RelWithDebInfo or MinSizeRel. +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE RELEASE CACHE STRING "Choose the type of build, options are: None, Debug, Release, RelWithDebInfo or MinSizeRel." FORCE) +endif (NOT CMAKE_BUILD_TYPE) + +# If the project uses Fortran ... +# Set module files directory (i.e. where .mod will be created) +set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) +# Add compilation flags: +include(TestFortranAcceptsFlag) +# Try -ffree-form option (GNU) +CHECK_Fortran_ACCEPTS_FLAG(-ffree-form Fortran_HAVE_ffree_form) +if(Fortran_HAVE_ffree_form) + set(Fortran_Free_Flag "-ffree-form") +else(Fortran_HAVE_ffree_form) + # Try -free (IFORT) + CHECK_Fortran_ACCEPTS_FLAG(-free Fortran_HAVE_free) + if(Fortran_HAVE_free) + set(Fortran_Free_Flag "-free") + else(Fortran_HAVE_free) + message(FATAL_ERROR "Can not find Fortran compiler free-form flag.") + # No other tests ... todo if we need exotic compilers ... + endif(Fortran_HAVE_free) +endif(Fortran_HAVE_ffree_form) +#append_Fortran_FLAGS(${Fortran_Free_Flag}) +#append_Fortran_FLAGS("-Wall -ffixed-form") +append_Fortran_FLAGS("-fPIC")# -mcmodel medium -shared-intel") + +# ============= Source and header files list ============= +# We scan all files with matching extension in directories +# containing sources. +# Source and header files list: +foreach(_DIR ${${PROJECT_NAME}_SRCDIRS}) + set(_DIR_FILES) + foreach(_EXT ${EXTS}) # Source files + file(GLOB _DIR_FILES_EXT ${_DIR}/${_EXT}) + if(_DIR_FILES_EXT) + list(APPEND ${PROJECT_NAME}_SRC ${_DIR_FILES_EXT}) + endif() + endforeach() + foreach(_EXT ${EXTS_HDRS}) # Headers + file(GLOB _DIR_FILES_EXT ${_DIR}/${_EXT}) + if(_DIR_FILES_EXT) + list(APPEND ${PROJECT_NAME}_HDRS ${_DIR_FILES_EXT}) + endif() + endforeach() +endforeach() +# We add headers to source files +list(APPEND ${PROJECT_NAME}_SRC ${${PROJECT_NAME}_HDRS}) + +display(${PROJECT_NAME}_HDRS) + +# -I +include_directories(${${PROJECT_NAME}_SRCDIRS}) +include_directories(${CMAKE_Fortran_MODULE_DIRECTORY}) + +# ============= Creates the executable ============= +add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRC}) + +# libs to link with EXE_NAME +target_link_libraries(${PROJECT_NAME} ${LIBS}) + +# ============= Prepare install ============= +# Everything will be installed in CMAKE_INSTALL_PREFIX/lib include and share +include(InstallPackage) + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + ) + +set(INSTALL_INCLUDE_DIR include CACHE PATH + "Installation directory for header files") +install(FILES ${${PROJECT_NAME}_HDRS} DESTINATION "${INSTALL_INCLUDE_DIR}") +install(DIRECTORY ${CMAKE_BINARY_DIR}/Modules DESTINATION "${INSTALL_INCLUDE_DIR}") + +# ============= RPATH ============= +# Concerning rpath see for example http://www.itk.org/Wiki/CMake_RPATH_handling + +# -------------------------------------------- +# do not skip the full RPATH for the build tree +set(CMAKE_SKIP_BUILD_RPATH FALSE) +# when building, don't use the install RPATH already +# (but later on when installing) +set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +# the RPATH to be used when installing +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# ============= Summary ============= +if(VERBOSE_MODE) + message(STATUS "====================== Summary ======================") + message(STATUS " Compiler : ${CMAKE_Fortran_COMPILER}") + message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}") + message(STATUS " Project will be installed in ${CMAKE_INSTALL_PREFIX}") + message(STATUS "====================== ======= ======================") +endif() diff --git a/CodesEnVrac/CodeGH/Examples/C_IN.DAT b/CodesEnVrac/CodeGH/Examples/C_IN.DAT new file mode 100644 index 000000000..36bf39a26 --- /dev/null +++ b/CodesEnVrac/CodeGH/Examples/C_IN.DAT @@ -0,0 +1,15 @@ +NX - number of particles in x direction +128 +t stop +30. +coef penalisation (en facteur de 1/delt) +100000. +Reynolds ou anu selon les cas +133 +coeff LES +0. +Frequence impression resultat +0.5 +width (=eps/dx) +0.1 + diff --git a/CodesEnVrac/CodeGH/INSTALL b/CodesEnVrac/CodeGH/INSTALL new file mode 100755 index 000000000..eef5ab399 --- /dev/null +++ b/CodesEnVrac/CodeGH/INSTALL @@ -0,0 +1,32 @@ + +Pour compiler/linker/installer l'executable "vicper" + +sources : le répertoire (chemin absolu) où se trouvent les sources ET le CMakeLists.txt (i.e CodeGH du dépôt svn) +build : un répertoire n'importe où (mais pas dans les sources du code) +rep_install : là où on veut installer le binaire +rep_simu : là où on va faire tourner la simu +Nbprocs : nombre de procs dispo sur la machine + +Il faut que les compilos soient accessibles, ainsi que la lib fftw qui va avec. +Par exemple sur Abel: +module load intel/ifort-9.0 +module load fftw-3.2.2-intel + +cd build +export FC=ifort F77=ifort (ou FC=gfortran F77=gfortran, au choix) +cmake -DCMAKE_INSTALL_PREFIX=rep_install sources +make -j N +make install + + +Utilisation : +rep_simu doit contenir un C_IN.DAT avec les bons paramètres. + +cd rep_simu +rep_install/bin/vicper + +et voila ... + +Pour se simplifier la vie : +export PATH=${PATH}:rep_install/bin + diff --git a/CodesEnVrac/CodeGH/main/main.f b/CodesEnVrac/CodeGH/main/main.f new file mode 100644 index 000000000..cf528858d --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main.f @@ -0,0 +1,418 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=4.5 + t2=5. + t3=5.5 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + +c t1=3.4 +c t2=3.8 +c t3=3.6 + t4=6. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128: + nx3=128 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=1000. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.5*dx1/vmax1) +c delt=0.5*dx2/vmax + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax + delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25*dx3/dvmax) +c if ((dvmax.ne.0.).and.(korder.eq.2)) +c 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3/dx3 + k_delt3=int(delt3/delt) + if (k_delt3.eq.0) then + k_delt=int(delt/delt3) + k_delt3=1 + k_delt=k_delt+1 + delt3=delt/float(k_delt) + else + delt3=float(k_delt3)*delt + k_delt=1 + endif + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + print*,'TIME ',time + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + do 111 ksubite=1,k_delt + print*,ic,k_delt3 + if ((ic.eq.k_delt3)) then + + np_bl=3 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt2,np_bl,ntagz) + call z_advect(dt2,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + endif + + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + + endif +111 continue + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_burgers.f b/CodesEnVrac/CodeGH/main/main_burgers.f new file mode 100644 index 000000000..2d495df44 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_burgers.f @@ -0,0 +1,154 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=(xmax-xmin)/float(nx1) + dx2=(xmax-xmin)/float(nx2) + zmax=xmax + + circlim=0.00001 + nx=nx1 + dx=dx1 + + t1=0.6 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + + t1=3.4 + t2=3.8 + t3=3.6 + t4=5. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=nx1 + dx3=(xmax-xmin)/float(nx3) + + dy1=dx1 + dz1=dx1 + ny1=nx1 + nz1=nx1 + dy2=dx2 + dz2=dx2 + ny2=nx2 + nz2=nx2 + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + + call init_burgers + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + call velox_burgers(vmax,dvmax) + print*,' time, VMAX, DVmax = ',time,vmax,dvmax,dvmax/dx3 + +c determination pas de temps: + delt3=0.4*dx3/vmax +c delt3=0. + if (dvmax.ne.0.) delt3=amax1(delt3,0.2*dx3/dvmax) + print*,' CFLs ',delt3*vmax/dx3 + dt=delt3 + np_bl=1 + + + call x_advect(dt,np_bl,npart_rho,ntagx) + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + +223 continue + + time=time+dt + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(33,*) psi1(i,5,5) + write(34,*) ug(i,5,5) + enddo + close(33) + + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_freeb.f b/CodesEnVrac/CodeGH/main/main_freeb.f new file mode 100644 index 000000000..d1c324b9f --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_freeb.f @@ -0,0 +1,434 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + drho=10. + drho=0. + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + nx=nx2 + dx=dx2 + + t1=0.5 + dtcompt=0.05 + t2=0.15 + t3=0.2 + t4=0.25 + t5=0.3 + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128 ou 256: + nx3=nx1 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + +c dt max pour diffusion + dtmax=0.5*dx1*dx1/anu + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call bubble(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c seuil de omax et dvmax pour eviter les trop gros dt: + omax=amax1(omax,10.) + dvmax=amax1(dvmax,10.) + +c determination pas de temps: + if ((ic.eq.0)) then + delt=.1/abs(omax) + if (vmax1.gt.0.) delt=amax1(delt,0.5*dx1/vmax1) + delt=amin1(delt,dtmax) +c delt=0.5*dx2/vmax +c delt3=2.*dx3/vmax +c delt3=0.5*dx2/vmax + delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25/dvmax) +c if ((dvmax.ne.0.).and.(korder.eq.2)) +c 1 delt3=amax1(delt3,0.5/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3 + k_delt3=int(delt3/delt) + if (k_delt3.eq.0) then + k_delt=int(delt/delt3) + k_delt3=1 + k_delt=k_delt+1 + delt3=delt/float(k_delt) + else + delt3=float(k_delt3)*delt + k_delt=1 + endif + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + print*,'TIME ',time + + call stretch_freeb(drho) + tau=0.001 + tau=0.01 + tau=0.1 + jc=2 + call stension(tau,jc) + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + do 111 ksubite=1,k_delt + print*,ic,k_delt3 + if ((ic.eq.k_delt3)) then + + np_bl=3 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt2,np_bl,ntagz) + call z_advect(dt2,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + endif + + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + + endif +111 continue + + tcompt=tcompt+delt + if ((time.ge.t1).and.(tcompt.ge.dtcompt)) then + tcompt=0. +c if (((time.gt.t1).and.(time.le.t1+1.5*delt3)). +c 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt3)). +c 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt3)). +c 1 or.((time.gt.t5).and.(time.le.t5+1.5*delt3)). +c 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt3))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + uu=sqrt(vxg(i,j,k)**2+vyg(i,j,k)**2+vzg(i,j,k)**2) + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,uu) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_freeb_full.f b/CodesEnVrac/CodeGH/main/main_freeb_full.f new file mode 100644 index 000000000..5904f3b31 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_freeb_full.f @@ -0,0 +1,433 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + drho=10. + drho=0. + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + nx=nx2 + dx=dx2 + + t1=0.5 + dtcompt=0.05 + t2=0.15 + t3=0.2 + t4=0.25 + t5=0.3 + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128 ou 256: + nx3=nx1 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + +c dt max pour diffusion + dtmax=0.5*dx1*dx1/anu + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call bubble(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c seuil de omax et dvmax pour eviter les trop gros dt: + omax=amax1(omax,10.) + dvmax=amax1(dvmax,10.) + +c determination pas de temps: + if ((ic.eq.0)) then + delt=.1/abs(omax) + if (vmax1.gt.0.) delt=amax1(delt,0.5*dx1/vmax1) + delt=amin1(delt,dtmax) +c delt=0.5*dx2/vmax +c delt3=2.*dx3/vmax +c delt3=0.5*dx2/vmax + delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25/dvmax) +c if ((dvmax.ne.0.).and.(korder.eq.2)) +c 1 delt3=amax1(delt3,0.5/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3 + k_delt3=int(delt3/delt) + if (k_delt3.eq.0) then + k_delt=int(delt/delt3) + k_delt3=1 + k_delt=k_delt+1 + delt3=delt/float(k_delt) + else + delt3=float(k_delt3)*delt + k_delt=1 + endif + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + print*,'TIME ',time + + call stretch_freeb(drho) + tau=0.001 + tau=0.01 + tau=0.1 + jc=2 + call stension(tau,jc) + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + do 111 ksubite=1,k_delt + print*,ic,k_delt3 + if ((ic.eq.k_delt3)) then + + np_bl=3 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt2,np_bl,ntagz) + call z_advect(dt2,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + endif + + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + + endif +111 continue + + tcompt=tcompt+delt + if ((time.ge.t1).and.(tcompt.ge.dtcompt)) then + tcompt=0. +c if (((time.gt.t1).and.(time.le.t1+1.5*delt3)). +c 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt3)). +c 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt3)). +c 1 or.((time.gt.t5).and.(time.le.t5+1.5*delt3)). +c 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt3))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_freeb_small.f b/CodesEnVrac/CodeGH/main/main_freeb_small.f new file mode 100644 index 000000000..4a82e6fc8 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_freeb_small.f @@ -0,0 +1,198 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + drho=10. + drho=0. + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + nx=nx2 + dx=dx2 + + t1=0.5 + dtcompt=0.05 + t2=0.15 + t3=0.2 + t4=0.25 + t5=0.3 + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128 ou 256: + nx3=nx1 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + +c dt max pour diffusion + dtmax=0.5*dx1*dx1/anu + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + + call bubble(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=0. + istep=0 + + dt=0.01 + tau=0.1 + jc=8 + call stension(tau,jc) + do k=1,nx1 + do j=1,nx1 + do i=1,nx1 + omg1(i,j,k)=dt*strg1(i,j,k) + omg2(i,j,k)=dt*strg2(i,j,k) + omg3(i,j,k)=dt*strg3(i,j,k) + enddo + enddo + enddo + + call velox(vmax1) + call veloxaux(vmax,dvmax) + + + + open(24,file='filerho') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + open(24,file='filevelox') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + uu=sqrt(vxg(i,j,k)**2+vyg(i,j,k)**2+vzg(i,j,k)**2) +c uu=sqrt(psi1(i,j,k)**2+psi2(i,j,k)**2+psi3(i,j,k)**2) + write(24,*) amax1(0.00001,uu) + enddo + enddo + enddo + close(24) + + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_full.f b/CodesEnVrac/CodeGH/main/main_full.f new file mode 100644 index 000000000..ffca36884 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_full.f @@ -0,0 +1,401 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.6 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + + t1=3.4 + t2=3.8 + t3=3.6 + t4=5. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((kk.gt.1).and.(ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.5*dx1/vmax1) + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax +c delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25*dx3/dvmax) + if ((dvmax.ne.0.).and.(korder.eq.2)) + 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3/dx3 + k_delt3=max(1,int(delt3/delt)) + delt3=float(k_delt3)*delt + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + if (kk.ge.1) then + + + print*,'TIME ',time + + endif + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + if (ic.eq.k_delt3) then + + np_bl=1 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + + endif + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + endif + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_full2.f b/CodesEnVrac/CodeGH/main/main_full2.f new file mode 100644 index 000000000..bffd93aab --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_full2.f @@ -0,0 +1,416 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=5. + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + +c t1=3.4 +c t2=3.8 + t3=3.6 + t4=4. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128: + nx3=128 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=1000. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.5*dx1/vmax1) +c delt=0.5*dx2/vmax + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax + delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.12*dx3/dvmax) +c if ((dvmax.ne.0.).and.(korder.eq.2)) +c 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3/dx3 + k_delt3=int(delt3/delt) + if (k_delt3.eq.0) then + k_delt=int(delt/delt3) + k_delt3=1 + k_delt=k_delt+1 + delt3=delt/float(k_delt) + else + delt3=float(k_delt3)*delt + k_delt=1 + endif + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + print*,'TIME ',time + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + do 111 ksubite=1,k_delt + print*,ic,k_delt3 + if ((ic.eq.k_delt3)) then + + np_bl=3 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + endif + + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + + endif +111 continue + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_full_nosplit.f b/CodesEnVrac/CodeGH/main/main_full_nosplit.f new file mode 100644 index 000000000..5019db500 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_full_nosplit.f @@ -0,0 +1,425 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.6 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + + t1=3.4 + t2=3.8 + t3=3.6 + t4=5. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + npart2=0 + do k=1,nz2 + do j=1,ny2 + do i=1,nx2 + if (ug(i,j,k).gt.0.0001) then + npart2=npart2+1 + xp2(npart2)=x0+float(i-1)*dx2 + yp2(npart2)=y0+float(j-1)*dx2 + zp2(npart2)=z0+float(k-1)*dx2 + phip(npart2)=ug(i,j,k) + endif + enddo + enddo + enddo + + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((kk.gt.1).and.(ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.25*dx1/vmax1) + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax +c delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25*dx3/dvmax) + if ((dvmax.ne.0.).and.(korder.eq.2)) + 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3/dx3 + k_delt3=max(1,int(delt3/delt)) + delt3=float(k_delt3)*delt + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + if (kk.ge.1) then + + + print*,'TIME ',time + + endif + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + if (ic.eq.k_delt3) then + + np_bl=1 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + +c RK 2 pour advection particules xp2 + + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2) + do i=1,npart2 + xp20(i)=xp2(i) + yp20(i)=yp2(i) + zp20(i)=zp2(i) + xp2(i)=xp2(i)+0.5*dt*vx2(i) + yp2(i)=yp2(i)+0.5*dt*vy2(i) + zp2(i)=zp2(i)+0.5*dt*vz2(i) + enddo +c call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2) + do i=1,npart2 + xp2(i)=xp20(i)+dt*vx2(i) + yp2(i)=yp20(i)+dt*vy2(i) + zp2(i)=zp20(i)+dt*vz2(i) + enddo + +c remesh tensoriel + + call remesh_rho(npart2,phip, + 1 xp2,yp2,zp2) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + endif + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_full_split.f b/CodesEnVrac/CodeGH/main/main_full_split.f new file mode 100644 index 000000000..b5a41d5f8 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_full_split.f @@ -0,0 +1,401 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.6 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + + t1=3.4 + t2=3.8 + t3=3.6 + t4=5. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((kk.gt.1).and.(ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.25*dx1/vmax1) + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax +c delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25*dx3/dvmax) + if ((dvmax.ne.0.).and.(korder.eq.2)) + 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, ' LCFL ',dvmax*delt3/dx3 + k_delt3=max(1,int(delt3/delt)) + delt3=float(k_delt3)*delt + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + if (kk.ge.1) then + + + print*,'TIME ',time + + endif + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + if (ic.eq.k_delt3) then + + np_bl=1 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + + endif + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + endif + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_old.f b/CodesEnVrac/CodeGH/main/main_old.f new file mode 100644 index 000000000..162646b67 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_old.f @@ -0,0 +1,445 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=16.*dx1 + zmax=0.5 + zmax=xmax + yt=0.55 + yb=0.45 +c yt=1. +c yb=0. + + t1=0.6 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=0. + t4=0. + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + j2=1+nint(yt/dx1) + j1=1+nint(yb/dx1) + yt=float(j2-1)*dx1 + yb=float(j1-1)*dx1 + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call jet(npart1,npart2,xp1,yp1,zp1, +c 1 xp2,yp2,zp2,omx,omy,omz,phip,dv1) + call readfield(npart1,npart2,xp1,yp1,zp1, + 1 xp2,yp2,zp2,omx,omy,omz,phip,dv1) + + print*,'npart1,npart2 ',npart1,npart2 +c call stream +c call velox_stream + call velox + call veloxaux(nx3,vmax) + + OPEN(33,file='VOLUMES',status='unknown') + OPEN(34,file='DECAY') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + do i=1,npart2 + xp20(i)=xp2(i) + yp20(i)=yp2(i) + zp20(i)=zp2(i) + enddo + + + do 550 ll=1,4 + + if (ll.eq.1) then + + if (kk.ge.1) then + + + print*,'TIME ',time + + endif + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1,nx4) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,circlim,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) + call velox + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + if (ic.eq.k_delt3) then + +c transport pour particules de rho avec RK2 splitte + +c call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp2(i)=xp20(i)+delt3*vx2(i)/2. + yp2(i)=yp20(i)+delt3*vy2(i)/2. + zp2(i)=zp20(i)+delt3*vz2(i)/2. + if (xp2(i).lt.xmin) xp2(i)=xp2(i)+xmax-xmin + if (xp2(i).gt.xmax) xp2(i)=xp2(i)-xmax+xmin + if (yp2(i).lt.ymin) yp2(i)=yp2(i)+ymax-ymin + if (yp2(i).gt.ymax) yp2(i)=yp2(i)-ymax+ymin + if (zp2(i).lt.zmin) zp2(i)=zp2(i)+zmax-zmin + if (zp2(i).gt.zmax) zp2(i)=zp2(i)-zmax+zmin + enddo + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) +c call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp2(i)=xp20(i)+delt3*vx2(i) + yp2(i)=yp20(i) + zp2(i)=zp20(i) + if (xp2(i).lt.xmin) xp2(i)=xp2(i)+xmax-xmin + if (xp2(i).gt.xmax) xp2(i)=xp2(i)-xmax+xmin + enddo + + call remesh_rhox(npart2,circlim,phip, + 1 xp2,yp2,zp2) + + print*, 'NPART apres remesh_rhox ',npart2 + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) +c call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp20(i)=xp2(i) + yp20(i)=yp2(i) + zp20(i)=zp2(i) + xp2(i)=xp20(i)-delt3*vx2(i)/2. + yp2(i)=yp20(i)+delt3*vy2(i)/2. + zp2(i)=zp20(i)+delt3*vz2(i)/2. + if (xp2(i).lt.xmin) xp2(i)=xp2(i)+xmax-xmin + if (xp2(i).gt.xmax) xp2(i)=xp2(i)-xmax+xmin + if (yp2(i).lt.ymin) yp2(i)=yp2(i)+ymax-ymin + if (yp2(i).gt.ymax) yp2(i)=yp2(i)-ymax+ymin + if (zp2(i).lt.zmin) zp2(i)=zp2(i)+zmax-zmin + if (zp2(i).gt.zmax) zp2(i)=zp2(i)-zmax+zmin + enddo + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) +c call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp2(i)=xp20(i) + yp2(i)=yp20(i)+delt3*vy2(i) + zp2(i)=zp20(i) + if (yp2(i).lt.ymin) yp2(i)=yp2(i)+ymax-ymin + if (yp2(i).gt.ymax) yp2(i)=yp2(i)-ymax+ymin + enddo + + call remesh_rhoy(npart2,circlim,phip, + 1 xp2,yp2,zp2) + + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) +c call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp20(i)=xp2(i) + yp20(i)=yp2(i) + zp20(i)=zp2(i) + xp2(i)=xp20(i)-delt3*vx2(i)/2. + yp2(i)=yp20(i)-delt3*vy2(i)/2. + zp2(i)=zp20(i)+delt3*vz2(i)/2. + if (xp2(i).lt.xmin) xp2(i)=xp2(i)+xmax-xmin + if (xp2(i).gt.xmax) xp2(i)=xp2(i)-xmax+xmin + if (yp2(i).lt.ymin) yp2(i)=yp2(i)+ymax-ymin + if (yp2(i).gt.ymax) yp2(i)=yp2(i)-ymax+ymin + if (zp2(i).lt.zmin) zp2(i)=zp2(i)+zmax-zmin + if (zp2(i).gt.zmax) zp2(i)=zp2(i)-zmax+zmin + enddo + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) +c call interho_cic(npart2,vx2,vy2,vz2,xp2,yp2,zp2,nx3) + do i=1,npart2 + xp2(i)=xp20(i) + yp2(i)=yp20(i) + zp2(i)=zp20(i)+delt3*vz2(i) + if (zp2(i).lt.zmin) zp2(i)=zp2(i)+zmax-zmin + if (zp2(i).gt.zmax) zp2(i)=zp2(i)-zmax+zmin + enddo + + call remesh_rhoz(npart2,circlim,phip, + 1 xp2,yp2,zp2) + + print*,' npart RHO apres remeshing ', kk,npart2 +c si on met dif_rho, on peut mettre en commentaire la boucle +c d'assignement a la fin de remesh_rhoz .. + call dif_rho(npart2,circlim,phip, + 1 xp2,yp2,zp2,anu_rho,delt3,coef_les,rhomax) + +c Fin de push / remesh rho /dif rho + call veloxaux(nx3,vmax) + delt=.25/abs(omax) + delt3=0.5*dx3/vmax +c delt3=delt + print*, ' Pas de temps omega et rho ', delt,delt3 + k_delt3=max(1,int(delt3/delt)) + delt3=float(k_delt3)*delt + ic=0 + endif + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep,npart2, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + +c go to 333 + + write(20) (((rhog(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + + + close(20) + close(2) + close(3) + close(4) + + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + open(2,file='part1.fin') + nn=nx1/2+1 + do i=1,nx + xx=(i-1)*dx + write(2,*) xx,rhog(10,i,2) + enddo + close(2) + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_small.f b/CodesEnVrac/CodeGH/main/main_small.f new file mode 100644 index 000000000..a757278e8 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_small.f @@ -0,0 +1,171 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tstop + close(1) + + circlim=-1. + + xmin=0. + ymin=0. + zmin=0. + xmax=1 + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.14 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=128 + dx3=xmax/float(nx3) + ic=0 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + call readfield(rhomax,vmax,dvmax) + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + print*,'VMAX et DV MX ',vmax,dvmax/dx3 +c delt3=0.0036 +c delt3=0.0144 + delt3=1. + if (dvmax.ne.0.) delt3=amin1(delt3,0.25*dx3/dvmax) + print*, ' ITE, TIME, Pas de temps ', kk,time,delt3 + print*, 'CFL1 CFL2 et LCFL ', + 1 vmax*delt3/dx3,vmax*delt3/dx2,dvmax*delt3/dx3 + print*,' Worstcase: LCF=2 x CFL1 = 1/2 CFL2' +c cfl=0.4 +c delt3=cfl*dx3/2. +c delt3=0.2*dx3/dvmax + + dt=delt3 + np_bl=3 + nx=nx2 + dx=dx2 + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + if (kk.eq.nit) then + + open(20,file='rho_bin',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + open(24,file='rho_asci') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + close(24) + endif + print*,'**** time, RHO MAX = ',time,umax + +223 continue + + + time=time+dt +20 continue + + +202 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_small_nosplit.f b/CodesEnVrac/CodeGH/main/main_small_nosplit.f new file mode 100644 index 000000000..2d28ed554 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_small_nosplit.f @@ -0,0 +1,201 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tstop + close(1) + + circlim=-1. + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.14 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=128 + dx3=xmax/float(nx3) + ic=0 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + call readfield(rhomax,vmax,dvmax) + + npart2=0 + do k=1,nz2 + do j=1,ny2 + do i=1,nx2 + if (ug(i,j,k).gt.0.0001) then + npart2=npart2+1 + xp2(npart2)=x0+float(i-1)*dx2 + yp2(npart2)=y0+float(j-1)*dx2 + zp2(npart2)=z0+float(k-1)*dx2 + phip(npart2)=ug(i,j,k) + endif + enddo + enddo + enddo + + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + +c call veloxaux(vmax,dvmax) + print*,'VMAX et DV MX ',vmax,dvmax/dx3 + delt3=0.0036 +c delt3=0.0144 +c if (dvmax.ne.0.) delt3=amin1(delt3,0.2*dx3/dvmax) + print*, ' ITE, TIME, Pas de temps ', kk,time,delt3 + print*, 'CFL1 CFL2 et LCFL ', + 1 vmax*delt3/dx3,vmax*delt3/dx2,dvmax*delt3/dx3 + print*,' Worstcase: LCF=2 x CFL1 = 1/2 CFL2' + + dt=delt3 + np_bl=1 + nx=nx2 + dx=dx2 + +c RK 2 pour advection particules xp2 + + call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2) + do i=1,npart2 + xp20(i)=xp2(i) + yp20(i)=yp2(i) + zp20(i)=zp2(i) + xp2(i)=xp2(i)+0.5*dt*vx2(i) + yp2(i)=yp2(i)+0.5*dt*vy2(i) + zp2(i)=zp2(i)+0.5*dt*vz2(i) + enddo +c call interho(npart2,vx2,vy2,vz2,xp2,yp2,zp2) + do i=1,npart2 + xp2(i)=xp20(i)+dt*vx2(i) + yp2(i)=yp20(i)+dt*vy2(i) + zp2(i)=zp20(i)+dt*vz2(i) + enddo + +c remesh tensoriel + circlim=0.0001 + call remesh_rho(npart2,phip, + 1 xp2,yp2,zp2) + +c diffusion + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + + open(20,file='rho_bin',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + open(24,file='rho_asci') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + +20 continue + + +202 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_small_split.f b/CodesEnVrac/CodeGH/main/main_small_split.f new file mode 100644 index 000000000..39ab09772 --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_small_split.f @@ -0,0 +1,165 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tstop + close(1) + + circlim=-1. + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=0.14 + t2=1.4 +c t3=0.784 +c t4=1.13 + t3=1000. + t4=1000. + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=128 + dx3=xmax/float(nx3) + ic=0 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + call readfield(rhomax,vmax,dvmax) + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + +c call veloxaux(vmax,dvmax) + print*,'VMAX et DV MX ',vmax,dvmax/dx3 + delt3=0.0036 + delt3=0.0144 + if (dvmax.ne.0.) delt3=amin1(delt3,0.2*dx3/dvmax) + print*, ' ITE, TIME, Pas de temps ', kk,time,delt3 + print*, 'CFL1 CFL2 et LCFL ', + 1 vmax*delt3/dx3,vmax*delt3/dx2,dvmax*delt3/dx3 + print*,' Worstcase: LCF=2 x CFL1 = 1/2 CFL2' + + dt=delt3 + np_bl=1 + nx=nx2 + dx=dx2 + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + + open(20,file='rho_bin',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + open(24,file='rho_asci') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + +20 continue + + +202 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/main/main_test.f b/CodesEnVrac/CodeGH/main/main_test.f new file mode 100644 index 000000000..aefd98bcb --- /dev/null +++ b/CodesEnVrac/CodeGH/main/main_test.f @@ -0,0 +1,184 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c nx3=128 + dx3=xmax/float(nx3) + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.003 + delt=delt0 + delt3=delt + + call readfield(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + call velox + call veloxaux(vmax,dvmax) + dvmax=0. + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + + print*,' LCFL = ',dvmax*delt3/dx3 + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + circlim=+0.0001 + dt=delt3 +c dt=0. + np_bl=2 + nx=nx2 + dx=dx2 + call x_advect(dt,np_bl) + call y_advect(dt,np_bl) + call z_advect(dt,np_bl) + + call dif_rho(anu_rho,dt) + umax=0. + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + close(24) + print*,'**** TIME et RHO MAX = ',time,umax + + +c Fin de push / remesh rho /dif rho + + if (time.gt.tstop) goto 202 + +20 continue +202 continue + + + write(filerho,140)istep +140 format('rho',i1) + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/C_IN.DAT b/CodesEnVrac/CodeGH/src-THI/C_IN.DAT new file mode 100644 index 000000000..979c75699 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/C_IN.DAT @@ -0,0 +1,16 @@ +-nombre de points pour flow +128 +-nombre de points pour traceurs +128 +-n1 d'iterations +10000 +- viscosite +0.001 +- Prandtl +0.0001 +- coef les +0.0 +- ordre du splitting +1 +- tstop +0.1 diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/bin2asc.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/bin2asc.f new file mode 100644 index 000000000..05887bc93 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/bin2asc.f @@ -0,0 +1,49 @@ + program bin2asc + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + dx=1./float(nx2) + + rhomax=0. + open(20,file='rho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,nx2),k=1,nx2) + + close(20) + + open(24,file='rho.vtk') + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + rhomax=amax1(rhomax,abs(ug(i,j,k))) + write(24,*) ug(i,j,k) + enddo + enddo + enddo + print*,'rhonax',rhomax + + + stop + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/dfftw3d.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/dfftw3d.f new file mode 100644 index 000000000..4d69b0a1d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/dfftw3d.f @@ -0,0 +1,151 @@ + subroutine fftw3d(r,c,nx,ny,nz,nxs2,nys2,nzs2,wk,irc) + +c +c Ce programme calcul la transformee de fourier rapide +c +C---------------------------------------------------------------------- +C TRANSFORMATION DE FOURIER REELLE<--->COMPLEXE TRI-DIMENSIONNELLE +C X : VECTEUR REEL DE DIMENSION (nx,ny,nz) +C C : VECTEUR COMPLEXE DE DIMENSION (0:nx/2,-ny/2+1:ny/2,-nz/2+1:nz/2) +C WK : Vecteur de travail pour les fftw de dimension (0:nx/2,0:ny-1,0:nz-1) +C IRC : =0: REELLE ---> COMPLEXE (X-->C) Directe +C <>0: COMPLEXE ---> REELLE (C-->X) inverse +C +C REMARQUE: +C CALCULE LA TRANSFORMATION SUIVANTE: +C +C X(J,K,L) J(1..nx),K(1..ny),L(1..Nz) <---> C(J,K,L) J=0..nx/2 K=-ny/2+1,...,ny/2, +C L=-nz/2+1,...,nz/2 +C +C---------------------------------------------------------------------- +c +c Declaration pour utiliser les routines fftw +c +c This file contains PARAMETER statements for various constants +c that can be passed to FFTW routines. You should include +c this file in any FORTRAN program that calls the fftw_f77 +c routines (either directly or with an #include statement +c if you use the C preprocessor). +c + + include '/opt/Softs/fftw/fftw-3.2.2-intel/include/fftw3.f' + +c INTEGER FFTW_FORWARD,FFTW_BACKWARD +c PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) +c +c INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL +c PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) +c +c INTEGER FFTW_ESTIMATE,FFTW_MEASURE +c PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) +ccc +c INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM +c PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) +c + integer plan,nx,ny,nz,nxs2,nys2,nzs2,irc,i,j,k +c + complex c,wk + dimension c(0:nxs2,1-nys2:nys2,1-nzs2:nzs2),wk(nxs2+1,ny,nz) +c + real r + dimension r(nx,ny,nz) +c + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=cmplx(0.0,0.0) + enddo + enddo + enddo +c + plan=0 + if (irc.eq.0) then + + call dfftw_plan_dft_r2c_3d(plan,nx,ny,nz,r,wk, + 1 FFTW_ESTIMATE) + call dfftw_execute(plan) + call dfftw_destroy_plan(plan) + + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=wk(i,j,k)/nx/ny/nz + enddo + enddo + enddo +c + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-1)=wk(i,j,k) + enddo + enddo + enddo +c + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-1)=wk(i,j+nys2+1,k) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-nzs2)=wk(i,j,k+nzs2+1) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-nzs2)=wk(i,j+nys2+1,k+nzs2+1) + enddo + enddo + enddo +c + else +c + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k)=c(i-1,j-1,k-1) + enddo + enddo + enddo +c + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k)=c(i-1,j-nys2,k-1) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k+nzs2+1)=c(i-1,j-1,k-nzs2) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k+nzs2+1)=c(i-1,j-nys2,k-nzs2) + enddo + enddo + enddo +c + call dfftw_plan_dft_c2r_3d(plan,nx,ny,nz,wk,r, + 1 FFTW_ESTIMATE) + call dfftw_execute(plan) + call dfftw_destroy_plan(plan) + + endif +c + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/filter_rho.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/filter_rho.f new file mode 100644 index 000000000..8caf193c8 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/filter_rho.f @@ -0,0 +1,128 @@ + program spec + + + include 'param_rho.i' + include 'param.h' + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + parameter(npg2=256) + parameter(npgb2=npg2/2) + + dimension rhog(npgx,npgy,npgz) + dimension ug(npg2,npg2,npg2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + real ijc(1-ngx2:ngx2,1-ngx2:ngx2,1-ngx2:ngx2) + real nrj(ngx2) + + complex cvx,wk2 + dimension cvx(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2) + dimension wk2(npgb2+1,npg2,npg2) + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + nx3=256 + + ny2=nx2 + nz2=nx2 + + nxb=nx2/2 + nyb=ny2/2 + nzb=nz2/2 + + nxb2=nx3/2 + nyb2=nx3/2 + nzb2=nx3/2 + + open(20,file='rho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + read(20) (((rhog(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + close(20) + + print*,' Lecture finie ' + + call fftw3d(rhog,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,0) + + do 10 k=1-nzb2,nzb2 + do 10 j=1-nyb2,nyb2 + do 10 i=0,nxb2 + cvx(i,j,k)=cux(i,j,k) +10 continue + + call fftw3d(ug,cvx,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + + open(24,file='half_rho') + + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx3," ",nx3," ",nx3 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",1./nx3," ",1./nx3," ",1./nx3 + WRITE(24,*) "POINT_DATA ",nx3*nx3*nx3 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + + + do k=1-nzb,nzb + do j=1-nyb,nyb + cfx(0,j,k)=cux(0,j,k) + do i=1,nxb + if (i.le.nxb-1) cfx(-i,j,k)=cux(i,j,k) + cfx(i,j,k)=cux(i,j,k) + enddo + enddo + enddo +c + print*,' sort de fft ' + + open(1,file='spectre') + + s=0. + do l=1,nxb2 +c + do k=1-nzb2-2,nzb2+2 + do j=1-nyb2-2,nyb2+2 + do i=1-nxb2-2,nxb2+2 + ijc(i,j,k)=float(i**2+j**2+k**2) + xmod=sqrt(ijc(i,j,k)) + if ((xmod.lt.l+0.5).and.(xmod.ge.l-0.5)) then + z=cabs(cfx(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + print*, 'L =',l + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + +c filter at half-size + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/init.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/init.f new file mode 100644 index 000000000..b6196f8b7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/init.f @@ -0,0 +1,90 @@ + subroutine readfield(rhomax,vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + real*8 tout(npgx,npgy,npgz,4) + + rhomax=0. + + open(20,file='datarho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + close(20) + + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + ug(i,j,k)=1. + rhomax=amax1(umax,abs(ug(i,j,k))) + enddo + enddo + enddo + +! goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi1(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi2(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi3(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + umax1=amax1(umax1,abs(psi1(i,j,k))) + umax2=amax1(umax2,abs(psi2(i,j,k))) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + vmax=amax1(umax1,umax2,umax3) + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + +111 continue + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/init_bubble.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/init_bubble.f new file mode 100644 index 000000000..866b448d8 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/init_bubble.f @@ -0,0 +1,73 @@ + subroutine bubble(npart,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension omx(*),omy(*),omz(*) + + pi=3.1415926 + pi2=2.*pi + circ=0. + x0=0. + y0=0. + z0=0. + + npart=0 + do i=1,nx1 + do j=1,ny1 + do k=1,nz1 + xx=(float(i)-1.)*dx1 + yy=(float(j)-1.)*dx1 + zz=(float(k)-1.)*dx1 + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. + strg1(i,j,k)=0. + strg2(i,j,k)=0. + strg3(i,j,k)=0. + vxg(i,j,k)=0. + vyg(i,j,k)=0. + vzg(i,j,k)=0. + npart=npart+1 + xp1(npart)=xx + yp1(npart)=yy + zp1(npart)=zz + dv1(npart)=dx1*dx1*dx1 + omx(npart)=0. + omy(npart)=0. + omz(npart)=0. + enddo + enddo + enddo + + tm=0. + do k=1,nz2 + do j=1,ny2 + do i=1,nx2 + ug(i,j,k)=0. + yy=abs(float(j-1)*dx2-0.5) + xx1=abs(float(i-1)*dx2-0.15) + xx2=abs(float(i-1)*dx2-0.45) + zz=abs(float(k-1)*dx2-0.5) + rr1=sqrt(xx1*xx1+yy*yy+zz*zz) + rr2=sqrt(xx2*xx2+yy*yy+zz*zz) + rr3=sqrt(xx2*xx2+yy*yy) +! if ((rr1.le.0.1).or.(rr2.lt.0.15)) then + if ((rr3.le.0.25)) then +! if ((xx2.le.0.15).and.(yy.lt.0.15).and.(zz.le.0.15)) then + ug(i,j,k)=1.+0.05*(strg1(i,j,k)-0.5) + ug(i,j,k)=1. + endif + tm=tm+ug(i,j,k) + enddo + enddo + enddo + + print*, ' MASSE SCALAIRE a init ',tm*dx2*dx2*dx2 + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/init_burgers.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/init_burgers.f new file mode 100644 index 000000000..eed7be66b --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/init_burgers.f @@ -0,0 +1,27 @@ + subroutine init_burgers + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + umax=0. + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + ug(i,j,k)=0. +c if ((j.eq.nx2/2).and.(k.eq.nx2/2)) then + if ((j.lt.9).and.(k.lt.9)) then + xx=xmin+(i-1)*dx2 + ug(i,j,k)=1. + if (xx.gt.0.5*(xmin+xmax)) ug(i,j,k)=-1. + endif + umax=amax1(umax,abs(ug(i,j,k))) + enddo + enddo + enddo + + print*, 'UMAX a init', umax + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_GB.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_GB.f new file mode 100644 index 000000000..bbe9a751f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_GB.f @@ -0,0 +1,48 @@ + subroutine readfield(rhomax,vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + real*8 vel(32,32,32,3) + real*8 dens(128,128,128) + + open(2,file='GB/data2read',form='binary', + 1 status='unknown') + read(2) buf1,buf2,buf3,buf4 + read(2) ((((vel(i,j,k,l), + 1 i=1,nx3),j=1,nx3),k=1,nx3),l=1,3) + read(2) (((dens(i,j,k), + 1 i=1,nx2),j=1,nx2),k=1,nx2) + + + vmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + vxg(i,j,k)=vel(i,j,k,1) + vyg(i,j,k)=vel(i,j,k,2) + vzg(i,j,k)=vel(i,j,k,3) + vmax=amax1(vmax,abs(vxg(i,j,k))) + vmax=amax1(vmax,abs(vyg(i,j,k))) + vmax=amax1(vmax,abs(vzg(i,j,k))) + enddo + enddo + enddo + + rhomax=0. + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + ug(i,j,k)=dens(i,j,k) + rhomax=amax1(rhomax,ug(i,j,k)) + enddo + enddo + enddo + + print*,' rhomax a init = ',rhomax + print*,' vmax a init = ',vmax + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_full.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_full.f new file mode 100644 index 000000000..9d4031174 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_full.f @@ -0,0 +1,78 @@ + subroutine readfield(npart,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + real*8 tout(npgx,npgy,npgz,4) + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension omx(*),omy(*),omz(*) + + pi=3.1415926 + pi2=2.*pi + circ=0. + x0=0. + y0=0. + z0=0. + + open(2,file='datax',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file='datay',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file='dataz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(20,file='datarho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + read(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + read(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + read(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + close(2) + close(3) + close(4) + close(20) + + npart=0 + rhomax=0. + do 10 i=1,nx1 + xx=(float(i)-1.)*dx1 + do 10 j=1,ny1 + yy=(float(j)-1.)*dx1 + do 10 k=1,nz1 + zz=(float(k)-1.)*dx1 + aux1=omg1(i,j,k) + aux2=omg2(i,j,k) + aux3=omg3(i,j,k) + if (abs(aux1)+abs(aux2)+abs(aux3).gt.0.0001) then + npart=npart+1 + xp1(npart)=xx + yp1(npart)=yy + zp1(npart)=zz + dv1(npart)=dx1*dx1*dx1 + omx(npart)=dv1(npart)*aux1 + omy(npart)=dv1(npart)*aux2 + omz(npart)=dv1(npart)*aux3 + circ=circ+omz(npart) + rhomax=amax1(rhomax,ug(i,j,k)) + endif +10 continue + print*, 'NPART ROMAX t=0 =', npart,rhomax + +! initailisation des particules de densite et de leurs pentes + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_small.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_small.f new file mode 100644 index 000000000..b6196f8b7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/initread_small.f @@ -0,0 +1,90 @@ + subroutine readfield(rhomax,vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + real*8 tout(npgx,npgy,npgz,4) + + rhomax=0. + + open(20,file='datarho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + close(20) + + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + ug(i,j,k)=1. + rhomax=amax1(umax,abs(ug(i,j,k))) + enddo + enddo + enddo + +! goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi1(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi2(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi3(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + umax1=amax1(umax1,abs(psi1(i,j,k))) + umax2=amax1(umax2,abs(psi2(i,j,k))) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + vmax=amax1(umax1,umax2,umax3) + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + +111 continue + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_cic.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_cic.f new file mode 100644 index 000000000..a82f25637 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_cic.f @@ -0,0 +1,149 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE interho(npart,g1,g2,g3,xp,yp,zp) + +C +C Interpolation routine with M'4 +C +! geometry=unit box, periodic in x and y +! last ponits in z direction assume extension by continuity +! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),rhog(npg,npg,npg) + + + do 10 i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + dyinv=1./dy3 + dzinv=1./dz3 + dh3=dx3*dy3*dz3 + dhinv3=1./dh3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + + DO 20 i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + yy1 = (y - float(jp1)*dy3-y0)*dyinv + zz1 = (z - float(kp1)*dz3-z0)*dzinv + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + +C +C on repositionne les points de grille par periodicite +! entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + + + jp1=mod(jp1+ny3,ny3) +1 + jp2=mod(jp2+ny3,ny3) +1 + + kp1=mod(kp1+nz3,nz3) +1 + kp2=mod(kp2+nz3,nz3) +1 + +C +C The M'4 scheme +C + + a1 = xx2 + b1 = yy2 + c1 = zz2 + + a2 = xx1 + b2 = yy1 + c2 = zz1 + + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + + g2(i)= g2(i) + gg2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + gg2(ip1,jp2,kp1)*a1*b2*c1 + + g3(i)= g3(i) + gg3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + gg3(ip1,jp2,kp1)*a1*b2*c1 +c + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + + g2(i)= g2(i) + gg2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + gg2(ip2,jp2,kp1)*a2*b2*c1 + + g3(i)= g3(i) + gg3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + gg3(ip2,jp2,kp1)*a2*b2*c1 +c + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + + g2(i)= g2(i) + gg2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + gg2(ip1,jp2,kp2)*a1*b2*c2 + + g3(i)= g3(i) + gg3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + gg3(ip1,jp2,kp2)*a1*b2*c2 +c + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + g2(i)= g2(i) + gg2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + gg2(ip2,jp2,kp2)*a2*b2*c2 + + g3(i)= g3(i) + gg3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + gg3(ip2,jp2,kp2)*a2*b2*c2 +c + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_m4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_m4.f new file mode 100644 index 000000000..e2f622a2d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/interho_m4.f @@ -0,0 +1,165 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE interho(npart,g1,g2,g3,xp,yp,zp) + +C +C Interpolation routine with M'4 +C +! geometry=unit box, periodic in x and y +! last ponits in z direction assume extension by continuity +! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),rhog(npg,npg,npg) + + + do 10 i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + dyinv=1./dy3 + dzinv=1./dz3 + dh3=dx3*dy3*dz3 + dhinv3=1./dh3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + + DO 20 i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + yy1 = (y - float(jp1)*dy3-y0)*dyinv + zz1 = (z - float(kp1)*dz3-z0)*dzinv + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + + xx3=2-xx1 + yy3=2-yy1 + zz3=2-zz1 + +C +C on repositionne les points de grille par periodicite +! entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + ip3=mod(ip3+nx3,nx3) +1 + + + jp1=mod(jp1+ny3,ny3) +1 + jp2=mod(jp2+ny3,ny3) +1 + jp3=mod(jp3+ny3,ny3) +1 + + kp1=mod(kp1+nz3,nz3) +1 + kp2=mod(kp2+nz3,nz3) +1 + kp3=mod(kp3+nz3,nz3) +1 + +C +C The M'4 scheme +C + + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + g1(i)= g1(i) + GG1(ip0,jp0,kp0)*a0*b0*c0 + g1(i)= g1(i) + GG1(ip0,jp1,kp0)*a0*b1*c0 + g1(i)= g1(i) + GG1(ip0,jp2,kp0)*a0*b2*c0 + g1(i)= g1(i) + GG1(ip0,jp3,kp0)*a0*b3*c0 + + g2(i)= g2(i) + GG2(ip0,jp0,kp0)*a0*b0*c0 + g2(i)= g2(i) + GG2(ip0,jp1,kp0)*a0*b1*c0 + g2(i)= g2(i) + GG2(ip0,jp2,kp0)*a0*b2*c0 + g2(i)= g2(i) + GG2(ip0,jp3,kp0)*a0*b3*c0 + + g3(i)= g3(i) + GG3(ip0,jp0,kp0)*a0*b0*c0 + g3(i)= g3(i) + GG3(ip0,jp1,kp0)*a0*b1*c0 + g3(i)= g3(i) + GG3(ip0,jp2,kp0)*a0*b2*c0 + g3(i)= g3(i) + GG3(ip0,jp3,kp0)*a0*b3*c0 +c + g1(i)= g1(i) + GG1(ip1,jp0,kp0)*a1*b0*c0 + g1(i)= g1(i) + GG1(ip1,jp1,kp0)*a1*b1*c0 + g1(i)= g1(i) + GG1(ip1,jp2,kp0)*a1*b2*c0 + g1(i)= g1(i) + GG1(ip1,jp3,kp0)*a1*b3*c0 + + g2(i)= g2(i) + GG2(ip1,jp0,kp0)*a1*b0*c0 + g2(i)= g2(i) + GG2(ip1,jp1,kp0)*a1*b1*c0 + g2(i)= g2(i) + GG2(ip1,jp2,kp0)*a1*b2*c0 + g2(i)= g2(i) + GG2(ip1,jp3,kp0)*a1*b3*c0 + + g3(i)= g3(i) + GG3(ip1,jp0,kp0)*a1*b0*c0 + g3(i)= g3(i) + GG3(ip1,jp1,kp0)*a1*b1*c0 + g3(i)= g3(i) + GG3(ip1,jp2,kp0)*a1*b2*c0 + g3(i)= g3(i) + GG3(ip1,jp3,kp0)*a1*b3*c0 +c + g1(i)= g1(i) + GG1(ip2,jp0,kp0)*a2*b0*c0 + g1(i)= g1(i) + GG1(ip2,jp1,kp0)*a2*b1*c0 + g1(i)= g1(i) + GG1(ip2,jp2,kp0)*a2*b2*c0 + g1(i)= g1(i) + GG1(ip2,jp3,kp0)*a2*b3*c0 +:wq + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers new file mode 100644 index 000000000..625c77346 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers @@ -0,0 +1,53 @@ +# +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = burgers + +OBJSF = init_burgers.o\ + main_burgers.o \ + velox_burgers.o \ + remeshx_l2_limit.o \ + remeshx_tag_limit.o \ + tag_particles_limit.o \ + x_advect_corec_limit.o \ + velox_x.o \ + slopes.o \ + fftw3d.o + +init_burgers.o: init_burgers.f param.i + ifort $(OPT3) -c init_burgers.f +main_burgers.o: main_burgers.f param.i + ifort $(OPT3) -c main_burgers.f +velox_burgers.o: velox_burgers.f param.i + ifort $(OPT3) -c velox_burgers.f +slopes.o: slopes.f param.i + ifort $(OPT3) -c slopes.f +x_advect_corec_limit.o: x_advect_corec_limit.f param.i + ifort $(OPT3) -c x_advect_corec_limit.f +remeshx_l2_limit.o: remeshx_l2_limit.f param.i + ifort $(OPT3) -c remeshx_l2_limit.f +remeshx_tag_limit.o: remeshx_tag_limit.f param.i + ifort $(OPT3) -c remeshx_tag_limit.f +tag_particles_limit.o: tag_particles_limit.f param.i + ifort $(OPT3) -c tag_particles_limit.f +velox_x.o: velox_x.f param.i + ifort $(OPT3) -c velox_x.f + +$(PROGRAM): $(OBJSF) + ifort $(OPT3) $(OBJSF) -lfftw3f -lfftw3_threads -o $(PROGRAM) + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers_nolimit b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers_nolimit new file mode 100644 index 000000000..b4abb2cb7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_burgers_nolimit @@ -0,0 +1,44 @@ +# +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = burgers + +OBJSF = init_burgers.o\ + main_burgers.o \ + velox_burgers.o \ + remeshx_l2.o \ + x_advect_orig.o \ + velox_x.o \ + fftw3d.o + +init_burgers.o: init_burgers.f param.i + ifort $(OPT3) -c init_burgers.f +main_burgers.o: main_burgers.f param.i + ifort $(OPT3) -c main_burgers.f +velox_burgers.o: velox_burgers.f param.i + ifort $(OPT3) -c velox_burgers.f +x_advect_orig.o: x_advect_orig.f param.i + ifort $(OPT3) -c x_advect_orig.f +remeshx_l2.o: remeshx_l2.f param.i + ifort $(OPT3) -c remeshx_l2.f +velox_x.o: velox_x.f param.i + ifort $(OPT3) -c velox_x.f + +$(PROGRAM): $(OBJSF) + ifort $(OPT3) $(OBJSF) -lfftw3f -lfftw3_threads -o $(PROGRAM) + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb new file mode 100644 index 000000000..d82b8c194 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb @@ -0,0 +1,112 @@ +# +# la commande f77 pour les dec est f77_520 +# +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = freeb + +all: $(PROGRAM) + +OBJSF = diag.o\ + init_bubble.o \ + intervm4.o \ + intersm4.o \ + interho.o \ + main_freeb.o \ + dif.o \ + dif_rho.o \ + remesh_om.o \ + remesh_rho.o \ + remeshx_l4.o \ + remeshy_l4.o \ + remeshz_l4.o \ + remeshx_l4_tag.o \ + remeshy_l4_tag.o \ + remeshz_l4_tag.o \ + tag_particles_l4.o \ + x_advect_l4.o \ + y_advect_l4.o \ + z_advect_l4.o \ + stretch_freeb.o \ + fftw3d.o \ + velox_x.o \ + velox_y.o \ + velox_z.o \ + veloxaux.o \ + stension.o \ + velox.o + +diag.o: diag.f param.i + ifort $(OPT3) -c diag.f +dif.o: dif.f param.i + ifort $(OPT3) -c dif.f +dif_rho.o: dif_rho.f param.i + ifort $(OPT3) -c dif_rho.f +init_bubble.o: init_bubble.f param.i + ifort $(OPT3) -c -g init_bubble.f +intervm4.o: intervm4.f param.i + ifort $(OPT3) -c intervm4.f +intersm4.o: intersm4.f param.i + ifort $(OPT3) -c intersm4.f +interho.o: interho.f param.i + ifort $(OPT3) -c interho.f +main_freeb.o: main_freeb.f param.i + ifort $(OPT3) -c -g main_freeb.f +remesh_om.o: remesh_om.f param.i + ifort $(OPT3) -c remesh_om.f +remesh_rho.o: remesh_rho.f param.i + ifort $(OPT3) -c remesh_rho.f +remeshx_l4.o: remeshx.f param.i + ifort $(OPT3) -c remeshx_l4.f +remeshy_l4.o: remeshy.f param.i + ifort $(OPT3) -c remeshy_l4.f +remeshz_l4.o: remeshz.f param.i + ifort $(OPT3) -c remeshz_l4.f +remeshx_l4_tag.o: remeshx_tag.f param.i + ifort $(OPT3) -c remeshx_l4_tag.f +remeshy_l4_tag.o: remeshy_tag.f param.i + ifort $(OPT3) -c remeshy_l4_tag.f +remeshz_l4_tag.o: remeshz_tag.f param.i + ifort $(OPT3) -c remeshz_l4_tag.f +x_advect_l4.o: x_advect_l4.f param.i + ifort $(OPT3) -c x_advect_l4.f +y_advect_l4.o: y_advect_l4.f param.i + ifort $(OPT3) -c y_advect_l4.f +z_advect_l4.o: z_advect_l4.f param.i + ifort $(OPT3) -c z_advect_l4.f +tag_particles_l4.o: tag_particles_l4.f param.i + ifort $(OPT3) -c tag_particles_l4.f +stretch_freeb.o: stretch_freeb.f param.i + ifort $(OPT3) -c stretch_freeb.f +velox.o: velox.f param.i + ifort $(OPT3) -c velox.f +velox_x.o: velox_x.f param.i + ifort $(OPT3) -c velox_x.f +velox_y.o: velox_y.f param.i + ifort $(OPT3) -c velox_y.f +velox_z.o: velox_z.f param.i + ifort $(OPT3) -c velox_z.f +veloxaux.o: veloxaux.f param.i + ifort $(OPT3) -c veloxaux.f +stension.o: stension.f param.i + ifort $(OPT3) -c stension.f +fftw3d.o: fftw3d.f param.i + ifort $(OPT3) -c fftw3d.f + + +$(PROGRAM): $(OBJSF) + ifort $(OPT3) $(OBJSF) -lfftw3f -lfftw3_threads -o $(PROGRAM) + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb_small b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb_small new file mode 100644 index 000000000..5ee412184 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_freeb_small @@ -0,0 +1,38 @@ +# +# la commande f77 pour les dec est f77_520 +# +FF =ifort + +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = freeb + +all: $(PROGRAM) + +OBJ = init_bubble.o\ + main_freeb_small.o \ + fftw3d.o \ + veloxaux.o \ + stension_fourier.o \ + velox.o + +%.o: %.f param.i arrays.h + $(FF) -o $@ -c $< $(OPT3) + +$(PROGRAM): $(OBJ) + ifort $(OPT3) $(OBJ) -lfftw3f -lfftw3_threads -o $(PROGRAM) + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_l4 b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_l4 new file mode 100644 index 000000000..9030608bc --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/makefile_l4 @@ -0,0 +1,112 @@ +# +# la commande f77 pour les dec est f77_520 +# +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = thi_l4 + +all: $(PROGRAM) + +OBJSF = diag.o\ + initread.o \ + initjet.o \ + intervm4.o \ + intersm4.o \ + interho.o \ + main.o \ + dif.o \ + dif_rho.o \ + remesh_om.o \ + remesh_rho.o \ + remeshx_l4.o \ + remeshy_l4.o \ + remeshz_l4.o \ + remeshx_l4_tag.o \ + remeshy_l4_tag.o \ + remeshz_l4_tag.o \ + tag_particles_l4.o \ + x_advect_l4.o \ + y_advect_l4.o \ + z_advect_l4.o \ + stretch.o \ + fftw3d.o \ + velox_x.o \ + velox_y.o \ + velox_z.o \ + veloxaux.o \ + velox.o + +diag.o: diag.f param.i + ifort $(OPT3) -c diag.f +dif.o: dif.f param.i + ifort $(OPT3) -c dif.f +dif_rho.o: dif_rho.f param.i + ifort $(OPT3) -c dif_rho.f +initread.o: initread.f param.i + ifort $(OPT3) -c -g initread.f +initjet.o: initjet.f param.i + ifort $(OPT3) -c -g initjet.f +intervm4.o: intervm4.f param.i + ifort $(OPT3) -c intervm4.f +intersm4.o: intersm4.f param.i + ifort $(OPT3) -c intersm4.f +interho.o: interho.f param.i + ifort $(OPT3) -c interho.f +main.o: main.f param.i + ifort $(OPT3) -c -g main.f +remesh_om.o: remesh_om.f param.i + ifort $(OPT3) -c remesh_om.f +remesh_rho.o: remesh_rho.f param.i + ifort $(OPT3) -c remesh_rho.f +remeshx_l4.o: remeshx.f param.i + ifort $(OPT3) -c remeshx_l4.f +remeshy_l4.o: remeshy.f param.i + ifort $(OPT3) -c remeshy_l4.f +remeshz_l4.o: remeshz.f param.i + ifort $(OPT3) -c remeshz_l4.f +remeshx_l4_tag.o: remeshx_tag.f param.i + ifort $(OPT3) -c remeshx_l4_tag.f +remeshy_l4_tag.o: remeshy_tag.f param.i + ifort $(OPT3) -c remeshy_l4_tag.f +remeshz_l4_tag.o: remeshz_tag.f param.i + ifort $(OPT3) -c remeshz_l4_tag.f +x_advect_l4.o: x_advect_l4.f param.i + ifort $(OPT3) -c x_advect_l4.f +y_advect_l4.o: y_advect_l4.f param.i + ifort $(OPT3) -c y_advect_l4.f +z_advect_l4.o: z_advect_l4.f param.i + ifort $(OPT3) -c z_advect_l4.f +tag_particles_l4.o: tag_particles_l4.f param.i + ifort $(OPT3) -c tag_particles_l4.f +stretch.o: stretch.f param.i + ifort $(OPT3) -c stretch.f +velox.o: velox.f param.i + ifort $(OPT3) -c velox.f +velox_x.o: velox_x.f param.i + ifort $(OPT3) -c velox_x.f +velox_y.o: velox_y.f param.i + ifort $(OPT3) -c velox_y.f +velox_z.o: velox_z.f param.i + ifort $(OPT3) -c velox_z.f +veloxaux.o: veloxaux.f param.i + ifort $(OPT3) -c veloxaux.f +fftw3d.o: fftw3d.f param.i + ifort $(OPT3) -c fftw3d.f + + +$(PROGRAM): $(OBJSF) + ifort $(OPT3) $(OBJSF) -lfftw3f -lfftw3_threads -o $(PROGRAM) + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_l4_tag.f new file mode 100644 index 000000000..29cacbfe4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_l4_tag.f @@ -0,0 +1,181 @@ + subroutine remesh_tag(ntag,itag,itype,icfl) + + + include 'param.i' + include 'param.h' + + integer itag(*),itype(*),icfl(*) + + dimension ug(npg),up(npg),xp(npg) + + dx2=dh + dxinv=1./dh + + do i=1,nx +! ug(i)=0. + enddo + + do n=1,ntag-1,4 +! do n=1,1 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! u1m=0. +! u0=0. +! u1p=2. +! u2p=0. + tm=u1m+u0+u1p+u2p + print*, 'TM avant remshtag', tm + print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), + 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv + print*, 'xx1p ',xx1p +! reperage des points de grille concernes +c de I-4 a I+4 ou I est point de grille a gauche de particule x0 + ip4m=ip0-4 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 + ip4m=mod(ip4m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + ug(ip4m)=ug(ip4m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(ip3m)=ug(ip3m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + ug(ip2m)=ug(ip2m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip1m)=ug(ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip0)=ug(ip0)+u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(ip1p)=ug(ip1p)+u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(ip2p)=ug(ip2p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(ip3p)=ug(ip3p)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip4p)=ug(ip4p)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else + print*,'c et d',n +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + ug(ip3m)=ug(ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(ip2m)=ug(ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + ug(ip1m)=ug(ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0+(xx0-1.)*(xx0+1.)*(xx0+2.)*(xx0+3)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(ip0)=ug(ip0)+u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=-(xx0-1.)*(xx0+1.)*(xx0+2.)*(xx0+3)/6. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(ip1p)=ug(ip1p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(ip2p)=ug(ip2p)+u1p*coef1p+u2p*coef2p + + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip3p)=ug(ip3p)+u2p*coef2p +c + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_rhom4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_rhom4.f new file mode 100644 index 000000000..89fa19ae2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_rhom4.f @@ -0,0 +1,379 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE remesh_rho(npart,phip, + 1 xp2,yp2,zp2) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp2(*),yp2(*),zp2(*) + dimension phip(*) + + + do 10 i=1,nx2 + do 10 j=1,ny2 + do 10 k=1,nz2 + ug(i,j,k)=0. +10 continue + + dy2=dx2 + dz2=dx2 + + dxinv=1./(dx2) + dyinv=dxinv + dzinv=dxinv + + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=0. + y0=0. + z0=0. + + vol=1. + + DO 20 n = 1,npart + + g1 = phip(n)/vol + + x = xp2(n) + y = yp2(n) + z = zp2(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +C Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dy2-y0)*dyinv + zz1 = (z - float(kp1)*dz2-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + +C +C on repositionne les points de grille par periodicite +! entre 0 et npx-1, puis on numerote de 1 a npx +C + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + + jp1=mod(jp1+ny2,ny2) +1 + jp0=mod(jp0+ny2,ny2) +1 + jp2=mod(jp2+ny2,ny2) +1 + jp3=mod(jp3+ny2,ny2) +1 + + kp1=mod(kp1+nz2,nz2) +1 + kp0=mod(kp0+nz2,nz2) +1 + kp2=mod(kp2+nz2,nz2) +1 + kp3=mod(kp3+nz2,nz2) +1 + +C The M'4 scheme +C + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + coef=a0*b0*c0 + ug(ip0,jp0,kp0) = ug(ip0,jp0,kp0) + g1*coef + + coef=a0*b0*c1 + ug(ip0,jp0,kp1) = ug(ip0,jp0,kp1) + g1*coef + + coef=a0*b0*c2 + ug(ip0,jp0,kp2) = ug(ip0,jp0,kp2) + g1*coef + + coef=a0*b0*c3 + ug(ip0,jp0,kp3) = ug(ip0,jp0,kp3) + g1*coef + +ccc + + coef=a0*b1*c0 + ug(ip0,jp1,kp0) = ug(ip0,jp1,kp0) + g1*coef + + coef=a0*b1*c1 + ug(ip0,jp1,kp1) = ug(ip0,jp1,kp1) + g1*coef + + coef=a0*b1*c2 + ug(ip0,jp1,kp2) = ug(ip0,jp1,kp2) + g1*coef + + coef=a0*b1*c3 + ug(ip0,jp1,kp3) = ug(ip0,jp1,kp3) + g1*coef + +ccc + + coef=a0*b2*c0 + ug(ip0,jp2,kp0) = ug(ip0,jp2,kp0) + g1*coef + + coef=a0*b2*c1 + ug(ip0,jp2,kp1) = ug(ip0,jp2,kp1) + g1*coef + + coef=a0*b2*c2 + ug(ip0,jp2,kp2) = ug(ip0,jp2,kp2) + g1*coef + + + coef=a0*b2*c3 + ug(ip0,jp2,kp3) = ug(ip0,jp2,kp3) + g1*coef + +ccc + + coef=a0*b3*c0 + ug(ip0,jp3,kp0) = ug(ip0,jp3,kp0) + g1*coef + + coef=a0*b3*c1 + ug(ip0,jp3,kp1) = ug(ip0,jp3,kp1) + g1*coef + + coef=a0*b3*c2 + ug(ip0,jp3,kp2) = ug(ip0,jp3,kp2) + g1*coef + + coef=a0*b3*c3 + ug(ip0,jp3,kp3) = ug(ip0,jp3,kp3) + g1*coef + +ccc + coef=a1*b0*c0 + ug(ip1,jp0,kp0) = ug(ip1,jp0,kp0) + g1*coef + + coef=a1*b0*c1 + ug(ip1,jp0,kp1) = ug(ip1,jp0,kp1) + g1*coef + + coef=a1*b0*c2 + ug(ip1,jp0,kp2) = ug(ip1,jp0,kp2) + g1*coef + + coef=a1*b0*c3 + ug(ip1,jp0,kp3) = ug(ip1,jp0,kp3) + g1*coef + +ccc + + coef=a1*b1*c0 + ug(ip1,jp1,kp0) = ug(ip1,jp1,kp0) + g1*coef + + coef=a1*b1*c1 + ug(ip1,jp1,kp1) = ug(ip1,jp1,kp1) + g1*coef + + coef=a1*b1*c2 + ug(ip1,jp1,kp2) = ug(ip1,jp1,kp2) + g1*coef + + coef=a1*b1*c3 + ug(ip1,jp1,kp3) = ug(ip1,jp1,kp3) + g1*coef + +ccc + + coef=a1*b2*c0 + ug(ip1,jp2,kp0) = ug(ip1,jp2,kp0) + g1*coef + + coef=a1*b2*c1 + ug(ip1,jp2,kp1) = ug(ip1,jp2,kp1) + g1*coef + + coef=a1*b2*c2 + ug(ip1,jp2,kp2) = ug(ip1,jp2,kp2) + g1*coef + + coef=a1*b2*c3 + ug(ip1,jp2,kp3) = ug(ip1,jp2,kp3) + g1*coef + +ccc + + coef=a1*b3*c0 + ug(ip1,jp3,kp0) = ug(ip1,jp3,kp0) + g1*coef + + coef=a1*b3*c1 + ug(ip1,jp3,kp1) = ug(ip1,jp3,kp1) + g1*coef + + coef=a1*b3*c2 + ug(ip1,jp3,kp2) = ug(ip1,jp3,kp2) + g1*coef + + coef=a1*b3*c3 + ug(ip1,jp3,kp3) = ug(ip1,jp3,kp3) + g1*coef + +ccc + coef=a2*b0*c0 + ug(ip2,jp0,kp0) = ug(ip2,jp0,kp0) + g1*coef + + coef=a2*b0*c1 + ug(ip2,jp0,kp1) = ug(ip2,jp0,kp1) + g1*coef + + coef=a2*b0*c2 + ug(ip2,jp0,kp2) = ug(ip2,jp0,kp2) + g1*coef + + coef=a2*b0*c3 + ug(ip2,jp0,kp3) = ug(ip2,jp0,kp3) + g1*coef + +ccc + + coef=a2*b1*c0 + ug(ip2,jp1,kp0) = ug(ip2,jp1,kp0) + g1*coef + + coef=a2*b1*c1 + ug(ip2,jp1,kp1) = ug(ip2,jp1,kp1) + g1*coef + + coef=a2*b1*c2 + ug(ip2,jp1,kp2) = ug(ip2,jp1,kp2) + g1*coef + + coef=a2*b1*c3 + ug(ip2,jp1,kp3) = ug(ip2,jp1,kp3) + g1*coef + +ccc + + coef=a2*b2*c0 + ug(ip2,jp2,kp0) = ug(ip2,jp2,kp0) + g1*coef + + coef=a2*b2*c1 + ug(ip2,jp2,kp1) = ug(ip2,jp2,kp1) + g1*coef + + coef=a2*b2*c2 + ug(ip2,jp2,kp2) = ug(ip2,jp2,kp2) + g1*coef + + coef=a2*b2*c3 + ug(ip2,jp2,kp3) = ug(ip2,jp2,kp3) + g1*coef + +ccc + + coef=a2*b3*c0 + ug(ip2,jp3,kp0) = ug(ip2,jp3,kp0) + g1*coef + + coef=a2*b3*c1 + ug(ip2,jp3,kp1) = ug(ip2,jp3,kp1) + g1*coef + + coef=a2*b3*c2 + ug(ip2,jp3,kp2) = ug(ip2,jp3,kp2) + g1*coef + + coef=a2*b3*c3 + ug(ip2,jp3,kp3) = ug(ip2,jp3,kp3) + g1*coef + +ccc + + coef=a3*b0*c0 + ug(ip3,jp0,kp0) = ug(ip3,jp0,kp0) + g1*coef + + coef=a3*b0*c1 + ug(ip3,jp0,kp1) = ug(ip3,jp0,kp1) + g1*coef + + coef=a3*b0*c2 + ug(ip3,jp0,kp2) = ug(ip3,jp0,kp2) + g1*coef + + coef=a3*b0*c3 + ug(ip3,jp0,kp3) = ug(ip3,jp0,kp3) + g1*coef + +ccc + + coef=a3*b1*c0 + ug(ip3,jp1,kp0) = ug(ip3,jp1,kp0) + g1*coef + + coef=a3*b1*c1 + ug(ip3,jp1,kp1) = ug(ip3,jp1,kp1) + g1*coef + + coef=a3*b1*c2 + ug(ip3,jp1,kp2) = ug(ip3,jp1,kp2) + g1*coef + + coef=a3*b1*c3 + ug(ip3,jp1,kp3) = ug(ip3,jp1,kp3) + g1*coef + +ccc + + coef=a3*b2*c0 + ug(ip3,jp2,kp0) = ug(ip3,jp2,kp0) + g1*coef + + coef=a3*b2*c1 + ug(ip3,jp2,kp1) = ug(ip3,jp2,kp1) + g1*coef + + coef=a3*b2*c2 + ug(ip3,jp2,kp2) = ug(ip3,jp2,kp2) + g1*coef + + coef=a3*b2*c3 + ug(ip3,jp2,kp3) = ug(ip3,jp2,kp3) + g1*coef + +ccc + + coef=a3*b3*c0 + ug(ip3,jp3,kp0) = ug(ip3,jp3,kp0) + g1*coef + + coef=a3*b3*c1 + ug(ip3,jp3,kp1) = ug(ip3,jp3,kp1) + g1*coef + + coef=a3*b3*c2 + ug(ip3,jp3,kp2) = ug(ip3,jp3,kp2) + g1*coef + + coef=a3*b3*c3 + ug(ip3,jp3,kp3) = ug(ip3,jp3,kp3) + g1*coef + +ccc + +20 CONTINUE + +! goto 1111 + + npart=0 + + do k=1,nz2 + z=z0+(k-1)*dz2 + do j=1,ny2 + y=y0+(j-1)*dy2 + do i=1,nx2 + x=x0+(i-1)*dx2 + strength=abs(ug(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + xp2(npart)=x + yp2(npart)=y + zp2(npart)=z + phip(npart)=ug(i,j,k)*vol + endif + enddo + enddo + enddo + +1111 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_tag.f new file mode 100644 index 000000000..83773b37e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remesh_tag.f @@ -0,0 +1,86 @@ + subroutine remesh_tag(ntag,itag,itype,icfl) + + + include 'param.i' + include 'param.h' + + dimension itag(*),itype(*),icfl(*) + + + dxinv=1./dx + x0=-1. + + do n=1,ntag,2 + i=itag(n) + ii=mod(i,nx)+1 + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + ip4=mod(ip4+nx,nx) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(ip0)=ug(ip0)+a0*u1 + ug(ip1)=ug(ip1)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(ip2)=ug(ip2)+xx1*u1-yy1*u2 + ug(ip3)=ug(ip3)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(ip4)=ug(ip4)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dx-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(ip0)=ug(ip0)+a0*u1 + ug(ip1)=ug(ip1)+(1.-a0)*u1+(1.-b2)*u2 + ug(ip2)=ug(ip2)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2.f new file mode 100644 index 000000000..f0ab054f1 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2.f @@ -0,0 +1,95 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + endif + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_limit.f new file mode 100644 index 000000000..0cf7c7f68 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_limit.f @@ -0,0 +1,71 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk,sl1,sl2) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*),sl1(*),sl2(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + if (itype(n).eq.1) ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c Lambda2: +c +c avec les pentes: + + a0=0.5*((xx1-0.5)**2)-sl2(n)/8. + a1=0.75-xx1**2+(sl1(n)+sl2(n))/8. + a2=0.5*((xx1+0.5)**2)-sl1(n)/8. + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_tag.f new file mode 100644 index 000000000..ac61cf49c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l2_tag.f @@ -0,0 +1,76 @@ + subroutine remeshx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag-1,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+xx1*u1-yy1*u2 + ug(ip3,jj,kk)=ug(ip3,jj,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(ip4,jj,kk)=ug(ip4,jj,kk)+b2*u2 + + else +! case (c') and (d') +c + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+b2*u2 + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4.f new file mode 100644 index 000000000..8104d3f89 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4.f @@ -0,0 +1,83 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + ug(ip3,jj,kk) = ug(ip3,jj,kk) + g1*a3 + ug(ip4,jj,kk) = ug(ip4,jj,kk) + g1*a4 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4_tag.f new file mode 100644 index 000000000..be95aa82c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + ug(ip3m,jj,kk)=ug(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(ip2m,jj,kk)=ug(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + ug(ip1m,jj,kk)=ug(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip1p,jj,kk)=ug(ip1p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(ip2p,jj,kk)=ug(ip2p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(ip3p,jj,kk)=ug(ip3p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(ip4p,jj,kk)=ug(ip4p,jj,kk)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip5p,jj,kk)=ug(ip5p,jj,kk)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + ug(ip3m,jj,kk)=ug(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(ip2m,jj,kk)=ug(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + ug(ip1m,jj,kk)=ug(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(ip0,jj,kk)=ug(ip0,jj,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(ip1p,jj,kk)=ug(ip1p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(ip2p,jj,kk)=ug(ip2p,jj,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(ip3p,jj,kk)=ug(ip3p,jj,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_m4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_m4.f new file mode 100644 index 000000000..7c8d24d8f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_m4.f @@ -0,0 +1,75 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + ug(ip3,jj,kk) = ug(ip3,jj,kk) + g1*a3 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4.f new file mode 100644 index 000000000..67c9cd8d3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4.f @@ -0,0 +1,70 @@ + subroutine remeshx_omx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg1(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg1(ip0,jj,kk) = omg1(ip0,jj,kk) + g1*a0 + omg1(ip1,jj,kk) = omg1(ip1,jj,kk) + g1*a1 + omg1(ip2,jj,kk) = omg1(ip2,jj,kk) + g1*a2 + omg1(ip3,jj,kk) = omg1(ip3,jj,kk) + g1*a3 + omg1(ip4,jj,kk) = omg1(ip4,jj,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4_tag.f new file mode 100644 index 000000000..a3e3b3e44 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omx_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshx_omx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg1(ip3m,jj,kk)=omg1(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(ip2m,jj,kk)=omg1(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg1(ip1m,jj,kk)=omg1(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(ip0,jj,kk)=omg1(ip0,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(ip1p,jj,kk)=omg1(ip1p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(ip2p,jj,kk)=omg1(ip2p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(ip3p,jj,kk)=omg1(ip3p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(ip4p,jj,kk)=omg1(ip4p,jj,kk)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(ip5p,jj,kk)=omg1(ip5p,jj,kk)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg1(ip3m,jj,kk)=omg1(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(ip2m,jj,kk)=omg1(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg1(ip1m,jj,kk)=omg1(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(ip0,jj,kk)=omg1(ip0,jj,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(ip1p,jj,kk)=omg1(ip1p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(ip2p,jj,kk)=omg1(ip2p,jj,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(ip3p,jj,kk)=omg1(ip3p,jj,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4.f new file mode 100644 index 000000000..ec4c3100f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4.f @@ -0,0 +1,70 @@ + subroutine remeshx_omy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg2(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg2(ip0,jj,kk) = omg2(ip0,jj,kk) + g1*a0 + omg2(ip1,jj,kk) = omg2(ip1,jj,kk) + g1*a1 + omg2(ip2,jj,kk) = omg2(ip2,jj,kk) + g1*a2 + omg2(ip3,jj,kk) = omg2(ip3,jj,kk) + g1*a3 + omg2(ip4,jj,kk) = omg2(ip4,jj,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4_tag.f new file mode 100644 index 000000000..c60b9e073 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omy_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshx_omy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +c reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +c print*,xx1m,xx0,xx1p,xx2p +c reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg2(ip3m,jj,kk)=omg2(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(ip2m,jj,kk)=omg2(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg2(ip1m,jj,kk)=omg2(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(ip0,jj,kk)=omg2(ip0,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(ip1p,jj,kk)=omg2(ip1p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(ip2p,jj,kk)=omg2(ip2p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(ip3p,jj,kk)=omg2(ip3p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(ip4p,jj,kk)=omg2(ip4p,jj,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(ip5p,jj,kk)=omg2(ip5p,jj,kk)+u2p*coef2p +c +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +c case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg2(ip3m,jj,kk)=omg2(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(ip2m,jj,kk)=omg2(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg2(ip1m,jj,kk)=omg2(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(ip0,jj,kk)=omg2(ip0,jj,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(ip1p,jj,kk)=omg2(ip1p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(ip2p,jj,kk)=omg2(ip2p,jj,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(ip3p,jj,kk)=omg2(ip3p,jj,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4.f new file mode 100644 index 000000000..7f79cf523 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4.f @@ -0,0 +1,70 @@ + subroutine remeshx_omz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg3(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg3(ip0,jj,kk) = omg3(ip0,jj,kk) + g1*a0 + omg3(ip1,jj,kk) = omg3(ip1,jj,kk) + g1*a1 + omg3(ip2,jj,kk) = omg3(ip2,jj,kk) + g1*a2 + omg3(ip3,jj,kk) = omg3(ip3,jj,kk) + g1*a3 + omg3(ip4,jj,kk) = omg3(ip4,jj,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4_tag.f new file mode 100644 index 000000000..2d25ebd4a --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_omz_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshx_omz_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg3(ip3m,jj,kk)=omg3(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(ip2m,jj,kk)=omg3(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg3(ip1m,jj,kk)=omg3(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(ip0,jj,kk)=omg3(ip0,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(ip1p,jj,kk)=omg3(ip1p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(ip2p,jj,kk)=omg3(ip2p,jj,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(ip3p,jj,kk)=omg3(ip3p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(ip4p,jj,kk)=omg3(ip4p,jj,kk)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(ip5p,jj,kk)=omg3(ip5p,jj,kk)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg3(ip3m,jj,kk)=omg3(ip3m,jj,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(ip2m,jj,kk)=omg3(ip2m,jj,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg3(ip1m,jj,kk)=omg3(ip1m,jj,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(ip0,jj,kk)=omg3(ip0,jj,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(ip1p,jj,kk)=omg3(ip1p,jj,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(ip2p,jj,kk)=omg3(ip2p,jj,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(ip3p,jj,kk)=omg3(ip3p,jj,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_tag_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_tag_limit.f new file mode 100644 index 000000000..2e5badafd --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshx_tag_limit.f @@ -0,0 +1,82 @@ + subroutine remeshx_tag(ntag,itag,itype,icfl,jj,kk,sl) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + dimension sl(*) + + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag-1,2 + i=itag(n) + ib=mod(i-2+nx,nx)+1 + ii=itag(n+1) + iib=mod(ii-2+nx,nx)+1 + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + a1=0.75-xx1**2+(sl(i)+sl(ib))/8. + b1=0.75-yy1**2+(sl(ii)+sl(iib))/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+xx1*u1-yy1*u2 + ug(ip3,jj,kk)=ug(ip3,jj,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(ip4,jj,kk)=ug(ip4,jj,kk)+b2*u2 + + else +! case (c') and (d') +c + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+b2*u2 + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2.f new file mode 100644 index 000000000..278ab014d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2.f @@ -0,0 +1,83 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_limit.f new file mode 100644 index 000000000..67dcbb934 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_limit.f @@ -0,0 +1,56 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk,sl1,sl2) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*),sl1(*),sl2(*) + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + if (itype(n).eq.1) ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c Lambda2: +c +c avec les pentes: + + a0=0.5*((xx1-0.5)**2)-sl2(n)/8. + a1=0.75-xx1**2+(sl1(n)+sl2(n))/8. + a2=0.5*((xx1+0.5)**2)-sl1(n)/8. + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_tag.f new file mode 100644 index 000000000..48ac7b517 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l2_tag.f @@ -0,0 +1,86 @@ + subroutine remeshy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+xx1*u1-yy1*u2 + ug(jj,ip3,kk)=ug(jj,ip3,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(jj,ip4,kk)=ug(jj,ip4,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4.f new file mode 100644 index 000000000..6790ace02 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4.f @@ -0,0 +1,83 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + ug(jj,ip3,kk) = ug(jj,ip3,kk) + g1*a3 + ug(jj,ip4,kk) = ug(jj,ip4,kk) + g1*a4 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4_tag.f new file mode 100644 index 000000000..bf2533047 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_l4_tag.f @@ -0,0 +1,178 @@ + subroutine remeshy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! do n=1,1 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + ug(jj,ip3m,kk)=ug(jj,ip3m,kk)+u1m*coef1m + +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(jj,ip2m,kk)=ug(jj,ip2m,kk)+u1m*coef1m+u0*coef0 + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + ug(jj,ip1m,kk)=ug(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p + +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,ip0,kk)=ug(jj,ip0,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,ip1p,kk)=ug(jj,ip1p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(jj,ip2p,kk)=ug(jj,ip2p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(jj,ip3p,kk)=ug(jj,ip3p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(jj,ip4p,kk)=ug(jj,ip4p,kk)+u1p*coef1p+u2p*coef2p + +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,ip5p,kk)=ug(jj,ip5p,kk)+u2p*coef2p + +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + ug(jj,ip3m,kk)=ug(jj,ip3m,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(jj,ip2m,kk)=ug(jj,ip2m,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + ug(jj,ip1m,kk)=ug(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(jj,ip1p,kk)=ug(jj,ip1p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(jj,ip2p,kk)=ug(jj,ip2p,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,ip3p,kk)=ug(jj,ip3p,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_m4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_m4.f new file mode 100644 index 000000000..1242e5467 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_m4.f @@ -0,0 +1,61 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + ug(jj,ip3,kk) = ug(jj,ip3,kk) + g1*a3 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4.f new file mode 100644 index 000000000..d5669b305 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4.f @@ -0,0 +1,70 @@ + subroutine remeshy_omx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg1(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg1(jj,ip0,kk) = omg1(jj,ip0,kk) + g1*a0 + omg1(jj,ip1,kk) = omg1(jj,ip1,kk) + g1*a1 + omg1(jj,ip2,kk) = omg1(jj,ip2,kk) + g1*a2 + omg1(jj,ip3,kk) = omg1(jj,ip3,kk) + g1*a3 + omg1(jj,ip4,kk) = omg1(jj,ip4,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4_tag.f new file mode 100644 index 000000000..0bbfb884d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omx_l4_tag.f @@ -0,0 +1,178 @@ + subroutine remeshy_omx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! do n=1,1 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg1(jj,ip3m,kk)=omg1(jj,ip3m,kk)+u1m*coef1m + +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(jj,ip2m,kk)=omg1(jj,ip2m,kk)+u1m*coef1m+u0*coef0 + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg1(jj,ip1m,kk)=omg1(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p + +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,ip0,kk)=omg1(jj,ip0,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,ip1p,kk)=omg1(jj,ip1p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(jj,ip2p,kk)=omg1(jj,ip2p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(jj,ip3p,kk)=omg1(jj,ip3p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(jj,ip4p,kk)=omg1(jj,ip4p,kk)+u1p*coef1p+u2p*coef2p + +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,ip5p,kk)=omg1(jj,ip5p,kk)+u2p*coef2p + +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg1(jj,ip3m,kk)=omg1(jj,ip3m,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(jj,ip2m,kk)=omg1(jj,ip2m,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg1(jj,ip1m,kk)=omg1(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(jj,ip0,kk)=omg1(jj,ip0,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(jj,ip1p,kk)=omg1(jj,ip1p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(jj,ip2p,kk)=omg1(jj,ip2p,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,ip3p,kk)=omg1(jj,ip3p,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4.f new file mode 100644 index 000000000..02cb35d2b --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4.f @@ -0,0 +1,70 @@ + subroutine remeshy_omy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg2(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +! Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg2(jj,ip0,kk) = omg2(jj,ip0,kk) + g1*a0 + omg2(jj,ip1,kk) = omg2(jj,ip1,kk) + g1*a1 + omg2(jj,ip2,kk) = omg2(jj,ip2,kk) + g1*a2 + omg2(jj,ip3,kk) = omg2(jj,ip3,kk) + g1*a3 + omg2(jj,ip4,kk) = omg2(jj,ip4,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4_tag.f new file mode 100644 index 000000000..37e666579 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omy_l4_tag.f @@ -0,0 +1,178 @@ + subroutine remeshy_omy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! do n=1,1 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg2(jj,ip3m,kk)=omg2(jj,ip3m,kk)+u1m*coef1m + +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(jj,ip2m,kk)=omg2(jj,ip2m,kk)+u1m*coef1m+u0*coef0 + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg2(jj,ip1m,kk)=omg2(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p + +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,ip0,kk)=omg2(jj,ip0,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,ip1p,kk)=omg2(jj,ip1p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(jj,ip2p,kk)=omg2(jj,ip2p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(jj,ip3p,kk)=omg2(jj,ip3p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(jj,ip4p,kk)=omg2(jj,ip4p,kk)+u1p*coef1p+u2p*coef2p + +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,ip5p,kk)=omg2(jj,ip5p,kk)+u2p*coef2p + +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg2(jj,ip3m,kk)=omg2(jj,ip3m,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(jj,ip2m,kk)=omg2(jj,ip2m,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg2(jj,ip1m,kk)=omg2(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(jj,ip0,kk)=omg2(jj,ip0,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(jj,ip1p,kk)=omg2(jj,ip1p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(jj,ip2p,kk)=omg2(jj,ip2p,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,ip3p,kk)=omg2(jj,ip3p,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4.f new file mode 100644 index 000000000..d21f51d66 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4.f @@ -0,0 +1,70 @@ + subroutine remeshy_omz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg3(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg3(jj,ip0,kk) = omg3(jj,ip0,kk) + g1*a0 + omg3(jj,ip1,kk) = omg3(jj,ip1,kk) + g1*a1 + omg3(jj,ip2,kk) = omg3(jj,ip2,kk) + g1*a2 + omg3(jj,ip3,kk) = omg3(jj,ip3,kk) + g1*a3 + omg3(jj,ip4,kk) = omg3(jj,ip4,kk) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4_tag.f new file mode 100644 index 000000000..0bbd81e3a --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_omz_l4_tag.f @@ -0,0 +1,178 @@ + subroutine remeshy_omz_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +c do n=1,1 +c reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +c reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg3(jj,ip3m,kk)=omg3(jj,ip3m,kk)+u1m*coef1m + +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(jj,ip2m,kk)=omg3(jj,ip2m,kk)+u1m*coef1m+u0*coef0 + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg3(jj,ip1m,kk)=omg3(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p + +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,ip0,kk)=omg3(jj,ip0,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,ip1p,kk)=omg3(jj,ip1p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(jj,ip2p,kk)=omg3(jj,ip2p,kk) + 1 +u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(jj,ip3p,kk)=omg3(jj,ip3p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p + +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(jj,ip4p,kk)=omg3(jj,ip4p,kk)+u1p*coef1p+u2p*coef2p + +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,ip5p,kk)=omg3(jj,ip5p,kk)+u2p*coef2p + +c +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +c case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg3(jj,ip3m,kk)=omg3(jj,ip3m,kk)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(jj,ip2m,kk)=omg3(jj,ip2m,kk)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg3(jj,ip1m,kk)=omg3(jj,ip1m,kk)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(jj,ip0,kk)=omg3(jj,ip0,kk)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(jj,ip1p,kk)=omg3(jj,ip1p,kk)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(jj,ip2p,kk)=omg3(jj,ip2p,kk)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,ip3p,kk)=omg3(jj,ip3p,kk)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_tag_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_tag_limit.f new file mode 100644 index 000000000..c99271410 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshy_tag_limit.f @@ -0,0 +1,92 @@ + subroutine remeshy_tag(ntag,itag,itype,icfl,jj,kk,sl) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + dimension sl(*) + + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ib=mod(i-2+nx,nx)+1 + ii=itag(n+1) + iib=mod(ii-2+nx,nx)+1 + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + a1=0.75-xx1**2+(sl(i)+sl(ib))/8. + b1=0.75-yy1**2+(sl(ii)+sl(iib))/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+xx1*u1-yy1*u2 + ug(jj,ip3,kk)=ug(jj,ip3,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(jj,ip4,kk)=ug(jj,ip4,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2.f new file mode 100644 index 000000000..835bfca44 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2.f @@ -0,0 +1,83 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_limit.f new file mode 100644 index 000000000..6306e6bcf --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_limit.f @@ -0,0 +1,55 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk,sl1,sl2) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*),sl1(*),sl2(*) + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + if (itype(n).eq.1) ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c Lambda2: +c +c avec les pentes: + + a0=0.5*((xx1-0.5)**2)-sl2(n)/8. + a1=0.75-xx1**2+(sl1(n)+sl2(n))/8. + a2=0.5*((xx1+0.5)**2)-sl1(n)/8. + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_tag.f new file mode 100644 index 000000000..af3a92781 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l2_tag.f @@ -0,0 +1,86 @@ + subroutine remeshz_tag(ntag,itag,itype,icfl,kk,jj) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+xx1*u1-yy1*u2 + ug(kk,jj,ip3)=ug(kk,jj,ip3)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(kk,jj,ip4)=ug(kk,jj,ip4)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+(1.-a0)*u1+(1.-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4.f new file mode 100644 index 000000000..43dfb7d95 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4.f @@ -0,0 +1,83 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + ug(jj,kk,ip3) = ug(jj,kk,ip3) + g1*a3 + ug(jj,kk,ip4) = ug(jj,kk,ip4) + g1*a4 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4_tag.f new file mode 100644 index 000000000..b93bfe3c9 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshz_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +c reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +c print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +c print*,xx1m,xx0,xx1p,xx2p +c reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + ug(jj,kk,ip3m)=ug(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(jj,kk,ip2m)=ug(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + ug(jj,kk,ip1m)=ug(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,kk,ip0)=ug(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,kk,ip1p)=ug(jj,kk,ip1p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(jj,kk,ip2p)=ug(jj,kk,ip2p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(jj,kk,ip3p)=ug(jj,kk,ip3p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(jj,kk,ip4p)=ug(jj,kk,ip4p)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,kk,ip5p)=ug(jj,kk,ip5p)+u2p*coef2p +c +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +c case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + ug(jj,kk,ip3m)=ug(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + ug(jj,kk,ip2m)=ug(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + ug(jj,kk,ip1m)=ug(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + ug(jj,kk,ip0)=ug(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + ug(jj,kk,ip1p)=ug(jj,kk,ip1p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + ug(jj,kk,ip2p)=ug(jj,kk,ip2p)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + ug(jj,kk,ip3p)=ug(jj,kk,ip3p)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_m4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_m4.f new file mode 100644 index 000000000..96b9ec719 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_m4.f @@ -0,0 +1,62 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + ug(jj,kk,ip3) = ug(jj,kk,ip3) + g1*a3 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4.f new file mode 100644 index 000000000..2434190c4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4.f @@ -0,0 +1,70 @@ + subroutine remeshz_omx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg1(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg1(jj,kk,ip0) = omg1(jj,kk,ip0) + g1*a0 + omg1(jj,kk,ip1) = omg1(jj,kk,ip1) + g1*a1 + omg1(jj,kk,ip2) = omg1(jj,kk,ip2) + g1*a2 + omg1(jj,kk,ip3) = omg1(jj,kk,ip3) + g1*a3 + omg1(jj,kk,ip4) = omg1(jj,kk,ip4) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4_tag.f new file mode 100644 index 000000000..a20f4b722 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omx_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshz_omx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg1(jj,kk,ip3m)=omg1(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(jj,kk,ip2m)=omg1(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg1(jj,kk,ip1m)=omg1(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,kk,ip0)=omg1(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,kk,ip1p)=omg1(jj,kk,ip1p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(jj,kk,ip2p)=omg1(jj,kk,ip2p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(jj,kk,ip3p)=omg1(jj,kk,ip3p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(jj,kk,ip4p)=omg1(jj,kk,ip4p)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,kk,ip5p)=omg1(jj,kk,ip5p)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg1(jj,kk,ip3m)=omg1(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg1(jj,kk,ip2m)=omg1(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg1(jj,kk,ip1m)=omg1(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg1(jj,kk,ip0)=omg1(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg1(jj,kk,ip1p)=omg1(jj,kk,ip1p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg1(jj,kk,ip2p)=omg1(jj,kk,ip2p)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg1(jj,kk,ip3p)=omg1(jj,kk,ip3p)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4.f new file mode 100644 index 000000000..f82df1cb4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4.f @@ -0,0 +1,70 @@ + subroutine remeshz_omy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg2(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg2(jj,kk,ip0) = omg2(jj,kk,ip0) + g1*a0 + omg2(jj,kk,ip1) = omg2(jj,kk,ip1) + g1*a1 + omg2(jj,kk,ip2) = omg2(jj,kk,ip2) + g1*a2 + omg2(jj,kk,ip3) = omg2(jj,kk,ip3) + g1*a3 + omg2(jj,kk,ip4) = omg2(jj,kk,ip4) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4_tag.f new file mode 100644 index 000000000..3044f7fe8 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omy_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshz_omy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg2(jj,kk,ip3m)=omg2(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(jj,kk,ip2m)=omg2(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg2(jj,kk,ip1m)=omg2(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,kk,ip0)=omg2(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,kk,ip1p)=omg2(jj,kk,ip1p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(jj,kk,ip2p)=omg2(jj,kk,ip2p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(jj,kk,ip3p)=omg2(jj,kk,ip3p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(jj,kk,ip4p)=omg2(jj,kk,ip4p)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,kk,ip5p)=omg2(jj,kk,ip5p)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg2(jj,kk,ip3m)=omg2(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg2(jj,kk,ip2m)=omg2(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg2(jj,kk,ip1m)=omg2(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg2(jj,kk,ip0)=omg2(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg2(jj,kk,ip1p)=omg2(jj,kk,ip1p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg2(jj,kk,ip2p)=omg2(jj,kk,ip2p)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg2(jj,kk,ip3p)=omg2(jj,kk,ip3p)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4.f new file mode 100644 index 000000000..342b5b7a1 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4.f @@ -0,0 +1,70 @@ + subroutine remeshz_omz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + omg3(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + else + ip1 = nint((x-x0)*dxinv) + endif + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + + + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=xx1-1. + xx3=xx1+2. + xx4=xx1-2. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c +c Lambda4: +c + a0 = -xx4*xx2*xx1*xx3/6. + a1 = xx0*xx2*xx3*xx4/4. + a2 = -xx0*xx1*xx3*xx4/6. + a3 = xx0*xx1*xx2*xx4/24. + a4 = xx0*xx1*xx2*xx3/24. + + omg3(jj,kk,ip0) = omg3(jj,kk,ip0) + g1*a0 + omg3(jj,kk,ip1) = omg3(jj,kk,ip1) + g1*a1 + omg3(jj,kk,ip2) = omg3(jj,kk,ip2) + g1*a2 + omg3(jj,kk,ip3) = omg3(jj,kk,ip3) + g1*a3 + omg3(jj,kk,ip4) = omg3(jj,kk,ip4) + g1*a4 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4_tag.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4_tag.f new file mode 100644 index 000000000..8e907cf9c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_omz_l4_tag.f @@ -0,0 +1,171 @@ + subroutine remeshz_omz_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + + do n=1,ntag-1,4 +! reperage des 4 particules taggees: positions, poids + i=itag(n) + ii=itag(n+1) + iii=itag(n+2) + iiii=itag(n+3) + x1m=xp(i) + x0=xp(ii) + x1p=xp(iii) + x2p=xp(iiii) + u1m=up(i) + u0=up(ii) + u1p=up(iii) + u2p=up(iiii) +! print*,n,i,x1m,x0,x1p,x2p,u1m,u0,u1p,u2p,itype(i),itype(ii), +c 1 itype(iii),itype(iiii) +c +c reperage du point de base pour les 4 particules taggees selon le type + if (itype(i).eq.0) then + ip0 = int((x0-xmin)*dxinv) + ip1m = int((x1m-xmin)*dxinv) + ip1p = nint((x1p-xmin)*dxinv) + ip2p = nint((x2p-xmin)*dxinv) + else + ip0 = nint((x0-xmin)*dxinv) + ip1m = nint((x1m-xmin)*dxinv) + ip1p = int((x1p-xmin)*dxinv) + ip2p = int((x2p-xmin)*dxinv) + endif + xx0 = (x0 - float(ip0)*dx2-xmin)*dxinv + xx1m = (x1m - float(ip1m)*dx2-xmin)*dxinv + xx1p = (x1p - float(ip1p)*dx2-xmin)*dxinv + xx2p = (x2p - float(ip2p)*dx2-xmin)*dxinv +! print*,xx1m,xx0,xx1p,xx2p +! reperage des points de grille concernes +c de I-3 a I+5 ou I est point de grille a gauche de particule x0 + ip3m=ip0-3 + ip2m=ip0-2 + ip1m=ip0-1 + ip5p=ip0+5 + ip4p=ip0+4 + ip3p=ip0+3 + ip2p=ip0+2 + ip1p=ip0+1 + ip0=mod(ip0+nx,nx) +1 + ip1p=mod(ip1p+nx,nx) +1 + ip2p=mod(ip2p+nx,nx) +1 + ip3p=mod(ip3p+nx,nx) +1 + ip4p=mod(ip4p+nx,nx) +1 + ip5p=mod(ip5p+nx,nx) +1 + ip1m=mod(ip1m+nx,nx) +1 + ip2m=mod(ip2m+nx,nx) +1 + ip3m=mod(ip3m+nx,nx) +1 +c cases (c) and (d) +c + if (itype(i).eq.0) then + coef1m=(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+1)/24. + omg3(jj,kk,ip3m)=omg3(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*xx1m*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(jj,kk,ip2m)=omg3(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*xx0*(xx0+2)/6. + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + omg3(jj,kk,ip1m)=omg3(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef1p=-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,kk,ip0)=omg3(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef1m=coef1m-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+3)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,kk,ip1p)=omg3(jj,kk,ip1p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + coef0=-(xx0-3.)*(xx0-1.)*(xx0+0.)*(xx0+1)/6. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(jj,kk,ip2p)=omg3(jj,kk,ip2p)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+1)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(jj,kk,ip3p)=omg3(jj,kk,ip3p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(jj,kk,ip4p)=omg3(jj,kk,ip4p)+u1p*coef1p+u2p*coef2p +! + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,kk,ip5p)=omg3(jj,kk,ip5p)+u2p*coef2p +c +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c +! case (c') and (d') + else +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+1)/24. + omg3(jj,kk,ip3m)=omg3(jj,kk,ip3m)+u1m*coef1m +c + coef1m=-(xx1m-2.)*(xx1m-1.)*(xx1m+0.)*(xx1m+2)/6. + coef0=(xx0-2.)*(xx0-1.)*xx0*(xx0+1)/24. + omg3(jj,kk,ip2m)=omg3(jj,kk,ip2m)+u1m*coef1m+u0*coef0 +c + coef1m=(xx1m-2.)*(xx1m-1.)*(xx1m+1.)*(xx1m+2)/4. + coef0=-(xx0-2.)*(xx0-1.)*(xx0+0.)*(xx0+2)/6. + coef1p=(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + omg3(jj,kk,ip1m)=omg3(jj,kk,ip1m)+u1m*coef1m+u0*coef0+u1p*coef1p +c + coef1m=-(xx1m-2.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/6. + coef1m=coef1m+(xx1m-1.)*(xx1m-0.)*(xx1m+1.)*(xx1m+2)/24. + coef0=(xx0-2.)*(xx0-1.)*(xx0+1.)*(xx0+2)/4. + coef0=coef0-(xx0-2.)*(xx0-0.)*(xx0+1.)*(xx0+2)/6. + coef0=coef0+(xx0-1.)*(xx0-0.)*(xx0+1.)*(xx0+2)/24. + coef0=coef0-(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+1)/24. + coef1p=coef1p-(xx1p-3.)*(xx1p-2.)*(xx1p-1.)*(xx1p+0)/24. + coef1p=coef1p-(xx1p-2.)*(xx1p-1.)*(xx1p+0.)*(xx1p+2)/6. + coef1p=coef1p+(xx1p-2.)*(xx1p-1.)*(xx1p+1.)*(xx1p+2)/4. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+1)/24. + coef2p=coef2p-(xx2p-2.)*(xx2p-1.)*(xx2p+0.)*(xx2p+2)/6. + omg3(jj,kk,ip0)=omg3(jj,kk,ip0)+ + 1 u1m*coef1m+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef0=(xx0-0.)*(xx0+1.)*(xx0+2.)*(xx0+3)/24. + coef1p=-(xx1p-2.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/6. + coef2p=(xx2p-2.)*(xx2p-1.)*(xx2p+1.)*(xx2p+2)/4. + omg3(jj,kk,ip1p)=omg3(jj,kk,ip1p)+u0*coef0+u1p*coef1p+u2p*coef2p +c + coef1p=(xx1p-1.)*(xx1p-0.)*(xx1p+1.)*(xx1p+2)/24. + coef2p=-(xx2p-2.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/6. + omg3(jj,kk,ip2p)=omg3(jj,kk,ip2p)+u1p*coef1p+u2p*coef2p +c + coef2p=(xx2p-1.)*(xx2p-0.)*(xx2p+1.)*(xx2p+2)/24. + omg3(jj,kk,ip3p)=omg3(jj,kk,ip3p)+u2p*coef2p + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_tag_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_tag_limit.f new file mode 100644 index 000000000..c50350527 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/remeshz_tag_limit.f @@ -0,0 +1,91 @@ + subroutine remeshz_tag(ntag,itag,itype,icfl,kk,jj,sl) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + dimension sl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ib=mod(i-2+nx,nx)+1 + ii=itag(n+1) + iib=mod(ii-2+nx,nx)+1 + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + a1=0.75-xx1**2+(sl(i)+sl(ib))/8. + b1=0.75-yy1**2+(sl(ii)+sl(iib))/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+xx1*u1-yy1*u2 + ug(kk,jj,ip3)=ug(kk,jj,ip3)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(kk,jj,ip4)=ug(kk,jj,ip4)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c version avec limituers de pente + a0=0.5*((xx1-0.5)**2)-sl(ib)/8. + b2=0.5*((yy1+0.5)**2)-sl(ii)/8. + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+(1.-a0)*u1+(1.-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/slopes.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/slopes.f new file mode 100644 index 000000000..7a38f2d96 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/slopes.f @@ -0,0 +1,54 @@ + subroutine slopes(dt,np,sl) + + include 'param.i' + include 'param.h' +! include 'arrays.h' + + common/remesh/xp0(npg),xp(npg),up(npg),vx(npg) + + dimension sl(*) + +c al1: pente pour v>0 +c al2: pente pour v<0 + + do n=1,np + sl(n)=0. + enddo +! goto 111 + do n=1,np + afl=vx(n)*dt/dx-nint(vx(n)*dt/dx) + phimax1=4.*amin1(0.9,(afl+0.5)**2) + phimax2=4.*amin1(0.9,(afl-0.5)**2) + nt=mod(n+nx,nx)+1 + ntt=mod(n+1+nx,nx)+1 + nb=mod(n-2+nx,nx)+1 + apu=up(nt)-up(n) + apuu=up(ntt)-up(nt) + apb=up(n)-up(nb) + al1=0. + al2=0. +c limiteur de pente + if (abs(apu).ge.0.00001) then + rr1=apb/apu + rr2=apuu/apu +c sweeby : + al1=amax1(0.,amin1(phimax1*rr1,phimax1)) + al1=amax1(al1,amin1(phimax1,rr1)) + al2=amax1(0.,amin1(phimax2*rr2,phimax2)) + al2=amax1(al2,amin1(phimax2,rr2)) +c van leer : + if (rr1.gt.0.) al1=phimax1*rr1/(1.+rr1) + if (rr2.gt.0.) al2=phimax2*rr2/(1.+rr2) + endif + sl(n)=al1 + if (afl.le.0.) sl(n)=al2 +c pour retrouver lambda 2 : sl=1 + sl(n)=0. + enddo +111 continue + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/spec.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec.f new file mode 100644 index 000000000..729241a58 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec.f @@ -0,0 +1,106 @@ + program spectre + parameter(n=32,ns2=n/2,n1=1-ns2) +c + complex u,v,w,um,vm,wm + dimension u(0:ns2,n1:ns2,n1:ns2), + 2 v(0:ns2,n1:ns2,n1:ns2), + 4 w(0:ns2,n1:ns2,n1:ns2), + 5 um(n1:ns2,n1:ns2,n1:ns2), + 6 vm(n1:ns2,n1:ns2,n1:ns2), + 7 wm(n1:ns2,n1:ns2,n1:ns2) +c + real ijc(n1:ns2,n1:ns2,n1:ns2) + real nrj(ns2),mod,pi, deuxpi,z,z0,zf,s + real mod0, modf,ct,t0 + real ru(n,n,n),rv(n,n,n),rw(n,n,n) + complex wk(ns2+1,n,n) +c + pi=acos(-1.0) + deuxpi=pi+pi + deuxpi3=(deuxpi)*(deuxpi)*(deuxpi) + ct=2/3 + +c open(11,FILE='v128000.ux', +c 1 FORM='unformatted', convert='big_endian', +c 1 status='old') +c read(11) (((ru(i,j,k),i=1,n),j=1,n),k=1,n) +c close(11) +c +c open(12,FILE='v128000.uy', +c 1 FORM='unformatted', convert='big_endian', +c 1 status='old') +c read(12) (((rv(i,j,k),i=1,n),j=1,n),k=1,n) +c close(12) +c +c open(13,FILE='v128000.uz', +c 1 FORM='unformatted', convert='big_endian', +c 1 status='old') +c read(13) (((rw(i,j,k),i=1,n),j=1,n),k=1,n) +c close(13) +c +c call fftw3d(ru,u,n,ns2,wk,0) +C +c call fftw3d(rv,v,n,ns2,wk,0) +C +c call fftw3d(rw,w,n,ns2,wk,0) +c + open(21,FILE='vel.u',FORM='UNFORMATTED', + 1 convert='big_endian', + 1 status='old') + read(21)t0 + read(21) (((u(i,j,k),i=0,ns2),j=n1,ns2),k=n1,ns2) + close(21) + open(22,FILE='vel.v',FORM='UNFORMATTED', + 1 convert='big_endian', + 1 status='old') + read(22) (((v(i,j,k),i=0,ns2),j=n1,ns2),k=n1,ns2) + close(22) + open(23,FILE='vel.w',FORM='UNFORMATTED', + 1 convert='big_endian', + 1 status='old') + read(23) (((w(i,j,k),i=0,ns2),j=n1,ns2),k=n1,ns2) + close(23) +c + do k=1-ns2,ns2 + do j=1-ns2,ns2 + um(0,j,k)=u(0,j,k) + vm(0,j,k)=v(0,j,k) + wm(0,j,k)=w(0,j,k) + do i=1,ns2 + um(-i,j,k)=u(i,j,k) + um(i,j,k)=u(i,j,k) + + vm(-i,j,k)=v(i,j,k) + vm(i,j,k)=v(i,j,k) +c + wm(-i,j,k)=w(i,j,k) + wm(i,j,k)=w(i,j,k) + enddo + enddo + enddo +c + open(1,file='spectreT0.97') + do l=1,ns2 +c + do k=1-ns2,ns2 + do j=1-ns2,ns2 + do i=1-ns2,ns2 + ijc(i,j,k)=float(i**2+j**2+k**2) + mod=sqrt(ijc(i,j,k)) + if ((mod.lt.l+0.5).and.(mod.ge.l-0.5)) then + z=cabs(um(i,j,k))**2+cabs(vm(i,j,k))**2+cabs(wm(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + stop + END diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_balarac.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_balarac.f new file mode 100644 index 000000000..40823bb1e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_balarac.f @@ -0,0 +1,115 @@ + program spec + + + include 'param_rho.i' +c include 'param.h' + + real*8 tout(npgx,npgy,npgz,4) + dimension rhog(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + real ijc(1-ngx2:ngx2,1-ngx2:ngx2,1-ngx2:ngx2) + real nrj(ngx2) + + + pi=3.1415926 + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + xmin=0. + ymin=0. + zmin=0. + xmax=1. + ymax=1. + zmax=1. + + ny2=nx2 + nz2=nx2 + + +c calucl de fonction courants 3d + + + nxb=nx2/2 + nyb=ny2/2 + nzb=nz2/2 + + open(11,FILE='data1', + 1 FORM='binary', +c 1 convert='big_endian', + 1 status='old') + read(11) nx,nx,nx,var + print*,nx,var + read(11) ((((tout(i,j,k,l),i=1,nx2),j=1,ny2),k=1,nz2),l=1,4) + close(11) + + rhomax=0. + do i=1,nx2 + do j=1,nx2 + do k=1,nx2 + rhog(i,j,k)=tout(i,j,k,4) + rhomax=amax1(rhomax,rhog(i,j,k)) + enddo + enddo + enddo + + open(2,file='datarho',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + write(2) ((((rhog(i,j,k)), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + + print*, 'rhomax = ',rhomax + close(2) + + + call fftw3d(rhog,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,0) + + + do k=1-nzb,nzb + do j=1-nyb,nyb + cfx(0,j,k)=cux(0,j,k) + do i=1,nxb + if (i.le.nxb-1) cfx(-i,j,k)=cux(i,j,k) + cfx(i,j,k)=cux(i,j,k) + enddo + enddo + enddo +c + open(1,file='spectre') + s=0. + do l=1,nxb +c + do k=1-nzb,nzb + do j=1-nyb,nyb + do i=1-nxb,nxb + ijc(i,j,k)=float(i**2+j**2+k**2) + xmod=sqrt(ijc(i,j,k)) + if ((xmod.lt.l+0.5).and.(xmod.ge.l-0.5)) then + z=cabs(cfx(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_energy.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_energy.f new file mode 100644 index 000000000..1710a0712 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_energy.f @@ -0,0 +1,145 @@ + program spec + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension aux3(npgx,npgy,npgz), + 1 aux1(npgx,npgy,npgz),aux2(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cux(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + real ijc(1-ngx2:ngx2,1-ngx2:ngx2,1-ngx2:ngx2) + real nrj(ngx2) + + + + pi=3.1415926 + pi2=2*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + ymax=pi2 + zmax=pi2 + + ny1=nx1 + nz1=nx1 + +c calucl de fonction courants 3d + + nxb=nx1/2 + nyb=ny1/2 + nzb=nz1/2 + + open(11,FILE='omx', + 1 FORM='unformatted', convert='big_endian', + 1 status='old') + read(11) (((omg1(i,j,k),i=1,nx1),j=1,ny1),k=1,nz1) + close(11) + + open(12,FILE='omy', + 1 FORM='unformatted', convert='big_endian', + 1 status='old') + read(12) (((omg2(i,j,k),i=1,nx1),j=1,ny1),k=1,nz1) + close(12) + + open(13,FILE='omz', + 1 FORM='unformatted', convert='big_endian', + 1 status='old') + read(13) (((omg3(i,j,k),i=1,nx1),j=1,ny1),k=1,nz1) + close(13) + + print*,'hello' + + call fftw3d(omg1,cfx,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg2,cfy,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg3,cfz,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + + print*,'hello' + +c coeff de normalisation pour laplacien en spectral + + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nzb,nzb + rk=float(k)*ak + do 10 j=1-nyb,nyb + rj=float(j)*aj + do 10 i=0,nxb + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) + if (r2.ne.0.) then +c + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + endif +10 continue + + + do k=1-nzb,nzb + do j=1-nyb,nyb + do i=1,nxb + if (i.le.nxb-1) cux(-i,j,k)=cux(i,j,k) + if (i.le.nxb-1) cuy(-i,j,k)=cuy(i,j,k) + if (i.le.nxb-1) cuz(-i,j,k)=cuz(i,j,k) + enddo + enddo + enddo +c + open(1,file='spectre_en') + do l=1,nxb +c + do k=1-nzb,nzb + do j=1-nyb,nyb + do i=1-nxb,nxb + ijc(i,j,k)=float(i**2+j**2+k**2) + xmod=sqrt(ijc(i,j,k)) + if ((xmod.lt.l+0.5).and.(xmod.ge.l-0.5)) then + z=cabs(cux(i,j,k))**2+cabs(cuy(i,j,k))**2+cabs(cuz(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + + + + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho.f new file mode 100644 index 000000000..d62a58474 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho.f @@ -0,0 +1,107 @@ + program spec + + + include 'param_rho.i' + include 'param.h' + + dimension rhog(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + real ijc(1-ngx2:ngx2,1-ngx2:ngx2,1-ngx2:ngx2) + real nrj(ngx2) + + + pi=3.1415926 + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + xmin=0. + ymin=0. + zmin=0. + xmax=1. + ymax=1. + zmax=1. + + ny2=nx2 + nz2=nx2 + + +c calucl de fonction courants 3d + + + nxb=nx2/2 + nyb=ny2/2 + nzb=nz2/2 + + open(11,FILE='rho') + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + read(11,*) rhog(i,j,k) + enddo + enddo + enddo + close(11) + + rhomax=0. + + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + rhomax=amax1(rhomax,abs(rhog(i,j,k))) + enddo + enddo + enddo + + print*,'rhomax',rhomax + + call fftw3d(rhog,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,0) + + + do k=1-nzb,nzb + do j=1-nyb,nyb + cfx(0,j,k)=cux(0,j,k) + do i=1,nxb + if (i.le.nxb-1) cfx(-i,j,k)=cux(i,j,k) + cfx(i,j,k)=cux(i,j,k) + enddo + enddo + enddo +c + open(1,file='spectre') + + s=0. + do l=1,nxb +c + do k=1-nzb,nzb + do j=1-nyb,nyb + do i=1-nxb,nxb + ijc(i,j,k)=float(i**2+j**2+k**2) + xmod=sqrt(ijc(i,j,k)) + if ((xmod.lt.l+0.5).and.(xmod.ge.l-0.5)) then + z=cabs(cfx(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho_orig.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho_orig.f new file mode 100644 index 000000000..3094bf429 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/spec_rho_orig.f @@ -0,0 +1,104 @@ + program spec + + + include 'param_rho.i' + include 'param.h' + + dimension rhog(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(1-ngx2:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + real ijc(1-ngx2:ngx2,1-ngx2:ngx2,1-ngx2:ngx2) + real nrj(ngx2) + + + pi=3.1415926 + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + + xmin=0. + ymin=0. + zmin=0. + xmax=1. + ymax=1. + zmax=1. + + ny2=nx2 + nz2=nx2 + + +c calucl de fonction courants 3d + + + nxb=nx2/2 + nyb=ny2/2 + nzb=nz2/2 + + open(11,FILE='rho', + 1 FORM='unformatted', convert='big_endian', + 1 status='old') + read(11) (((rhog(i,j,k),i=1,nx2),j=1,ny2),k=1,nz2) + close(11) + + rhomax=0. + + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + rhomax=amax1(rhomax,abs(rhog(i,j,k))) + enddo + enddo + enddo + + print*,'rhomax',rhomax + + call fftw3d(rhog,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,0) + call fftw3d(rhog,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,0) + + + do k=1-nzb,nzb + do j=1-nyb,nyb + cfx(0,j,k)=cux(0,j,k) + do i=1,nxb + if (i.le.nxb-1) cfx(-i,j,k)=cux(i,j,k) + cfx(i,j,k)=cux(i,j,k) + enddo + enddo + enddo +c + open(1,file='spectre') + + s=0. + do l=1,nxb +c + do k=1-nzb,nzb + do j=1-nyb,nyb + do i=1-nxb,nxb + ijc(i,j,k)=float(i**2+j**2+k**2) + xmod=sqrt(ijc(i,j,k)) + if ((xmod.lt.l+0.5).and.(xmod.ge.l-0.5)) then + z=cabs(cfx(i,j,k))**2 + s=s+z + endif + enddo + enddo + enddo +c + nrj(l)=s +c + write(1,*)l,nrj(l)/2 + s=0. + enddo + close(1) +c + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/stension.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension.f new file mode 100644 index 000000000..7640c3f4f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension.f @@ -0,0 +1,126 @@ + subroutine stension(tau,ic) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension gradrhox(npg,npg,npg),anormx(npg,npg,npg) + dimension gradrhoy(npg,npg,npg),anormy(npg,npg,npg) + dimension gradrhoz(npg,npg,npg),anormz(npg,npg,npg) + dimension curv(npg,npg,npg) + + + + pi=3.1415926 + spi=sqrt(pi) + phibar=0.5 + + taudxinv=tau/(float(ic)*(2.*dx)**3) + al=0. + +! cas ou on ne passe pas par stretch d'abor: + + goto 1111 + do k=1,nx + do j=1,nx + do i=1,nx + strg1(i,j,k)=0. + strg2(i,j,k)=0. + strg3(i,j,k)=0. + enddo + enddo + enddo +1111 continue + +c cas ou on utilise grd rho comme level set + eps=2.*float(ic)*dx + eps2=eps**2 + +! calcul de gradrho et normale + + do i=1,nx + it=mod(i+ic+nx-1,nx)+1 + ib=mod(i-ic+nx-1,nx)+1 + do j=1,nx + jt=mod(j+ic+nx-1,nx)+1 + jb=mod(j-ic+nx-1,nx)+1 + do k=1,nx + kt=mod(k+ic+nx-1,nx)+1 + kb=mod(k-ic+nx-1,nx)+1 + gradrhoz(i,j,k)=ug(i,j,kt)-ug(i,j,kb) + gradrhoy(i,j,k)=ug(i,jt,k)-ug(i,jb,k) + gradrhox(i,j,k)=ug(it,j,k)-ug(ib,j,k) + gradrho=sqrt(gradrhox(i,j,k)**2 + & +gradrhoy(i,j,k)**2+gradrhoz(i,j,k)**2) + anormx(i,j,k)=0. + anormy(i,j,k)=0. + anormz(i,j,k)=0. + if ((abs(ug(i,j,k)-0.5).lt.0.1).or.(gradrho.ge.0.00001)) then + anormx(i,j,k)=gradrhox(i,j,k)/gradrho + anormy(i,j,k)=gradrhoy(i,j,k)/gradrho + anormz(i,j,k)=gradrhoz(i,j,k)/gradrho + endif +c al=al+gradrho + enddo + enddo + enddo + +! calcul de courbure x gradrho + + do i=1,nx + it=mod(i+1+nx-1,nx)+1 + ib=mod(i-1+nx-1,nx)+1 + do j=1,nx + jt=mod(j+1+nx-1,nx)+1 + jb=mod(j-1+nx-1,nx)+1 + do k=1,nx + kt=mod(k+1+nx-1,nx)+1 + kb=mod(k-1+nx-1,nx)+1 + acurv=anormx(it,j,k)-anormx(ib,j,k) + acurv=acurv+anormy(i,jt,k)-anormy(i,jb,k) + acurv=acurv+anormz(i,j,kt)-anormz(i,j,kb) + gradrhox(i,j,k)=gradrhox(i,j,k)*acurv + gradrhoy(i,j,k)=gradrhoy(i,j,k)*acurv + gradrhoz(i,j,k)=gradrhoz(i,j,k)*acurv +! curv(i,j,k)=acurv + enddo + enddo + enddo + +! curl de tension superificielle + + strmax=0. + do i=1,nx + it=mod(i+1+nx-1,nx)+1 + ib=mod(i-1+nx-1,nx)+1 + do j=1,nx + jt=mod(j+1+nx-1,nx)+1 + jb=mod(j-1+nx-1,nx)+1 + do k=1,nx + kt=mod(k+1+nx-1,nx)+1 + kb=mod(k-1+nx-1,nx)+1 + strg1(i,j,k)=strg1(i,j,k)- + & (gradrhoz(i,jt,k)-gradrhoz(i,jb,k))*taudxinv + & +(gradrhoy(i,j,kt)-gradrhoy(i,j,kb))*taudxinv + strg2(i,j,k)=strg2(i,j,k)- + & (gradrhox(i,j,kt)-gradrhox(i,j,kb))*taudxinv + & +(gradrhoz(it,j,k)-gradrhoz(ib,j,k))*taudxinv + strg3(i,j,k)=strg3(i,j,k)- + & (gradrhoy(it,j,k)-gradrhoy(ib,j,k))*taudxinv + & +(gradrhox(i,jt,k)-gradrhox(i,jb,k))*taudxinv + strmax=amax1(strmax,abs(strg1(i,j,k))) + strmax=amax1(strmax,abs(strg2(i,j,k))) + strmax=amax1(strmax,abs(strg3(i,j,k))) + enddo + enddo + enddo + + print*, 'STRMAX ',strmax +112 continue + +c al=al*dx*dx*dx/eps + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_fourier.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_fourier.f new file mode 100644 index 000000000..7d5fda83e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_fourier.f @@ -0,0 +1,128 @@ + subroutine stension(tau,ic) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension gradrhox(npg,npg,npg),anormx(npg,npg,npg) + dimension gradrhoy(npg,npg,npg),anormy(npg,npg,npg) + dimension gradrhoz(npg,npg,npg),anormz(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + + pi=3.1415926 + spi=sqrt(pi) + phibar=0.5 + + taudxinv=tau/(float(ic)*(2.*dx)**2) + al=0. + + nx1=nx + ny1=nx + nz1=nx + + +c cas ou on utilise grd rho comme level set + eps=2.*float(ic)*dx + eps2=eps**2 + +! calcul de gradrho et normale + + do i=1,nx + it=mod(i+ic+nx-1,nx)+1 + ib=mod(i-ic+nx-1,nx)+1 + do j=1,nx + jt=mod(j+ic+nx-1,nx)+1 + jb=mod(j-ic+nx-1,nx)+1 + do k=1,nx + kt=mod(k+ic+nx-1,nx)+1 + kb=mod(k-ic+nx-1,nx)+1 + gradrhoz(i,j,k)=ug(i,j,kt)-ug(i,j,kb) + gradrhoy(i,j,k)=ug(i,jt,k)-ug(i,jb,k) + gradrhox(i,j,k)=ug(it,j,k)-ug(ib,j,k) + gradrho=sqrt(gradrhox(i,j,k)**2 + & +gradrhoy(i,j,k)**2+gradrhoz(i,j,k)**2) + anormx(i,j,k)=0. + anormy(i,j,k)=0. + anormz(i,j,k)=0. + if ((abs(ug(i,j,k)-0.5).lt.0.4).or.(gradrho.ge.0.00001)) then + anormx(i,j,k)=gradrhox(i,j,k)/gradrho + anormy(i,j,k)=gradrhoy(i,j,k)/gradrho + anormz(i,j,k)=gradrhoz(i,j,k)/gradrho + endif +c al=al+gradrho + enddo + enddo + enddo + +! calcul de courbure x gradrho + + do i=1,nx + it=mod(i+1+nx-1,nx)+1 + ib=mod(i-1+nx-1,nx)+1 + do j=1,nx + jt=mod(j+1+nx-1,nx)+1 + jb=mod(j-1+nx-1,nx)+1 + do k=1,nx + kt=mod(k+1+nx-1,nx)+1 + kb=mod(k-1+nx-1,nx)+1 + acurv=anormx(it,j,k)-anormx(ib,j,k) + acurv=acurv+anormy(i,jt,k)-anormy(i,jb,k) + acurv=acurv+anormz(i,j,kt)-anormz(i,j,kb) + gradrhox(i,j,k)=gradrhox(i,j,k)*acurv*taudxinv + gradrhoy(i,j,k)=gradrhoy(i,j,k)*acurv*taudxinv + gradrhoz(i,j,k)=gradrhoz(i,j,k)*acurv*taudxinv + enddo + enddo + enddo + +! curl de tension superificielle +! en fourier + + nxb=nx1/2 + nyb=ny1/2 + nzb=nz1/2 + + call fftw3d(gradrhox,cfx,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(gradrhoy,cfy,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(gradrhoz,cfz,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nzb,nzb + rk=float(k)*ak + do 10 j=1-nyb,nyb + rj=float(j)*aj + do 10 i=0,nxb + ri=float(i)*ai + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k)) + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k)) + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k)) +10 continue + + + call fftw3d(strg1,cux,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + call fftw3d(strg2,cuy,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + call fftw3d(strg3,cuz,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_old.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_old.f new file mode 100644 index 000000000..7640c3f4f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/stension_old.f @@ -0,0 +1,126 @@ + subroutine stension(tau,ic) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension gradrhox(npg,npg,npg),anormx(npg,npg,npg) + dimension gradrhoy(npg,npg,npg),anormy(npg,npg,npg) + dimension gradrhoz(npg,npg,npg),anormz(npg,npg,npg) + dimension curv(npg,npg,npg) + + + + pi=3.1415926 + spi=sqrt(pi) + phibar=0.5 + + taudxinv=tau/(float(ic)*(2.*dx)**3) + al=0. + +! cas ou on ne passe pas par stretch d'abor: + + goto 1111 + do k=1,nx + do j=1,nx + do i=1,nx + strg1(i,j,k)=0. + strg2(i,j,k)=0. + strg3(i,j,k)=0. + enddo + enddo + enddo +1111 continue + +c cas ou on utilise grd rho comme level set + eps=2.*float(ic)*dx + eps2=eps**2 + +! calcul de gradrho et normale + + do i=1,nx + it=mod(i+ic+nx-1,nx)+1 + ib=mod(i-ic+nx-1,nx)+1 + do j=1,nx + jt=mod(j+ic+nx-1,nx)+1 + jb=mod(j-ic+nx-1,nx)+1 + do k=1,nx + kt=mod(k+ic+nx-1,nx)+1 + kb=mod(k-ic+nx-1,nx)+1 + gradrhoz(i,j,k)=ug(i,j,kt)-ug(i,j,kb) + gradrhoy(i,j,k)=ug(i,jt,k)-ug(i,jb,k) + gradrhox(i,j,k)=ug(it,j,k)-ug(ib,j,k) + gradrho=sqrt(gradrhox(i,j,k)**2 + & +gradrhoy(i,j,k)**2+gradrhoz(i,j,k)**2) + anormx(i,j,k)=0. + anormy(i,j,k)=0. + anormz(i,j,k)=0. + if ((abs(ug(i,j,k)-0.5).lt.0.1).or.(gradrho.ge.0.00001)) then + anormx(i,j,k)=gradrhox(i,j,k)/gradrho + anormy(i,j,k)=gradrhoy(i,j,k)/gradrho + anormz(i,j,k)=gradrhoz(i,j,k)/gradrho + endif +c al=al+gradrho + enddo + enddo + enddo + +! calcul de courbure x gradrho + + do i=1,nx + it=mod(i+1+nx-1,nx)+1 + ib=mod(i-1+nx-1,nx)+1 + do j=1,nx + jt=mod(j+1+nx-1,nx)+1 + jb=mod(j-1+nx-1,nx)+1 + do k=1,nx + kt=mod(k+1+nx-1,nx)+1 + kb=mod(k-1+nx-1,nx)+1 + acurv=anormx(it,j,k)-anormx(ib,j,k) + acurv=acurv+anormy(i,jt,k)-anormy(i,jb,k) + acurv=acurv+anormz(i,j,kt)-anormz(i,j,kb) + gradrhox(i,j,k)=gradrhox(i,j,k)*acurv + gradrhoy(i,j,k)=gradrhoy(i,j,k)*acurv + gradrhoz(i,j,k)=gradrhoz(i,j,k)*acurv +! curv(i,j,k)=acurv + enddo + enddo + enddo + +! curl de tension superificielle + + strmax=0. + do i=1,nx + it=mod(i+1+nx-1,nx)+1 + ib=mod(i-1+nx-1,nx)+1 + do j=1,nx + jt=mod(j+1+nx-1,nx)+1 + jb=mod(j-1+nx-1,nx)+1 + do k=1,nx + kt=mod(k+1+nx-1,nx)+1 + kb=mod(k-1+nx-1,nx)+1 + strg1(i,j,k)=strg1(i,j,k)- + & (gradrhoz(i,jt,k)-gradrhoz(i,jb,k))*taudxinv + & +(gradrhoy(i,j,kt)-gradrhoy(i,j,kb))*taudxinv + strg2(i,j,k)=strg2(i,j,k)- + & (gradrhox(i,j,kt)-gradrhox(i,j,kb))*taudxinv + & +(gradrhoz(it,j,k)-gradrhoz(ib,j,k))*taudxinv + strg3(i,j,k)=strg3(i,j,k)- + & (gradrhoy(it,j,k)-gradrhoy(ib,j,k))*taudxinv + & +(gradrhox(i,jt,k)-gradrhox(i,jb,k))*taudxinv + strmax=amax1(strmax,abs(strg1(i,j,k))) + strmax=amax1(strmax,abs(strg2(i,j,k))) + strmax=amax1(strmax,abs(strg3(i,j,k))) + enddo + enddo + enddo + + print*, 'STRMAX ',strmax +112 continue + +c al=al*dx*dx*dx/eps + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/stretch_freeb.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/stretch_freeb.f new file mode 100644 index 000000000..6b27b6ca4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/stretch_freeb.f @@ -0,0 +1,77 @@ + subroutine stretch_freeb(drho) + +! terme de stretching 3D sur grille + forcing du a densite variable +! dans approx de Bouss. +! gravite orientee selon axe des x +! la densite est recuperee du scalaire ug + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dy1=dx1 + dz1=dx1 + + dxinv=1./(12.*dx1) + dyinv=1./(12.*dy1) + dzinv=1./(12.*dz1) + + do k=1,nz1 + kt=mod(k+nz1,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + ktt=mod(k+1+nz1,nz1)+1 + kbb=mod(k-3+nz1,nz1)+1 +cc + do j=1,ny1 + jt=mod(j+ny1,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + jtt=mod(j+1+ny1,ny1)+1 + jbb=mod(j-3+ny1,ny1)+1 +cc + do i=1,nx1 + it=mod(i+nx1,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + itt=mod(i+1+nx1,nx1)+1 + ibb=mod(i-3+nx1,nx1)+1 + +c + aux1=omg1(itt,j,k)*vxg(itt,j,k)+8.*(omg1(ib,j,k)*vxg(ib,j,k)- + 1 omg1(it,j,k)*vxg(it,j,k))-omg1(ibb,j,k)*vxg(ibb,j,k) + aux2=omg2(i,jtt,k)*vxg(i,jtt,k)+8.*(omg2(i,jb,k)*vxg(i,jb,k)- + 1 omg2(i,jt,k)*vxg(i,jt,k))-omg2(i,jbb,k)*vxg(i,jbb,k) + aux3=omg3(i,j,ktt)*vxg(i,j,ktt)+8.*(omg3(i,j,kb)*vxg(i,j,kb)- + 1 omg3(i,j,kt)*vxg(i,j,kt))-omg3(i,j,kbb)*vxg(i,j,kbb) + + strg1(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv +c + aux1=omg1(itt,j,k)*vyg(itt,j,k)+8.*(omg1(ib,j,k)*vyg(ib,j,k)- + 1 omg1(it,j,k)*vyg(it,j,k))-omg1(ibb,j,k)*vyg(ibb,j,k) + aux2=omg2(i,jtt,k)*vyg(i,jtt,k)+8.*(omg2(i,jb,k)*vyg(i,jb,k)- + 1 omg2(i,jt,k)*vyg(i,jt,k))-omg2(i,jbb,k)*vyg(i,jbb,k) + aux3=omg3(i,j,ktt)*vyg(i,j,ktt)+8.*(omg3(i,j,kb)*vyg(i,j,kb)- + 1 omg3(i,j,kt)*vyg(i,j,kt))-omg3(i,j,kbb)*vyg(i,j,kbb) + + strg2(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv +! terme venant de densite varaible + aux=ug(i,j,ktt)+8*(ug(i,j,kb)-ug(i,j,kt))-ug(i,j,kbb) + strg2(i,j,k)=strg2(i,j,k)-drho*aux*dzinv +! + aux1=omg1(itt,j,k)*vzg(itt,j,k)+8.*(omg1(ib,j,k)*vzg(ib,j,k)- + 1 omg1(it,j,k)*vzg(it,j,k))-omg1(ibb,j,k)*vzg(ibb,j,k) + aux2=omg2(i,jtt,k)*vzg(i,jtt,k)+8.*(omg2(i,jb,k)*vzg(i,jb,k)- + 1 omg2(i,jt,k)*vzg(i,jt,k))-omg2(i,jbb,k)*vzg(i,jbb,k) + aux3=omg3(i,j,ktt)*vzg(i,j,ktt)+8.*(omg3(i,j,kb)*vzg(i,j,kb)- + 1 omg3(i,j,kt)*vzg(i,j,kt))-omg3(i,j,kbb)*vzg(i,j,kbb) + + strg3(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv +! terme venant de densite varaible + aux=ug(i,jtt,k)+8*(ug(i,jb,k)-ug(i,jt,k))-ug(i,jbb,k) + strg3(i,j,k)=strg3(i,j,k)+drho*aux*dyinv + + enddo + enddo + enddo + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l2.f new file mode 100644 index 000000000..dcaa28c01 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l2.f @@ -0,0 +1,181 @@ + subroutine tag_particles(npart,npart_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + include 'param.i' + include 'param.h' + + common/remesh/xp(npg),xp1(npg),up(npg),vx(npg) + + integer icfl(*),itype(*),itype_aux(*),itag(*) + dimension xp_aux(*),up_aux(*),vx_aux(*) + + integer ntype(npg),ncfl(npg),npart_bl(npg),i_nbl(npg) + dimension amin_lambda(npg) + + +c ntype(nbl) : type de bloc (1=centre ou 0=left) pour choix de la formule +c remaillage +c itype(npart) : idem pour les particules de ces blocks +c ncfl(nbl)=cfl-nint ou cfl-int selon le type +c icfl(npart) : idem pour particules de cs blocks +c xp_aux(npart_aux): particles inside the blocks, for plain remeshing +c itype_aux(npart_aux) : type de block pour ces particules +c ntag: number of tagged particles, for special remeshing +c itag(ntag): pointer for tagged particles +c i_nbl(nbl) indice de la derniere particule du bloc nbl + +c cfl=delt/dx + + x0=xmin + + + m=np_bl+1 + nblock=nx/(m) + dx_bl=float(m)*dx + dx_bl_inv=1./dx_bl + +c on range les partucles par block +c et on calcule lambda moyen pour chaque block + + do nbl=1,nblock + amin_lambda(nbl)=111. + npart_bl(nbl)=0 + i_nbl(nbl)=0 + enddo + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(i)*cfl) + npart_bl(nbl)=npart_bl(nbl)+1 + i_nbl(nbl)=i + enddo + +c on ajoute la particule a droite du bloc (si elle existe) pour calculer +c le amin_lambda, pour eviter pbms a l'interface entre blocs de meme type +c (a corriger: pour l'instant je ne regarde pas le dernier bloc avec xp(1) + + do nbl=1,nblock-1 + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((ii.lt.npart).and.(xp(ii+1).lt.xp(ii)+1.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif + enddo + +c le dernier bloc (a la main ..) + + nbl=nblock + if (i_nbl(nbl).ne.0) then + if ((xp(npart).ge.xmax-1.5*dx).and.(xp(1).lt.xmin+0.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(1)*cfl) + endif + endif + + +c et on en deduit type de block (1=centre vs 0=left) et l'indice du bloc + + + do nbl=1,nblock + if (amin_lambda(nbl).lt.nint(amin_lambda(nbl))) then + ntype(nbl)=1 + ncfl(nbl)=nint(amin_lambda(nbl)) + else + ntype(nbl)=0 + ncfl(nbl)=int(amin_lambda(nbl)) + if (amin_lambda(nbl).lt.0) ncfl(nbl)=int(amin_lambda(nbl))-1 + endif + +c print*,'nbl et type',nbl, ntype(nbl),amin_lambda(nbl) + enddo +c +c on affecte le type et l'indice cfl du bloc sur ses particules + + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + itype(i)=ntype(nbl) + icfl(i)=ncfl(nbl) +c print*,'nbl et type',nbl,i, itype(i),icfl(i) + enddo + + +c on tagge les particules entre les blocs successifs non vides qui: +c sont de type et indice cfl differents +c (cases b,c,b',c' du papier) + + ntag=0 + npart_aux=0 + j=2 + jc=0 + do i=2,npart-1 + j=j+jc + if (j.ge.npart) go to 111 + jj=j+1 +c print*,j,icfl(j),icfl(jj),itype(j),itype(jj) + if ((icfl(j).ne.icfl(jj)).and.(itype(j).ne.itype(jj)) + 1 .and.(xp(jj).le.xp(j)+1.5*dx)) then + ntag=ntag+1 + itag(ntag)=j + ntag=ntag+1 + itag(ntag)=j+1 +c print*,' **** TAGGED ',j,xp(j),itype(j),icfl(j),vx(j)*delt/dx, +c 1 nint(vx(j)*delt/dx) +c print*,' **** TAGGED ',jj,xp(jj),itype(jj),icfl(jj),vx(jj)*delt/dx, +c 1 nint(vx(jj)*delt/dx) + jc=2 + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(j) + up_aux(npart_aux)=up(j) + vx_aux(npart_aux)=vx(j) + itype_aux(npart_aux)=itype(j) +c print*,'REGULAR',npart_aux,xp_aux(npart_aux),up_aux(npart_aux) +c 1 ,vx_aux(j)*delt/dx,icfl(j) + jc=1 + endif + enddo + +111 continue + +c on regarde a part la premiere et la derniere particule +c (je ne sais pas faire autrement pour l'instant) + + if (npart.ge.1) then + + if ((icfl(1).ne.icfl(npart)).and.(itype(1).ne.itype(npart)) + 1 .and.(xp(npart).ge.xp(1)+(float(nx)-1.5)*dx) + 1 .and.(itag(ntag).ne.npart)) then +c 1 ) then + ntag=ntag+1 + itag(ntag)=npart + ntag=ntag+1 + itag(ntag)=1 +c print*,' TAGGED ',j,xp(j),icfl(j) + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(1) + up_aux(npart_aux)=up(1) + vx_aux(npart_aux)=vx(1) + itype_aux(npart_aux)=itype(1) +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + if (npart.gt.1) then + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(npart) + up_aux(npart_aux)=up(npart) + vx_aux(npart_aux)=vx(npart) + itype_aux(npart_aux)=itype(npart) + endif +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + endif + + endif + + + +! if (ntag.ne.0) print*,'npart,NTAG, NPART_AUX = ',npart,ntag,npart_aux + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l4.f new file mode 100644 index 000000000..e0c1334fb --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_l4.f @@ -0,0 +1,147 @@ + subroutine tag_particles(npart,npart_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + include 'param.i' + include 'param.h' + + common/remesh/xp(npg),xp1(npg),up(npg),vx(npg) + + integer icfl(*),itype(*),itype_aux(*),itag(*) + dimension xp_aux(*),up_aux(*),vx_aux(*) + + integer ntype(npg),ncfl(npg),npart_bl(npg),i_nbl(npg) + dimension amin_lambda(npg) + + +c ntype(nbl) : type de bloc (1=centre ou 0=left) pour choix de la formule +c remaillage +c itype(npart) : idem pour les particules de ces blocks +c ncfl(nbl)=cfl-nint ou cfl-int selon le type +c icfl(npart) : idem pour particules de cs blocks +c xp_aux(npart_aux): particles inside the blocks, for plain remeshing +c itype_aux(npart_aux) : type de block pour ces particules +c ntag: number of tagged particles, for special remeshing +c itag(ntag): pointer for tagged particles +c i_nbl(nbl) indice de la derniere particule du bloc nbl + + x0=xmin + + m=np_bl+1 + nblock=nx/(m) + dx_bl=float(m)*dx + dx_bl_inv=1./dx_bl + +c on range les partucles par block +c et on calcule lambda moyen pour chaque block + + do nbl=1,nblock + amin_lambda(nbl)=111. + npart_bl(nbl)=0 + i_nbl(nbl)=0 + enddo + + do i=1,npart + nbl=1+int((xp(i)-x0+0.0001)*dx_bl_inv) + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(i)*cfl) + npart_bl(nbl)=npart_bl(nbl)+1 + i_nbl(nbl)=i + enddo + +c on ajoute la particule a droite du bloc (si elle existe) pour calculer +c le amin_lambda, pour eviter pbms a l'interface entre blocs de meme type +c (a corriger: pour l'instant je ne regarde pas le dernier bloc avec xp(1) + + do nbl=1,nblock-1 + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((ii.lt.npart).and.(xp(ii+1).lt.xp(ii)+1.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif +! print*, 'TYPES ',nbl,ii,amin_lambda(nbl) + enddo + +c le dernier bloc (a la main ..) + + nbl=nblock + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((xp(ii).ge.xmax-1.5*dx).and.(xp(ii+1).lt.xmin+0.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif + + +c et on en deduit type de block (1=centre vs 0=left) et l'indice du bloc + + + do nbl=1,nblock + if (amin_lambda(nbl).lt.nint(amin_lambda(nbl))) then + ntype(nbl)=1 + ncfl(nbl)=nint(amin_lambda(nbl)) + else + ntype(nbl)=0 + ncfl(nbl)=int(amin_lambda(nbl)) + if (amin_lambda(nbl).lt.0) ncfl(nbl)=int(amin_lambda(nbl))-1 + endif + +c print*,'nbl et type',nbl, ntype(nbl),amin_lambda(nbl) + enddo +c +c on affecte le type et l'indice cfl du bloc sur ses particules + + + do i=1,npart + nbl=1+int((xp(i)-x0+0.0001)*dx_bl_inv) + itype(i)=ntype(nbl) + icfl(i)=ncfl(nbl) +c print*,'nbl et type',nbl,i, itype(i),icfl(i) + enddo + + +c on tagge les particules entre les blocs successifs non vides qui: dfdsfdfdfsdsdffsdfsdfsdfsdfsdfsdf +c sont de type et indice cfl differents +c (cases b,c,b',c' du papier) + + ntag=0 + npart_aux=0 + j=1 + jc=0 + do i=1,npart + j=j+jc + if (j.gt.npart) go to 111 + j1=j + jj=j+1 + jjj=j+2 + if ((jjj.le.npart).and.(icfl(jj).ne.icfl(jjj)) + 1 .and.(itype(jj).ne.itype(jjj)) + 1 .and.(xp(jjj).le.xmin+amod(xp(jj)+1.5*dx-xmin,xmax-xmin))) then + ntag=ntag+1 + itag(ntag)=j1 + ntag=ntag+1 + itag(ntag)=jj + ntag=ntag+1 + itag(ntag)=jjj + ntag=ntag+1 + itag(ntag)=j+3 + jc=4 +! cprint*,'tags',ntag,j1,jj,jjj,j+3 +! print*,' Blocs', itype(jj),icfl(jj),itype(jjj),icfl(jjj) +! print*,xp(jj),xp(jjj) + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(j1) + up_aux(npart_aux)=up(j1) + vx_aux(npart_aux)=vx(j1) + itype_aux(npart_aux)=itype(j1) + jc=1 + endif + enddo + +111 continue + if (npart_aux+ntag.ne.npart) print*,'ATT**',j,npart_aux,ntag,jc + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_limit.f new file mode 100644 index 000000000..333f22fd3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/tag_particles_limit.f @@ -0,0 +1,185 @@ + subroutine tag_particles(npart,npart_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux,sl,sl1,sl2) + + include 'param.i' + include 'param.h' + + common/remesh/xp(npg),xp1(npg),up(npg),vx(npg) + + integer icfl(*),itype(*),itype_aux(*),itag(*) + dimension xp_aux(*),up_aux(*),vx_aux(*) + dimension sl(*),sl1(*),sl2(*) + + integer ntype(npg),ncfl(npg),npart_bl(npg),i_nbl(npg) + dimension amin_lambda(npg) + + +c ntype(nbl) : type de bloc (1=centre ou 0=left) pour choix de la formule +c remaillage +c itype(npart) : idem pour les particules de ces blocks +c ncfl(nbl)=cfl-nint ou cfl-int selon le type +c icfl(npart) : idem pour particules de cs blocks +c xp_aux(npart_aux): particles inside the blocks, for plain remeshing +c itype_aux(npart_aux) : type de block pour ces particules +c ntag: number of tagged particles, for special remeshing +c itag(ntag): pointer for tagged particles +c i_nbl(nbl) indice de la derniere particule du bloc nbl + + x0=xmin + + dh=dx + + m=np_bl+1 + nblock=nx/(m) + dx_bl=float(m)*dh + dx_bl_inv=1./dx_bl + +c on range les partucles par block +c et on calcule lambda moyen pour chaque block + + do nbl=1,nblock + amin_lambda(nbl)=111. + npart_bl(nbl)=0 + i_nbl(nbl)=0 + enddo + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(i)*cfl) + npart_bl(nbl)=npart_bl(nbl)+1 + i_nbl(nbl)=i + enddo + +c on ajoute la particule a droite du bloc (si elle existe) pour calculer +c le amin_lambda, pour eviter pbms a l'interface entre blocs de meme type +c (a corriger: pour l'instant je ne regarde pas le dernier bloc avec xp(1) + + do nbl=1,nblock-1 + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((ii.lt.npart).and.(xp(ii+1).lt.xp(ii)+1.5*dh)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif + enddo + +c le dernier bloc (a la main ..) + + nbl=nblock + if (i_nbl(nbl).ne.0) then + if ((xp(npart).ge.xmax-1.5*dh).and.(xp(1).lt.xmin+0.5*dh)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(1)*cfl) + endif + endif + + +c et on en deduit type de block (1=centre vs 0=left) et l'indice du bloc + + + do nbl=1,nblock + if (amin_lambda(nbl).lt.nint(amin_lambda(nbl))+0.00001) then + ntype(nbl)=1 + ncfl(nbl)=nint(amin_lambda(nbl)) + else + ntype(nbl)=0 + ncfl(nbl)=int(amin_lambda(nbl)) + if (amin_lambda(nbl).lt.0) ncfl(nbl)=int(amin_lambda(nbl))-1 + endif + +c print*,'nbl et type',nbl, ntype(nbl),amin_lambda(nbl) + enddo +c +c on affecte le type et l'indice cfl du bloc sur ses particules + + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + itype(i)=ntype(nbl) + icfl(i)=ncfl(nbl) +c print*,'nbl et type',nbl,i, itype(i),icfl(i) + enddo + + +c on tagge les particules entre les blocs successifs non vides qui: +c sont de type et indice cfl differents +c (cases b,c,b',c' du papier) + + ntag=0 + npart_aux=0 + j=2 + jc=0 + do i=2,npart-1 + j=j+jc + if (j.ge.npart) go to 111 + jj=j+1 +c print*,j,icfl(j),icfl(jj),itype(j),itype(jj) + if ((icfl(j).ne.icfl(jj)).and.(itype(j).ne.itype(jj)) + 1 .and.(xp(jj).le.xp(j)+1.5*dh)) then + ntag=ntag+1 + itag(ntag)=j + ntag=ntag+1 + itag(ntag)=j+1 +c print*,' **** TAGGED ',j,xp(j),itype(j),icfl(j),vx(j)*delt/dh, +c 1 nint(vx(j)*delt/dh) +c print*,' **** TAGGED ',jj,xp(jj),itype(jj),icfl(jj),vx(jj)*delt/dh, +c 1 nint(vx(jj)*delt/dh) + jc=2 + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(j) + up_aux(npart_aux)=up(j) + vx_aux(npart_aux)=vx(j) + sl1(npart_aux)=sl(j) + sl2(npart_aux)=sl(j-1) + itype_aux(npart_aux)=itype(j) +c print*,'REGULAR',npart_aux,xp_aux(npart_aux),up_aux(npart_aux) +c 1 ,vx_aux(j)*delt/dh,icfl(j) + jc=1 + endif + enddo + +111 continue + +c on regarde a part la premiere et la derniere particule +c (je ne sais pas faire autrement pour l'instant) + + if (npart.ge.1) then + + if ((icfl(1).ne.icfl(npart)).and.(itype(1).ne.itype(npart)) + 1 .and.(xp(npart).ge.xp(1)+(float(nx)-1.5)*dh) + 1 .and.(itag(ntag).ne.npart)) then +c 1 ) then + ntag=ntag+1 + itag(ntag)=npart + ntag=ntag+1 + itag(ntag)=1 +c print*,' TAGGED ',j,xp(j),icfl(j) + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(1) + up_aux(npart_aux)=up(1) + vx_aux(npart_aux)=vx(1) + sl1(npart_aux)=sl(1) + sl2(npart_aux)=sl(npart) + itype_aux(npart_aux)=itype(1) +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + if (npart.gt.1) then + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(npart) + up_aux(npart_aux)=up(npart) + vx_aux(npart_aux)=vx(npart) + sl1(npart_aux)=sl(npart) + sl2(npart_aux)=sl(npart-1) + itype_aux(npart_aux)=itype(npart) + endif +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + endif + + endif + +! print*,'npart,NTAG, NPART_AUX = ',npart,ntag,npart_aux + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_bar.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_bar.f new file mode 100644 index 000000000..763978724 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_bar.f @@ -0,0 +1,119 @@ + subroutine velox_bar(delt) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension aux3(npgx,npgy,npgz), + 1 aux1(npgx,npgy,npgz),aux2(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + + pi=3.1415926 + +! calcu de grad rho x g + + do k=1,nz2 + kt=mod(k+nz1,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + ktt=mod(k+1+nz1,nz1)+1 + kbb=mod(k-3+nz1,nz1)+1 +cc + do j=1,ny2 + jt=mod(j+ny1,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + jtt=mod(j+1+ny1,ny1)+1 + jbb=mod(j-3+ny1,ny1)+1 +cc + do i=1,nx2 + it=mod(i+nx1,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + itt=mod(i+1+nx1,nx1)+1 + ibb=mod(i-3+nx1,nx1)+1 + + aux=ug(i,j,ktt)+8*(ug(i,j,kb)-ug(i,j,kt))-ug(i,j,kbb) + cfy(i,j,k)=-aux*drho*delt/(12.*dx2) + aux=ug(i,jtt,k)+8*(ug(i,jb,k)-ug(i,jt,k))-ug(i,jbb,k) + cfz(i,j,k)=+aux*drho*delt/(12.*dx2) + + enddo + enddo + enddo + +! calucl de fonction courants 3d + + nxb=nx2/2 + nyb=ny2/2 + nzb=nz2/2 + +c call fftw3d(omg1,cfx,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg2,cfy,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg3,cfz,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + +c coeff de normalisation pour laplacien en spectral + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nzb,nzb + rk=float(k)*ak + do 10 j=1-nyb,nyb + rj=float(j)*aj + do 10 i=0,nxb + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) + if (r2.ne.0.) then +c + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 +c cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(ri*cfz(i,j,k))/r2 +c cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k))/r2 + endif +10 continue + + call fftw3d(aux1,cux,nx2,ny2,nz2,nxb,nyb,nzb,wk,1) + call fftw3d(aux2,cuy,nx2,ny2,nz2,nxb,nyb,nzb,wk,1) + call fftw3d(aux3,cuz,nx2,ny2,nz2,nxb,nyb,nzb,wk,1) + + vxmax=0. + vymax=0. + vzmax=0. + do k=1,nz1 + do j=1,ny1 + do i=1,nx1 + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + vxmax=amax1(vxmax,abs(vxg(i,j,k))) + vymax=amax1(vymax,abs(vyg(i,j,k))) + vzmax=amax1(vzmax,abs(vzg(i,j,k))) + enddo + enddo + enddo + print*,' VXMAX sur grille ',vxmax,vymax,vzmax + vmax=amax1(vxmax,vymax) + vmax=amax1(vmax,vzmax) + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_burgers.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_burgers.f new file mode 100644 index 000000000..c4f007a00 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/velox_burgers.f @@ -0,0 +1,70 @@ + subroutine velox_burgers(vxmax,dvmax) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cux,cvx,wk,wk2 + dimension cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz), + 1 wk2(ngx2+1,npgy,npgz) + + dimension aux2(npgx,npgy,npgz) + + pi=3.1415926 + +c Fourier + + nxb=nx1/2 + nyb=ny1/2 + nzb=nz1/2 + + nxb2=nx3/2 + nyb2=nx3/2 + nzb2=nx3/2 + dx3=(xmax-xmin)/float(nx3) + + call fftw3d(ug,cux,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + +c filtre lineaire + + do 10 k=1-nzb,nzb + do 10 j=1-nyb,nyb + do 10 i=1,nxb + xi=(sin(8.*pi*i*dx3)/(8.*pi*i*dx3))**2 + cux(i,j,k)=cux(i,j,k)*xi +10 continue + +c retour ds l'espace physique + + call fftw3d(aux2,cux,nx1,ny1,nz1,nxb,nyb,nzb,wk2,1) + + vxmax=0. + dvmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + psi1(i,j,k)=aux2(i,j,k) + vxmax=amax1(vxmax,abs(psi1(i,j,k))) + enddo + enddo + enddo + print*,' VXMAX sur grille ',vxmax + + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + enddo + enddo + enddo + + do i=1,nx3 +c print*, psi1(1,i,1),psi1(i,2,2),psi1(i,128,128) + enddo + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_full.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_full.f new file mode 100644 index 000000000..2fde30906 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_full.f @@ -0,0 +1,112 @@ + subroutine veloxaux(vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + parameter(npg2=32) + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + dimension aux1(npg2,npg2,npg2),aux2(npg2,npg2,npg2) + dimension aux3(npg2,npg2,npg2) + + parameter(npgb2=npg2/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + complex cvx,cvy,cvz,wk2 + dimension cvx(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvy(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvz(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 wk2(npgb2+1,npg2,npg2) + + pi=3.1415926 + + nxb2=nx3/2 + nyb2=nx3/2 + nzb2=nx3/2 + + do 10 k=1-nzb2,nzb2 + do 10 j=1-nyb2,nyb2 + do 10 i=0,nxb2 + cvx(i,j,k)=cux(i,j,k) + cvy(i,j,k)=cuy(i,j,k) + cvz(i,j,k)=cuz(i,j,k) +10 continue + + + call fftw3d(aux3,cvz,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + call fftw3d(aux2,cvy,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + call fftw3d(aux1,cvx,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + +! ecriture fhciers grille NX2 + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + psi1(i,j,k)=-aux1(i,j,k) + umax1=amax1(umax1,abs(psi1(i,j,k))) + psi2(i,j,k)=-aux2(i,j,k) + umax2=amax1(umax2,abs(psi2(i,j,k))) + psi3(i,j,k)=-aux3(i,j,k) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + + + print*,'umax', umax1,umax2,umax3 + vmax=amax1(umax1,umax2,umax3) + + goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(20) ((((psi1(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(21,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(21) ((((psi2(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(22,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(22) ((((psi3(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + close(20) + close(21) + close(22) + +111 continue + + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_small.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_small.f new file mode 100644 index 000000000..72d58284b --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_small.f @@ -0,0 +1,57 @@ + subroutine veloxaux(vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + pi=3.1415926 + + dx3=2.*(xmax-xmin)/float(nx3) + + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + do k=1,nx3 + kt=mod(k,nx3)+1 + pi2z=xmin+float(k-1)*dx3 + piz=0.5*pi2z + do j=1,nx3 + jt=mod(j,nx3)+1 + pi2y=xmin+float(j-1)*dx3 + piy=0.5*pi2y + do i=1,nx3 + it=mod(i,nx3)+1 + pi2x=xmin+float(i-1)*dx3 + pix=0.5*pi2x + psi1(i,j,k)=2.*sin(pix)*sin(pix)*sin(pi2y)*sin(pi2z) + umax1=amax1(umax1,abs(psi1(i,j,k))) + psi2(i,j,k)=-sin(pi2x)*sin(piy)*sin(piy)*sin(pi2z) + umax2=amax1(umax2,abs(psi2(i,j,k))) + psi3(i,j,k)=-sin(pi2x)*sin(piz)*sin(piz)*sin(pi2y) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + + print*,'umax', umax1,umax2,umax3 + vmax=amax1(umax1,umax2,umax3) + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_v2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_v2.f new file mode 100644 index 000000000..adbe919d4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/veloxaux_v2.f @@ -0,0 +1,140 @@ + subroutine veloxaux(vmax,dvmax) + +! version de veloxaux ou on prend les 32 premiers +! modes de la vitesse, on padde avec des 0 jusqu'a nx2 (128 ou 256) +! et on fait fft inverse sur une grille nx2 + + include 'param.i' + include 'param.h' + include 'arrays.h' + + parameter(npg2=128) + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + dimension aux1(npg2,npg2,npg2),aux2(npg2,npg2,npg2) + dimension aux3(npg2,npg2,npg2) + + parameter(npgb2=npg2/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + complex cvx,cvy,cvz,wk2 + dimension cvx(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvy(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvz(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 wk2(npgb2+1,npg2,npg2) + + pi=3.1415926 + + nxb2=nx3/2 + nyb2=nx3/2 + nzb2=nx3/2 + nxb2=16 + nyb2=16 + nzb2=16 + nxb=nx1/2 + nyb=nx1/2 + nzb=nx1/2 + + dx3=2.*(xmax-xmin)/float(nx3) + + do 20 k=1-nzb,nzb + do 20 j=1-nyb,nyb + do 20 i=0,nxb + cvx(i,j,k)=0. + cvy(i,j,k)=0. + cvz(i,j,k)=0. +20 continue + + do 10 k=1-nzb2,nzb2 + do 10 j=1-nyb2,nyb2 + do 10 i=0,nxb2 + cvx(i,j,k)=cux(i,j,k) + cvy(i,j,k)=cuy(i,j,k) + cvz(i,j,k)=cuz(i,j,k) +10 continue + +c call fftw3d(aux3,cvz,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) +c call fftw3d(aux2,cvy,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) +c call fftw3d(aux1,cvx,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + call fftw3d(aux3,cvz,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + call fftw3d(aux2,cvy,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + call fftw3d(aux1,cvx,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + +! ecriture fhciers grille NX2 + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + dvxmax=0. + dvymax=0. + dvzmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + psi1(i,j,k)=-aux1(i,j,k) + umax1=amax1(umax1,abs(psi1(i,j,k))) + psi2(i,j,k)=-aux2(i,j,k) + umax2=amax1(umax2,abs(psi2(i,j,k))) + psi3(i,j,k)=-aux3(i,j,k) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvxmax=amax1(dvxmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvymax=amax1(dvymax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvzmax=amax1(dvzmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + + dvmax=amax1(dvxmax,dvymax) + dvmax=amax1(dvmax,dvzmax) + + print*,'umax', umax1,umax2,umax3 + print*,'DVMAXs ',dvxmax,dvymax,dvzmax + + vmax=amax1(umax1,umax2,umax3) + + goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(20) ((((psi1(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(21,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(21) ((((psi2(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(22,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(22) ((((psi3(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + close(20) + close(21) + close(22) + +111 continue + + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec.f new file mode 100644 index 000000000..0f79ca21c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec.f @@ -0,0 +1,87 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +! initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + +222 continue + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np_aux,xp_aux,up_aux,itype_aux,jr,kr) + if (ntag.ne.0) call remeshx_tag(ntag,itag,itype,icfl,jr,kr) + +! fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec_limit.f new file mode 100644 index 000000000..f6c444ec5 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_corec_limit.f @@ -0,0 +1,97 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + dimension sl(npg),sl1(npg),sl2(npg) + + + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +! initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + do n=1,np +! vx(n)=up(n) +! if ((j.eq.3).and.(k.eq.3)) print*,vx(n) + enddo +! pentes pour limiteurs + + call slopes(dt,np,sl) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux,sl,sl1,sl2) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + +222 continue + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np_aux,xp_aux,up_aux,itype_aux,jr,kr,sl1,sl2) + if (ntag.ne.0) call remeshx_tag(ntag,itag,itype,icfl,jr,kr,sl) + +! fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l2.f new file mode 100644 index 000000000..613a943aa --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l2.f @@ -0,0 +1,79 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +c routine d'advection en x : +c parcours des lignes horozontales +c intilisation de particules +c calcul des vitesses par RK2 +c tag des particules en focntion des varaitions de cfl +c push and remesh + +c cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +c 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +c initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np,xp_aux,up_aux,itype,jr,kr) + +c fin de ligne j,k: + npart=npart+np + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l4.f new file mode 100644 index 000000000..cbaa3dcd4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_l4.f @@ -0,0 +1,124 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +c routine d'advection en x : +c parcours des lignes horozontales +c intilisation de particules +c calcul des vitesses par RK2 +c tag des particules en focntion des varaitions de cfl +c push and remesh + +c cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + tm=0. + npart=0 + ntag_total=0 + + m=np_bl+1 + +c 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + yy=xmin+float(j-1)*dx + np=0 + jj=3 + ic=0 + do i=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(ug(j1,j,k))+abs(ug(j2,j,k))+abs(ug(j3,j,k)) + 1 +abs(ug(j4,j,k)).ge.circlim)) then + np=np+1 + up(np)=ug(j1,j,k) + tm=tm+ug(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=ug(j2,j,k) + tm=tm+ug(j2,j,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=ug(j3,j,k) + tm=tm+ug(j3,j,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=ug(j4,j,k) + tm=tm+ug(j4,j,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(ug(j1,j,k)).ge.circlim)) then + np=np+1 + up(np)=ug(j1,j,k) + tm=tm+ug(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + if (ntag+np_aux.ne.np) print*, ntag,np_aux,np + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np_aux,xp_aux,up_aux,itype_aux,jr,kr) + if (ntag.ne.0) call remeshx_tag(ntag,itag,itype,icfl,jr,kr) + +c fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'TM debut de x_advect', tm*dx*dx*dx + print*, 'NPART, NTAG selon x ', npart,ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omy_l4.f new file mode 100644 index 000000000..d21567ae8 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omy_l4.f @@ -0,0 +1,118 @@ + subroutine x_advect_omy(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + tm=0. + npart=0 + ntag_total=0 + + m=np_bl+1 + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + yy=xmin+float(j-1)*dx + np=0 + jj=3 + ic=0 + do i=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(ug(j1,j,k))+abs(ug(j2,j,k))+abs(ug(j3,j,k)) + 1 +abs(ug(j4,j,k)).ge.circlim)) then + np=np+1 + up(np)=omg2(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg2(j2,j,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg2(j3,j,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg2(j4,j,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg2(j1,j,k)).ge.circlim)) then + np=np+1 + up(np)=omg2(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + if (ntag+np_aux.ne.np) print*, ntag,np_aux,np + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx_omy(np_aux,xp_aux,up_aux,itype_aux,jr,kr) + if (ntag.ne.0) call remeshx_omy_tag(ntag,itag,itype,icfl,jr,kr) + +! fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG selon x ', npart,ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omz_l4.f new file mode 100644 index 000000000..3efc2214c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_omz_l4.f @@ -0,0 +1,117 @@ + subroutine x_advect_omz(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + m=np_bl+1 + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + yy=xmin+float(j-1)*dx + np=0 + jj=3 + ic=0 + do i=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(omg3(j1,j,k))+abs(omg3(j2,j,k))+abs(omg3(j3,j,k)) + 1 +abs(omg3(j4,j,k)).ge.circlim)) then + np=np+1 + up(np)=omg3(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg3(j2,j,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg3(j3,j,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg3(j4,j,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg3(j1,j,k)).ge.circlim)) then + np=np+1 + up(np)=omg3(j1,j,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + if (ntag+np_aux.ne.np) print*, ntag,np_aux,np + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx_omz(np_aux,xp_aux,up_aux,itype_aux,jr,kr) + if (ntag.ne.0) call remeshx_omz_tag(ntag,itag,itype,icfl,jr,kr) + +! fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG selon x ', npart,ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_orig.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_orig.f new file mode 100644 index 000000000..14dc11331 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/x_advect_orig.f @@ -0,0 +1,79 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +! initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np,xp_aux,up_aux,itype,jr,kr) + +! fin de ligne j,k: + npart=npart+np + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec.f new file mode 100644 index 000000000..3c7c0d786 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec.f @@ -0,0 +1,80 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + + +! cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + ntag_total=0 + +! on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +! initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(j-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np_aux,xp_aux,up_aux,itype_aux,ir,kr) + if (ntag.ne.0) call remeshy_tag(ntag,itag,itype,icfl,ir,kr) + +! fin de ligne i : + ntag_total=ntag_total+ntag + endif + enddo + enddo + print*, ' NTAG apres y advect ', ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec_limit.f new file mode 100644 index 000000000..4255e2096 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_corec_limit.f @@ -0,0 +1,82 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + dimension sl(npg),sl1(npg),sl2(npg) + +! cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + ntag_total=0 + +! on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +! initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(j-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) +c pentes pour limiteurs + + call slopes(dt,np,sl) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux,sl,sl1,sl2) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np_aux,xp_aux,up_aux,itype_aux,ir,kr,sl1,sl2) + if (ntag.ne.0) call remeshy_tag(ntag,itag,itype,icfl,ir,kr,sl) + +! fin de ligne i : + ntag_total=ntag_total+ntag + endif + enddo + enddo + print*, ' NTAG apres y advect ', ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l2.f new file mode 100644 index 000000000..511f416fa --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l2.f @@ -0,0 +1,63 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +! initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(j-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(j-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np,xp_aux,up_aux,itype,ir,kr) +! fin de ligne i : + + endif + enddo + enddo + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l4.f new file mode 100644 index 000000000..ae513525f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_l4.f @@ -0,0 +1,120 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + tm=0. + npart=0 + ntag_total=0 + + m=np_bl+1 + +! on balaie le lignes verticales + + print*,'circlim =',circlim + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do j=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(ug(i,j1,k))+abs(ug(i,j2,k))+abs(ug(i,j3,k)) + 1 +abs(ug(i,j4,k)).ge.circlim)) then + np=np+1 + up(np)=ug(i,j1,k) + tm=tm+ug(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=ug(i,j2,k) + tm=tm+ug(i,j2,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=ug(i,j3,k) + tm=tm+ug(i,j3,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=ug(i,j4,k) + tm=tm+ug(i,j4,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(ug(i,j1,k)).ge.circlim)) then + np=np+1 + up(np)=ug(i,j1,k) + tm=tm+ug(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np_aux,xp_aux,up_aux,itype_aux,ir,kr) + if (ntag.ne.0) + 1 call remeshy_tag(ntag,itag,itype,icfl,ir,kr) + +! fin de ligne i : + + endif + npart=npart+np + ntag_total=ntag_total+ntag + if (ntag_total.lt.0) print*, 'BIZZ ',ntag,i,k + enddo + enddo + + print*, 'TM debut de y_advect', tm*dx*dx*dx + print*, ' NTAG apres y advect ', ntag_total + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omy_l4.f new file mode 100644 index 000000000..8af976af9 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omy_l4.f @@ -0,0 +1,113 @@ + subroutine y_advect_omy(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + npart=0 + ntag_total=0 + + m=np_bl+1 + +! on balaie le lignes verticales + + print*,'circlim =',circlim + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do j=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(omg2(i,j1,k))+abs(omg2(i,j2,k))+abs(omg2(i,j3,k)) + 1 +abs(omg2(i,j4,k)).ge.circlim)) then + np=np+1 + up(np)=omg2(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg2(i,j2,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg2(i,j3,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg2(i,j4,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg2(i,j1,k)).ge.circlim)) then + np=np+1 + up(np)=omg2(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy_omy(np_aux,xp_aux,up_aux,itype_aux,ir,kr) + if (ntag.ne.0) + 1 call remeshy_omy_tag(ntag,itag,itype,icfl,ir,kr) + +! fin de ligne i : + + endif + npart=npart+np + ntag_total=ntag_total+ntag + if (ntag_total.lt.0) print*, 'BIZZ ',ntag,i,k + enddo + enddo + + print*, ' NTAG apres y advect ', ntag_total + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omz_l4.f new file mode 100644 index 000000000..0ecd00a96 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_omz_l4.f @@ -0,0 +1,113 @@ + subroutine y_advect_omz(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + npart=0 + ntag_total=0 + + m=np_bl+1 + +! on balaie le lignes verticales + + print*,'circlim =',circlim + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do j=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(omg3(i,j1,k))+abs(omg3(i,j2,k))+abs(omg3(i,j3,k)) + 1 +abs(omg3(i,j4,k)).ge.circlim)) then + np=np+1 + up(np)=omg3(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg3(i,j2,k) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg3(i,j3,k) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg3(i,j4,k) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg3(i,j1,k)).ge.circlim)) then + np=np+1 + up(np)=omg3(i,j1,k) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy_omz(np_aux,xp_aux,up_aux,itype_aux,ir,kr) + if (ntag.ne.0) + 1 call remeshy_omz_tag(ntag,itag,itype,icfl,ir,kr) + +! fin de ligne i : + + endif + npart=npart+np + ntag_total=ntag_total+ntag + if (ntag_total.lt.0) print*, 'BIZZ ',ntag,i,k + enddo + enddo + + print*, ' NTAG apres y advect ', ntag_total + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_orig.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_orig.f new file mode 100644 index 000000000..511f416fa --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/y_advect_orig.f @@ -0,0 +1,63 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +! initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(j-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(j-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np,xp_aux,up_aux,itype,ir,kr) +! fin de ligne i : + + endif + enddo + enddo + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec.f new file mode 100644 index 000000000..38620f9a2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec.f @@ -0,0 +1,79 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! cf=dt/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + ntag_total=0 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +! initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(k-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np_aux,xp_aux,up_aux,itype_aux,ir,jr) + if (ntag.ne.0) call remeshz_tag(ntag,itag,itype,icfl,ir,jr) + +! fin de ligne k : + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec_limit.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec_limit.f new file mode 100644 index 000000000..646256326 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_corec_limit.f @@ -0,0 +1,84 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + dimension sl(npg),sl1(npg),sl2(npg) + +! cf=dt/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + ntag_total=0 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +! initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(k-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) +c pentes pour limiteurs + + call slopes(dt,np,sl) + + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux,sl,sl1,sl2) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np_aux,xp_aux,up_aux,itype_aux,ir,jr,sl1,sl2) + if (ntag.ne.0) call remeshz_tag(ntag,itag,itype,icfl,ir,jr,sl) + +! fin de ligne k : + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l2.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l2.f new file mode 100644 index 000000000..52daac924 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l2.f @@ -0,0 +1,63 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +! initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(k-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(k-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np,xp_aux,up_aux,itype,ir,jr) +! fin de ligne k : + endif + enddo + enddo + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l4.f new file mode 100644 index 000000000..610b937f4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_l4.f @@ -0,0 +1,113 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cf=ldx/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + tm=0. + m=np_bl+1 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do k=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(ug(i,j,j1))+abs(ug(i,j,j2))+abs(ug(i,j,j3)) + 1 +abs(ug(i,j,j4)).ge.circlim)) then + np=np+1 + up(np)=ug(i,j,j1) + tm=tm+ug(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=ug(i,j,j2) + tm=tm+ug(i,j,j2) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=ug(i,j,j3) + tm=tm+ug(i,j,j3) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=ug(i,j,j4) + tm=tm+ug(i,j,j4) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(ug(i,j,j1)).ge.circlim)) then + np=np+1 + up(np)=ug(i,j,j1) + tm=tm+ug(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np_aux,xp_aux,up_aux,itype_aux,ir,jr) + if (ntag.ne.0) call remeshz_tag(ntag,itag,itype,icfl,ir,jr) + +! fin de ligne k : + + endif + enddo + enddo + + print*, 'TM debut de z_advect', tm*dx*dx*dx + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omy_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omy_l4.f new file mode 100644 index 000000000..f424ef285 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omy_l4.f @@ -0,0 +1,106 @@ + subroutine z_advect_omy(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cf=ldx/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + m=np_bl+1 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do k=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(omg2(i,j,j1))+abs(omg2(i,j,j2))+abs(omg2(i,j,j3)) + 1 +abs(omg2(i,j,j4)).ge.circlim)) then + np=np+1 + up(np)=omg2(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg2(i,j,j2) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg2(i,j,j3) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg2(i,j,j4) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg2(i,j,j1)).ge.circlim)) then + np=np+1 + up(np)=omg2(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz_omy(np_aux,xp_aux,up_aux,itype_aux,ir,jr) + if (ntag.ne.0) call remeshz_omy_tag(ntag,itag,itype,icfl,ir,jr) + +! fin de ligne k : + + endif + enddo + enddo + + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omz_l4.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omz_l4.f new file mode 100644 index 000000000..9b403d8f7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_omz_l4.f @@ -0,0 +1,106 @@ + subroutine z_advect_omz(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + +! cf=ldx/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + m=np_bl+1 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + yy=xmin+float(i-1)*dx + np=0 + jj=3 + ic=0 + do k=3,nx+2 + jj=jj+ic + if (jj.gt.nx+2) go to 111 + j1=mod(jj-1,nx)+1 + j2=mod(jj,nx)+1 + j3=mod(jj+1,nx)+1 + j4=mod(jj+2,nx)+1 + if ((mod(j1,m).eq.m-1).and. + 1 (abs(omg3(i,j,j1))+abs(omg3(i,j,j2))+abs(omg3(i,j,j3)) + 1 +abs(omg3(i,j,j4)).ge.circlim)) then + np=np+1 + up(np)=omg3(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + np=np+1 + up(np)=omg3(i,j,j2) + xp(np)=xmin+float(j2-1)*dx + np=np+1 + up(np)=omg3(i,j,j3) + xp(np)=xmin+float(j3-1)*dx + np=np+1 + up(np)=omg3(i,j,j4) + xp(np)=xmin+float(j4-1)*dx + ic=4 + elseif ((abs(omg3(i,j,j1)).ge.circlim)) then + np=np+1 + up(np)=omg3(i,j,j1) + xp(np)=xmin+float(j1-1)*dx + ic=1 + else + ic=1 + endif + enddo +111 continue + +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz_omz(np_aux,xp_aux,up_aux,itype_aux,ir,jr) + if (ntag.ne.0) call remeshz_omz_tag(ntag,itag,itype,icfl,ir,jr) + +! fin de ligne k : + + endif + enddo + enddo + + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_orig.f b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_orig.f new file mode 100644 index 000000000..52daac924 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/NotUsed/z_advect_orig.f @@ -0,0 +1,63 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +! initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(k-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(k-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np,xp_aux,up_aux,itype,ir,jr) +! fin de ligne k : + endif + enddo + enddo + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/README b/CodesEnVrac/CodeGH/src-THI/README new file mode 100644 index 000000000..2f8f0cc5e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/README @@ -0,0 +1,54 @@ +9/07/2010 + +recopie en partie CEA/OM/JET/BILEVEL +pour tester remaillage de scalaire avec corrections +(routines de Remesh_test/3Dlin_new) + +*_full routniens completes (NX + scalaire) +*_small routines avec suelement transport scalaire par champ de vitess de la sphere cisaillee + +3/09/2010 +filter_rho: routne qui ne calcule le spectre de rho que pour les premiers modes et +qui retroune un rho filtre (pour ne pas avoir a trimblaer des fichiers trop lourds a visualiser) + +Janvier 2011: + +mis un pue d'oordre pour tester les spectres de rho avec les differents reamillage + +main_small_split: juste advectnio d'un scalaire avec un champ de vitesse fixe +lu dans initread.f ; champ turublent 128^3, fourni par GB, obtenu par filtre 32^2, padde avec des 0 jusqu'a 128 (data2write) +remaillage splitte lambda 2, + RK 2 +*_advec_orig ou __advec_corec: routnes d'advection avec remaillages 1D d'origine ou corriges + +main_small_nosplit: idem mais avec remaillage tensoriel m'4 +o +1 ite en temps: les fomules non-corrigees plittees donnes une remontee du bout de spectre +pour cfl > 0.5 +formules corrigees eliminent le probleme (juste legere inflexion du spctre autour de 20 + +formules M'4 tensorielle adonne des bumps successifs sur spectre. (qulque soit cfl car itype =0 dans l'implementation de m'4) + +ecrit remesh*_m4 (avec itype =0 : formules a gauche) +cree remeshx,y,z et mis dans le makefile (pour pouvoir changer les +formules de reamillage 1D) + +cree *_limit.f a partir des formules avec limteurs testes et valides dans +directory Limt + +15/02/11 +tentative de fiare burgers 1d avec transport par champe filtre (avec fft3D ..) +-> routnes *_burgers*, makefile_burgers .. +pas concluat (les pentes en 1/epsilon créées des overshoots ce qui est normal a poteiroiri (quel que soit le pas de temps, meme avec remesh M3) + + +20/06/11 +commence a faire du denste varaible. +remesh lmabda4 corrigees +makfeil_freeb +1) Boussinesq sans tension superificielle +makefile_freeb +-> routne init_freeb (avec scalaire = densite dans une sphere) +main_freeb ou on ajoute +2) tension superificielle ajoutee : stension.f +teste, ok qualitativement avec lcfl O.5 nu=0.0005 et Pr=0.0001, nx=256 filtre a 64, tau=0.01 +ex= rho_256x64_tau=0.01_t=05.gz, 0.55 et 0.8 diff --git a/CodesEnVrac/CodeGH/src-THI/arrays.h b/CodesEnVrac/CodeGH/src-THI/arrays.h new file mode 100644 index 000000000..e45762cf0 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/arrays.h @@ -0,0 +1,10 @@ + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),vx(npg) + + diff --git a/CodesEnVrac/CodeGH/src-THI/diag.f b/CodesEnVrac/CodeGH/src-THI/diag.f new file mode 100644 index 000000000..d1fc519cb --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/diag.f @@ -0,0 +1,92 @@ + subroutine diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + +! calcul sur une grille mxmxm de (a,b)**3 du +! div w, enstro et energy + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension umean(npgy) + + + + eps3=dx1**3 + vol=eps3 + + dxinv2=0.5/dx1 + dyinv2=0.5/dx1 + dzinv2=0.5/dx1 + + omax=0. + rhomax=0. + div=0. + domax=0. + ener=0. + enstro=0. + dudymax=0. + do 10 k=1,nz1 + kt=mod(k,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + do 10 j=1,ny1 + jt=mod(j,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + do 10 i=1,nx1 + it=mod(i,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + aux1=omg1(it,j,k)-omg1(ib,j,k) + aux2=omg2(i,jt,k)-omg2(i,jb,k) + aux3=(omg3(i,j,kt)-omg3(i,j,kb)) + psi1(i,j,k)=(aux1*dxinv2+aux2*dyinv2+aux3*dzinv2) + div=div+((aux1*dxinv2+aux2*dyinv2+aux3*dzinv2)**2)*eps3 + domax=domax+((abs(aux1*dxinv2)+abs(aux2*dyinv2)+ + 1 abs(aux3*dzinv2))**2)*eps3 + enerx=vxg(i,j,k)*vxg(i,j,k) + enery=vyg(i,j,k)*vyg(i,j,k) + enerz=vzg(i,j,k)*vzg(i,j,k) + strengthx=omg1(i,j,k)*omg1(i,j,k) + strengthy=omg2(i,j,k)*omg2(i,j,k) + strengthz=omg3(i,j,k)*omg3(i,j,k) + omax=amax1(omax,sqrt(strengthx+strengthy+strengthz)) + rhomax=amax1(rhomax,ug(i,j,k)) + enstro=enstro+(strengthx+strengthy+strengthz)*vol + ener=ener+(enerx+enery+enerz)*vol +10 continue + +! goto 111 + + do j=1,ny1 + umean(j)=0. + do i=1,nx1 + do k=1,nz1 + umean(j)=umean(j)+dx1*dx1*vxg(i,j,k) + enddo + enddo + enddo + + dudymax=0. + do j=2,ny1-1 + dudymax=amax1(dudymax,umean(j+1)-umean(j-1)) + enddo + + width=0. + if (dudymax.ne.0.) width=2.*dx1/dudymax + if (domax.ne.0) div=div/domax + +111 continue + + + VOL1=0. + VOL2=0. + VOL3=0. + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).ge.0.5) VOL1=VOL1+dx2*dx2*dx2 + if (ug(i,j,k).ge.0.75) VOL2=VOL2+dx2*dx2*dx2 + enddo + enddo + enddo + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/dif.f b/CodesEnVrac/CodeGH/src-THI/dif.f new file mode 100644 index 000000000..ab491a109 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/dif.f @@ -0,0 +1,154 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE dif_om(npart,om1,om2,om3, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax1) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + dxinv=1./(dx1) + dy1=dx1 + dz1=dx1 + dyinv=dxinv + dzinv=dxinv + + npart=0 + vol=dx1**3 + + do k=1,nz1 + z=zmin+(k-1)*dz1 + do j=1,ny1 + y=ymin+(j-1)*dy1 + do i=1,nx1 + x=xmin+(i-1)*dx1 + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx1**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + enddo + enddo + enddo + +! goto 1001 + + dzdx=(dz1/dx1)**2 + dzdy=(dz1/dy1)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +c boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +c boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx1-1,nx1)+1 + j2=mod(jj+ly+ny1-1,ny1)+1 + k2=mod(kk+lz+nz1-1,nz1)+1 + gammasrc1=omg1(i2,j2,k2)*vol + gammasrc2=omg2(i2,j2,k2)*vol + gammasrc3=omg3(i2,j2,k2)*vol + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + dvx=(vxsrc-vxrcv)/dx1 + dvy=(vysrc-vyrcv)/dy1 + dvz=(vzsrc-vzrcv)/dz1 + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + ales=amax1(0.,-dvx*lx-dvy*ly-dvz*lz) +c ales=abs(dvx*lx+dvy*ly+dvz*lz) + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + akernel2=2.5/((1.+r)*2.8333) + factor=akernel/(dz1*dz1) + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)* + 1 (anu*factor+coef_les*ales*akernel2) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)* + 1 (anu*factor+coef_les*ales*akernel2) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)* + 1 (anu*factor+coef_les*ales*akernel2) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy1*dx1*dz1/dv1(i)) + +c enddo pour caluc de dom sur les particules + enddo + +1001 continue + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv1(i)) + omax0=amax1(omax0,abs(om2(i))/dv1(i)) + omax0=amax1(omax0,abs(om3(i))/dv1(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv1(i)) + omax1=amax1(omax1,abs(om2(i))/dv1(i)) + omax1=amax1(omax1,abs(om3(i))/dv1(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/dif_rho.f b/CodesEnVrac/CodeGH/src-THI/dif_rho.f new file mode 100644 index 000000000..405711fb7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/dif_rho.f @@ -0,0 +1,40 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE dif_rho(anu,dt) + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + anudt=anu*dt/(dx2**2) + + rhomax1=0. + rhomax2=0. + + do k=1,nz2 + kt=mod(k,nz2)+1 + kb=mod(k-2+nz2,nz2)+1 + do j=1,ny2 + jt=mod(j,nz2)+1 + jb=mod(j-2+nz2,nz2)+1 + do i=1,nx2 + it=mod(i,nz2)+1 + ib=mod(i-2+nz2,nz2)+1 + drho=ug(it,j,k)+ug(ib,j,k)+ug(i,jt,k)+ug(i,jb,k)+ug(i,j,kt)+ug(i,j,kb) + drho=drho-6.*ug(i,j,k) + rhomax1=amax1(rhomax1,abs(ug(i,j,k))) + ug(i,j,k)=ug(i,j,k)+anudt*drho + rhomax2=amax1(rhomax2,abs(ug(i,j,k))) + enddo + enddo + enddo + + print*, 'RHOMAX avant et apres DIFF ',rhomax1,rhomax2 + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/fftw_f77.i b/CodesEnVrac/CodeGH/src-THI/fftw_f77.i new file mode 100644 index 000000000..26c352402 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/fftw_f77.i @@ -0,0 +1,17 @@ +c This file contains PARAMETER statements for various constants +c that can be passed to FFTW routines. You should include +c this file in any FORTRAN program that calls the fftw_f77 +c routines (either directly or with an #include statement +c if you use the C preprocessor). + + INTEGER FFTW_FORWARD,FFTW_BACKWARD + PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) + + INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL + PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) + + INTEGER FFTW_ESTIMATE,FFTW_MEASURE + PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) + + INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM + PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) diff --git a/CodesEnVrac/CodeGH/src-THI/fortranize.h b/CodesEnVrac/CodeGH/src-THI/fortranize.h new file mode 100644 index 000000000..fb4a6b8b6 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/fortranize.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1997,1998 Massachusetts Institute of Technology + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef FORTRANIZE_H +#define FORTRANIZE_H + +/* + * convert C name -> FORTRAN name. On some systems, + * append an underscore. On other systems, use all caps. + * + * x is the lower case name, X is the all caps name. + */ + +#if defined(CRAY) || defined(_UNICOS) || defined(_CRAYMPP) +#define FORTRANIZE(x,X) X /* all upper-case on the Cray */ + +#elif defined(IBM6000) || defined(_AIX) +#define FORTRANIZE(x,X) x /* all lower-case on RS/6000 */ + +#elif defined(__hpux) +#define FORTRANIZE(x,X) x /* all lower-case on HP-UX */ + +#elif defined(USING_G77) /* users should define this when using with the g77 + Fortran compiler */ +#define FORTRANIZE(x,X) x##__ /* g77 expects *two* underscores after + names with an underscore */ + +#else +#define FORTRANIZE(x,X) x##_ /* use all lower-case with underscore + by default */ + +#endif + +#endif /* FORTRANIZE_H */ diff --git a/CodesEnVrac/CodeGH/src-THI/initjet.f b/CodesEnVrac/CodeGH/src-THI/initjet.f new file mode 100644 index 000000000..7b136b188 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/initjet.f @@ -0,0 +1,143 @@ + subroutine jet(npart,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension omx(*),omy(*),omz(*) + + pi=3.1415926 + pi2=2.*pi + circ=0. + x0=0. + y0=0. + z0=0. +! momentum thickness + width=0.01 +! noise level for the flow + ampl=0.05 +! ampl=0.0 +! apltude of wave for vx + ampl3=0.3 +! noise level for the scalar + ampl2=0.05 + ampl2=0. + + open(20,file='random',form='unformatted', + 1 status='unknown') + + read(20) (((strg1(i,j,k),strg2(i,j,k),strg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + + + do i=1,nx1 + do j=1,ny1 + do k=1,nz1 + yy=abs(float(j-1)*dx1-0.5) + aux=(0.1-2.*yy)/(4.*width) + aux4=abs(aux**2) + strg1(i,j,k)=exp(-aux4)*(strg1(i,j,k)-0.5) + strg2(i,j,k)=exp(-aux4)*(strg2(i,j,k)-0.5) + strg3(i,j,k)=exp(-aux4)*(strg3(i,j,k)-0.5) + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. + ug(i,j,k)=0. + enddo + enddo + enddo + + vxmax=0. + + do i=1,nx1 + xx=float(i-1)*dx1 + do k=1,nz1 + zz=float(k-1)*dx1 + do j=1,ny1 + yy=abs(float(j-1)*dx1-0.5) + aux=(0.1-2.*yy)/(4.*width) +c vxg(i,j,k)=0.5*(1.+tanh(aux))*(1.+ampl*strg1(i,j,k)) + vxg(i,j,k)=0.5*(1.+tanh(aux))*(1.+ampl3*sin(4*pi2*(xx))) + vxg(i,j,k)=vxg(i,j,k)*(1.+ampl*strg1(i,j,k)) + vyg(i,j,k)=ampl*strg2(i,j,k) + vzg(i,j,k)=ampl*strg3(i,j,k) + vxmax=amax1(vxmax,abs(vxg(i,j,k))) + enddo + enddo + enddo + + print*, 'VXMAX =', VXMAX + + dxinv=0.5/dx1 + npart=0 + do 10 i=1,nx1 + it=mod(i+nx1,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + xx=(float(i)-1.)*dx1 + do 10 j=1,ny1 + jt=mod(j+ny1,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + yy=(float(j)-1.)*dx1 + do 10 k=1,nz1 + kt=mod(k+nz1,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + zz=(float(k)-1.)*dx1 + dwdx=vzg(it,j,k)-vzg(ib,j,k) + dwdy=vzg(i,jt,k)-vzg(i,jb,k) + dudy=vxg(i,jt,k)-vxg(i,jb,k) + dudz=vxg(i,j,kt)-vxg(i,j,kb) + dvdx=vyg(it,j,k)-vyg(ib,j,k) + dvdz=vyg(i,j,kt)-vyg(i,j,kb) + aux3=(dvdx-dudy)*dxinv + aux1=(dwdy-dvdz)*dxinv + aux2=(dudz-dwdx)*dxinv +ccc +! aux1=0. +! aux2=0. + omg1(i,j,k)=aux1 + omg2(i,j,k)=aux2 + omg3(i,j,k)=aux3 + if (abs(aux1)+abs(aux2)+abs(aux3).gt.0.0001) then + npart=npart+1 + xp1(npart)=xx + yp1(npart)=yy + zp1(npart)=zz + dv1(npart)=dx1*dx1*dx1 + omx(npart)=dv1(npart)*aux1 + omy(npart)=dv1(npart)*aux2 + omz(npart)=dv1(npart)*aux3 + circ=circ+omz(npart) + endif +10 continue + print*, 'NPART =', npart + do i=1,npart +! omz(npart)=omz(npart)-circ/float(npart) + enddo + + tm=0. + do k=1,nz2 + do j=1,ny2 + yy=abs(float(j-1)*dx2-0.5) + aux=(0.1-2.*yy)/(4.*width) + aux2=aux**2 + do i=1,nx2 + ug(i,j,k)=0. +c ug(i,j,k)=1. + val=0.5*(1.+tanh(aux))*(1.+ampl2*strg3(i,j,k)) + if (val.gt.0.0001) then + npart_rho=npart_rho+1 + ug(i,j,k)=val + tm=tm+val +c ug(i,j,k)=1. + endif + enddo + enddo + enddo + + print*, ' MASSE SCALAIRE a init ',tm*dx2*dx2*dx2 + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/initread.f b/CodesEnVrac/CodeGH/src-THI/initread.f new file mode 100644 index 000000000..63dbae8d4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/initread.f @@ -0,0 +1,81 @@ + subroutine readfield(rhomax,vmax,dvmax) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + real*8 tout(npgx,npgy,npgz,4) + + rhomax=0. + + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + ug(i,j,k)=1. + rhomax=amax1(umax,abs(ug(i,j,k))) + enddo + enddo + enddo + +! goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi1(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi2(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + open(20,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + read(20) (((psi3(i,j,k), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + + close(20) + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + umax1=amax1(umax1,abs(psi1(i,j,k))) + umax2=amax1(umax2,abs(psi2(i,j,k))) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + vmax=amax1(umax1,umax2,umax3) + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvmax=amax1(dvmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvmax=amax1(dvmax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvmax=amax1(dvmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + +111 continue + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/interho.f b/CodesEnVrac/CodeGH/src-THI/interho.f new file mode 100644 index 000000000..f422a1ff0 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/interho.f @@ -0,0 +1,149 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE interho(npart,g1,g2,g3,xp,yp,zp) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + + do 10 i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + dyinv=1./dy3 + dzinv=1./dz3 + dh3=dx3*dy3*dz3 + dhinv3=1./dh3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + + DO 20 i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + yy1 = (y - float(jp1)*dy3-y0)*dyinv + zz1 = (z - float(kp1)*dz3-z0)*dzinv + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + + + jp1=mod(jp1+ny3,ny3) +1 + jp2=mod(jp2+ny3,ny3) +1 + + kp1=mod(kp1+nz3,nz3) +1 + kp2=mod(kp2+nz3,nz3) +1 + +C +C The M'4 scheme +C + + a1 = xx2 + b1 = yy2 + c1 = zz2 + + a2 = xx1 + b2 = yy1 + c2 = zz1 + + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + + g2(i)= g2(i) + gg2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + gg2(ip1,jp2,kp1)*a1*b2*c1 + + g3(i)= g3(i) + gg3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + gg3(ip1,jp2,kp1)*a1*b2*c1 +c + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + + g2(i)= g2(i) + gg2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + gg2(ip2,jp2,kp1)*a2*b2*c1 + + g3(i)= g3(i) + gg3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + gg3(ip2,jp2,kp1)*a2*b2*c1 +c + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + + g2(i)= g2(i) + gg2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + gg2(ip1,jp2,kp2)*a1*b2*c2 + + g3(i)= g3(i) + gg3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + gg3(ip1,jp2,kp2)*a1*b2*c2 +c + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + g2(i)= g2(i) + gg2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + gg2(ip2,jp2,kp2)*a2*b2*c2 + + g3(i)= g3(i) + gg3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + gg3(ip2,jp2,kp2)*a2*b2*c2 +c + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/intersm4.f90 b/CodesEnVrac/CodeGH/src-THI/intersm4.f90 new file mode 100644 index 000000000..c8f17e55a --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/intersm4.f90 @@ -0,0 +1,372 @@ +! + SUBROUTINE intersm4(npart,g1,g2,g3,xp,yp,zp) + +! +! Interpolation routine with M'4 +! +! geometry=unit box, periodic in x and y +! last ponits in z direction assume extension by continuity +! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + include 'param.i' + include 'param.h' + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & ug(npg,npg,npg) + + + dy1=dx1 + dz1=dx1 + + do 10 i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. +10 continue + + dxinv=1./dx1 + dyinv=1./dy1 + dzinv=1./dz1 + dh3=dx1*dy1*dz1 + dhinv3=1./dh3 + + +!-------------------------------------------------------------------- +!- PART II : Determination of the circulation of each particle +!-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + DO 20 i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + +! get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx1-x0)*dxinv + yy1 = (y - float(jp1)*dy1-y0)*dyinv + zz1 = (z - float(kp1)*dz1-z0)*dzinv + xx0=xx1+1 + yy0=yy1+1 + zz0=zz1+1 + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + + xx3=2-xx1 + yy3=2-yy1 + zz3=2-zz1 + + +! +! on repositionne les points de grille par periodicite +! entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx1,nx1) +1 + ip0=mod(ip0+nx1,nx1) +1 + ip2=mod(ip2+nx1,nx1) +1 + ip3=mod(ip3+nx1,nx1) +1 + +! print*,ip0,ip1,ip2,ip3 + + jp1=mod(jp1+ny1,ny1) +1 + jp0=mod(jp0+ny1,ny1) +1 + jp2=mod(jp2+ny1,ny1) +1 + jp3=mod(jp3+ny1,ny1) +1 + + kp1=mod(kp1+nz1,nz1) +1 + kp0=mod(kp0+nz1,nz1) +1 + kp2=mod(kp2+nz1,nz1) +1 + kp3=mod(kp3+nz1,nz1) +1 +C +! The M'4 scheme +! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + g1(i)= g1(i) + GG1(ip0,jp0,kp0)*a0*b0*c0 + g1(i)= g1(i) + GG1(ip0,jp1,kp0)*a0*b1*c0 + g1(i)= g1(i) + GG1(ip0,jp2,kp0)*a0*b2*c0 + g1(i)= g1(i) + GG1(ip0,jp3,kp0)*a0*b3*c0 + + g2(i)= g2(i) + GG2(ip0,jp0,kp0)*a0*b0*c0 + g2(i)= g2(i) + GG2(ip0,jp1,kp0)*a0*b1*c0 + g2(i)= g2(i) + GG2(ip0,jp2,kp0)*a0*b2*c0 + g2(i)= g2(i) + GG2(ip0,jp3,kp0)*a0*b3*c0 + + g3(i)= g3(i) + GG3(ip0,jp0,kp0)*a0*b0*c0 + g3(i)= g3(i) + GG3(ip0,jp1,kp0)*a0*b1*c0 + g3(i)= g3(i) + GG3(ip0,jp2,kp0)*a0*b2*c0 + g3(i)= g3(i) + GG3(ip0,jp3,kp0)*a0*b3*c0 + + g1(i)= g1(i) + GG1(ip1,jp0,kp0)*a1*b0*c0 + g1(i)= g1(i) + GG1(ip1,jp1,kp0)*a1*b1*c0 + g1(i)= g1(i) + GG1(ip1,jp2,kp0)*a1*b2*c0 + g1(i)= g1(i) + GG1(ip1,jp3,kp0)*a1*b3*c0 + + g2(i)= g2(i) + GG2(ip1,jp0,kp0)*a1*b0*c0 + g2(i)= g2(i) + GG2(ip1,jp1,kp0)*a1*b1*c0 + g2(i)= g2(i) + GG2(ip1,jp2,kp0)*a1*b2*c0 + g2(i)= g2(i) + GG2(ip1,jp3,kp0)*a1*b3*c0 + + g3(i)= g3(i) + GG3(ip1,jp0,kp0)*a1*b0*c0 + g3(i)= g3(i) + GG3(ip1,jp1,kp0)*a1*b1*c0 + g3(i)= g3(i) + GG3(ip1,jp2,kp0)*a1*b2*c0 + g3(i)= g3(i) + GG3(ip1,jp3,kp0)*a1*b3*c0 + + g1(i)= g1(i) + GG1(ip2,jp0,kp0)*a2*b0*c0 + g1(i)= g1(i) + GG1(ip2,jp1,kp0)*a2*b1*c0 + g1(i)= g1(i) + GG1(ip2,jp2,kp0)*a2*b2*c0 + g1(i)= g1(i) + GG1(ip2,jp3,kp0)*a2*b3*c0 + + g2(i)= g2(i) + GG2(ip2,jp0,kp0)*a2*b0*c0 + g2(i)= g2(i) + GG2(ip2,jp1,kp0)*a2*b1*c0 + g2(i)= g2(i) + GG2(ip2,jp2,kp0)*a2*b2*c0 + g2(i)= g2(i) + GG2(ip2,jp3,kp0)*a2*b3*c0 + + g3(i)= g3(i) + GG3(ip2,jp0,kp0)*a2*b0*c0 + g3(i)= g3(i) + GG3(ip2,jp1,kp0)*a2*b1*c0 + g3(i)= g3(i) + GG3(ip2,jp2,kp0)*a2*b2*c0 + g3(i)= g3(i) + GG3(ip2,jp3,kp0)*a2*b3*c0 + + g1(i)= g1(i) + GG1(ip3,jp0,kp0)*a3*b0*c0 + g1(i)= g1(i) + GG1(ip3,jp1,kp0)*a3*b1*c0 + g1(i)= g1(i) + GG1(ip3,jp2,kp0)*a3*b2*c0 + g1(i)= g1(i) + GG1(ip3,jp3,kp0)*a3*b3*c0 + + g2(i)= g2(i) + GG2(ip3,jp0,kp0)*a3*b0*c0 + g2(i)= g2(i) + GG2(ip3,jp1,kp0)*a3*b1*c0 + g2(i)= g2(i) + GG2(ip3,jp2,kp0)*a3*b2*c0 + g2(i)= g2(i) + GG2(ip3,jp3,kp0)*a3*b3*c0 + + g3(i)= g3(i) + GG3(ip3,jp0,kp0)*a3*b0*c0 + g3(i)= g3(i) + GG3(ip3,jp1,kp0)*a3*b1*c0 + g3(i)= g3(i) + GG3(ip3,jp2,kp0)*a3*b2*c0 + g3(i)= g3(i) + GG3(ip3,jp3,kp0)*a3*b3*c0 + + g1(i)= g1(i) + GG1(ip0,jp0,kp1)*a0*b0*c1 + g1(i)= g1(i) + GG1(ip0,jp1,kp1)*a0*b1*c1 + g1(i)= g1(i) + GG1(ip0,jp2,kp1)*a0*b2*c1 + g1(i)= g1(i) + GG1(ip0,jp3,kp1)*a0*b3*c1 + + g2(i)= g2(i) + GG2(ip0,jp0,kp1)*a0*b0*c1 + g2(i)= g2(i) + GG2(ip0,jp1,kp1)*a0*b1*c1 + g2(i)= g2(i) + GG2(ip0,jp2,kp1)*a0*b2*c1 + g2(i)= g2(i) + GG2(ip0,jp3,kp1)*a0*b3*c1 + + g3(i)= g3(i) + GG3(ip0,jp0,kp1)*a0*b0*c1 + g3(i)= g3(i) + GG3(ip0,jp1,kp1)*a0*b1*c1 + g3(i)= g3(i) + GG3(ip0,jp2,kp1)*a0*b2*c1 + g3(i)= g3(i) + GG3(ip0,jp3,kp1)*a0*b3*c1 + + g1(i)= g1(i) + GG1(ip1,jp0,kp1)*a1*b0*c1 + g1(i)= g1(i) + GG1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + GG1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + GG1(ip1,jp3,kp1)*a1*b3*c1 + + g2(i)= g2(i) + GG2(ip1,jp0,kp1)*a1*b0*c1 + g2(i)= g2(i) + GG2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + GG2(ip1,jp2,kp1)*a1*b2*c1 + g2(i)= g2(i) + GG2(ip1,jp3,kp1)*a1*b3*c1 + + g3(i)= g3(i) + GG3(ip1,jp0,kp1)*a1*b0*c1 + g3(i)= g3(i) + GG3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + GG3(ip1,jp2,kp1)*a1*b2*c1 + g3(i)= g3(i) + GG3(ip1,jp3,kp1)*a1*b3*c1 + + g1(i)= g1(i) + GG1(ip2,jp0,kp1)*a2*b0*c1 + g1(i)= g1(i) + GG1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + GG1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + GG1(ip2,jp3,kp1)*a2*b3*c1 + + g2(i)= g2(i) + GG2(ip2,jp0,kp1)*a2*b0*c1 + g2(i)= g2(i) + GG2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + GG2(ip2,jp2,kp1)*a2*b2*c1 + g2(i)= g2(i) + GG2(ip2,jp3,kp1)*a2*b3*c1 + + g3(i)= g3(i) + GG3(ip2,jp0,kp1)*a2*b0*c1 + g3(i)= g3(i) + GG3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + GG3(ip2,jp2,kp1)*a2*b2*c1 + g3(i)= g3(i) + GG3(ip2,jp3,kp1)*a2*b3*c1 + + g1(i)= g1(i) + GG1(ip3,jp0,kp1)*a3*b0*c1 + g1(i)= g1(i) + GG1(ip3,jp1,kp1)*a3*b1*c1 + g1(i)= g1(i) + GG1(ip3,jp2,kp1)*a3*b2*c1 + g1(i)= g1(i) + GG1(ip3,jp3,kp1)*a3*b3*c1 + + g2(i)= g2(i) + GG2(ip3,jp0,kp1)*a3*b0*c1 + g2(i)= g2(i) + GG2(ip3,jp1,kp1)*a3*b1*c1 + g2(i)= g2(i) + GG2(ip3,jp2,kp1)*a3*b2*c1 + g2(i)= g2(i) + GG2(ip3,jp3,kp1)*a3*b3*c1 + + g3(i)= g3(i) + GG3(ip3,jp0,kp1)*a3*b0*c1 + g3(i)= g3(i) + GG3(ip3,jp1,kp1)*a3*b1*c1 + g3(i)= g3(i) + GG3(ip3,jp2,kp1)*a3*b2*c1 + g3(i)= g3(i) + GG3(ip3,jp3,kp1)*a3*b3*c1 + + g1(i)= g1(i) + GG1(ip0,jp0,kp2)*a0*b0*c2 + g1(i)= g1(i) + GG1(ip0,jp1,kp2)*a0*b1*c2 + g1(i)= g1(i) + GG1(ip0,jp2,kp2)*a0*b2*c2 + g1(i)= g1(i) + GG1(ip0,jp3,kp2)*a0*b3*c2 + + g2(i)= g2(i) + GG2(ip0,jp0,kp2)*a0*b0*c2 + g2(i)= g2(i) + GG2(ip0,jp1,kp2)*a0*b1*c2 + g2(i)= g2(i) + GG2(ip0,jp2,kp2)*a0*b2*c2 + g2(i)= g2(i) + GG2(ip0,jp3,kp2)*a0*b3*c2 + + g3(i)= g3(i) + GG3(ip0,jp0,kp2)*a0*b0*c2 + g3(i)= g3(i) + GG3(ip0,jp1,kp2)*a0*b1*c2 + g3(i)= g3(i) + GG3(ip0,jp2,kp2)*a0*b2*c2 + g3(i)= g3(i) + GG3(ip0,jp3,kp2)*a0*b3*c2 + + g1(i)= g1(i) + GG1(ip1,jp0,kp2)*a1*b0*c2 + g1(i)= g1(i) + GG1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + GG1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + GG1(ip1,jp3,kp2)*a1*b3*c2 + + g2(i)= g2(i) + GG2(ip1,jp0,kp2)*a1*b0*c2 + g2(i)= g2(i) + GG2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + GG2(ip1,jp2,kp2)*a1*b2*c2 + g2(i)= g2(i) + GG2(ip1,jp3,kp2)*a1*b3*c2 + + g3(i)= g3(i) + GG3(ip1,jp0,kp2)*a1*b0*c2 + g3(i)= g3(i) + GG3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + GG3(ip1,jp2,kp2)*a1*b2*c2 + g3(i)= g3(i) + GG3(ip1,jp3,kp2)*a1*b3*c2 + + g1(i)= g1(i) + GG1(ip2,jp0,kp2)*a2*b0*c2 + g1(i)= g1(i) + GG1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + GG1(ip2,jp2,kp2)*a2*b2*c2 + g1(i)= g1(i) + GG1(ip2,jp3,kp2)*a2*b3*c2 + + g2(i)= g2(i) + GG2(ip2,jp0,kp2)*a2*b0*c2 + g2(i)= g2(i) + GG2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + GG2(ip2,jp2,kp2)*a2*b2*c2 + g2(i)= g2(i) + GG2(ip2,jp3,kp2)*a2*b3*c2 + + g3(i)= g3(i) + GG3(ip2,jp0,kp2)*a2*b0*c2 + g3(i)= g3(i) + GG3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + GG3(ip2,jp2,kp2)*a2*b2*c2 + g3(i)= g3(i) + GG3(ip2,jp3,kp2)*a2*b3*c2 + + g1(i)= g1(i) + GG1(ip3,jp0,kp2)*a3*b0*c2 + g1(i)= g1(i) + GG1(ip3,jp1,kp2)*a3*b1*c2 + g1(i)= g1(i) + GG1(ip3,jp2,kp2)*a3*b2*c2 + g1(i)= g1(i) + GG1(ip3,jp3,kp2)*a3*b3*c2 + + g2(i)= g2(i) + GG2(ip3,jp0,kp2)*a3*b0*c2 + g2(i)= g2(i) + GG2(ip3,jp1,kp2)*a3*b1*c2 + g2(i)= g2(i) + GG2(ip3,jp2,kp2)*a3*b2*c2 + g2(i)= g2(i) + GG2(ip3,jp3,kp2)*a3*b3*c2 + + g3(i)= g3(i) + GG3(ip3,jp0,kp2)*a3*b0*c2 + g3(i)= g3(i) + GG3(ip3,jp1,kp2)*a3*b1*c2 + g3(i)= g3(i) + GG3(ip3,jp2,kp2)*a3*b2*c2 + g3(i)= g3(i) + GG3(ip3,jp3,kp2)*a3*b3*c2 + + g1(i)= g1(i) + GG1(ip0,jp0,kp3)*a0*b0*c3 + g1(i)= g1(i) + GG1(ip0,jp1,kp3)*a0*b1*c3 + g1(i)= g1(i) + GG1(ip0,jp2,kp3)*a0*b2*c3 + g1(i)= g1(i) + GG1(ip0,jp3,kp3)*a0*b3*c3 + + g2(i)= g2(i) + GG2(ip0,jp0,kp3)*a0*b0*c3 + g2(i)= g2(i) + GG2(ip0,jp1,kp3)*a0*b1*c3 + g2(i)= g2(i) + GG2(ip0,jp2,kp3)*a0*b2*c3 + g2(i)= g2(i) + GG2(ip0,jp3,kp3)*a0*b3*c3 + + g3(i)= g3(i) + GG3(ip0,jp0,kp3)*a0*b0*c3 + g3(i)= g3(i) + GG3(ip0,jp1,kp3)*a0*b1*c3 + g3(i)= g3(i) + GG3(ip0,jp2,kp3)*a0*b2*c3 + g3(i)= g3(i) + GG3(ip0,jp3,kp3)*a0*b3*c3 + + g1(i)= g1(i) + GG1(ip1,jp0,kp3)*a1*b0*c3 + g1(i)= g1(i) + GG1(ip1,jp1,kp3)*a1*b1*c3 + g1(i)= g1(i) + GG1(ip1,jp2,kp3)*a1*b2*c3 + g1(i)= g1(i) + GG1(ip1,jp3,kp3)*a1*b3*c3 + + g2(i)= g2(i) + GG2(ip1,jp0,kp3)*a1*b0*c3 + g2(i)= g2(i) + GG2(ip1,jp1,kp3)*a1*b1*c3 + g2(i)= g2(i) + GG2(ip1,jp2,kp3)*a1*b2*c3 + g2(i)= g2(i) + GG2(ip1,jp3,kp3)*a1*b3*c3 + + g3(i)= g3(i) + GG3(ip1,jp0,kp3)*a1*b0*c3 + g3(i)= g3(i) + GG3(ip1,jp1,kp3)*a1*b1*c3 + g3(i)= g3(i) + GG3(ip1,jp2,kp3)*a1*b2*c3 + g3(i)= g3(i) + GG3(ip1,jp3,kp3)*a1*b3*c3 + + g1(i)= g1(i) + GG1(ip2,jp0,kp3)*a2*b0*c3 + g1(i)= g1(i) + GG1(ip2,jp1,kp3)*a2*b1*c3 + g1(i)= g1(i) + GG1(ip2,jp2,kp3)*a2*b2*c3 + g1(i)= g1(i) + GG1(ip2,jp3,kp3)*a2*b3*c3 + + g2(i)= g2(i) + GG2(ip2,jp0,kp3)*a2*b0*c3 + g2(i)= g2(i) + GG2(ip2,jp1,kp3)*a2*b1*c3 + g2(i)= g2(i) + GG2(ip2,jp2,kp3)*a2*b2*c3 + g2(i)= g2(i) + GG2(ip2,jp3,kp3)*a2*b3*c3 + + g3(i)= g3(i) + GG3(ip2,jp0,kp3)*a2*b0*c3 + g3(i)= g3(i) + GG3(ip2,jp1,kp3)*a2*b1*c3 + g3(i)= g3(i) + GG3(ip2,jp2,kp3)*a2*b2*c3 + g3(i)= g3(i) + GG3(ip2,jp3,kp3)*a2*b3*c3 + + g1(i)= g1(i) + GG1(ip3,jp0,kp3)*a3*b0*c3 + g1(i)= g1(i) + GG1(ip3,jp1,kp3)*a3*b1*c3 + g1(i)= g1(i) + GG1(ip3,jp2,kp3)*a3*b2*c3 + g1(i)= g1(i) + GG1(ip3,jp3,kp3)*a3*b3*c3 + + g2(i)= g2(i) + GG2(ip3,jp0,kp3)*a3*b0*c3 + g2(i)= g2(i) + GG2(ip3,jp1,kp3)*a3*b1*c3 + g2(i)= g2(i) + GG2(ip3,jp2,kp3)*a3*b2*c3 + g2(i)= g2(i) + GG2(ip3,jp3,kp3)*a3*b3*c3 + + g3(i)= g3(i) + GG3(ip3,jp0,kp3)*a3*b0*c3 + g3(i)= g3(i) + GG3(ip3,jp1,kp3)*a3*b1*c3 + g3(i)= g3(i) + GG3(ip3,jp2,kp3)*a3*b2*c3 + g3(i)= g3(i) + GG3(ip3,jp3,kp3)*a3*b3*c3 + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/intervm4.f90 b/CodesEnVrac/CodeGH/src-THI/intervm4.f90 new file mode 100644 index 000000000..c9511fabe --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/intervm4.f90 @@ -0,0 +1,375 @@ +! +SUBROUTINE intervm4(npart,g1,g2,g3,xp,yp,zp) + + ! + ! Interpolation routine with M'4 + ! + ! geometry=unit box, periodic in x and y + ! last ponits in z direction assume extension by continuity + ! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + + !---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + + dy1=dx1 + dz1=dx1 + + do i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. + end do + + dxinv=1./dx1 + dyinv=1./dy1 + dzinv=1./dz1 + dh3=dx1*dy1*dz1 + dhinv3=1./dh3 + + !-------------------------------------------------------------------- + !- PART II : Determination of the circulation of each particle + !-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + + DO i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + + ! get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx1-x0)*dxinv + yy1 = (y - float(jp1)*dy1-y0)*dyinv + zz1 = (z - float(kp1)*dz1-z0)*dzinv + + xx0=xx1+1 + yy0=yy1+1 + zz0=zz1+1 + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + + xx3=2-xx1 + yy3=2-yy1 + zz3=2-zz1 + + + ! + ! on repositionne les points de grille par periodicite + ! entre 0 et m-1, puis on numerote de 1 a m + C + ip1=mod(ip1+nx1,nx1) +1 + ip0=mod(ip0+nx1,nx1) +1 + ip2=mod(ip2+nx1,nx1) +1 + ip3=mod(ip3+nx1,nx1) +1 + + ! print*,ip0,ip1,ip2,ip3 + + jp1=mod(jp1+ny1,ny1) +1 + jp0=mod(jp0+ny1,ny1) +1 + jp2=mod(jp2+ny1,ny1) +1 + jp3=mod(jp3+ny1,ny1) +1 + + kp1=mod(kp1+nz1,nz1) +1 + kp0=mod(kp0+nz1,nz1) +1 + kp2=mod(kp2+nz1,nz1) +1 + kp3=mod(kp3+nz1,nz1) +1 + + ! + ! The M'4 scheme + ! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + g1(i)= g1(i) + GG1(ip0,jp0,kp0)*a0*b0*c0 + g1(i)= g1(i) + GG1(ip0,jp1,kp0)*a0*b1*c0 + g1(i)= g1(i) + GG1(ip0,jp2,kp0)*a0*b2*c0 + g1(i)= g1(i) + GG1(ip0,jp3,kp0)*a0*b3*c0 + + g2(i)= g2(i) + GG2(ip0,jp0,kp0)*a0*b0*c0 + g2(i)= g2(i) + GG2(ip0,jp1,kp0)*a0*b1*c0 + g2(i)= g2(i) + GG2(ip0,jp2,kp0)*a0*b2*c0 + g2(i)= g2(i) + GG2(ip0,jp3,kp0)*a0*b3*c0 + + g3(i)= g3(i) + GG3(ip0,jp0,kp0)*a0*b0*c0 + g3(i)= g3(i) + GG3(ip0,jp1,kp0)*a0*b1*c0 + g3(i)= g3(i) + GG3(ip0,jp2,kp0)*a0*b2*c0 + g3(i)= g3(i) + GG3(ip0,jp3,kp0)*a0*b3*c0 + + g1(i)= g1(i) + GG1(ip1,jp0,kp0)*a1*b0*c0 + g1(i)= g1(i) + GG1(ip1,jp1,kp0)*a1*b1*c0 + g1(i)= g1(i) + GG1(ip1,jp2,kp0)*a1*b2*c0 + g1(i)= g1(i) + GG1(ip1,jp3,kp0)*a1*b3*c0 + + g2(i)= g2(i) + GG2(ip1,jp0,kp0)*a1*b0*c0 + g2(i)= g2(i) + GG2(ip1,jp1,kp0)*a1*b1*c0 + g2(i)= g2(i) + GG2(ip1,jp2,kp0)*a1*b2*c0 + g2(i)= g2(i) + GG2(ip1,jp3,kp0)*a1*b3*c0 + + g3(i)= g3(i) + GG3(ip1,jp0,kp0)*a1*b0*c0 + g3(i)= g3(i) + GG3(ip1,jp1,kp0)*a1*b1*c0 + g3(i)= g3(i) + GG3(ip1,jp2,kp0)*a1*b2*c0 + g3(i)= g3(i) + GG3(ip1,jp3,kp0)*a1*b3*c0 + + g1(i)= g1(i) + GG1(ip2,jp0,kp0)*a2*b0*c0 + g1(i)= g1(i) + GG1(ip2,jp1,kp0)*a2*b1*c0 + g1(i)= g1(i) + GG1(ip2,jp2,kp0)*a2*b2*c0 + g1(i)= g1(i) + GG1(ip2,jp3,kp0)*a2*b3*c0 + + g2(i)= g2(i) + GG2(ip2,jp0,kp0)*a2*b0*c0 + g2(i)= g2(i) + GG2(ip2,jp1,kp0)*a2*b1*c0 + g2(i)= g2(i) + GG2(ip2,jp2,kp0)*a2*b2*c0 + g2(i)= g2(i) + GG2(ip2,jp3,kp0)*a2*b3*c0 + + g3(i)= g3(i) + GG3(ip2,jp0,kp0)*a2*b0*c0 + g3(i)= g3(i) + GG3(ip2,jp1,kp0)*a2*b1*c0 + g3(i)= g3(i) + GG3(ip2,jp2,kp0)*a2*b2*c0 + g3(i)= g3(i) + GG3(ip2,jp3,kp0)*a2*b3*c0 + + g1(i)= g1(i) + GG1(ip3,jp0,kp0)*a3*b0*c0 + g1(i)= g1(i) + GG1(ip3,jp1,kp0)*a3*b1*c0 + g1(i)= g1(i) + GG1(ip3,jp2,kp0)*a3*b2*c0 + g1(i)= g1(i) + GG1(ip3,jp3,kp0)*a3*b3*c0 + + g2(i)= g2(i) + GG2(ip3,jp0,kp0)*a3*b0*c0 + g2(i)= g2(i) + GG2(ip3,jp1,kp0)*a3*b1*c0 + g2(i)= g2(i) + GG2(ip3,jp2,kp0)*a3*b2*c0 + g2(i)= g2(i) + GG2(ip3,jp3,kp0)*a3*b3*c0 + + g3(i)= g3(i) + GG3(ip3,jp0,kp0)*a3*b0*c0 + g3(i)= g3(i) + GG3(ip3,jp1,kp0)*a3*b1*c0 + g3(i)= g3(i) + GG3(ip3,jp2,kp0)*a3*b2*c0 + g3(i)= g3(i) + GG3(ip3,jp3,kp0)*a3*b3*c0 + + g1(i)= g1(i) + GG1(ip0,jp0,kp1)*a0*b0*c1 + g1(i)= g1(i) + GG1(ip0,jp1,kp1)*a0*b1*c1 + g1(i)= g1(i) + GG1(ip0,jp2,kp1)*a0*b2*c1 + g1(i)= g1(i) + GG1(ip0,jp3,kp1)*a0*b3*c1 + + g2(i)= g2(i) + GG2(ip0,jp0,kp1)*a0*b0*c1 + g2(i)= g2(i) + GG2(ip0,jp1,kp1)*a0*b1*c1 + g2(i)= g2(i) + GG2(ip0,jp2,kp1)*a0*b2*c1 + g2(i)= g2(i) + GG2(ip0,jp3,kp1)*a0*b3*c1 + + g3(i)= g3(i) + GG3(ip0,jp0,kp1)*a0*b0*c1 + g3(i)= g3(i) + GG3(ip0,jp1,kp1)*a0*b1*c1 + g3(i)= g3(i) + GG3(ip0,jp2,kp1)*a0*b2*c1 + g3(i)= g3(i) + GG3(ip0,jp3,kp1)*a0*b3*c1 + + g1(i)= g1(i) + GG1(ip1,jp0,kp1)*a1*b0*c1 + g1(i)= g1(i) + GG1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + GG1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + GG1(ip1,jp3,kp1)*a1*b3*c1 + + g2(i)= g2(i) + GG2(ip1,jp0,kp1)*a1*b0*c1 + g2(i)= g2(i) + GG2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + GG2(ip1,jp2,kp1)*a1*b2*c1 + g2(i)= g2(i) + GG2(ip1,jp3,kp1)*a1*b3*c1 + + g3(i)= g3(i) + GG3(ip1,jp0,kp1)*a1*b0*c1 + g3(i)= g3(i) + GG3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + GG3(ip1,jp2,kp1)*a1*b2*c1 + g3(i)= g3(i) + GG3(ip1,jp3,kp1)*a1*b3*c1 + + g1(i)= g1(i) + GG1(ip2,jp0,kp1)*a2*b0*c1 + g1(i)= g1(i) + GG1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + GG1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + GG1(ip2,jp3,kp1)*a2*b3*c1 + + g2(i)= g2(i) + GG2(ip2,jp0,kp1)*a2*b0*c1 + g2(i)= g2(i) + GG2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + GG2(ip2,jp2,kp1)*a2*b2*c1 + g2(i)= g2(i) + GG2(ip2,jp3,kp1)*a2*b3*c1 + + g3(i)= g3(i) + GG3(ip2,jp0,kp1)*a2*b0*c1 + g3(i)= g3(i) + GG3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + GG3(ip2,jp2,kp1)*a2*b2*c1 + g3(i)= g3(i) + GG3(ip2,jp3,kp1)*a2*b3*c1 + + g1(i)= g1(i) + GG1(ip3,jp0,kp1)*a3*b0*c1 + g1(i)= g1(i) + GG1(ip3,jp1,kp1)*a3*b1*c1 + g1(i)= g1(i) + GG1(ip3,jp2,kp1)*a3*b2*c1 + g1(i)= g1(i) + GG1(ip3,jp3,kp1)*a3*b3*c1 + + g2(i)= g2(i) + GG2(ip3,jp0,kp1)*a3*b0*c1 + g2(i)= g2(i) + GG2(ip3,jp1,kp1)*a3*b1*c1 + g2(i)= g2(i) + GG2(ip3,jp2,kp1)*a3*b2*c1 + g2(i)= g2(i) + GG2(ip3,jp3,kp1)*a3*b3*c1 + + g3(i)= g3(i) + GG3(ip3,jp0,kp1)*a3*b0*c1 + g3(i)= g3(i) + GG3(ip3,jp1,kp1)*a3*b1*c1 + g3(i)= g3(i) + GG3(ip3,jp2,kp1)*a3*b2*c1 + g3(i)= g3(i) + GG3(ip3,jp3,kp1)*a3*b3*c1 + + g1(i)= g1(i) + GG1(ip0,jp0,kp2)*a0*b0*c2 + g1(i)= g1(i) + GG1(ip0,jp1,kp2)*a0*b1*c2 + g1(i)= g1(i) + GG1(ip0,jp2,kp2)*a0*b2*c2 + g1(i)= g1(i) + GG1(ip0,jp3,kp2)*a0*b3*c2 + + g2(i)= g2(i) + GG2(ip0,jp0,kp2)*a0*b0*c2 + g2(i)= g2(i) + GG2(ip0,jp1,kp2)*a0*b1*c2 + g2(i)= g2(i) + GG2(ip0,jp2,kp2)*a0*b2*c2 + g2(i)= g2(i) + GG2(ip0,jp3,kp2)*a0*b3*c2 + + g3(i)= g3(i) + GG3(ip0,jp0,kp2)*a0*b0*c2 + g3(i)= g3(i) + GG3(ip0,jp1,kp2)*a0*b1*c2 + g3(i)= g3(i) + GG3(ip0,jp2,kp2)*a0*b2*c2 + g3(i)= g3(i) + GG3(ip0,jp3,kp2)*a0*b3*c2 + + g1(i)= g1(i) + GG1(ip1,jp0,kp2)*a1*b0*c2 + g1(i)= g1(i) + GG1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + GG1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + GG1(ip1,jp3,kp2)*a1*b3*c2 + + g2(i)= g2(i) + GG2(ip1,jp0,kp2)*a1*b0*c2 + g2(i)= g2(i) + GG2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + GG2(ip1,jp2,kp2)*a1*b2*c2 + g2(i)= g2(i) + GG2(ip1,jp3,kp2)*a1*b3*c2 + + g3(i)= g3(i) + GG3(ip1,jp0,kp2)*a1*b0*c2 + g3(i)= g3(i) + GG3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + GG3(ip1,jp2,kp2)*a1*b2*c2 + g3(i)= g3(i) + GG3(ip1,jp3,kp2)*a1*b3*c2 + + g1(i)= g1(i) + GG1(ip2,jp0,kp2)*a2*b0*c2 + g1(i)= g1(i) + GG1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + GG1(ip2,jp2,kp2)*a2*b2*c2 + g1(i)= g1(i) + GG1(ip2,jp3,kp2)*a2*b3*c2 + + g2(i)= g2(i) + GG2(ip2,jp0,kp2)*a2*b0*c2 + g2(i)= g2(i) + GG2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + GG2(ip2,jp2,kp2)*a2*b2*c2 + g2(i)= g2(i) + GG2(ip2,jp3,kp2)*a2*b3*c2 + + g3(i)= g3(i) + GG3(ip2,jp0,kp2)*a2*b0*c2 + g3(i)= g3(i) + GG3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + GG3(ip2,jp2,kp2)*a2*b2*c2 + g3(i)= g3(i) + GG3(ip2,jp3,kp2)*a2*b3*c2 + + g1(i)= g1(i) + GG1(ip3,jp0,kp2)*a3*b0*c2 + g1(i)= g1(i) + GG1(ip3,jp1,kp2)*a3*b1*c2 + g1(i)= g1(i) + GG1(ip3,jp2,kp2)*a3*b2*c2 + g1(i)= g1(i) + GG1(ip3,jp3,kp2)*a3*b3*c2 + + g2(i)= g2(i) + GG2(ip3,jp0,kp2)*a3*b0*c2 + g2(i)= g2(i) + GG2(ip3,jp1,kp2)*a3*b1*c2 + g2(i)= g2(i) + GG2(ip3,jp2,kp2)*a3*b2*c2 + g2(i)= g2(i) + GG2(ip3,jp3,kp2)*a3*b3*c2 + + g3(i)= g3(i) + GG3(ip3,jp0,kp2)*a3*b0*c2 + g3(i)= g3(i) + GG3(ip3,jp1,kp2)*a3*b1*c2 + g3(i)= g3(i) + GG3(ip3,jp2,kp2)*a3*b2*c2 + g3(i)= g3(i) + GG3(ip3,jp3,kp2)*a3*b3*c2 + + g1(i)= g1(i) + GG1(ip0,jp0,kp3)*a0*b0*c3 + g1(i)= g1(i) + GG1(ip0,jp1,kp3)*a0*b1*c3 + g1(i)= g1(i) + GG1(ip0,jp2,kp3)*a0*b2*c3 + g1(i)= g1(i) + GG1(ip0,jp3,kp3)*a0*b3*c3 + + g2(i)= g2(i) + GG2(ip0,jp0,kp3)*a0*b0*c3 + g2(i)= g2(i) + GG2(ip0,jp1,kp3)*a0*b1*c3 + g2(i)= g2(i) + GG2(ip0,jp2,kp3)*a0*b2*c3 + g2(i)= g2(i) + GG2(ip0,jp3,kp3)*a0*b3*c3 + + g3(i)= g3(i) + GG3(ip0,jp0,kp3)*a0*b0*c3 + g3(i)= g3(i) + GG3(ip0,jp1,kp3)*a0*b1*c3 + g3(i)= g3(i) + GG3(ip0,jp2,kp3)*a0*b2*c3 + g3(i)= g3(i) + GG3(ip0,jp3,kp3)*a0*b3*c3 + + g1(i)= g1(i) + GG1(ip1,jp0,kp3)*a1*b0*c3 + g1(i)= g1(i) + GG1(ip1,jp1,kp3)*a1*b1*c3 + g1(i)= g1(i) + GG1(ip1,jp2,kp3)*a1*b2*c3 + g1(i)= g1(i) + GG1(ip1,jp3,kp3)*a1*b3*c3 + + g2(i)= g2(i) + GG2(ip1,jp0,kp3)*a1*b0*c3 + g2(i)= g2(i) + GG2(ip1,jp1,kp3)*a1*b1*c3 + g2(i)= g2(i) + GG2(ip1,jp2,kp3)*a1*b2*c3 + g2(i)= g2(i) + GG2(ip1,jp3,kp3)*a1*b3*c3 + + g3(i)= g3(i) + GG3(ip1,jp0,kp3)*a1*b0*c3 + g3(i)= g3(i) + GG3(ip1,jp1,kp3)*a1*b1*c3 + g3(i)= g3(i) + GG3(ip1,jp2,kp3)*a1*b2*c3 + g3(i)= g3(i) + GG3(ip1,jp3,kp3)*a1*b3*c3 + + g1(i)= g1(i) + GG1(ip2,jp0,kp3)*a2*b0*c3 + g1(i)= g1(i) + GG1(ip2,jp1,kp3)*a2*b1*c3 + g1(i)= g1(i) + GG1(ip2,jp2,kp3)*a2*b2*c3 + g1(i)= g1(i) + GG1(ip2,jp3,kp3)*a2*b3*c3 + + g2(i)= g2(i) + GG2(ip2,jp0,kp3)*a2*b0*c3 + g2(i)= g2(i) + GG2(ip2,jp1,kp3)*a2*b1*c3 + g2(i)= g2(i) + GG2(ip2,jp2,kp3)*a2*b2*c3 + g2(i)= g2(i) + GG2(ip2,jp3,kp3)*a2*b3*c3 + + g3(i)= g3(i) + GG3(ip2,jp0,kp3)*a2*b0*c3 + g3(i)= g3(i) + GG3(ip2,jp1,kp3)*a2*b1*c3 + g3(i)= g3(i) + GG3(ip2,jp2,kp3)*a2*b2*c3 + g3(i)= g3(i) + GG3(ip2,jp3,kp3)*a2*b3*c3 + + g1(i)= g1(i) + GG1(ip3,jp0,kp3)*a3*b0*c3 + g1(i)= g1(i) + GG1(ip3,jp1,kp3)*a3*b1*c3 + g1(i)= g1(i) + GG1(ip3,jp2,kp3)*a3*b2*c3 + g1(i)= g1(i) + GG1(ip3,jp3,kp3)*a3*b3*c3 + + g2(i)= g2(i) + GG2(ip3,jp0,kp3)*a3*b0*c3 + g2(i)= g2(i) + GG2(ip3,jp1,kp3)*a3*b1*c3 + g2(i)= g2(i) + GG2(ip3,jp2,kp3)*a3*b2*c3 + g2(i)= g2(i) + GG2(ip3,jp3,kp3)*a3*b3*c3 + + g3(i)= g3(i) + GG3(ip3,jp0,kp3)*a3*b0*c3 + g3(i)= g3(i) + GG3(ip3,jp1,kp3)*a3*b1*c3 + g3(i)= g3(i) + GG3(ip3,jp2,kp3)*a3*b2*c3 + g3(i)= g3(i) + GG3(ip3,jp3,kp3)*a3*b3*c3 + + end DO + +end SUBROUTINE intervm4 diff --git a/CodesEnVrac/CodeGH/src-THI/main.f b/CodesEnVrac/CodeGH/src-THI/main.f new file mode 100644 index 000000000..a29a6832d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/main.f @@ -0,0 +1,419 @@ + program cylindre + +c versnio de main avec splitting x,y,z du transport/remesh de rho +c le poussuer/remaille de om et rho sont dissocies +c comma main_full, mais avec cfl 0.5 pour advection de rho +c (et possibilite de sous-ite pour advection de rho avec dt3 < dt) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(npm),yp1(npm),zp1(npm),dv1(npm) + dimension xp2(npm),yp2(npm),zp2(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx1(npm),vy1(npm),vz1(npm) + dimension vx2(npm),vy2(npm),vz2(npm) + dimension strx(npm),stry(npm),strz(npm) + dimension phip(npm) +c tableuax supplementaries pour RK + dimension xp10(npm),yp10(npm),zp10(npm) + dimension xp20(npm),yp20(npm),zp20(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv1(4,npm),vyv1(4,npm),vzv1(4,npm) + dimension vxv2(4,npm),vyv2(4,npm),vzv2(4,npm) + + dimension para(4) + dimension enstrophy(0:10000),energy(0:10000),divergence(0:10000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filerho,fileomx,fileomy,fileomz + + + pi=3.1415926 + pi2=2.*pi + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx1 + READ(1,*) + read(1,*) nx2 + READ(1,*) + read(1,*)nit + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)anu_rho + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)korder + READ(1,*) + read(1,*)tstop + close(1) + idif=1 + iper=0 + + + xmin=0. + ymin=0. + zmin=0. + xmax=pi2 + xmax=1. + ymax=xmax + dx1=xmax/float(nx1) + dx2=xmax/float(nx2) + zmax=xmax + + t1=4.5 + t2=5. + t3=5.5 +c t3=0.784 +c t4=1.13 +c t3=1000. + t4=1000. + +c t1=3.4 +c t2=3.8 +c t3=3.6 +c t4=6. +c resolution pour rho +c et initalisation des comptuer utlise pour +c avoir des pas de temps distincts en rho et omega + + nx3=32 +c cas ou on utilise veloxax_v2 (filtre en spectral +c puis on padde avec des 0 puis on fftinverse sur une +c grille 128: + nx3=nx1 + + dx3=xmax/float(nx3) + ic=0 + k_delt3=1 + + dy1=dx1 + dz1=dx1 + ny1=nint(float(nx1)*ymax/xmax) + nz1=nint(float(nx1)*zmax/xmax) + ymax=float(ny1)*dy1 + zmax=float(nz1)*dz1 + dy2=dx2 + dz2=dx2 + ny2=nint(float(nx2)*ymax/xmax) + nz2=nint(float(nx2)*zmax/xmax) + + print*, nx1,ny1,nz1,xmax,ymax,zmax + + + delt0=1.5*dx1 + delt0=0.0001 + delt=delt0 + delt3=delt +c delt=0.0 + +c call readfield(npart1,xp1,yp1,zp1, +c 1 omx,omy,omz,dv1) + call jet(npart1,xp1,yp1,zp1, + 1 omx,omy,omz,dv1) + + print*,'npart1 ',npart1 + + OPEN(33,file='DIAG1',status='unknown') + OPEN(34,file='DIAG2',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + omax=1000. + istep=0 + + do 20 kk=1,nit + + time=time+delt + + call velox(vmax1) + call veloxaux(vmax,dvmax) + +c determination pas de temps: + if ((ic.eq.0)) then + delt=.25/abs(omax) + delt=amax1(delt,0.5*dx1/vmax1) +c delt=0.5*dx2/vmax + delt3=2.*dx3/vmax + delt3=0.5*dx2/vmax + delt3=1.*delt + if (dvmax.ne.0.) delt3=amax1(delt3,0.25/dvmax) +c if ((dvmax.ne.0.).and.(korder.eq.2)) +c 1 delt3=amax1(delt3,0.5*dx3/dvmax) +c delt3=delt + print*, ' TIME, Pas de temps omega et rho ', time,delt,delt3 + print*, 'dvmax',dvmax + print*, ' LCFL ',dvmax*delt3 + k_delt3=int(delt3/delt) + if (k_delt3.eq.0) then + k_delt=int(delt/delt3) + k_delt3=1 + k_delt=k_delt+1 + delt3=delt/float(k_delt) + else + delt3=float(k_delt3)*delt + k_delt=1 + endif + print*,' CFLs ',delt3*vmax/dx3,delt3*vmax/dx2 + endif + + deltconv=delt + + delt1=deltconv/6. + +c ADVECTION particules de vorticite + +c on fait les sous-iterations R.K. + + do i=1,npart1 + xp10(i)=xp1(i) + yp10(i)=yp1(i) + zp10(i)=zp1(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) + enddo + + do 550 ll=1,4 + + if (ll.eq.1) then + + print*,'TIME ',time + + call stretch + + endif + + nx4=nx1 + + call intervm4(npart1,vx1,vy1,vz1,xp1,yp1,zp1) + call intersm4(npart1,strx,stry,strz,xp1,yp1,zp1) + + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + do 520 i=1,npart1 + vxv1(ll,i)=vx1(i) + vyv1(ll,i)=vy1(i) + vzv1(ll,i)=vz1(i) + strxv(ll,i)=dv1(i)*strx(i) + stryv(ll,i)=dv1(i)*stry(i) + strzv(ll,i)=dv1(i)*strz(i) + xp1(i)=xp10(i)+para(ll)*deltconv*vx1(i) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + yp1(i)=yp10(i)+para(ll)*deltconv*vy1(i) + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + zp1(i)=zp10(i)+para(ll)*deltconv*vz1(i) + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv1(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv1(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv1(i)*strz(i) + vxmax=amax1(vxmax,(vx1(i))) + vxmin=amin1(vxmin,(vx1(i))) + vymax=amax1(vymax,(vy1(i))) + vymin=amin1(vymin,(vy1(i))) + vzmax=amax1(vzmax,(vz1(i))) + vzmin=amin1(vzmin,(vz1(i))) +520 continue + +550 continue + +c FIN des sous-ite RK pour transport de vorticite +c ********************** + + xpmin=10. + ypmin=10. + xpmax=0. + ypmax=0. + yleft=1000. + yright=-1000. + + do i=1,npart1 + xp1(i)=xp10(i)+delt1* + 1 (vxv1(1,i)+2.*vxv1(2,i)+2.*vxv1(3,i)+vxv1(4,i)) + yp1(i)=yp10(i)+delt1* + 1 (vyv1(1,i)+2.*vyv1(2,i)+2.*vyv1(3,i)+vyv1(4,i)) + zp1(i)=zp10(i)+delt1* + 1 (vzv1(1,i)+2.*vzv1(2,i)+2.*vzv1(3,i)+vzv1(4,i)) + if (xp1(i).lt.xmin) xp1(i)=xp1(i)+xmax-xmin + if (xp1(i).gt.xmax) xp1(i)=xp1(i)-xmax+xmin + if (yp1(i).lt.ymin) yp1(i)=yp1(i)+ymax-ymin + if (yp1(i).gt.ymax) yp1(i)=yp1(i)-ymax+ymin + if (zp1(i).lt.zmin) zp1(i)=zp1(i)+zmax-zmin + if (zp1(i).gt.zmax) zp1(i)=zp1(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) + enddo + +700 continue + +c fin d'adection de particules de vorticite + + +c + +c Remesh des particules de vorticite +C puis diffusion de vorticite +c ********************** + + circlim=+0.0001 +c circlim=0. + + call remesh_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1) + print*,' npart OM apres remeshing ', kk,npart1 + call dif_om(npart1,omx,omy,omz, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax) +4444 continue + +c icrementation du comptuer pour decider ou non d +c d'advecter/remailler en rho (pas de temps disticnts) + ic=ic+1 + do 111 ksubite=1,k_delt + print*,ic,k_delt3 + if ((ic.eq.k_delt3)) then + + np_bl=3 + dx=dx2 + nx=nx2 + dt=delt3 + dt2=delt3/2. + dt3=delt3/2. + + if (korder.eq.2) then + call y_advect(dt2,np_bl,ntagy) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call z_advect(dt2,np_bl,ntagz) + call z_advect(dt2,np_bl,ntagz) + call x_advect(dt3,np_bl,npart_rho,ntagx) + call y_advect(dt2,np_bl,ntagy) + else + call x_advect(dt,np_bl,npart_rho,ntagx) + call y_advect(dt,np_bl,ntagy) + call z_advect(dt,np_bl,ntagz) + endif + + + ntag=max(ntagx,ntagy) + ntag=max(ntag,ntagz) + + call dif_rho(anu_rho,dt) + +c Fin de push / remesh rho /dif rho + ic=0 + +c quelques diagnostiques + call diag(ener,enstro,div,omax,rhomax,width,VOL1,VOL2) + write(33,*) time,npart_rho,ntag,vmax*CFL,enstro + write(34,*) time,width,VOL1,VOL2 + + endif +111 continue + + tcompt=tcompt+delt + if (((time.gt.t1).and.(time.le.t1+1.5*delt)). + 1 or.((time.gt.t2).and.(time.le.t2+1.5*delt)). + 1 or.((time.gt.t4).and.(time.le.t4+1.5*delt)). + 1 or.((time.gt.t3).and.(time.le.t3+1.5*delt))) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, '*' + write(filerho,140)istep +140 format('rho',i1) + write(fileomx,141)istep +141 format('omx',i1) + write(fileomy,142)istep +142 format('omy',i1) + write(fileomz,143)istep +143 format('omz',i1) + + goto 222 + open(20,file=filerho,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(2,file=fileomx,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(3,file=fileomy,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + open(4,file=fileomz,form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + + + write(20) (((ug(i,j,k), + 1 i=1,nx2),j=1,ny2),k=1,nz2) + write(2) ((((omg1(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(3) ((((omg2(i,j,k)), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + write(4) (((omg3(i,j,k), + 1 i=1,nx1),j=1,ny1),k=1,nz1) + close(20) + close(2) + close(3) + close(4) + goto 223 +222 continue + + open(24,file=filerho) + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx2," ",nx2," ",nx2 + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx2," ",dx2," ",dx2 + WRITE(24,*) "POINT_DATA ",nx2*nx2*nx2 + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx2 + do j=1,nx2 + do i=1,nx2 + umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,ug(i,j,k)) + enddo + enddo + enddo + close(24) + print*,'**** RHO MAX = ',umax + +223 continue + + endif + + if (time.gt.tstop) goto 202 + +20 continue + +202 continue + + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/src-THI/make b/CodesEnVrac/CodeGH/src-THI/make new file mode 100644 index 000000000..4667b6e48 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/make @@ -0,0 +1,11 @@ + 128 128 128 1.000000 1.000000 + 1.000000 + VXMAX = 1.291362 + NPART = 791552 + npart1 791552 + VXMAX sur grille 0.9833295 0.1099195 1.6970979E-02 + umax 0.9903467 9.3841553E-02 3.0463261E-03 + TIME, Pas de temps omega et rho 9.9999997E-05 1.9862365E-03 1.9721629E-03 + LCFL 4.6338923E-03 + CFLs 3.1473007E-02 0.2517841 + TIME 9.9999997E-05 diff --git a/CodesEnVrac/CodeGH/src-THI/makefile b/CodesEnVrac/CodeGH/src-THI/makefile new file mode 100644 index 000000000..15b431180 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/makefile @@ -0,0 +1,112 @@ +# +# la commande f77 pour les dec est f77_520 +# +OPT = -I/sw/include + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl +#OPT3 = -O3 -r8 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g +#OPT3 = -O -p + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = thi_l2 + +all: $(PROGRAM) + +OBJSF = diag.o\ + initread.o \ + initjet.o \ + intervm4.o \ + intersm4.o \ + interho.o \ + main.o \ + dif.o \ + dif_rho.o \ + remesh_om.o \ + remesh_rho.o \ + remeshx.o \ + remeshy.o \ + remeshz.o \ + remeshx_tag.o \ + remeshy_tag.o \ + remeshz_tag.o \ + tag_particles.o \ + x_advect.o \ + y_advect.o \ + z_advect.o \ + stretch.o \ + fftw3d.o \ + velox_x.o \ + velox_y.o \ + velox_z.o \ + veloxaux.o \ + velox.o + +diag.o: diag.f param.i + ifort $(OPT3) -c diag.f +dif.o: dif.f param.i + ifort $(OPT3) -c dif.f +dif_rho.o: dif_rho.f param.i + ifort $(OPT3) -c dif_rho.f +initread.o: initread.f param.i + ifort $(OPT3) -c -g initread.f +initjet.o: initjet.f param.i + ifort $(OPT3) -c -g initjet.f +intervm4.o: intervm4.f param.i + ifort $(OPT3) -c intervm4.f +intersm4.o: intersm4.f param.i + ifort $(OPT3) -c intersm4.f +interho.o: interho.f param.i + ifort $(OPT3) -c interho.f +main.o: main.f param.i + ifort $(OPT3) -c -g main.f +remesh_om.o: remesh_om.f param.i + ifort $(OPT3) -c remesh_om.f +remesh_rho.o: remesh_rho.f param.i + ifort $(OPT3) -c remesh_rho.f +remeshx.o: remeshx.f param.i + ifort $(OPT3) -c remeshx.f +remeshy.o: remeshy.f param.i + ifort $(OPT3) -c remeshy.f +remeshz.o: remeshz.f param.i + ifort $(OPT3) -c remeshz.f +remeshx_tag.o: remeshx_tag.f param.i + ifort $(OPT3) -c remeshx_tag.f +remeshy_tag.o: remeshy_tag.f param.i + ifort $(OPT3) -c remeshy_tag.f +remeshz_tag.o: remeshz_tag.f param.i + ifort $(OPT3) -c remeshz_tag.f +x_advect.o: x_advect.f param.i + ifort $(OPT3) -c x_advect.f +y_advect.o: y_advect.f param.i + ifort $(OPT3) -c y_advect.f +z_advect.o: z_advect.f param.i + ifort $(OPT3) -c z_advect.f +tag_particles.o: tag_particles.f param.i + ifort $(OPT3) -c tag_particles.f +stretch.o: stretch.f param.i + ifort $(OPT3) -c stretch.f +velox.o: velox.f param.i + ifort $(OPT3) -c velox.f +velox_x.o: velox_x.f param.i + ifort $(OPT3) -c velox_x.f +velox_y.o: velox_y.f param.i + ifort $(OPT3) -c velox_y.f +velox_z.o: velox_z.f param.i + ifort $(OPT3) -c velox_z.f +veloxaux.o: veloxaux.f param.i + ifort $(OPT3) -c veloxaux.f +fftw3d.o: fftw3d.f param.i + ifort $(OPT3) -c fftw3d.f + + +$(PROGRAM): $(OBJSF) + ifort $(OPT3) $(OBJSF) -lfftw3f -lfftw3_threads -o $(PROGRAM) + diff --git a/CodesEnVrac/CodeGH/src-THI/param.h b/CodesEnVrac/CodeGH/src-THI/param.h new file mode 100644 index 000000000..e6e8a2c9d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/param.h @@ -0,0 +1,3 @@ + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,dx1 + common nx2,ny2,nz2,dx2,nx3 + common circlim,cfl,nx,dx \ No newline at end of file diff --git a/CodesEnVrac/CodeGH/src-THI/param_rho.i b/CodesEnVrac/CodeGH/src-THI/param_rho.i new file mode 100644 index 000000000..58afe3b17 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/param_rho.i @@ -0,0 +1,3 @@ + parameter(npgx=256,npgy=256,npgz=256) + parameter(npg=256) + diff --git a/CodesEnVrac/CodeGH/src-THI/remesh_om.f90 b/CodesEnVrac/CodeGH/src-THI/remesh_om.f90 new file mode 100644 index 000000000..d1aefc01d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remesh_om.f90 @@ -0,0 +1,465 @@ +!================================================================ +SUBROUTINE remesh_om(npart,om1,om2,om3,xp1,yp1,zp1,dv1) + ! This subroutine asssigns vorticity on a grid + !---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + + + do i=1,nx1 + do j=1,ny1 + do k=1,nz1 + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. + end do + end do + end do + + dy1=dx1 + dz1=dx1 + + dxinv=1./(dx1) + dyinv=dxinv + dzinv=dxinv + + + + !-------------------------------------------------------------------- + !- PART II : Determination of the circulation of each particle + !-------------------------------------------------------------------- + + x0=0. + y0=0. + z0=0. + + vol=dx1*dx1*dx1 + + DO n = 1,npart + + g2 = om1(n)/vol + g3 = om2(n)/vol + g4 = om3(n)/vol + + x = xp1(n) + y = yp1(n) + z = zp1(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + ! Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx1-x0)*dxinv + yy1 = (y - float(jp1)*dy1-y0)*dyinv + zz1 = (z - float(kp1)*dz1-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + + ! + ! on repositionne les points de grille par periodicite + ! entre 0 et npx-1, puis on numerote de 1 a npx + ! + + ip1=mod(ip1+nx1,nx1) +1 + ip0=mod(ip0+nx1,nx1) +1 + ip2=mod(ip2+nx1,nx1) +1 + ip3=mod(ip3+nx1,nx1) +1 + + jp1=mod(jp1+ny1,ny1) +1 + jp0=mod(jp0+ny1,ny1) +1 + jp2=mod(jp2+ny1,ny1) +1 + jp3=mod(jp3+ny1,ny1) +1 + + kp1=mod(kp1+nz1,nz1) +1 + kp0=mod(kp0+nz1,nz1) +1 + kp2=mod(kp2+nz1,nz1) +1 + kp3=mod(kp3+nz1,nz1) +1 + + ! The M'4 scheme + ! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + ! b1=1. + ! b0=0. + ! b2=0. + ! b3=0. + ! a1=1. + ! a0=0. + ! a2=0. + ! a3=0. + ! c1=1. + ! c0=0. + ! c2=0. + ! c3=0. + + + coef=a0*b0*c0 + omg1(ip0,jp0,kp0) = omg1(ip0,jp0,kp0) + g2*coef + omg2(ip0,jp0,kp0) = omg2(ip0,jp0,kp0) + g3*coef + omg3(ip0,jp0,kp0) = omg3(ip0,jp0,kp0) + g4*coef + + coef=a0*b0*c1 + omg1(ip0,jp0,kp1) = omg1(ip0,jp0,kp1) + g2*coef + omg2(ip0,jp0,kp1) = omg2(ip0,jp0,kp1) + g3*coef + omg3(ip0,jp0,kp1) = omg3(ip0,jp0,kp1) + g4*coef + + coef=a0*b0*c2 + omg1(ip0,jp0,kp2) = omg1(ip0,jp0,kp2) + g2*coef + omg2(ip0,jp0,kp2) = omg2(ip0,jp0,kp2) + g3*coef + omg3(ip0,jp0,kp2) = omg3(ip0,jp0,kp2) + g4*coef + + coef=a0*b0*c3 + omg1(ip0,jp0,kp3) = omg1(ip0,jp0,kp3) + g2*coef + omg2(ip0,jp0,kp3) = omg2(ip0,jp0,kp3) + g3*coef + omg3(ip0,jp0,kp3) = omg3(ip0,jp0,kp3) + g4*coef + + coef=a0*b1*c0 + omg1(ip0,jp1,kp0) = omg1(ip0,jp1,kp0) + g2*coef + omg2(ip0,jp1,kp0) = omg2(ip0,jp1,kp0) + g3*coef + omg3(ip0,jp1,kp0) = omg3(ip0,jp1,kp0) + g4*coef + + coef=a0*b1*c1 + omg1(ip0,jp1,kp1) = omg1(ip0,jp1,kp1) + g2*coef + omg2(ip0,jp1,kp1) = omg2(ip0,jp1,kp1) + g3*coef + omg3(ip0,jp1,kp1) = omg3(ip0,jp1,kp1) + g4*coef + + coef=a0*b1*c2 + omg1(ip0,jp1,kp2) = omg1(ip0,jp1,kp2) + g2*coef + omg2(ip0,jp1,kp2) = omg2(ip0,jp1,kp2) + g3*coef + omg3(ip0,jp1,kp2) = omg3(ip0,jp1,kp2) + g4*coef + + coef=a0*b1*c3 + omg1(ip0,jp1,kp3) = omg1(ip0,jp1,kp3) + g2*coef + omg2(ip0,jp1,kp3) = omg2(ip0,jp1,kp3) + g3*coef + omg3(ip0,jp1,kp3) = omg3(ip0,jp1,kp3) + g4*coef + + coef=a0*b2*c0 + omg1(ip0,jp2,kp0) = omg1(ip0,jp2,kp0) + g2*coef + omg2(ip0,jp2,kp0) = omg2(ip0,jp2,kp0) + g3*coef + omg3(ip0,jp2,kp0) = omg3(ip0,jp2,kp0) + g4*coef + + coef=a0*b2*c1 + omg1(ip0,jp2,kp1) = omg1(ip0,jp2,kp1) + g2*coef + omg2(ip0,jp2,kp1) = omg2(ip0,jp2,kp1) + g3*coef + omg3(ip0,jp2,kp1) = omg3(ip0,jp2,kp1) + g4*coef + + coef=a0*b2*c2 + omg1(ip0,jp2,kp2) = omg1(ip0,jp2,kp2) + g2*coef + omg2(ip0,jp2,kp2) = omg2(ip0,jp2,kp2) + g3*coef + omg3(ip0,jp2,kp2) = omg3(ip0,jp2,kp2) + g4*coef + + + coef=a0*b2*c3 + omg1(ip0,jp2,kp3) = omg1(ip0,jp2,kp3) + g2*coef + omg2(ip0,jp2,kp3) = omg2(ip0,jp2,kp3) + g3*coef + omg3(ip0,jp2,kp3) = omg3(ip0,jp2,kp3) + g4*coef + + coef=a0*b3*c0 + omg1(ip0,jp3,kp0) = omg1(ip0,jp3,kp0) + g2*coef + omg2(ip0,jp3,kp0) = omg2(ip0,jp3,kp0) + g3*coef + omg3(ip0,jp3,kp0) = omg3(ip0,jp3,kp0) + g4*coef + + coef=a0*b3*c1 + omg1(ip0,jp3,kp1) = omg1(ip0,jp3,kp1) + g2*coef + omg2(ip0,jp3,kp1) = omg2(ip0,jp3,kp1) + g3*coef + omg3(ip0,jp3,kp1) = omg3(ip0,jp3,kp1) + g4*coef + + coef=a0*b3*c2 + omg1(ip0,jp3,kp2) = omg1(ip0,jp3,kp2) + g2*coef + omg2(ip0,jp3,kp2) = omg2(ip0,jp3,kp2) + g3*coef + omg3(ip0,jp3,kp2) = omg3(ip0,jp3,kp2) + g4*coef + + coef=a0*b3*c3 + omg1(ip0,jp3,kp3) = omg1(ip0,jp3,kp3) + g2*coef + omg2(ip0,jp3,kp3) = omg2(ip0,jp3,kp3) + g3*coef + omg3(ip0,jp3,kp3) = omg3(ip0,jp3,kp3) + g4*coef + + coef=a1*b0*c0 + omg1(ip1,jp0,kp0) = omg1(ip1,jp0,kp0) + g2*coef + omg2(ip1,jp0,kp0) = omg2(ip1,jp0,kp0) + g3*coef + omg3(ip1,jp0,kp0) = omg3(ip1,jp0,kp0) + g4*coef + + coef=a1*b0*c1 + omg1(ip1,jp0,kp1) = omg1(ip1,jp0,kp1) + g2*coef + omg2(ip1,jp0,kp1) = omg2(ip1,jp0,kp1) + g3*coef + omg3(ip1,jp0,kp1) = omg3(ip1,jp0,kp1) + g4*coef + + coef=a1*b0*c2 + omg1(ip1,jp0,kp2) = omg1(ip1,jp0,kp2) + g2*coef + omg2(ip1,jp0,kp2) = omg2(ip1,jp0,kp2) + g3*coef + omg3(ip1,jp0,kp2) = omg3(ip1,jp0,kp2) + g4*coef + + coef=a1*b0*c3 + omg1(ip1,jp0,kp3) = omg1(ip1,jp0,kp3) + g2*coef + omg2(ip1,jp0,kp3) = omg2(ip1,jp0,kp3) + g3*coef + omg3(ip1,jp0,kp3) = omg3(ip1,jp0,kp3) + g4*coef + + coef=a1*b1*c0 + omg1(ip1,jp1,kp0) = omg1(ip1,jp1,kp0) + g2*coef + omg2(ip1,jp1,kp0) = omg2(ip1,jp1,kp0) + g3*coef + omg3(ip1,jp1,kp0) = omg3(ip1,jp1,kp0) + g4*coef + + coef=a1*b1*c1 + omg1(ip1,jp1,kp1) = omg1(ip1,jp1,kp1) + g2*coef + omg2(ip1,jp1,kp1) = omg2(ip1,jp1,kp1) + g3*coef + omg3(ip1,jp1,kp1) = omg3(ip1,jp1,kp1) + g4*coef + + coef=a1*b1*c2 + omg1(ip1,jp1,kp2) = omg1(ip1,jp1,kp2) + g2*coef + omg2(ip1,jp1,kp2) = omg2(ip1,jp1,kp2) + g3*coef + omg3(ip1,jp1,kp2) = omg3(ip1,jp1,kp2) + g4*coef + + coef=a1*b1*c3 + omg1(ip1,jp1,kp3) = omg1(ip1,jp1,kp3) + g2*coef + omg2(ip1,jp1,kp3) = omg2(ip1,jp1,kp3) + g3*coef + omg3(ip1,jp1,kp3) = omg3(ip1,jp1,kp3) + g4*coef + + coef=a1*b2*c0 + omg1(ip1,jp2,kp0) = omg1(ip1,jp2,kp0) + g2*coef + omg2(ip1,jp2,kp0) = omg2(ip1,jp2,kp0) + g3*coef + omg3(ip1,jp2,kp0) = omg3(ip1,jp2,kp0) + g4*coef + + coef=a1*b2*c1 + omg1(ip1,jp2,kp1) = omg1(ip1,jp2,kp1) + g2*coef + omg2(ip1,jp2,kp1) = omg2(ip1,jp2,kp1) + g3*coef + omg3(ip1,jp2,kp1) = omg3(ip1,jp2,kp1) + g4*coef + + coef=a1*b2*c2 + omg1(ip1,jp2,kp2) = omg1(ip1,jp2,kp2) + g2*coef + omg2(ip1,jp2,kp2) = omg2(ip1,jp2,kp2) + g3*coef + omg3(ip1,jp2,kp2) = omg3(ip1,jp2,kp2) + g4*coef + + coef=a1*b2*c3 + omg1(ip1,jp2,kp3) = omg1(ip1,jp2,kp3) + g2*coef + omg2(ip1,jp2,kp3) = omg2(ip1,jp2,kp3) + g3*coef + omg3(ip1,jp2,kp3) = omg3(ip1,jp2,kp3) + g4*coef + + coef=a1*b3*c0 + omg1(ip1,jp3,kp0) = omg1(ip1,jp3,kp0) + g2*coef + omg2(ip1,jp3,kp0) = omg2(ip1,jp3,kp0) + g3*coef + omg3(ip1,jp3,kp0) = omg3(ip1,jp3,kp0) + g4*coef + + coef=a1*b3*c1 + omg1(ip1,jp3,kp1) = omg1(ip1,jp3,kp1) + g2*coef + omg2(ip1,jp3,kp1) = omg2(ip1,jp3,kp1) + g3*coef + omg3(ip1,jp3,kp1) = omg3(ip1,jp3,kp1) + g4*coef + + coef=a1*b3*c2 + omg1(ip1,jp3,kp2) = omg1(ip1,jp3,kp2) + g2*coef + omg2(ip1,jp3,kp2) = omg2(ip1,jp3,kp2) + g3*coef + omg3(ip1,jp3,kp2) = omg3(ip1,jp3,kp2) + g4*coef + + coef=a1*b3*c3 + omg1(ip1,jp3,kp3) = omg1(ip1,jp3,kp3) + g2*coef + omg2(ip1,jp3,kp3) = omg2(ip1,jp3,kp3) + g3*coef + omg3(ip1,jp3,kp3) = omg3(ip1,jp3,kp3) + g4*coef + + coef=a2*b0*c0 + omg1(ip2,jp0,kp0) = omg1(ip2,jp0,kp0) + g2*coef + omg2(ip2,jp0,kp0) = omg2(ip2,jp0,kp0) + g3*coef + omg3(ip2,jp0,kp0) = omg3(ip2,jp0,kp0) + g4*coef + + coef=a2*b0*c1 + omg1(ip2,jp0,kp1) = omg1(ip2,jp0,kp1) + g2*coef + omg2(ip2,jp0,kp1) = omg2(ip2,jp0,kp1) + g3*coef + omg3(ip2,jp0,kp1) = omg3(ip2,jp0,kp1) + g4*coef + + coef=a2*b0*c2 + omg1(ip2,jp0,kp2) = omg1(ip2,jp0,kp2) + g2*coef + omg2(ip2,jp0,kp2) = omg2(ip2,jp0,kp2) + g3*coef + omg3(ip2,jp0,kp2) = omg3(ip2,jp0,kp2) + g4*coef + + coef=a2*b0*c3 + omg1(ip2,jp0,kp3) = omg1(ip2,jp0,kp3) + g2*coef + omg2(ip2,jp0,kp3) = omg2(ip2,jp0,kp3) + g3*coef + omg3(ip2,jp0,kp3) = omg3(ip2,jp0,kp3) + g4*coef + + coef=a2*b1*c0 + omg1(ip2,jp1,kp0) = omg1(ip2,jp1,kp0) + g2*coef + omg2(ip2,jp1,kp0) = omg2(ip2,jp1,kp0) + g3*coef + omg3(ip2,jp1,kp0) = omg3(ip2,jp1,kp0) + g4*coef + + coef=a2*b1*c1 + omg1(ip2,jp1,kp1) = omg1(ip2,jp1,kp1) + g2*coef + omg2(ip2,jp1,kp1) = omg2(ip2,jp1,kp1) + g3*coef + omg3(ip2,jp1,kp1) = omg3(ip2,jp1,kp1) + g4*coef + + coef=a2*b1*c2 + omg1(ip2,jp1,kp2) = omg1(ip2,jp1,kp2) + g2*coef + omg2(ip2,jp1,kp2) = omg2(ip2,jp1,kp2) + g3*coef + omg3(ip2,jp1,kp2) = omg3(ip2,jp1,kp2) + g4*coef + + coef=a2*b1*c3 + omg1(ip2,jp1,kp3) = omg1(ip2,jp1,kp3) + g2*coef + omg2(ip2,jp1,kp3) = omg2(ip2,jp1,kp3) + g3*coef + omg3(ip2,jp1,kp3) = omg3(ip2,jp1,kp3) + g4*coef + + coef=a2*b2*c0 + omg1(ip2,jp2,kp0) = omg1(ip2,jp2,kp0) + g2*coef + omg2(ip2,jp2,kp0) = omg2(ip2,jp2,kp0) + g3*coef + omg3(ip2,jp2,kp0) = omg3(ip2,jp2,kp0) + g4*coef + + coef=a2*b2*c1 + omg1(ip2,jp2,kp1) = omg1(ip2,jp2,kp1) + g2*coef + omg2(ip2,jp2,kp1) = omg2(ip2,jp2,kp1) + g3*coef + omg3(ip2,jp2,kp1) = omg3(ip2,jp2,kp1) + g4*coef + + coef=a2*b2*c2 + omg1(ip2,jp2,kp2) = omg1(ip2,jp2,kp2) + g2*coef + omg2(ip2,jp2,kp2) = omg2(ip2,jp2,kp2) + g3*coef + omg3(ip2,jp2,kp2) = omg3(ip2,jp2,kp2) + g4*coef + + coef=a2*b2*c3 + omg1(ip2,jp2,kp3) = omg1(ip2,jp2,kp3) + g2*coef + omg2(ip2,jp2,kp3) = omg2(ip2,jp2,kp3) + g3*coef + omg3(ip2,jp2,kp3) = omg3(ip2,jp2,kp3) + g4*coef + + coef=a2*b3*c0 + omg1(ip2,jp3,kp0) = omg1(ip2,jp3,kp0) + g2*coef + omg2(ip2,jp3,kp0) = omg2(ip2,jp3,kp0) + g3*coef + omg3(ip2,jp3,kp0) = omg3(ip2,jp3,kp0) + g4*coef + + coef=a2*b3*c1 + omg1(ip2,jp3,kp1) = omg1(ip2,jp3,kp1) + g2*coef + omg2(ip2,jp3,kp1) = omg2(ip2,jp3,kp1) + g3*coef + omg3(ip2,jp3,kp1) = omg3(ip2,jp3,kp1) + g4*coef + + coef=a2*b3*c2 + omg1(ip2,jp3,kp2) = omg1(ip2,jp3,kp2) + g2*coef + omg2(ip2,jp3,kp2) = omg2(ip2,jp3,kp2) + g3*coef + omg3(ip2,jp3,kp2) = omg3(ip2,jp3,kp2) + g4*coef + + coef=a2*b3*c3 + omg1(ip2,jp3,kp3) = omg1(ip2,jp3,kp3) + g2*coef + omg2(ip2,jp3,kp3) = omg2(ip2,jp3,kp3) + g3*coef + omg3(ip2,jp3,kp3) = omg3(ip2,jp3,kp3) + g4*coef + + coef=a3*b0*c0 + omg1(ip3,jp0,kp0) = omg1(ip3,jp0,kp0) + g2*coef + omg2(ip3,jp0,kp0) = omg2(ip3,jp0,kp0) + g3*coef + omg3(ip3,jp0,kp0) = omg3(ip3,jp0,kp0) + g4*coef + + coef=a3*b0*c1 + omg1(ip3,jp0,kp1) = omg1(ip3,jp0,kp1) + g2*coef + omg2(ip3,jp0,kp1) = omg2(ip3,jp0,kp1) + g3*coef + omg3(ip3,jp0,kp1) = omg3(ip3,jp0,kp1) + g4*coef + + coef=a3*b0*c2 + omg1(ip3,jp0,kp2) = omg1(ip3,jp0,kp2) + g2*coef + omg2(ip3,jp0,kp2) = omg2(ip3,jp0,kp2) + g3*coef + omg3(ip3,jp0,kp2) = omg3(ip3,jp0,kp2) + g4*coef + + coef=a3*b0*c3 + omg1(ip3,jp0,kp3) = omg1(ip3,jp0,kp3) + g2*coef + omg2(ip3,jp0,kp3) = omg2(ip3,jp0,kp3) + g3*coef + omg3(ip3,jp0,kp3) = omg3(ip3,jp0,kp3) + g4*coef + + coef=a3*b1*c0 + omg1(ip3,jp1,kp0) = omg1(ip3,jp1,kp0) + g2*coef + omg2(ip3,jp1,kp0) = omg2(ip3,jp1,kp0) + g3*coef + omg3(ip3,jp1,kp0) = omg3(ip3,jp1,kp0) + g4*coef + + coef=a3*b1*c1 + omg1(ip3,jp1,kp1) = omg1(ip3,jp1,kp1) + g2*coef + omg2(ip3,jp1,kp1) = omg2(ip3,jp1,kp1) + g3*coef + omg3(ip3,jp1,kp1) = omg3(ip3,jp1,kp1) + g4*coef + + coef=a3*b1*c2 + omg1(ip3,jp1,kp2) = omg1(ip3,jp1,kp2) + g2*coef + omg2(ip3,jp1,kp2) = omg2(ip3,jp1,kp2) + g3*coef + omg3(ip3,jp1,kp2) = omg3(ip3,jp1,kp2) + g4*coef + + coef=a3*b1*c3 + omg1(ip3,jp1,kp3) = omg1(ip3,jp1,kp3) + g2*coef + omg2(ip3,jp1,kp3) = omg2(ip3,jp1,kp3) + g3*coef + omg3(ip3,jp1,kp3) = omg3(ip3,jp1,kp3) + g4*coef + + coef=a3*b2*c0 + omg1(ip3,jp2,kp0) = omg1(ip3,jp2,kp0) + g2*coef + omg2(ip3,jp2,kp0) = omg2(ip3,jp2,kp0) + g3*coef + omg3(ip3,jp2,kp0) = omg3(ip3,jp2,kp0) + g4*coef + + coef=a3*b2*c1 + omg1(ip3,jp2,kp1) = omg1(ip3,jp2,kp1) + g2*coef + omg2(ip3,jp2,kp1) = omg2(ip3,jp2,kp1) + g3*coef + omg3(ip3,jp2,kp1) = omg3(ip3,jp2,kp1) + g4*coef + + coef=a3*b2*c2 + omg1(ip3,jp2,kp2) = omg1(ip3,jp2,kp2) + g2*coef + omg2(ip3,jp2,kp2) = omg2(ip3,jp2,kp2) + g3*coef + omg3(ip3,jp2,kp2) = omg3(ip3,jp2,kp2) + g4*coef + + coef=a3*b2*c3 + omg1(ip3,jp2,kp3) = omg1(ip3,jp2,kp3) + g2*coef + omg2(ip3,jp2,kp3) = omg2(ip3,jp2,kp3) + g3*coef + omg3(ip3,jp2,kp3) = omg3(ip3,jp2,kp3) + g4*coef + + coef=a3*b3*c0 + omg1(ip3,jp3,kp0) = omg1(ip3,jp3,kp0) + g2*coef + omg2(ip3,jp3,kp0) = omg2(ip3,jp3,kp0) + g3*coef + omg3(ip3,jp3,kp0) = omg3(ip3,jp3,kp0) + g4*coef + + coef=a3*b3*c1 + omg1(ip3,jp3,kp1) = omg1(ip3,jp3,kp1) + g2*coef + omg2(ip3,jp3,kp1) = omg2(ip3,jp3,kp1) + g3*coef + omg3(ip3,jp3,kp1) = omg3(ip3,jp3,kp1) + g4*coef + + coef=a3*b3*c2 + omg1(ip3,jp3,kp2) = omg1(ip3,jp3,kp2) + g2*coef + omg2(ip3,jp3,kp2) = omg2(ip3,jp3,kp2) + g3*coef + omg3(ip3,jp3,kp2) = omg3(ip3,jp3,kp2) + g4*coef + + coef=a3*b3*c3 + omg1(ip3,jp3,kp3) = omg1(ip3,jp3,kp3) + g2*coef + omg2(ip3,jp3,kp3) = omg2(ip3,jp3,kp3) + g3*coef + omg3(ip3,jp3,kp3) = omg3(ip3,jp3,kp3) + g4*coef + + end DO + +end SUBROUTINE remesh_om diff --git a/CodesEnVrac/CodeGH/src-THI/remesh_rho.f b/CodesEnVrac/CodeGH/src-THI/remesh_rho.f new file mode 100644 index 000000000..89fa19ae2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remesh_rho.f @@ -0,0 +1,379 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE remesh_rho(npart,phip, + 1 xp2,yp2,zp2) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp2(*),yp2(*),zp2(*) + dimension phip(*) + + + do 10 i=1,nx2 + do 10 j=1,ny2 + do 10 k=1,nz2 + ug(i,j,k)=0. +10 continue + + dy2=dx2 + dz2=dx2 + + dxinv=1./(dx2) + dyinv=dxinv + dzinv=dxinv + + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=0. + y0=0. + z0=0. + + vol=1. + + DO 20 n = 1,npart + + g1 = phip(n)/vol + + x = xp2(n) + y = yp2(n) + z = zp2(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +C Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dy2-y0)*dyinv + zz1 = (z - float(kp1)*dz2-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + +C +C on repositionne les points de grille par periodicite +! entre 0 et npx-1, puis on numerote de 1 a npx +C + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + + jp1=mod(jp1+ny2,ny2) +1 + jp0=mod(jp0+ny2,ny2) +1 + jp2=mod(jp2+ny2,ny2) +1 + jp3=mod(jp3+ny2,ny2) +1 + + kp1=mod(kp1+nz2,nz2) +1 + kp0=mod(kp0+nz2,nz2) +1 + kp2=mod(kp2+nz2,nz2) +1 + kp3=mod(kp3+nz2,nz2) +1 + +C The M'4 scheme +C + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + coef=a0*b0*c0 + ug(ip0,jp0,kp0) = ug(ip0,jp0,kp0) + g1*coef + + coef=a0*b0*c1 + ug(ip0,jp0,kp1) = ug(ip0,jp0,kp1) + g1*coef + + coef=a0*b0*c2 + ug(ip0,jp0,kp2) = ug(ip0,jp0,kp2) + g1*coef + + coef=a0*b0*c3 + ug(ip0,jp0,kp3) = ug(ip0,jp0,kp3) + g1*coef + +ccc + + coef=a0*b1*c0 + ug(ip0,jp1,kp0) = ug(ip0,jp1,kp0) + g1*coef + + coef=a0*b1*c1 + ug(ip0,jp1,kp1) = ug(ip0,jp1,kp1) + g1*coef + + coef=a0*b1*c2 + ug(ip0,jp1,kp2) = ug(ip0,jp1,kp2) + g1*coef + + coef=a0*b1*c3 + ug(ip0,jp1,kp3) = ug(ip0,jp1,kp3) + g1*coef + +ccc + + coef=a0*b2*c0 + ug(ip0,jp2,kp0) = ug(ip0,jp2,kp0) + g1*coef + + coef=a0*b2*c1 + ug(ip0,jp2,kp1) = ug(ip0,jp2,kp1) + g1*coef + + coef=a0*b2*c2 + ug(ip0,jp2,kp2) = ug(ip0,jp2,kp2) + g1*coef + + + coef=a0*b2*c3 + ug(ip0,jp2,kp3) = ug(ip0,jp2,kp3) + g1*coef + +ccc + + coef=a0*b3*c0 + ug(ip0,jp3,kp0) = ug(ip0,jp3,kp0) + g1*coef + + coef=a0*b3*c1 + ug(ip0,jp3,kp1) = ug(ip0,jp3,kp1) + g1*coef + + coef=a0*b3*c2 + ug(ip0,jp3,kp2) = ug(ip0,jp3,kp2) + g1*coef + + coef=a0*b3*c3 + ug(ip0,jp3,kp3) = ug(ip0,jp3,kp3) + g1*coef + +ccc + coef=a1*b0*c0 + ug(ip1,jp0,kp0) = ug(ip1,jp0,kp0) + g1*coef + + coef=a1*b0*c1 + ug(ip1,jp0,kp1) = ug(ip1,jp0,kp1) + g1*coef + + coef=a1*b0*c2 + ug(ip1,jp0,kp2) = ug(ip1,jp0,kp2) + g1*coef + + coef=a1*b0*c3 + ug(ip1,jp0,kp3) = ug(ip1,jp0,kp3) + g1*coef + +ccc + + coef=a1*b1*c0 + ug(ip1,jp1,kp0) = ug(ip1,jp1,kp0) + g1*coef + + coef=a1*b1*c1 + ug(ip1,jp1,kp1) = ug(ip1,jp1,kp1) + g1*coef + + coef=a1*b1*c2 + ug(ip1,jp1,kp2) = ug(ip1,jp1,kp2) + g1*coef + + coef=a1*b1*c3 + ug(ip1,jp1,kp3) = ug(ip1,jp1,kp3) + g1*coef + +ccc + + coef=a1*b2*c0 + ug(ip1,jp2,kp0) = ug(ip1,jp2,kp0) + g1*coef + + coef=a1*b2*c1 + ug(ip1,jp2,kp1) = ug(ip1,jp2,kp1) + g1*coef + + coef=a1*b2*c2 + ug(ip1,jp2,kp2) = ug(ip1,jp2,kp2) + g1*coef + + coef=a1*b2*c3 + ug(ip1,jp2,kp3) = ug(ip1,jp2,kp3) + g1*coef + +ccc + + coef=a1*b3*c0 + ug(ip1,jp3,kp0) = ug(ip1,jp3,kp0) + g1*coef + + coef=a1*b3*c1 + ug(ip1,jp3,kp1) = ug(ip1,jp3,kp1) + g1*coef + + coef=a1*b3*c2 + ug(ip1,jp3,kp2) = ug(ip1,jp3,kp2) + g1*coef + + coef=a1*b3*c3 + ug(ip1,jp3,kp3) = ug(ip1,jp3,kp3) + g1*coef + +ccc + coef=a2*b0*c0 + ug(ip2,jp0,kp0) = ug(ip2,jp0,kp0) + g1*coef + + coef=a2*b0*c1 + ug(ip2,jp0,kp1) = ug(ip2,jp0,kp1) + g1*coef + + coef=a2*b0*c2 + ug(ip2,jp0,kp2) = ug(ip2,jp0,kp2) + g1*coef + + coef=a2*b0*c3 + ug(ip2,jp0,kp3) = ug(ip2,jp0,kp3) + g1*coef + +ccc + + coef=a2*b1*c0 + ug(ip2,jp1,kp0) = ug(ip2,jp1,kp0) + g1*coef + + coef=a2*b1*c1 + ug(ip2,jp1,kp1) = ug(ip2,jp1,kp1) + g1*coef + + coef=a2*b1*c2 + ug(ip2,jp1,kp2) = ug(ip2,jp1,kp2) + g1*coef + + coef=a2*b1*c3 + ug(ip2,jp1,kp3) = ug(ip2,jp1,kp3) + g1*coef + +ccc + + coef=a2*b2*c0 + ug(ip2,jp2,kp0) = ug(ip2,jp2,kp0) + g1*coef + + coef=a2*b2*c1 + ug(ip2,jp2,kp1) = ug(ip2,jp2,kp1) + g1*coef + + coef=a2*b2*c2 + ug(ip2,jp2,kp2) = ug(ip2,jp2,kp2) + g1*coef + + coef=a2*b2*c3 + ug(ip2,jp2,kp3) = ug(ip2,jp2,kp3) + g1*coef + +ccc + + coef=a2*b3*c0 + ug(ip2,jp3,kp0) = ug(ip2,jp3,kp0) + g1*coef + + coef=a2*b3*c1 + ug(ip2,jp3,kp1) = ug(ip2,jp3,kp1) + g1*coef + + coef=a2*b3*c2 + ug(ip2,jp3,kp2) = ug(ip2,jp3,kp2) + g1*coef + + coef=a2*b3*c3 + ug(ip2,jp3,kp3) = ug(ip2,jp3,kp3) + g1*coef + +ccc + + coef=a3*b0*c0 + ug(ip3,jp0,kp0) = ug(ip3,jp0,kp0) + g1*coef + + coef=a3*b0*c1 + ug(ip3,jp0,kp1) = ug(ip3,jp0,kp1) + g1*coef + + coef=a3*b0*c2 + ug(ip3,jp0,kp2) = ug(ip3,jp0,kp2) + g1*coef + + coef=a3*b0*c3 + ug(ip3,jp0,kp3) = ug(ip3,jp0,kp3) + g1*coef + +ccc + + coef=a3*b1*c0 + ug(ip3,jp1,kp0) = ug(ip3,jp1,kp0) + g1*coef + + coef=a3*b1*c1 + ug(ip3,jp1,kp1) = ug(ip3,jp1,kp1) + g1*coef + + coef=a3*b1*c2 + ug(ip3,jp1,kp2) = ug(ip3,jp1,kp2) + g1*coef + + coef=a3*b1*c3 + ug(ip3,jp1,kp3) = ug(ip3,jp1,kp3) + g1*coef + +ccc + + coef=a3*b2*c0 + ug(ip3,jp2,kp0) = ug(ip3,jp2,kp0) + g1*coef + + coef=a3*b2*c1 + ug(ip3,jp2,kp1) = ug(ip3,jp2,kp1) + g1*coef + + coef=a3*b2*c2 + ug(ip3,jp2,kp2) = ug(ip3,jp2,kp2) + g1*coef + + coef=a3*b2*c3 + ug(ip3,jp2,kp3) = ug(ip3,jp2,kp3) + g1*coef + +ccc + + coef=a3*b3*c0 + ug(ip3,jp3,kp0) = ug(ip3,jp3,kp0) + g1*coef + + coef=a3*b3*c1 + ug(ip3,jp3,kp1) = ug(ip3,jp3,kp1) + g1*coef + + coef=a3*b3*c2 + ug(ip3,jp3,kp2) = ug(ip3,jp3,kp2) + g1*coef + + coef=a3*b3*c3 + ug(ip3,jp3,kp3) = ug(ip3,jp3,kp3) + g1*coef + +ccc + +20 CONTINUE + +! goto 1111 + + npart=0 + + do k=1,nz2 + z=z0+(k-1)*dz2 + do j=1,ny2 + y=y0+(j-1)*dy2 + do i=1,nx2 + x=x0+(i-1)*dx2 + strength=abs(ug(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + xp2(npart)=x + yp2(npart)=y + zp2(npart)=z + phip(npart)=ug(i,j,k)*vol + endif + enddo + enddo + enddo + +1111 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/remeshx.f b/CodesEnVrac/CodeGH/src-THI/remeshx.f new file mode 100644 index 000000000..7c8d24d8f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshx.f @@ -0,0 +1,75 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + ug(ip3,jj,kk) = ug(ip3,jj,kk) + g1*a3 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshx_m6.f b/CodesEnVrac/CodeGH/src-THI/remeshx_m6.f new file mode 100644 index 000000000..e8f62fc01 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshx_m6.f @@ -0,0 +1,83 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + ip5 = ip1 + 3 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=-xx1+1. + xx3=xx1+2. + xx4=-xx1+2. + xx5=-xx1+3. + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + ip5=mod(ip5+nx2,nx2) +1 +c +c M'6 +c + a0 =(xx0-1.)*(xx0-2.)*(25.*xx0**3-114.*xx0**2+153.*xx0-48.)/24. + a1 =-(xx1-1.)*(25.*xx1**4-38.*xx1**3-3.*xx1**2+12.*xx1+12)/12. + a2 =-(xx2-1.)*(25.*xx2**4-38.*xx2**3-3.*xx2**2+12.*xx2+12)/12. + a3 =-(xx3-2)*(5.*xx3-8.)*(xx3-3.)**3/24. + a4 =(xx4-1.)*(xx4-2.)*(25.*xx4**3-114.*xx4**2+153.*xx4-48.)/24. + a5 =-(xx5-2)*(5.*xx5-8.)*(xx5-3.)**3/24. + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + ug(ip3,jj,kk) = ug(ip3,jj,kk) + g1*a3 + ug(ip4,jj,kk) = ug(ip4,jj,kk) + g1*a4 + ug(ip5,jj,kk) = ug(ip5,jj,kk) + g1*a5 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshx_tag.f b/CodesEnVrac/CodeGH/src-THI/remeshx_tag.f new file mode 100644 index 000000000..ac61cf49c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshx_tag.f @@ -0,0 +1,76 @@ + subroutine remeshx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag-1,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+xx1*u1-yy1*u2 + ug(ip3,jj,kk)=ug(ip3,jj,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(ip4,jj,kk)=ug(ip4,jj,kk)+b2*u2 + + else +! case (c') and (d') +c + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+b2*u2 + + endif + enddo + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshy.f b/CodesEnVrac/CodeGH/src-THI/remeshy.f new file mode 100644 index 000000000..1242e5467 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshy.f @@ -0,0 +1,61 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + ug(jj,ip3,kk) = ug(jj,ip3,kk) + g1*a3 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshy_m6.f b/CodesEnVrac/CodeGH/src-THI/remeshy_m6.f new file mode 100644 index 000000000..c88cc3151 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshy_m6.f @@ -0,0 +1,83 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension xp1(*),up1(*),itype(*) + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + ip5 = ip1 + 3 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=-xx1+1. + xx3=xx1+2. + xx4=-xx1+2. + xx5=-xx1+3. + + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + ip5=mod(ip5+nx2,nx2) +1 +c +c M'6 +c + a0 =(xx0-1.)*(xx0-2.)*(25.*xx0**3-114.*xx0**2+153.*xx0-48.)/24. + a1 =-(xx1-1.)*(25.*xx1**4-38.*xx1**3-3.*xx1**2+12.*xx1+12)/12. + a2 =-(xx2-1.)*(25.*xx2**4-38.*xx2**3-3.*xx2**2+12.*xx2+12)/12. + a3 =-(xx3-2)*(5.*xx3-8.)*(xx3-3.)**3/24. + a4 =(xx4-1.)*(xx4-2.)*(25.*xx4**3-114.*xx4**2+153.*xx4-48.)/24. + a5 =-(xx5-2)*(5.*xx5-8.)*(xx5-3.)**3/24. + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + ug(jj,ip3,kk) = ug(jj,ip3,kk) + g1*a3 + ug(jj,ip4,kk) = ug(jj,ip4,kk) + g1*a4 + ug(jj,ip5,kk) = ug(jj,ip5,kk) + g1*a5 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshy_tag.f b/CodesEnVrac/CodeGH/src-THI/remeshy_tag.f new file mode 100644 index 000000000..48ac7b517 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshy_tag.f @@ -0,0 +1,86 @@ + subroutine remeshy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+xx1*u1-yy1*u2 + ug(jj,ip3,kk)=ug(jj,ip3,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(jj,ip4,kk)=ug(jj,ip4,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshz.f b/CodesEnVrac/CodeGH/src-THI/remeshz.f new file mode 100644 index 000000000..96b9ec719 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshz.f @@ -0,0 +1,62 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +! remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 + 2 + +! print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + xx3=2.-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + +c +c left-M'4: +c + a0 = .5*((2.-xx0)**2)*(1.-xx0) + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + a3 = .5*((2.-xx3)**2)*(1.-xx3) + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + ug(jj,kk,ip3) = ug(jj,kk,ip3) + g1*a3 + + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshz_m6.f b/CodesEnVrac/CodeGH/src-THI/remeshz_m6.f new file mode 100644 index 000000000..f3461757e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshz_m6.f @@ -0,0 +1,81 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + ip3 = ip1 - 2 + ip4 = ip1 + 2 + ip5 = ip1 + 3 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1. + xx2=-xx1+1. + xx3=xx1+2. + xx4=-xx1+2. + xx5=-xx1+3. + + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + ip5=mod(ip5+nx2,nx2) +1 +c +c M'6 +c + a0 =(xx0-1.)*(xx0-2.)*(25.*xx0**3-114.*xx0**2+153.*xx0-48.)/24. + a1 =-(xx1-1.)*(25.*xx1**4-38.*xx1**3-3.*xx1**2+12.*xx1+12)/12. + a2 =-(xx2-1.)*(25.*xx2**4-38.*xx2**3-3.*xx2**2+12.*xx2+12)/12. + a3 =-(xx3-2)*(5.*xx3-8.)*(xx3-3.)**3/24. + a4 =(xx4-1.)*(xx4-2.)*(25.*xx4**3-114.*xx4**2+153.*xx4-48.)/24. + a5 =-(xx5-2)*(5.*xx5-8.)*(xx5-3.)**3/24. + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + ug(jj,kk,ip3) = ug(jj,kk,ip3) + g1*a3 + ug(jj,kk,ip4) = ug(jj,kk,ip4) + g1*a4 + ug(jj,kk,ip5) = ug(jj,kk,ip5) + g1*a5 + + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/CodeGH/src-THI/remeshz_tag.f b/CodesEnVrac/CodeGH/src-THI/remeshz_tag.f new file mode 100644 index 000000000..af3a92781 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/remeshz_tag.f @@ -0,0 +1,86 @@ + subroutine remeshz_tag(ntag,itag,itype,icfl,kk,jj) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +! case (c) and (d) +c +! if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+xx1*u1-yy1*u2 + ug(kk,jj,ip3)=ug(kk,jj,ip3)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(kk,jj,ip4)=ug(kk,jj,ip4)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +! else +! case (d) +! endif + else +! case (c') and (d') +c +! if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+(1.-a0)*u1+(1.-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+b2*u2 +! print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +! else +! case (d') +! endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-THI/sfftw3d.f90 b/CodesEnVrac/CodeGH/src-THI/sfftw3d.f90 new file mode 100644 index 000000000..ebc912395 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/sfftw3d.f90 @@ -0,0 +1,142 @@ +subroutine fftw3d(r,c,nx,ny,nz,nxs2,nys2,nzs2,wk,irc) + + ! Ce programme calcul la transformee de fourier rapide + !---------------------------------------------------------------------- + ! TRANSFORMATION DE FOURIER REELLE<--->COMPLEXE TRI-DIMENSIONNELLE + ! X : VECTEUR REEL DE DIMENSION (nx,ny,nz) + ! C : VECTEUR COMPLEXE DE DIMENSION (0:nx/2,-ny/2+1:ny/2,-nz/2+1:nz/2) + ! WK : Vecteur de travail pour les fftw de dimension (0:nx/2,0:ny-1,0:nz-1) + ! IRC : =0: REELLE ---> COMPLEXE (X-->C) Directe + ! <>0: COMPLEXE ---> REELLE (C-->X) inverse + ! + ! REMARQUE: + ! CALCULE LA TRANSFORMATION SUIVANTE: + ! + ! X(J,K,L) J(1..nx),K(1..ny),L(1..Nz) <---> C(J,K,L) J=0..nx/2 K=-ny/2+1,...,ny/2, + ! L=-nz/2+1,...,nz/2 + ! + !---------------------------------------------------------------------- + ! + ! Declaration pour utiliser les routines fftw + ! + ! This file contains PARAMETER statements for various constants + ! that can be passed to FFTW routines. You should include + ! this file in any FORTRAN program that calls the fftw_f77 + ! routines (either directly or with an #include statement + ! if you use the C preprocessor). + ! + + include '/opt/Softs/fftw/fftw-3.2.2-intel/include/fftw3.f' + + ! INTEGER FFTW_FORWARD,FFTW_BACKWARD + ! PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) + ! + ! INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL + ! PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) + ! + ! INTEGER FFTW_ESTIMATE,FFTW_MEASURE + ! PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) + ! INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM + ! PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) + + integer plan,nx,ny,nz,nxs2,nys2,nzs2,irc,i,j,k + + complex c,wk + dimension c(0:nxs2,1-nys2:nys2,1-nzs2:nzs2),wk(nxs2+1,ny,nz) + + real r + dimension r(nx,ny,nz) + + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=cmplx(0.0,0.0) + enddo + enddo + enddo + + plan=0 + if (irc.eq.0) then + + call sfftw_plan_dft_r2c_3d(plan,nx,ny,nz,r,wk,FFTW_ESTIMATE) + call sfftw_execute(plan) + call sfftw_destroy_plan(plan) + + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=wk(i,j,k)/nx/ny/nz + enddo + enddo + enddo + + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-1)=wk(i,j,k) + enddo + enddo + enddo + + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-1)=wk(i,j+nys2+1,k) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-nzs2)=wk(i,j,k+nzs2+1) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-nzs2)=wk(i,j+nys2+1,k+nzs2+1) + enddo + enddo + enddo + else + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k)=c(i-1,j-1,k-1) + enddo + enddo + enddo + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k)=c(i-1,j-nys2,k-1) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k+nzs2+1)=c(i-1,j-1,k-nzs2) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k+nzs2+1)=c(i-1,j-nys2,k-nzs2) + enddo + enddo + enddo + + call sfftw_plan_dft_c2r_3d(plan,nx,ny,nz,wk,r,FFTW_ESTIMATE) + call sfftw_execute(plan) + call sfftw_destroy_plan(plan) + + endif + return +end subroutine fftw3d diff --git a/CodesEnVrac/CodeGH/src-THI/stretch.f b/CodesEnVrac/CodeGH/src-THI/stretch.f new file mode 100644 index 000000000..7173c5cda --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/stretch.f @@ -0,0 +1,100 @@ + subroutine stretch + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dy1=dx1 + dz1=dx1 + + dxinv=1./(12.*dx1) + dyinv=1./(12.*dy1) + dzinv=1./(12.*dz1) + + do k=1,nz1 + kt=mod(k+nz1,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + ktt=mod(k+1+nz1,nz1)+1 + kbb=mod(k-3+nz1,nz1)+1 +cc + do j=1,ny1 + jt=mod(j+ny1,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + jtt=mod(j+1+ny1,ny1)+1 + jbb=mod(j-3+ny1,ny1)+1 +cc + do i=1,nx1 + it=mod(i+nx1,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + itt=mod(i+1+nx1,nx1)+1 + ibb=mod(i-3+nx1,nx1)+1 + +c + aux1= +omg1(itt,j,k)*vxg(itt,j,k) ++8.*(omg1(ib,j,k)*vxg(ib,j,k) +-omg1(it,j,k)*vxg(it,j,k)) +-omg1(ibb,j,k)*vxg(ibb,j,k) + + + aux2= +omg2(i,jtt,k)*vxg(i,jtt,k) ++8.*(omg2(i,jb,k)*vxg(i,jb,k) +-omg2(i,jt,k)*vxg(i,jt,k)) +-omg2(i,jbb,k)*vxg(i,jbb,k) + + aux3= +omg3(i,j,ktt)*vxg(i,j,ktt) ++8.*(omg3(i,j,kb)*vxg(i,j,kb) +-omg3(i,j,kt)*vxg(i,j,kt)) +-omg3(i,j,kbb)*vxg(i,j,kbb) + +strg1(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv + + aux1= +omg1(itt,j,k)*vyg(itt,j,k) ++8.*(omg1(ib,j,k)*vyg(ib,j,k) +-omg1(it,j,k)*vyg(it,j,k)) +-omg1(ibb,j,k)*vyg(ibb,j,k) + + aux2= +omg2(i,jtt,k)*vyg(i,jtt,k) ++8.*(omg2(i,jb,k)*vyg(i,jb,k) +-omg2(i,jt,k)*vyg(i,jt,k)) +-omg2(i,jbb,k)*vyg(i,jbb,k) + + aux3= +omg3(i,j,ktt)*vyg(i,j,ktt) ++8.*(omg3(i,j,kb)*vyg(i,j,kb) +-omg3(i,j,kt)*vyg(i,j,kt)) +-omg3(i,j,kbb)*vyg(i,j,kbb) + + strg2(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv + + aux1= +omg1(itt,j,k)*vzg(itt,j,k) ++8.*(omg1(ib,j,k)*vzg(ib,j,k) +-omg1(it,j,k)*vzg(it,j,k)) +-omg1(ibb,j,k)*vzg(ibb,j,k) + + aux2= +omg2(i,jtt,k)*vzg(i,jtt,k) ++8.*(omg2(i,jb,k)*vzg(i,jb,k) +-omg2(i,jt,k)*vzg(i,jt,k)) +-omg2(i,jbb,k)*vzg(i,jbb,k) + + aux3= +omg3(i,j,ktt)*vzg(i,j,ktt) ++8.*(omg3(i,j,kb)*vzg(i,j,kb) +-omg3(i,j,kt)*vzg(i,j,kt)) +-omg3(i,j,kbb)*vzg(i,j,kbb) + + strg3(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv + + enddo + enddo + enddo + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/tag_particles.f b/CodesEnVrac/CodeGH/src-THI/tag_particles.f new file mode 100644 index 000000000..b2a5d0fff --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/tag_particles.f @@ -0,0 +1,181 @@ + subroutine tag_particles(npart,npart_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + include 'param.i' + include 'param.h' + + common/remesh/xp(npg),xp1(npg),up(npg),vx(npg) + + integer icfl(*),itype(*),itype_aux(*),itag(*) + dimension xp_aux(*),up_aux(*),vx_aux(*) + + integer ntype(npg),ncfl(npg),npart_bl(npg),i_nbl(npg) + dimension amin_lambda(npg) + + +c ntype(nbl) : type de bloc (1=centre ou 0=left) pour choix de la formule +c remaillage +c itype(npart) : idem pour les particules de ces blocks +c ncfl(nbl)=cfl-nint ou cfl-int selon le type +c icfl(npart) : idem pour particules de cs blocks +c xp_aux(npart_aux): particles inside the blocks, for plain remeshing +c itype_aux(npart_aux) : type de block pour ces particules +c ntag: number of tagged particles, for special remeshing +c itag(ntag): pointer for tagged particles +c i_nbl(nbl) indice de la derniere particule du bloc nbl + +c cfl=delt/dx + + x0=xmin + + + m=np_bl+1 + nblock=nx/(m) + dx_bl=float(m)*dx + dx_bl_inv=1./dx_bl + +c on range les partucles par block +c et on calcule lambda moyen pour chaque block + + do nbl=1,nblock + amin_lambda(nbl)=111. + npart_bl(nbl)=0 + i_nbl(nbl)=0 + enddo + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(i)*cfl) + npart_bl(nbl)=npart_bl(nbl)+1 + i_nbl(nbl)=i + enddo + +c on ajoute la particule a droite du bloc (si elle existe) pour calculer +c le amin_lambda, pour eviter pbms a l'interface entre blocs de meme type +c (a corriger: pour l'instant je ne regarde pas le dernier bloc avec xp(1) + + do nbl=1,nblock-1 + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((ii.lt.npart).and.(xp(ii+1).lt.xp(ii)+1.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif + enddo + +c le dernier bloc (a la main ..) + + nbl=nblock + if (i_nbl(nbl).ne.0) then + if ((xp(npart).ge.xmax-1.5*dx).and.(xp(1).lt.xmin+0.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(1)*cfl) + endif + endif + + +c et on en deduit type de block (1=centre vs 0=left) et l'indice du bloc + + + do nbl=1,nblock + if (amin_lambda(nbl).lt.nint(amin_lambda(nbl))) then + ntype(nbl)=1 + ncfl(nbl)=nint(amin_lambda(nbl)) + else + ntype(nbl)=0 + ncfl(nbl)=int(amin_lambda(nbl)) + if (amin_lambda(nbl).lt.0) ncfl(nbl)=int(amin_lambda(nbl))-1 + endif + +c print*,'nbl et type',nbl, ntype(nbl),amin_lambda(nbl) + enddo +c +c on affecte le type et l'indice cfl du bloc sur ses particules + + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + itype(i)=ntype(nbl) + icfl(i)=ncfl(nbl) +c print*,'nbl et type',nbl,i, itype(i),icfl(i) + enddo + + +c on tagge les particules entre les blocs successifs non vides qui: +c sont de type et indice cfl differents +c (cases b,c,b',c' du papier) + + ntag=0 + npart_aux=0 + j=2 + jc=0 + do i=2,npart-1 + j=j+jc + if (j.ge.npart) go to 111 + jj=j+1 +c print*,j,icfl(j),icfl(jj),itype(j),itype(jj) + if ((icfl(j).ne.icfl(jj)).and.(itype(j).ne.itype(jj)) + 1 .and.(xp(jj).le.xp(j)+1.5*dx)) then + ntag=ntag+1 + itag(ntag)=j + ntag=ntag+1 + itag(ntag)=j+1 +c print*,' **** TAGGED ',j,xp(j),itype(j),icfl(j),vx(j)*delt/dx, +c 1 nint(vx(j)*delt/dx) +c print*,' **** TAGGED ',jj,xp(jj),itype(jj),icfl(jj),vx(jj)*delt/dx, +c 1 nint(vx(jj)*delt/dx) + jc=2 + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(j) + up_aux(npart_aux)=up(j) + vx_aux(npart_aux)=vx(j) + itype_aux(npart_aux)=itype(j) +c print*,'REGULAR',npart_aux,xp_aux(npart_aux),up_aux(npart_aux) +c 1 ,vx_aux(j)*delt/dx,icfl(j) + jc=1 + endif + enddo + +111 continue + +c on regarde a part la premiere et la derniere particule +c (je ne sais pas faire autrement pour l'instant) + + if (npart.ge.1) then + + if ((icfl(1).ne.icfl(npart)).and.(itype(1).ne.itype(npart)) + 1 .and.(xp(npart).ge.xp(1)+(float(nx)-1.5)*dx) + 1 .and.(itag(ntag).ne.npart)) then +c 1 ) then + ntag=ntag+1 + itag(ntag)=npart + ntag=ntag+1 + itag(ntag)=1 +c print*,' TAGGED ',j,xp(j),icfl(j) + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(1) + up_aux(npart_aux)=up(1) + vx_aux(npart_aux)=vx(1) + itype_aux(npart_aux)=itype(1) +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + if (npart.gt.1) then + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(npart) + up_aux(npart_aux)=up(npart) + vx_aux(npart_aux)=vx(npart) + itype_aux(npart_aux)=itype(npart) + endif +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + endif + + endif + + + +c if (ntag.ne.0) print*,'npart,NTAG, NPART_AUX = ',npart,ntag,npart_aux + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/velox.f b/CodesEnVrac/CodeGH/src-THI/velox.f new file mode 100644 index 000000000..d3e208211 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/velox.f @@ -0,0 +1,124 @@ + subroutine velox(vmax,delt) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension aux3(npgx,npgy,npgz), + 1 aux1(npgx,npgy,npgz),aux2(npgx,npgy,npgz) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + + pi=3.1415926 + + dxinv=1./(2.*dx1) + +c calucl de fonction courants 3d + + nxb=nx1/2 + nyb=ny1/2 + nzb=nz1/2 + + call fftw3d(omg1,cfx,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg2,cfy,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + call fftw3d(omg3,cfz,nx1,ny1,nz1,nxb,nyb,nzb,wk,0) + +c coeff de normalisation pour laplacien en spectral + + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nzb,nzb + rk=float(k)*ak + do 10 j=1-nyb,nyb + rj=float(j)*aj + do 10 i=0,nxb + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) + if (r2.ne.0.) then +c + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + endif +10 continue + + + call fftw3d(aux1,cux,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + call fftw3d(aux2,cuy,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + call fftw3d(aux3,cuz,nx1,ny1,nz1,nxb,nyb,nzb,wk,1) + +c calcul de du/dt + (u.grad)u stocke dans strg +c pour terme barotrope (dans stretch_freeb) +c (si pas boussinesq) +c (cf /home/ghcottet/FS/2D/FFT velox_fft et bar) +c et update des vitesses + + vxmax=0. + vymax=0. + vzmax=0. + do k=1,nz1 + do j=1,ny1 + do i=1,nx1 + strg1(i,j,k)=(-aux1(i,j,k)-vxg(i,j,k))/delt + strg2(i,j,k)=(-aux2(i,j,k)-vyg(i,j,k))/delt + strg3(i,j,k)=(-aux3(i,j,k)-vzg(i,j,k))/delt + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + vxmax=amax1(vxmax,abs(vxg(i,j,k))) + vymax=amax1(vymax,abs(vyg(i,j,k))) + vzmax=amax1(vzmax,abs(vzg(i,j,k))) + enddo + enddo + enddo + print*,' VXMAX sur grille ',vxmax,vymax,vzmax + vmax=amax1(vxmax,vymax) + vmax=amax1(vmax,vzmax) + + do k=1,nz1 + kt=mod(k+nz1,nz1)+1 + kb=mod(k-2+nz1,nz1)+1 + do j=1,ny1 + jt=mod(j+ny1,ny1)+1 + jb=mod(j-2+ny1,ny1)+1 + do i=1,nx1 + it=mod(i+nx1,nx1)+1 + ib=mod(i-2+nx1,nx1)+1 + strg1(i,j,k)=strg1(i,j,k)+vxg(i,j,k)*(vxg(it,j,k)-vxg(ib,j,k))*dxinv + strg1(i,j,k)=strg1(i,j,k)+vyg(i,j,k)*(vxg(i,jt,k)-vxg(i,jb,k))*dxinv + strg1(i,j,k)=strg1(i,j,k)+vzg(i,j,k)*(vxg(i,j,kt)-vxg(i,j,kb))*dxinv + strg2(i,j,k)=strg2(i,j,k)+vxg(i,j,k)*(vyg(it,j,k)-vyg(ib,j,k))*dxinv + strg2(i,j,k)=strg2(i,j,k)+vyg(i,j,k)*(vyg(i,jt,k)-vyg(i,jb,k))*dxinv + strg2(i,j,k)=strg2(i,j,k)+vzg(i,j,k)*(vyg(i,j,kt)-vyg(i,j,kb))*dxinv + strg3(i,j,k)=strg3(i,j,k)+vxg(i,j,k)*(vzg(it,j,k)-vzg(ib,j,k))*dxinv + strg3(i,j,k)=strg3(i,j,k)+vyg(i,j,k)*(vzg(i,jt,k)-vzg(i,jb,k))*dxinv + strg3(i,j,k)=strg3(i,j,k)+vzg(i,j,k)*(vzg(i,j,kt)-vzg(i,j,kb))*dxinv + enddo + enddo + enddo + + + return + end + diff --git a/CodesEnVrac/CodeGH/src-THI/velox_x.f b/CodesEnVrac/CodeGH/src-THI/velox_x.f new file mode 100644 index 000000000..b87a522b0 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/velox_x.f @@ -0,0 +1,106 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_x(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g1(npg) + + do 10 i=1,npart + g1(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/velox_y.f b/CodesEnVrac/CodeGH/src-THI/velox_y.f new file mode 100644 index 000000000..64e8c6bd6 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/velox_y.f @@ -0,0 +1,104 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_y(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g2(npg) + + do 10 i=1,npart + g2(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g2(i)= g2(i) + gg2(jp1,ip1,kp1)*a1*b1*c1 + g2(i)= g2(i) + gg2(jp1,ip2,kp1)*a2*b1*c1 + g2(i)= g2(i) + gg2(jp2,ip1,kp1)*a1*b2*c1 + g2(i)= g2(i) + gg2(jp2,ip2,kp1)*a2*b2*c1 + g2(i)= g2(i) + gg2(jp1,ip1,kp2)*a1*b1*c2 + g2(i)= g2(i) + gg2(jp1,ip2,kp2)*a2*b1*c2 + g2(i)= g2(i) + gg2(jp2,ip1,kp2)*a1*b2*c2 + g2(i)= g2(i) + gg2(jp2,ip2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/velox_z.f b/CodesEnVrac/CodeGH/src-THI/velox_z.f new file mode 100644 index 000000000..40151259f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/velox_z.f @@ -0,0 +1,105 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_z(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g3(npg) + + + do 10 i=1,npart + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g3(i)= g3(i) + gg3(jp1,kp1,ip1)*a1*b1*c1 + g3(i)= g3(i) + gg3(jp1,kp1,ip2)*a2*b1*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip1)*a1*b2*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip2)*a2*b2*c1 + g3(i)= g3(i) + gg3(jp1,kp2,ip1)*a1*b1*c2 + g3(i)= g3(i) + gg3(jp1,kp2,ip2)*a2*b1*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip1)*a1*b2*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip2)*a2*b2*c2 + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-THI/veloxaux.f b/CodesEnVrac/CodeGH/src-THI/veloxaux.f new file mode 100644 index 000000000..0f64cd117 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/veloxaux.f @@ -0,0 +1,159 @@ + subroutine veloxaux(vmax,dvmax) + +c version de veloxaux ou on prend les 32 premiers +c modes de la vitesse, on padde avec des 0 jusqu'a nx2 (128 ou 256) +c et on fait fft inverse sur une grille nx2 + + include 'param.i' + include 'param.h' + include 'arrays.h' + + parameter(npg2=npg) + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + dimension aux1(npg2,npg2,npg2),aux2(npg2,npg2,npg2) + dimension aux3(npg2,npg2,npg2) + + parameter(npgb2=npg2/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + complex cvx,cvy,cvz,wk2 + dimension cvx(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvy(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 cvz(0:npgb2,1-npgb2:npgb2,1-npgb2:npgb2), + 1 wk2(npgb2+1,npg2,npg2) + + dx3=(xmax-xmin)/float(nx3) + + goto 113 +c si on veut pas filter .. + + do k=1,nx1 + do j=1,nx1 + do i=1,nx1 + aux1(i,j,k)=-vxg(i,j,k) + aux2(i,j,k)=-vyg(i,j,k) + aux3(i,j,k)=-vzg(i,j,k) + enddo + enddo + enddo + + go to 112 + +113 continue + + pi=3.1415926 + + nxb2=nx3/2 + nyb2=nx3/2 + nzb2=nx3/2 + nxb2=32 + nyb2=32 + nzb2=32 + nxb=nx1/2 + nyb=nx1/2 + nzb=nx1/2 + + do 20 k=1-nzb,nzb + do 20 j=1-nyb,nyb + do 20 i=0,nxb + cvx(i,j,k)=0. + cvy(i,j,k)=0. + cvz(i,j,k)=0. +20 continue + + do 10 k=1-nzb2,nzb2 + do 10 j=1-nyb2,nyb2 + do 10 i=0,nxb2 + cvx(i,j,k)=cux(i,j,k) + cvy(i,j,k)=cuy(i,j,k) + cvz(i,j,k)=cuz(i,j,k) +10 continue + +c call fftw3d(aux3,cvz,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) +c call fftw3d(aux2,cvy,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) +c call fftw3d(aux1,cvx,nx3,nx3,nx3,nxb2,nyb2,nzb2,wk2,1) + call fftw3d(aux3,cvz,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + call fftw3d(aux2,cvy,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + call fftw3d(aux1,cvx,nx1,nx1,nx1,nxb,nyb,nzb,wk2,1) + +c ecriture fhciers grille NX2 + +112 continue + + umax1=0. + umax2=0. + umax3=0. + dvmax=0. + dvxmax=0. + dvymax=0. + dvzmax=0. + do k=1,nx3 + do j=1,nx3 + do i=1,nx3 + psi1(i,j,k)=-aux1(i,j,k) + umax1=amax1(umax1,abs(psi1(i,j,k))) + psi2(i,j,k)=-aux2(i,j,k) + umax2=amax1(umax2,abs(psi2(i,j,k))) + psi3(i,j,k)=-aux3(i,j,k) + umax3=amax1(umax3,abs(psi3(i,j,k))) + enddo + enddo + enddo + + do k=1,nx3 + kt=mod(k,nx3)+1 + do j=1,nx3 + jt=mod(j,nx3)+1 + do i=1,nx3 + it=mod(i,nx3)+1 + dvxmax=amax1(dvxmax,abs(psi1(it,j,k)-psi1(i,j,k))) + dvymax=amax1(dvymax,abs(psi2(i,jt,k)-psi2(i,j,k))) + dvzmax=amax1(dvzmax,abs(psi3(i,j,kt)-psi3(i,j,k))) + enddo + enddo + enddo + + dvmax=amax1(dvxmax,dvymax) + dvmax=amax1(dvmax,dvzmax)/dx3 + + print*,'umax', umax1,umax2,umax3 + print*,'DVMAXs ',dvxmax/dx3,dvymax/dx3,dvzmax/dx3 + + vmax=amax1(umax1,umax2,umax3) + + goto 111 + + open(20,file='datavelx',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(20) ((((psi1(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(21,file='datavely',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(21) ((((psi2(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + open(22,file='datavelz',form='unformatted', + 1 convert='big_endian', + 1 status='unknown') + write(22) ((((psi3(i,j,k)), + 1 i=1,nx3),j=1,nx3),k=1,nx3) + close(20) + close(21) + close(22) + +111 continue + + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/x_advect.f b/CodesEnVrac/CodeGH/src-THI/x_advect.f new file mode 100644 index 000000000..0f79ca21c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/x_advect.f @@ -0,0 +1,87 @@ + subroutine x_advect(dt,np_bl,npart,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! routine d'advection en x : +! parcours des lignes horozontales +! intilisation de particules +! calcul des vitesses par RK2 +! tag des particules en focntion des varaitions de cfl +! push and remesh + +! cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +! 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +! initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + +222 continue + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np_aux,xp_aux,up_aux,itype_aux,jr,kr) + if (ntag.ne.0) call remeshx_tag(ntag,itag,itype,icfl,jr,kr) + +! fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/y_advect.f b/CodesEnVrac/CodeGH/src-THI/y_advect.f new file mode 100644 index 000000000..bc8a8519c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/y_advect.f @@ -0,0 +1,80 @@ + subroutine y_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + + +c cfl=dt/dx utilisse pour calculs de blocs et correction + cfl=dt/dx + + ntag_total=0 + +c on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +c initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(j-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np_aux,xp_aux,up_aux,itype_aux,ir,kr) + if (ntag.ne.0) call remeshy_tag(ntag,itag,itype,icfl,ir,kr) + +c fin de ligne i : + ntag_total=ntag_total+ntag + endif + enddo + enddo + print*, ' NTAG apres y advect ', ntag_total + + + return + end diff --git a/CodesEnVrac/CodeGH/src-THI/z_advect.f b/CodesEnVrac/CodeGH/src-THI/z_advect.f new file mode 100644 index 000000000..38620f9a2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-THI/z_advect.f @@ -0,0 +1,79 @@ + subroutine z_advect(dt,np_bl,ntag_total) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +! cf=dt/dx utilise pour calucls de blocs et correction + cfl=dt/dx + + ntag_total=0 + +! on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +! initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(k-1)*dx + endif + enddo +! tag, push and remesh sur la ligne + if (np.ne.0) then + +! evaluation des vitesse pour RK2 + + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + if (xp(ii).lt.xmin) xp(ii)=xp(ii)+xmax-xmin + enddo + endif + + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np_aux,xp_aux,up_aux,itype_aux,ir,jr) + if (ntag.ne.0) call remeshz_tag(ntag,itag,itype,icfl,ir,jr) + +! fin de ligne k : + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, ' NTAG apres z_advect ', ntag_total + + return + end + diff --git a/CodesEnVrac/CodeGH/src-common/fftw3d.f90 b/CodesEnVrac/CodeGH/src-common/fftw3d.f90 new file mode 100644 index 000000000..797162e97 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-common/fftw3d.f90 @@ -0,0 +1,147 @@ +subroutine fftw3d(r,c,nx,ny,nz,nxs2,nys2,nzs2,wk,irc) + + ! Ce programme calcul la transformee de fourier rapide + !---------------------------------------------------------------------- + ! TRANSFORMATION DE FOURIER REELLE<--->COMPLEXE TRI-DIMENSIONNELLE + ! X : VECTEUR REEL DE DIMENSION (nx,ny,nz) + ! C : VECTEUR COMPLEXE DE DIMENSION (0:nx/2,-ny/2+1:ny/2,-nz/2+1:nz/2) + ! WK : Vecteur de travail pour les fftw de dimension (0:nx/2,0:ny-1,0:nz-1) + ! IRC : =0: REELLE ---> COMPLEXE (X-->C) Directe + ! <>0: COMPLEXE ---> REELLE (C-->X) inverse + ! + ! REMARQUE: + ! CALCULE LA TRANSFORMATION SUIVANTE: + ! + ! X(J,K,L) J(1..nx),K(1..ny),L(1..Nz) <---> C(J,K,L) J=0..nx/2 K=-ny/2+1,...,ny/2, + ! L=-nz/2+1,...,nz/2 + ! + !---------------------------------------------------------------------- + ! + ! Declaration pour utiliser les routines fftw + ! + ! This file contains PARAMETER statements for various constants + ! that can be passed to FFTW routines. You should include + ! this file in any FORTRAN program that calls the fftw_f77 + ! routines (either directly or with an #include statement + ! if you use the C preprocessor). + + + include 'fftw3.f' + + ! INTEGER FFTW_FORWARD,FFTW_BACKWARD + ! PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) + ! + ! INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL + ! PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) + ! + ! INTEGER FFTW_ESTIMATE,FFTW_MEASURE + ! PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) + ! + ! INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM + ! PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) + ! + integer plan,nx,ny,nz,nxs2,nys2,nzs2,irc,i,j,k + ! + complex c,wk + dimension c(0:nxs2,1-nys2:nys2,1-nzs2:nzs2),wk(nxs2+1,ny,nz) + ! + real r + dimension r(nx,ny,nz) + ! + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=cmplx(0.0,0.0) + enddo + enddo + enddo + ! + plan=0 + if (irc.eq.0) then + + call sfftw_plan_dft_r2c_3d(plan,nx,ny,nz,r,wk,FFTW_ESTIMATE) + call sfftw_execute(plan) + call sfftw_destroy_plan(plan) + + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=wk(i,j,k)/nx/ny/nz + enddo + enddo + enddo + + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-1)=wk(i,j,k) + enddo + enddo + enddo + + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-1)=wk(i,j+nys2+1,k) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-nzs2)=wk(i,j,k+nzs2+1) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-nzs2)=wk(i,j+nys2+1,k+nzs2+1) + enddo + enddo + enddo + + else + + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k)=c(i-1,j-1,k-1) + enddo + enddo + enddo + + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k)=c(i-1,j-nys2,k-1) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k+nzs2+1)=c(i-1,j-1,k-nzs2) + enddo + enddo + enddo + + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k+nzs2+1)=c(i-1,j-nys2,k-nzs2) + enddo + enddo + enddo + + call sfftw_plan_dft_c2r_3d(plan,nx,ny,nz,wk,r,FFTW_ESTIMATE) + call sfftw_execute(plan) + call sfftw_destroy_plan(plan) + + endif + + return +end subroutine fftw3d diff --git a/CodesEnVrac/CodeGH/src-common/param.i b/CodesEnVrac/CodeGH/src-common/param.i new file mode 100644 index 000000000..fe75c83f0 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-common/param.i @@ -0,0 +1,2 @@ + parameter(npm=2100000,npgx=128,npgy=128,npgz=128) + parameter(npg=npgx) diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/array.h b/CodesEnVrac/CodeGH/src-sphere/NotUsed/array.h new file mode 100644 index 000000000..3d4ab26a7 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/array.h @@ -0,0 +1,6 @@ + COMMON/GRID/ omg1(-1:npg,-1:npg,-1:npg), + & omg2(-1:npg,-1:npg,-1:npg),omg3(-1:npg,-1:npg,-1:npg), + & vxg(npg,npg,npg),vyg(npg,npg,npg),vzg(npg,npg,npg), + & psi1(npg,npg,npg),psi2(npg,npg,npg),psi3(npg,npg,npg), + & strg1(npg,npg,npg),strg2(npg,npg,npg),strg3(npg,npg,npg) + diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/bar.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/bar.f new file mode 100644 index 000000000..479b896e4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/bar.f @@ -0,0 +1,55 @@ + subroutine bar(saut) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + +c calcul du terme barotrope +c -1/rho(curl rho).(grad p)/rho + + + pi=3.1415926 + topi=2./pi + spi=sqrt(pi) + + eps=dx*width + eps2=eps**2 + + dxinv=1./(2.*dx) + dyinv=1./(2.*dy) + +c terme barotrope + + astr=0. + do i=1,nx + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + do k=1,nz + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + arg=phig(i,j,k) + rho=1.+arg + argx=phig(it,j,k)-phig(ib,j,k) + argy=phig(i,jt,k)-phig(i,jb,k) + argz=phig(i,j,kt)-phig(i,j,kb) + sautz=-1.-dvz(i,j,k)/rho + sautx=-dvx(i,j,k)/rho + sauty=-dvy(i,j,k)/rho + strg1(i,j,k)=strg1(i,j,k)+(argy*sautz-argz*sauty)/(2.*dx) + strg2(i,j,k)=strg2(i,j,k)+(argz*sautx-argx*sautz)/(2.*dx) + strg3(i,j,k)=strg3(i,j,k)+(argx*sauty-argy*sautx)/(2.*dx) + astr=amax1(astr,abs(strg1(i,j,k))) + enddo + enddo + enddo + +111 continue + + + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/common4grid.h b/CodesEnVrac/CodeGH/src-sphere/NotUsed/common4grid.h new file mode 100644 index 000000000..f6226d7fd --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/common4grid.h @@ -0,0 +1,6 @@ + COMMON/GRID/ omg1(-1:npgx,-1:npgy,-1:npgz), + & omg2(-1:npgx,-1:npgy,-1:npgz),omg3(-1:npgx,-1:npgy,-1:npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz),strg3(npgx,npgy,npgz) + diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/diag.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/diag.f new file mode 100644 index 000000000..6fe9a2798 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/diag.f @@ -0,0 +1,56 @@ + subroutine diag(ener,enstro,div,omax) + +c calcul sur une grille mxmxm de (a,b)**3 du +c div w, enstro et energy + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + + eps3=dx*dy*dz + vol=eps3 + + dxinv2=0.5/dx + dyinv2=0.5/dy + dzinv2=0.5/dz + + omax=0. + div=0. + domax=0. + ener=0. + enstro=0. + do 10 i=1,nx + it=mod(i,nx)+1 + ib=mod(i-2+nx,nx)+1 + do 10 j=1,ny + jt=mod(j,ny)+1 + jb=mod(j-2+ny,ny)+1 + do 20 k=1,nz + kt=mod(k,nz)+1 + kb=mod(k-2+nz,nz)+1 + aux1=omg1(it,j,k)-omg1(ib,j,k) + aux2=omg2(i,jt,k)-omg2(i,jb,k) + aux3=(omg3(i,j,kt)-omg3(i,j,kb)) + psi1(i,j,k)=(aux1*dxinv2+aux2*dyinv2+aux3*dzinv2) + div=div+((aux1*dxinv2+aux2*dyinv2+aux3*dzinv2)**2)*eps3 + domax=domax+((abs(aux1*dxinv2)+abs(aux2*dyinv2)+ + 1 abs(aux3*dzinv2))**2)*eps3 + enerx=vxg(i,j,k)*vxg(i,j,k) + enery=vyg(i,j,k)*vyg(i,j,k) + enerz=vzg(i,j,k)*vzg(i,j,k) + strengthx=omg1(i,j,k)*omg1(i,j,k) + strengthy=omg2(i,j,k)*omg2(i,j,k) + strengthz=omg3(i,j,k)*omg3(i,j,k) + omax=amax1(omax,sqrt(strengthx+strengthy+strengthz)) + enstro=enstro+(strengthx+strengthy+strengthz)*vol + ener=ener+(enerx+enery+enerz)*vol +20 continue +10 continue + + if (domax.ne.0) div=div/domax + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif.f new file mode 100644 index 000000000..fd94b05c3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif.f @@ -0,0 +1,154 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE dif_om(npart,om1,om2,om3, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax1) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + dxinv=1./(dx1) + dy1=dx1 + dz1=dx1 + dyinv=dxinv + dzinv=dxinv + + npart=0 + vol=dx1**3 + + do k=1,nz1 + z=zmin+(k-1)*dz1 + do j=1,ny1 + y=ymin+(j-1)*dy1 + do i=1,nx1 + x=xmin+(i-1)*dx1 + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx1**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + enddo + enddo + enddo + +c goto 1001 + + dzdx=(dz1/dx1)**2 + dzdy=(dz1/dy1)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +c boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +c boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx1-1,nx1)+1 + j2=mod(jj+ly+ny1-1,ny1)+1 + k2=mod(kk+lz+nz1-1,nz1)+1 + gammasrc1=omg1(i2,j2,k2)*vol + gammasrc2=omg2(i2,j2,k2)*vol + gammasrc3=omg3(i2,j2,k2)*vol + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + dvx=(vxsrc-vxrcv)/dx1 + dvy=(vysrc-vyrcv)/dy1 + dvz=(vzsrc-vzrcv)/dz1 + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + ales=amax1(0.,-dvx*lx-dvy*ly-dvz*lz) +c ales=abs(dvx*lx+dvy*ly+dvz*lz) + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + akernel2=2.5/((1.+r)*2.8333) + factor=akernel/(dz1*dz1) + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)* + 1 (anu*factor+coef_les*ales*akernel2) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)* + 1 (anu*factor+coef_les*ales*akernel2) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)* + 1 (anu*factor+coef_les*ales*akernel2) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy1*dx1*dz1/dv1(i)) + +c enddo pour caluc de dom sur les particules + enddo + +1001 continue + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv1(i)) + omax0=amax1(omax0,abs(om2(i))/dv1(i)) + omax0=amax1(omax0,abs(om3(i))/dv1(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv1(i)) + omax1=amax1(omax1,abs(om2(i))/dv1(i)) + omax1=amax1(omax1,abs(om3(i))/dv1(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif_om_part.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif_om_part.f new file mode 100644 index 000000000..fd94b05c3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/dif_om_part.f @@ -0,0 +1,154 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE dif_om(npart,om1,om2,om3, + 1 xp1,yp1,zp1,dv1,anu,delt,coef_les,omax1) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + dxinv=1./(dx1) + dy1=dx1 + dz1=dx1 + dyinv=dxinv + dzinv=dxinv + + npart=0 + vol=dx1**3 + + do k=1,nz1 + z=zmin+(k-1)*dz1 + do j=1,ny1 + y=ymin+(j-1)*dy1 + do i=1,nx1 + x=xmin+(i-1)*dx1 + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx1**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + enddo + enddo + enddo + +c goto 1001 + + dzdx=(dz1/dx1)**2 + dzdy=(dz1/dy1)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +c boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +c boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx1-1,nx1)+1 + j2=mod(jj+ly+ny1-1,ny1)+1 + k2=mod(kk+lz+nz1-1,nz1)+1 + gammasrc1=omg1(i2,j2,k2)*vol + gammasrc2=omg2(i2,j2,k2)*vol + gammasrc3=omg3(i2,j2,k2)*vol + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + dvx=(vxsrc-vxrcv)/dx1 + dvy=(vysrc-vyrcv)/dy1 + dvz=(vzsrc-vzrcv)/dz1 + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + ales=amax1(0.,-dvx*lx-dvy*ly-dvz*lz) +c ales=abs(dvx*lx+dvy*ly+dvz*lz) + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + akernel2=2.5/((1.+r)*2.8333) + factor=akernel/(dz1*dz1) + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)* + 1 (anu*factor+coef_les*ales*akernel2) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)* + 1 (anu*factor+coef_les*ales*akernel2) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)* + 1 (anu*factor+coef_les*ales*akernel2) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy1*dx1*dz1/dv1(i)) + +c enddo pour caluc de dom sur les particules + enddo + +1001 continue + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv1(i)) + omax0=amax1(omax0,abs(om2(i))/dv1(i)) + omax0=amax1(omax0,abs(om3(i))/dv1(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv1(i)) + omax1=amax1(omax1,abs(om2(i))/dv1(i)) + omax1=amax1(omax1,abs(om3(i))/dv1(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw3d_new.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw3d_new.f new file mode 100644 index 000000000..cd940baf5 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw3d_new.f @@ -0,0 +1,155 @@ + subroutine fftw3d(r,c,nx,ny,nz,nxs2,nys2,nzs2,wk,irc) +c +c Ce programme calcul la transformee de fourier rapide +c +C---------------------------------------------------------------------- +C TRANSFORMATION DE FOURIER REELLE<--->COMPLEXE TRI-DIMENSIONNELLE +C X : VECTEUR REEL DE DIMENSION (nx,ny,nz) +C C : VECTEUR COMPLEXE DE DIMENSION (0:nx/2,-ny/2+1:ny/2,-nz/2+1:nz/2) +C WK : Vecteur de travail pour les fftw de dimension (0:nx/2,0:ny-1,0:nz-1) +C IRC : =0: REELLE ---> COMPLEXE (X-->C) Directe +C <>0: COMPLEXE ---> REELLE (C-->X) inverse +C +C REMARQUE: +C CALCULE LA TRANSFORMATION SUIVANTE: +C +C X(J,K,L) J(1..nx),K(1..ny),L(1..Nz) <---> C(J,K,L) J=0..nx/2 K=-ny/2+1,...,ny/2, +C L=-nz/2+1,...,nz/2 +C +C---------------------------------------------------------------------- +c +c Declaration pour utiliser les routines fftw +c +c This file contains PARAMETER statements for various constants +c that can be passed to FFTW routines. You should include +c this file in any FORTRAN program that calls the fftw_f77 +c routines (either directly or with an #include statement +c if you use the C preprocessor). +c + INTEGER FFTW_FORWARD,FFTW_BACKWARD + PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) +c + INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL + PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) +c + INTEGER FFTW_ESTIMATE,FFTW_MEASURE + PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) +c + INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM + PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) +c + integer plan,nx,ny,nz,nxs2,nys2,nzs2,irc,i,j,k +c + complex c,wk + dimension c(0:nxs2,1-nys2:nys2,1-nzs2:nzs2),wk(nxs2+1,ny,nz) +c + real r + dimension r(nx,ny,nz) +c +c print*,nx,ny,nz,nxs2,nys2,nzs2,r(2,5,1) + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=cmplx(0.0,0.0) + enddo + enddo + enddo +c + if (irc.eq.0) then +c + call rfftw3d_f77_create_plan(plan,nx,ny,nz,FFTW_FORWARD, + 1 FFTW_ESTIMATE) +c 1 FFTW_MEASURE) +c + call rfftwnd_f77_one_real_to_complex(plan,r,wk) +c +c print*,'coucou',wk(2,5,1) + call rfftwnd_f77_destroy_plan(plan) +c + do k=1,nz + do j=1,ny + do i=1,nxs2+1 + wk(i,j,k)=wk(i,j,k)/nx/ny/nz + enddo + enddo + enddo +c print*,wk(2,5,1) +c + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-1)=wk(i,j,k) + enddo + enddo + enddo +c + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-1)=wk(i,j+nys2+1,k) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + c(i-1,j-1,k-nzs2)=wk(i,j,k+nzs2+1) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + c(i-1,j-nys2,k-nzs2)=wk(i,j+nys2+1,k+nzs2+1) + enddo + enddo + enddo +c + else +c + do k=1,nzs2+1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k)=c(i-1,j-1,k-1) + enddo + enddo + enddo +c + do k=1,nzs2+1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k)=c(i-1,j-nys2,k-1) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2+1 + do i=1,nxs2+1 + wk(i,j,k+nzs2+1)=c(i-1,j-1,k-nzs2) + enddo + enddo + enddo +c + do k=1,nzs2-1 + do j=1,nys2-1 + do i=1,nxs2+1 + wk(i,j+nys2+1,k+nzs2+1)=c(i-1,j-nys2,k-nzs2) + enddo + enddo + enddo +c + call rfftw3d_f77_create_plan(plan,nx,ny,nz,FFTW_BACKWARD, + 1 FFTW_ESTIMATE) +c 1 FFTW_MEASURE) +c + call rfftwnd_f77_one_complex_to_real(plan,wk,r) +c + call rfftwnd_f77_destroy_plan(plan) +c + endif +c + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw_f77.i b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw_f77.i new file mode 100644 index 000000000..26c352402 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fftw_f77.i @@ -0,0 +1,17 @@ +c This file contains PARAMETER statements for various constants +c that can be passed to FFTW routines. You should include +c this file in any FORTRAN program that calls the fftw_f77 +c routines (either directly or with an #include statement +c if you use the C preprocessor). + + INTEGER FFTW_FORWARD,FFTW_BACKWARD + PARAMETER (FFTW_FORWARD=-1,FFTW_BACKWARD=1) + + INTEGER FFTW_REAL_TO_COMPLEX,FFTW_COMPLEX_TO_REAL + PARAMETER (FFTW_REAL_TO_COMPLEX=-1,FFTW_COMPLEX_TO_REAL=1) + + INTEGER FFTW_ESTIMATE,FFTW_MEASURE + PARAMETER (FFTW_ESTIMATE=0,FFTW_MEASURE=1) + + INTEGER FFTW_IN_PLACE,FFTW_USE_WISDOM + PARAMETER (FFTW_IN_PLACE=8,FFTW_USE_WISDOM=16) diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/fortranize.h b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fortranize.h new file mode 100644 index 000000000..fb4a6b8b6 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/fortranize.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1997,1998 Massachusetts Institute of Technology + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef FORTRANIZE_H +#define FORTRANIZE_H + +/* + * convert C name -> FORTRAN name. On some systems, + * append an underscore. On other systems, use all caps. + * + * x is the lower case name, X is the all caps name. + */ + +#if defined(CRAY) || defined(_UNICOS) || defined(_CRAYMPP) +#define FORTRANIZE(x,X) X /* all upper-case on the Cray */ + +#elif defined(IBM6000) || defined(_AIX) +#define FORTRANIZE(x,X) x /* all lower-case on RS/6000 */ + +#elif defined(__hpux) +#define FORTRANIZE(x,X) x /* all lower-case on HP-UX */ + +#elif defined(USING_G77) /* users should define this when using with the g77 + Fortran compiler */ +#define FORTRANIZE(x,X) x##__ /* g77 expects *two* underscores after + names with an underscore */ + +#else +#define FORTRANIZE(x,X) x##_ /* use all lower-case with underscore + by default */ + +#endif + +#endif /* FORTRANIZE_H */ diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/main_2ways.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/main_2ways.f new file mode 100644 index 000000000..5f692d838 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/main_2ways.f @@ -0,0 +1,273 @@ + program cylindre + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp(npm),yp(npm),zp(npm),dv(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx(npm),vy(npm),vz(npm) + dimension strx(npm),stry(npm),strz(npm) + + dimension domx(npm),domy(npm),domz(npm) +c tableuax supplementaries pour RK + dimension xp0(npm),yp0(npm),zp0(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv(4,npm),vyv(4,npm),vzv(4,npm) + dimension para(4) + dimension enstrophy(0:1000),energy(0:1000),divergence(0:1000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filevelx,filevely,filevelz + + + pi=3.1415926 + pi2=2.*pi + + + + + + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx + READ(1,*) + read(1,*)tstop + READ(1,*) + read(1,*)coef + READ(1,*) + read(1,*)anu + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tvisu + READ(1,*) + read(1,*) width + + + close(1) + tvisu=0.3 + idif=1 + + xmin=-0. + xmax=1. + ymin=0. + ymax=1. + zmin=xmin + zmax=xmax + + ny=nx + nz=nx + dx=(xmax-xmin)/(nx) + dy=(ymax-ymin)/(ny) + dz=(zmax-zmin)/(nz) + + delt=0.01 + + + call init(npart,xp,yp,zp,omx,omy,omz,dv) + + OPEN(33,file='SPEED',status='unknown') + +c debut des iterations + + time=0. + tcompt=0. + istep=0 + nit=10000 + + do 20 kk=1,nit + + time=time+delt + + deltconv=delt + delt1=delt/6. + + call velox_fft + call vfix +c call vhat(delt) + + print*, ' VITESSE = ',vzh + + call pen(coef_pen,omx,omy,omz,delt) +c call bar(saut) + + call stretch + + + +c on fait les sous-iterations R.K. + + do 10 i=1,npart + xp0(i)=xp(i) + yp0(i)=yp(i) + zp0(i)=zp(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) +10 continue + + do 550 ll=1,4 + + call intervm4(npart,vx,vy,vz,xp,yp,zp) + call intersm4(npart,strx,stry,strz,xp,yp,zp) + +c increment des positions et poids correspondant aux sous-ite +c RK +c ********************** + + vxmax=0. + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + vzmax=0. + do 520 i=1,npart + vxv(ll,i)=vx(i) + vyv(ll,i)=vy(i) + vzv(ll,i)=vz(i) + strxv(ll,i)=dv(i)*strx(i) + stryv(ll,i)=dv(i)*stry(i) + strzv(ll,i)=dv(i)*strz(i) + xp(i)=xp0(i)+para(ll)*deltconv*vx(i) + if (xp(i).lt.xmin) xp(i)=xp(i)+xmax-xmin + if (xp(i).gt.xmax) xp(i)=xp(i)-xmax+xmin + yp(i)=yp0(i)+para(ll)*deltconv*vy(i) + if (yp(i).lt.ymin) yp(i)=yp(i)+ymax-ymin + if (yp(i).gt.ymax) yp(i)=yp(i)-ymax+ymin + zp(i)=zp0(i)+para(ll)*deltconv*vz(i) + if (zp(i).lt.zmin) zp(i)=zp(i)+zmax-zmin + if (zp(i).gt.zmax) zp(i)=zp(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv(i)*strz(i) + vxmax=amax1(vxmax,(vx(i))) + vxmin=amin1(vxmin,(vx(i))) + vymax=amax1(vymax,(vy(i))) + vymin=amin1(vymin,(vy(i))) + vzmax=amax1(vzmax,(vz(i))) + vzmin=amin1(vzmin,(vz(i))) +520 continue +c print*,' vitesses max ',vxmax,vxmin,vymax,vymin,vzmax,vzmin + +550 continue + +c FIN des sous-ite RK +c ********************** + +c Increments des positions et poids pour +c la partie transport-deformation du tourbillon + + + xleft=xmax + xright=xmin + yleft=ymax + yright=ymin + zleft=zmax + zright=zmin + do 900 i=1,npart + xp(i)=xp0(i)+delt1*(vxv(1,i)+2.*vxv(2,i)+2.*vxv(3,i)+vxv(4,i)) + yp(i)=yp0(i)+delt1*(vyv(1,i)+2.*vyv(2,i)+2.*vyv(3,i)+vyv(4,i)) + zp(i)=zp0(i)+delt1*(vzv(1,i)+2.*vzv(2,i)+2.*vzv(3,i)+vzv(4,i)) + zp(i)=zp(i)-delt*vzh + xleft=amin1(xleft,xp(i)) + xright=amax1(xright,xp(i)) + yleft=amin1(yleft,yp(i)) + yright=amax1(yright,yp(i)) + zleft=amin1(zleft,zp(i)) + zright=amax1(zright,zp(i)) + if (xp(i).lt.xmin) xp(i)=xp(i)+xmax-xmin + if (xp(i).gt.xmax) xp(i)=xp(i)-xmax+xmin + if (yp(i).lt.ymin) yp(i)=yp(i)+ymax-ymin + if (yp(i).gt.ymax) yp(i)=yp(i)-ymax+ymin + if (zp(i).lt.zmin) zp(i)=zp(i)+zmax-zmin + if (zp(i).gt.zmax) zp(i)=zp(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+ + 1 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+ + 1 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+ + 1 2.*strzv(3,i)+strzv(4,i)) +900 continue + + + + +c Remshing + Diffusion +c ********************** + +c circlim=0.0001 +c circulation mimimum pour troncature de la vorticite dans remaillage + circlim=-10. + + + call remeshdif(npart,circlim,omx,omy,omz, + 1 xp,yp,zp,dv,anu,delt) + + print*,' npart apres remeshing ', kk,npart + + xg=0. + yg=0. + zg=0. + tm=0. + + if ((tcompt.gt.tvisu).or.(kk.eq.0)) then + istep=istep+1 + print*, ' ****** IMPRESSION des RESULTATS: ', istep, ' ******' + + write(filevelx,140)istep +140 format('velx',i1) + if (istep.ge.10) then + write(filevelx,141)istep + endif +141 format('velx',i2) + write(filevely,150)istep +150 format('vely',i1) + if (istep.ge.10) then + write(filevely,151)istep + endif +151 format('vely',i2) + write(filevelz,160)istep +160 format('velz',i1) + if (istep.ge.10) then + write(filevelz,161)istep + endif +161 format('velz',i2) + + open(2,file=filevelx,form='unformatted', +c 1 convert='big_endian', + 1 status='unknown') + open(3,file=filevely,form='unformatted', +c 1 convert='big_endian', + 1 status='unknown') + open(4,file=filevelz,form='unformatted', +c 1 convert='big_endian', + 1 status='unknown') + write(2) (((vxg(i,j,k), + 1 i=1,nx),j=1,ny),k=1,nz) + write(3) (((vyg(i,j,k), + 1 i=1,nx),j=1,ny),k=1,nz) + write(4) (((vzg(i,j,k), + 1 i=1,nx),j=1,ny),k=1,nz) + close(2) + close(3) + close(4) + + tcompt=0. + endif + + write(32,*) time,vzh + + if (time.gt.5.) goto 201 + +20 continue + +201 continue + stop + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/makefile b/CodesEnVrac/CodeGH/src-sphere/NotUsed/makefile new file mode 100644 index 000000000..6edcdf30f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/makefile @@ -0,0 +1,37 @@ +# +# la commande f77 pour les dec est f77_520 +# +FF =ifort +OPT = -I/${INCLUDE} + +OPT2 = -O3 -tpp2 -ipo -nolib_inline -ipo_obj -ldl + +OPT4 = -g +OPT3 = -O3 -tpp2 -ldl -g + +CFLAGS = -pg -DUSING_G77 + +FFLAGS = -O3 + +LDFLAGS = -pg + +PROGRAM = vicper256b + +EXEC = vicper256b + +all: $(PROGRAM) + + +OBJ = main.o init.o reinit.o \ + vfix.o drag.o drag_surface.o \ +intervm4.o remesh.o \ +dif_om.o remesh_om.o \ +intersm4.o stretch.o pen_dif_fft.o \ +pen.o fftw3d.o velox_fft.o velox_dif.o diff_fft.o + +%.o: %.f param.i arrays.h + $(FF) -o $@ -c $< $(OPT3) + + +$(PROGRAM): $(OBJ) + ifort $(OPT3) $(OBJ) -lfftw3f -lfftw3_threads -lfftw3 -o $(EXEC) diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_expl.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_expl.f new file mode 100644 index 000000000..a53f0daf2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_expl.f @@ -0,0 +1,47 @@ + subroutine pen(coef_pen) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + +c condition limite v=v_h en vorticite par penalisation explicite + + pi=3.1415926 + topi=2./pi + spi=sqrt(pi) + + eps=float(nc)*dx + eps=dx/1000. + eps2=eps**2 + + dxinv=1./(2.*dx) + dyinv=1./(2.*dy) + + +c penalisation sous forme : curl[ (v-vh)H] + + do i=1,nx + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + arg=phig(i,j) + argt=phig(it,j) + argb=phig(ib,j) + term1=(coef_pen*(vyh-vyg(it,j)))*argt + term2=(coef_pen*(vyh-vyg(ib,j)))*argb + akappa(i,j)=(term1-term2)/(2.*dx) + argt=phig(i,jt) + argb=phig(i,jb) + term1=(coef_pen*(vxh-vxg(i,jt)))*argt + term2=(coef_pen*(vxh-vxg(i,jb)))*argb + akappa(i,j)=akappa(i,j)-(term1-term2)/(2.*dx) + enddo + enddo + +111 continue + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_impl.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_impl.f new file mode 100644 index 000000000..b4f5817a5 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/pen_impl.f @@ -0,0 +1,86 @@ + subroutine pen(coef_pen,omx,omy,omz,delt) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension domg(npg,npg,npg) + dimension omx(*),omy(*),omz(*) + +c condition limite v=vh par penalisation implicite en vorticite + + pi=3.1415926 + topi=2./pi + spi=sqrt(pi) + + eps=float(nc)*dx + eps=dx/1000. + eps2=eps**2 + + dxinv=1./(2.*dx) + dyinv=1./(2.*dy) + + cdelt=coef_pen*delt + + +c penalisation sous forme : +c omega_n+1=curl[(u_n+coef_pen*delt*vh)/(1+coef_pen)] + + npart=0 + do k=1,nz + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + do i=1,nx + npart=npart+1 + strg1(i,j)=0. + strg3(i,j)=0. + strg3(i,j)=0. + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + arg=phig(i,j,k) + argt=phig(i,jt,k) + argb=phig(i,jb,k) + argu=phig(i,j,kt) + argd=phig(i,j,kb) + argr=phig(it,j,k) + argl=phig(ib,j,k) + +c x-component: + term1=(vzg(i,jt,k)+argt*cdelt*vzh)/(1.+cdelt*argt) + term2=(vzg(i,jb,k)+argb*cdelt*vzh)/(1.+cdelt*argb) + domg(i,j,k)=(term1-term2)/(2.*dx)-omg1(i,j,k) + term1=(vyg(i,j,kt)+argu*cdelt*vyh)/(1.+cdelt*argu) + term2=(vyg(i,j,kb)+argd*cdelt*vyh)/(1.+cdelt*argd) + domg(i,j,k)=domg(i,j,k)-(term1-term2)/(2.*dx) + omx(npart)=omx(npart)+(dx**2)*domg(i,j,k) + +c y-component: + term1=(vxg(i,j,kt)+argu*cdelt*vxh)/(1.+cdelt*argu) + term2=(vxg(i,j,kb)+argd*cdelt*vxh)/(1.+cdelt*argd) + domg(i,j,k)=(term1-term2)/(2.*dx)-omg2(i,j,k) + term1=(vzg(it,j,k)+argr*cdelt*vzh)/(1.+cdelt*argr) + term2=(vzg(ib,j,k)+argl*cdelt*vzh)/(1.+cdelt*argl) + omy(npart)=omy(npart)+(dx**2)*domg(i,j,k) + +c z-component: + term1=(vyg(it,j,k)+argu*cdelt*vyh)/(1.+cdelt*argr) + term2=(vyg(ib,j,k)+argd*cdelt*vyh)/(1.+cdelt*argl) + domg(i,j,k)=(term1-term2)/(2.*dx)-omg3(i,j,k) + term1=(vxg(i,jt,k)+argr*cdelt*vxh)/(1.+cdelt*argt) + term2=(vxg(i,jb,k)+argl*cdelt*vxh)/(1.+cdelt*argb) + omz(npart)=omz(npart)+(dx**2)*domg(i,j,k) + + enddo + enddo + enddo + + + +111 continue + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/poisson.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/poisson.f new file mode 100644 index 000000000..a365591c5 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/poisson.f @@ -0,0 +1,4477 @@ + SUBROUTINE CFFTB(N,C,WSAVE) +C***BEGIN PROLOGUE CFFTB +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 851111 (YYMMDD) +C***CATEGORY NO. J1A2 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Unnormalized inverse of CFFTF. +C***DESCRIPTION +C +C Subroutine CFFTB computes the backward complex discrete Fourier +C transform (the Fourier synthesis). Equivalently, CFFTB computes +C a complex periodic sequence from its Fourier coefficients. +C The transform is defined below at output parameter C. +C +C A call of CFFTF followed by a call of CFFTB will multiply the +C sequence by N. +C +C The array WSAVE which is used by subroutine CFFTB must be +C initialized by calling subroutine CFFTI(N,WSAVE). +C +C Input Parameters +C +C +C N the length of the complex sequence C. The method is +C more efficient when N is the product of small primes. +C +C C a complex array of length N which contains the sequence +C +C WSAVE a real work array which must be dimensioned at least 4*N+15 +C in the program that calls CFFTB. The WSAVE array must be +C initialized by calling subroutine CFFTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C The same WSAVE array can be used by CFFTF and CFFTB. +C +C Output Parameters +C +C C For J=1,...,N +C +C C(J)=the sum from K=1,...,N of +C +C C(K)*EXP(I*(J-1)*(K-1)*2*PI/N) +C +C where I=SQRT(-1) +C +C WSAVE contains initialization calculations which must not be +C destroyed between calls of subroutine CFFTF or CFFTB +C***REFERENCES (NONE) +C***ROUTINES CALLED CFFTB1 +C***END PROLOGUE CFFTB + COMPLEX C + DIMENSION C(*) ,WSAVE(*) +C***FIRST EXECUTABLE STATEMENT CFFTB + IF (N .EQ. 1) RETURN + IW1 = N+N+1 + IW2 = IW1+N+N + CALL CFFTB1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2)) + RETURN + END + SUBROUTINE CFFTB1(N,C,CH,WA,IFAC) +C***BEGIN PROLOGUE CFFTB1 +C***REFER TO CFFTB +C***ROUTINES CALLED PASSB,PASSB2,PASSB3,PASSB4,PASSB5 +C***END PROLOGUE CFFTB1 + DIMENSION CH(1) ,C(1) ,WA(1) ,IFAC(1) +C***FIRST EXECUTABLE STATEMENT CFFTB1 + NF = IFAC(2) + NA = 0 + L1 = 1 + IW = 1 + DO 116 K1=1,NF + IP = IFAC(K1+2) + L2 = IP*L1 + IDO = N/L2 + IDOT = IDO+IDO + IDL1 = IDOT*L1 + IF (IP .NE. 4) GO TO 103 + IX2 = IW+IDOT + IX3 = IX2+IDOT + IF (NA .NE. 0) GO TO 101 + CALL PASSB4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3)) + GO TO 102 + 101 CALL PASSB4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3)) + 102 NA = 1-NA + GO TO 115 + 103 IF (IP .NE. 2) GO TO 106 + IF (NA .NE. 0) GO TO 104 + CALL PASSB2 (IDOT,L1,C,CH,WA(IW)) + GO TO 105 + 104 CALL PASSB2 (IDOT,L1,CH,C,WA(IW)) + 105 NA = 1-NA + GO TO 115 + 106 IF (IP .NE. 3) GO TO 109 + IX2 = IW+IDOT + IF (NA .NE. 0) GO TO 107 + CALL PASSB3 (IDOT,L1,C,CH,WA(IW),WA(IX2)) + GO TO 108 + 107 CALL PASSB3 (IDOT,L1,CH,C,WA(IW),WA(IX2)) + 108 NA = 1-NA + GO TO 115 + 109 IF (IP .NE. 5) GO TO 112 + IX2 = IW+IDOT + IX3 = IX2+IDOT + IX4 = IX3+IDOT + IF (NA .NE. 0) GO TO 110 + CALL PASSB5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + GO TO 111 + 110 CALL PASSB5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + 111 NA = 1-NA + GO TO 115 + 112 IF (NA .NE. 0) GO TO 113 + CALL PASSB (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW)) + GO TO 114 + 113 CALL PASSB (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW)) + 114 IF (NAC .NE. 0) NA = 1-NA + 115 L1 = L2 + IW = IW+(IP-1)*IDOT + 116 CONTINUE + IF (NA .EQ. 0) RETURN + N2 = N+N + DO 117 I=1,N2 + C(I) = CH(I) + 117 CONTINUE + RETURN + END + SUBROUTINE CFFTF(N,C,WSAVE) +C***BEGIN PROLOGUE CFFTF +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 851111 (YYMMDD) +C***CATEGORY NO. J1A2 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Forward transform of a complex, periodic sequence. +C***DESCRIPTION +C +C Subroutine CFFTF computes the forward complex discrete Fourier +C transform (the Fourier analysis). Equivalently, CFFTF computes +C the Fourier coefficients of a complex periodic sequence. +C The transform is defined below at output parameter C. +C +C The transform is not normalized. To obtain a normalized transform +C the output must be divided by N. Otherwise a call of CFFTF +C followed by a call of CFFTB will multiply the sequence by N. +C +C The array WSAVE which is used by subroutine CFFTF must be +C initialized by calling subroutine CFFTI(N,WSAVE). +C +C Input Parameters +C +C +C N the length of the complex sequence C. The method is +C more efficient when N is the product of small primes. +C +C C a complex array of length N which contains the sequence +C +C WSAVE a real work array which must be dimensioned at least 4*N+15 +C in the program that calls CFFTF. The WSAVE array must be +C initialized by calling subroutine CFFTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C The same WSAVE array can be used by CFFTF and CFFTB. +C +C Output Parameters +C +C C for J=1,...,N +C +C C(J)=the sum from K=1,...,N of +C +C C(K)*EXP(-I*(J-1)*(K-1)*2*PI/N) +C +C where I=SQRT(-1) +C +C WSAVE contains initialization calculations which must not be +C destroyed between calls of subroutine CFFTF or CFFTB +C***REFERENCES (NONE) +C***ROUTINES CALLED CFFTF1 +C***END PROLOGUE CFFTF + COMPLEX C + DIMENSION C(*) ,WSAVE(*) +C***FIRST EXECUTABLE STATEMENT CFFTF + IF (N .EQ. 1) RETURN + IW1 = N+N+1 + IW2 = IW1+N+N + CALL CFFTF1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2)) + RETURN + END + SUBROUTINE CFFTF1(N,C,CH,WA,IFAC) +C***BEGIN PROLOGUE CFFTF1 +C***REFER TO CFFTF +C***ROUTINES CALLED PASSF,PASSF2,PASSF3,PASSF4,PASSF5 +C***END PROLOGUE CFFTF1 + DIMENSION CH(1) ,C(1) ,WA(1) ,IFAC(1) +C***FIRST EXECUTABLE STATEMENT CFFTF1 + NF = IFAC(2) + NA = 0 + L1 = 1 + IW = 1 + DO 116 K1=1,NF + IP = IFAC(K1+2) + L2 = IP*L1 + IDO = N/L2 + IDOT = IDO+IDO + IDL1 = IDOT*L1 + IF (IP .NE. 4) GO TO 103 + IX2 = IW+IDOT + IX3 = IX2+IDOT + IF (NA .NE. 0) GO TO 101 + CALL PASSF4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3)) + GO TO 102 + 101 CALL PASSF4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3)) + 102 NA = 1-NA + GO TO 115 + 103 IF (IP .NE. 2) GO TO 106 + IF (NA .NE. 0) GO TO 104 + CALL PASSF2 (IDOT,L1,C,CH,WA(IW)) + GO TO 105 + 104 CALL PASSF2 (IDOT,L1,CH,C,WA(IW)) + 105 NA = 1-NA + GO TO 115 + 106 IF (IP .NE. 3) GO TO 109 + IX2 = IW+IDOT + IF (NA .NE. 0) GO TO 107 + CALL PASSF3 (IDOT,L1,C,CH,WA(IW),WA(IX2)) + GO TO 108 + 107 CALL PASSF3 (IDOT,L1,CH,C,WA(IW),WA(IX2)) + 108 NA = 1-NA + GO TO 115 + 109 IF (IP .NE. 5) GO TO 112 + IX2 = IW+IDOT + IX3 = IX2+IDOT + IX4 = IX3+IDOT + IF (NA .NE. 0) GO TO 110 + CALL PASSF5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + GO TO 111 + 110 CALL PASSF5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + 111 NA = 1-NA + GO TO 115 + 112 IF (NA .NE. 0) GO TO 113 + CALL PASSF (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW)) + GO TO 114 + 113 CALL PASSF (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW)) + 114 IF (NAC .NE. 0) NA = 1-NA + 115 L1 = L2 + IW = IW+(IP-1)*IDOT + 116 CONTINUE + IF (NA .EQ. 0) RETURN + N2 = N+N + DO 117 I=1,N2 + C(I) = CH(I) + 117 CONTINUE + RETURN + END + SUBROUTINE CFFTI(N,WSAVE) +C***BEGIN PROLOGUE CFFTI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A2 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for CFFTF and CFFTB. +C***DESCRIPTION +C +C Subroutine CFFTI initializes the array WSAVE which is used in +C both CFFTF and CFFTB. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the sequence to be transformed +C +C Output Parameter +C +C WSAVE a work array which must be dimensioned at least 4*N+15. +C The same work array can be used for both CFFTF and CFFTB +C as long as N remains unchanged. Different WSAVE arrays +C are required for different values of N. The contents of +C WSAVE must not be changed between calls of CFFTF or CFFTB. +C***REFERENCES (NONE) +C***ROUTINES CALLED CFFTI1 +C***END PROLOGUE CFFTI + DIMENSION WSAVE(1) +C***FIRST EXECUTABLE STATEMENT CFFTI + IF (N .EQ. 1) RETURN + IW1 = N+N+1 + IW2 = IW1+N+N + CALL CFFTI1 (N,WSAVE(IW1),WSAVE(IW2)) + RETURN + END + SUBROUTINE CFFTI1(N,WA,IFAC) +C***BEGIN PROLOGUE CFFTI1 +C***REFER TO CFFTI +C***ROUTINES CALLED (NONE) +C***END PROLOGUE CFFTI1 + DIMENSION WA(1) ,IFAC(1) ,NTRYH(4) + DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/3,4,2,5/ +C***FIRST EXECUTABLE STATEMENT CFFTI1 + NL = N + NF = 0 + J = 0 + 101 J = J+1 + IF (J-4) 102,102,103 + 102 NTRY = NTRYH(J) + GO TO 104 + 103 NTRY = NTRY+2 + 104 NQ = NL/NTRY + NR = NL-NTRY*NQ + IF (NR) 101,105,101 + 105 NF = NF+1 + IFAC(NF+2) = NTRY + NL = NQ + IF (NTRY .NE. 2) GO TO 107 + IF (NF .EQ. 1) GO TO 107 + DO 106 I=2,NF + IB = NF-I+2 + IFAC(IB+2) = IFAC(IB+1) + 106 CONTINUE + IFAC(3) = 2 + 107 IF (NL .NE. 1) GO TO 104 + IFAC(1) = N + IFAC(2) = NF + TPI = 6.28318530717959 + ARGH = TPI/FLOAT(N) + I = 2 + L1 = 1 + DO 110 K1=1,NF + IP = IFAC(K1+2) + LD = 0 + L2 = L1*IP + IDO = N/L2 + IDOT = IDO+IDO+2 + IPM = IP-1 + DO 109 J=1,IPM + I1 = I + WA(I-1) = 1. + WA(I) = 0. + LD = LD+L1 + FI = 0. + ARGLD = FLOAT(LD)*ARGH + DO 108 II=4,IDOT,2 + I = I+2 + FI = FI+1. + ARG = FI*ARGLD + WA(I-1) = COS(ARG) + WA(I) = SIN(ARG) + 108 CONTINUE + IF (IP .LE. 5) GO TO 109 + WA(I1-1) = WA(I-1) + WA(I1) = WA(I) + 109 CONTINUE + L1 = L2 + 110 CONTINUE + RETURN + END + SUBROUTINE COSQB(N,X,WSAVE) +C***BEGIN PROLOGUE COSQB +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Unnormalized inverse of COSQF. +C***DESCRIPTION +C +C Subroutine COSQB computes the fast Fourier transform of quarter +C wave data. That is, COSQB computes a sequence from its +C representation in terms of a cosine series with odd wave numbers. +C The transform is defined below at output parameter X. +C +C COSQB is the unnormalized inverse of COSQF since a call of COSQB +C followed by a call of COSQF will multiply the input sequence X +C by 4*N. +C +C The array WSAVE which is used by subroutine COSQB must be +C initialized by calling subroutine COSQI(N,WSAVE). +C +C +C Input Parameters +C +C N the length of the array X to be transformed. The method +C is most efficient when N is a product of small primes. +C +C X an array which contains the sequence to be transformed +C +C WSAVE a work array that must be dimensioned at least 3*N+15 +C in the program that calls COSQB. The WSAVE array must be +C initialized by calling subroutine COSQI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X For I=1,...,N +C +C X(I)= the sum from K=1 to K=N of +C +C 4*X(K)*COS((2*K-1)*(I-1)*PI/(2*N)) +C +C A call of COSQB followed by a call of +C COSQF will multiply the sequence X by 4*N. +C Therefore COSQF is the unnormalized inverse +C of COSQB. +C +C WSAVE contains initialization calculations which must not +C be destroyed between calls of COSQB or COSQF. +C***REFERENCES (NONE) +C***ROUTINES CALLED COSQB1 +C***END PROLOGUE COSQB + DIMENSION X(1) ,WSAVE(1) + DATA TSQRT2 /2.82842712474619/ +C***FIRST EXECUTABLE STATEMENT COSQB + IF (N-2) 101,102,103 + 101 X(1) = 4.*X(1) + RETURN + 102 X1 = 4.*(X(1)+X(2)) + X(2) = TSQRT2*(X(1)-X(2)) + X(1) = X1 + RETURN + 103 CALL COSQB1 (N,X,WSAVE,WSAVE(N+1)) + RETURN + END + SUBROUTINE COSQB1(N,X,W,XH) +C***BEGIN PROLOGUE COSQB1 +C***REFER TO COSQB +C***ROUTINES CALLED RFFTB +C***END PROLOGUE COSQB1 + DIMENSION X(1) ,W(1) ,XH(1) +C***FIRST EXECUTABLE STATEMENT COSQB1 + NS2 = (N+1)/2 + NP2 = N+2 + DO 101 I=3,N,2 + XIM1 = X(I-1)+X(I) + X(I) = X(I)-X(I-1) + X(I-1) = XIM1 + 101 CONTINUE + X(1) = X(1)+X(1) + MODN = MOD(N,2) + IF (MODN .EQ. 0) X(N) = X(N)+X(N) + CALL RFFTB (N,X,XH) + DO 102 K=2,NS2 + KC = NP2-K + XH(K) = W(K-1)*X(KC)+W(KC-1)*X(K) + XH(KC) = W(K-1)*X(K)-W(KC-1)*X(KC) + 102 CONTINUE + IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*(X(NS2+1)+X(NS2+1)) + DO 103 K=2,NS2 + KC = NP2-K + X(K) = XH(K)+XH(KC) + X(KC) = XH(K)-XH(KC) + 103 CONTINUE + X(1) = X(1)+X(1) + RETURN + END + SUBROUTINE COSQF(N,X,WSAVE) +C***BEGIN PROLOGUE COSQF +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Forward cosine transform with odd wave numbers. +C***DESCRIPTION +C +C Subroutine COSQF computes the fast Fourier transform of quarter +C wave data. That is, COSQF computes the coefficients in a cosine +C series representation with only odd wave numbers. The transform +C is defined below at Output Parameter X +C +C COSQF is the unnormalized inverse of COSQB since a call of COSQF +C followed by a call of COSQB will multiply the input sequence X +C by 4*N. +C +C The array WSAVE which is used by subroutine COSQF must be +C initialized by calling subroutine COSQI(N,WSAVE). +C +C +C Input Parameters +C +C N the length of the array X to be transformed. The method +C is most efficient when N is a product of small primes. +C +C X an array which contains the sequence to be transformed +C +C WSAVE a work array which must be dimensioned at least 3*N+15 +C in the program that calls COSQF. The WSAVE array must be +C initialized by calling subroutine COSQI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X For I=1,...,N +C +C X(I) = X(1) plus the sum from K=2 to K=N of +C +C 2*X(K)*COS((2*I-1)*(K-1)*PI/(2*N)) +C +C A call of COSQF followed by a call of +C COSQB will multiply the sequence X by 4*N. +C Therefore COSQB is the unnormalized inverse +C of COSQF. +C +C WSAVE contains initialization calculations which must not +C be destroyed between calls of COSQF or COSQB. +C***REFERENCES (NONE) +C***ROUTINES CALLED COSQF1 +C***END PROLOGUE COSQF + DIMENSION X(1) ,WSAVE(1) + DATA SQRT2 /1.4142135623731/ +C***FIRST EXECUTABLE STATEMENT COSQF + IF (N-2) 102,101,103 + 101 TSQX = SQRT2*X(2) + X(2) = X(1)-TSQX + X(1) = X(1)+TSQX + 102 RETURN + 103 CALL COSQF1 (N,X,WSAVE,WSAVE(N+1)) + RETURN + END + SUBROUTINE COSQF1(N,X,W,XH) +C***BEGIN PROLOGUE COSQF1 +C***REFER TO COSQF +C***ROUTINES CALLED RFFTF +C***END PROLOGUE COSQF1 + DIMENSION X(1) ,W(1) ,XH(1) +C***FIRST EXECUTABLE STATEMENT COSQF1 + NS2 = (N+1)/2 + NP2 = N+2 + DO 101 K=2,NS2 + KC = NP2-K + XH(K) = X(K)+X(KC) + XH(KC) = X(K)-X(KC) + 101 CONTINUE + MODN = MOD(N,2) + IF (MODN .EQ. 0) XH(NS2+1) = X(NS2+1)+X(NS2+1) + DO 102 K=2,NS2 + KC = NP2-K + X(K) = W(K-1)*XH(KC)+W(KC-1)*XH(K) + X(KC) = W(K-1)*XH(K)-W(KC-1)*XH(KC) + 102 CONTINUE + IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*XH(NS2+1) + CALL RFFTF (N,X,XH) + DO 103 I=3,N,2 + XIM1 = X(I-1)-X(I) + X(I) = X(I-1)+X(I) + X(I-1) = XIM1 + 103 CONTINUE + RETURN + END + SUBROUTINE COSQI(N,WSAVE) +C***BEGIN PROLOGUE COSQI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for COSQF and COSQB. +C***DESCRIPTION +C +C Subroutine COSQI initializes the array WSAVE which is used in +C both COSQF and COSQB. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the array to be transformed. The method +C is most efficient when N is a product of small primes. +C +C Output Parameter +C +C WSAVE a work array which must be dimensioned at least 3*N+15. +C The same work array can be used for both COSQF and COSQB +C as long as N remains unchanged. Different WSAVE arrays +C are required for different values of N. The contents of +C WSAVE must not be changed between calls of COSQF or COSQB. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTI +C***END PROLOGUE COSQI + DIMENSION WSAVE(1) + DATA PIH /1.57079632679491/ +C***FIRST EXECUTABLE STATEMENT COSQI + DT = PIH/FLOAT(N) + FK = 0. + DO 101 K=1,N + FK = FK+1. + WSAVE(K) = COS(FK*DT) + 101 CONTINUE + CALL RFFTI (N,WSAVE(N+1)) + RETURN + END + SUBROUTINE COST(N,X,WSAVE) +C***BEGIN PROLOGUE COST +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 851219 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Cosine transform of a real, even sequence. +C***DESCRIPTION +C +C Subroutine COST computes the discrete Fourier cosine transform +C of an even sequence X(I). The transform is defined below at output +C parameter X. +C +C COST is the unnormalized inverse of itself since a call of COST +C followed by another call of COST will multiply the input sequence +C X by 2*(N-1). The transform is defined below at output parameter X. +C +C The array WSAVE which is used by subroutine COST must be +C initialized by calling subroutine COSTI(N,WSAVE). +C +C Input Parameters +C +C N the length of the sequence X. N must be greater than 1. +C The method is most efficient when N-1 is a product of +C small primes. +C +C X an array which contains the sequence to be transformed +C +C WSAVE a work array which must be dimensioned at least 3*N+15 +C in the program that calls COST. The WSAVE array must be +C initialized by calling subroutine COSTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X For I=1,...,N +C +C X(I) = X(1)+(-1)**(I-1)*X(N) +C +C + the sum from K=2 to K=N-1 +C +C 2*X(K)*COS((K-1)*(I-1)*PI/(N-1)) +C +C A call of COST followed by another call of +C COST will multiply the sequence X by 2*(N-1). +C Hence COST is the unnormalized inverse +C of itself. +C +C WSAVE contains initialization calculations which must not be +C destroyed between calls of COST. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTF +C***END PROLOGUE COST + DIMENSION X(1) ,WSAVE(1) +C***FIRST EXECUTABLE STATEMENT COST + NM1 = N-1 + NP1 = N+1 + NS2 = N/2 + IF (N-2) 106,101,102 + 101 X1H = X(1)+X(2) + X(2) = X(1)-X(2) + X(1) = X1H + RETURN + 102 IF (N .GT. 3) GO TO 103 + X1P3 = X(1)+X(3) + TX2 = X(2)+X(2) + X(2) = X(1)-X(3) + X(1) = X1P3+TX2 + X(3) = X1P3-TX2 + RETURN + 103 C1 = X(1)-X(N) + X(1) = X(1)+X(N) + DO 104 K=2,NS2 + KC = NP1-K + T1 = X(K)+X(KC) + T2 = X(K)-X(KC) + C1 = C1+WSAVE(KC)*T2 + T2 = WSAVE(K)*T2 + X(K) = T1-T2 + X(KC) = T1+T2 + 104 CONTINUE + MODN = MOD(N,2) + IF (MODN .NE. 0) X(NS2+1) = X(NS2+1)+X(NS2+1) + CALL RFFTF (NM1,X,WSAVE(N+1)) + XIM2 = X(2) + X(2) = C1 + DO 105 I=4,N,2 + XI = X(I) + X(I) = X(I-2)-X(I-1) + X(I-1) = XIM2 + XIM2 = XI + 105 CONTINUE + IF (MODN .NE. 0) X(N) = XIM2 + 106 RETURN + END + SUBROUTINE COSTI(N,WSAVE) +C***BEGIN PROLOGUE COSTI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for COST. +C***DESCRIPTION +C +C Subroutine COSTI initializes the array WSAVE which is used in +C subroutine COST. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the sequence to be transformed. The method +C is most efficient when N-1 is a product of small primes. +C +C Output Parameter +C +C WSAVE a work array which must be dimensioned at least 3*N+15. +C Different WSAVE arrays are required for different values +C of N. The contents of WSAVE must not be changed between +C calls of COST. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTI +C***END PROLOGUE COSTI + DIMENSION WSAVE(1) + DATA PI /3.14159265358979/ +C***FIRST EXECUTABLE STATEMENT COSTI + IF (N .LE. 3) RETURN + NM1 = N-1 + NP1 = N+1 + NS2 = N/2 + DT = PI/FLOAT(NM1) + FK = 0. + DO 101 K=2,NS2 + KC = NP1-K + FK = FK+1. + WSAVE(K) = 2.*SIN(FK*DT) + WSAVE(KC) = 2.*COS(FK*DT) + 101 CONTINUE + CALL RFFTI (NM1,WSAVE(N+1)) + RETURN + END + SUBROUTINE HW3CRT(XS,XF,L,LBDCND,BDXS,BDXF,YS,YF,M,MBDCND,BDYS, + 1 BDYF,ZS,ZF,N,NBDCND,BDZS,BDZF,ELMBDA,LDIMF,MDIMF,F,PERTRB, + 2 IERROR,W) +C***BEGIN PROLOGUE HW3CRT +C***DATE WRITTEN 801001 (YYMMDD) +C***REVISION DATE 830415 (YYMMDD) +C***CATEGORY NO. I2B1A1A +C***KEYWORDS CARTESIAN,ELLIPTIC,FISHPACK,HELMHOLTZ,PDE +C***AUTHOR ADAMS, J., (NCAR) +C SWARZTRAUBER, P., (NCAR) +C SWEET, R., (NCAR) +C***PURPOSE Subroutine HW3CRT solves the standard seven-point finite +C difference approximation to the Helmholtz equation in +C Cartesian coordinates. +C***DESCRIPTION +C +C Subroutine HW3CRT solves the standard seven-point finite +C difference approximation to the Helmholtz equation in Cartesian +C coordinates: +C +C (d/dX)(dU/dX) + (d/dY)(dU/dY) + (d/dZ)(dU/dZ) +C +C + LAMBDA*U = F(X,Y,Z) . +C +C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +C +C +C * * * * * * * * Parameter Description * * * * * * * * * * +C +C +C * * * * * * On Input * * * * * * +C +C XS,XF +C The range of X, i.e. XS .LE. X .LE. XF . +C XS must be less than XF. +C +C L +C The number of panels into which the interval (XS,XF) is +C subdivided. Hence, there will be L+1 grid points in the +C X-direction given by X(I) = XS+(I-1)DX for I=1,2,...,L+1, +C where DX = (XF-XS)/L is the panel width. L must be at +C least 5 . +C +C LBDCND +C Indicates the type of boundary conditions at X = XS and X = XF. +C +C = 0 If the solution is periodic in X, i.e. +C U(L+I,J,K) = U(I,J,K). +C = 1 If the solution is specified at X = XS and X = XF. +C = 2 If the solution is specified at X = XS and the derivative +C of the solution with respect to X is specified at X = XF. +C = 3 If the derivative of the solution with respect to X is +C specified at X = XS and X = XF. +C = 4 If the derivative of the solution with respect to X is +C specified at X = XS and the solution is specified at X=XF. +C +C BDXS +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to X at X = XS. +C when LBDCND = 3 or 4, +C +C BDXS(J,K) = (d/dX)U(XS,Y(J),Z(K)), J=1,2,...,M+1, +C K=1,2,...,N+1. +C +C When LBDCND has any other value, BDXS is a dummy variable. +C BDXS must be dimensioned at least (M+1)*(N+1). +C +C BDXF +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to X at X = XF. +C When LBDCND = 2 or 3, +C +C BDXF(J,K) = (d/dX)U(XF,Y(J),Z(K)), J=1,2,...,M+1, +C K=1,2,...,N+1. +C +C When LBDCND has any other value, BDXF is a dummy variable. +C BDXF must be dimensioned at least (M+1)*(N+1). +C +C YS,YF +C The range of Y, i.e. YS .LE. Y .LE. YF. +C YS must be less than YF. +C +C M +C The number of panels into which the interval (YS,YF) is +C subdivided. Hence, there will be M+1 grid points in the +C Y-direction given by Y(J) = YS+(J-1)DY for J=1,2,...,M+1, +C where DY = (YF-YS)/M is the panel width. M must be at +C least 5 . +C +C MBDCND +C Indicates the type of boundary conditions at Y = YS and Y = YF. +C +C = 0 If the solution is periodic in Y, i.e. +C U(I,M+J,K) = U(I,J,K). +C = 1 If the solution is specified at Y = YS and Y = YF. +C = 2 If the solution is specified at Y = YS and the derivative +C of the solution with respect to Y is specified at Y = YF. +C = 3 If the derivative of the solution with respect to Y is +C specified at Y = YS and Y = YF. +C = 4 If the derivative of the solution with respect to Y is +C specified at Y = YS and the solution is specified at Y=YF. +C +C BDYS +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to Y at Y = YS. +C When MBDCND = 3 or 4, +C +C BDYS(I,K) = (d/dY)U(X(I),YS,Z(K)), I=1,2,...,L+1, +C K=1,2,...,N+1. +C +C When MBDCND has any other value, BDYS is a dummy variable. +C BDYS must be dimensioned at least (L+1)*(N+1). +C +C BDYF +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to Y at Y = YF. +C When MBDCND = 2 or 3, +C +C BDYF(I,K) = (d/dY)U(X(I),YF,Z(K)), I=1,2,...,L+1, +C K=1,2,...,N+1. +C +C When MBDCND has any other value, BDYF is a dummy variable. +C BDYF must be dimensioned at least (L+1)*(N+1). +C +C ZS,ZF +C The range of Z, i.e. ZS .LE. Z .LE. ZF. +C ZS must be less than ZF. +C +C N +C The number of panels into which the interval (ZS,ZF) is +C subdivided. Hence, there will be N+1 grid points in the +C Z-direction given by Z(K) = ZS+(K-1)DZ for K=1,2,...,N+1, +C where DZ = (ZF-ZS)/N is the panel width. N must be at least 5. +C +C NBDCND +C Indicates the type of boundary conditions at Z = ZS and Z = ZF. +C +C = 0 If the solution is periodic in Z, i.e. +C U(I,J,N+K) = U(I,J,K). +C = 1 If the solution is specified at Z = ZS and Z = ZF. +C = 2 If the solution is specified at Z = ZS and the derivative +C of the solution with respect to Z is specified at Z = ZF. +C = 3 If the derivative of the solution with respect to Z is +C specified at Z = ZS and Z = ZF. +C = 4 If the derivative of the solution with respect to Z is +C specified at Z = ZS and the solution is specified at Z=ZF. +C +C BDZS +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to Z at Z = ZS. +C When NBDCND = 3 or 4, +C +C BDZS(I,J) = (d/dZ)U(X(I),Y(J),ZS), I=1,2,...,L+1, +C J=1,2,...,M+1. +C +C When NBDCND has any other value, BDZS is a dummy variable. +C BDZS must be dimensioned at least (L+1)*(M+1). +C +C BDZF +C A two-dimensional array that specifies the values of the +C derivative of the solution with respect to Z at Z = ZF. +C When NBDCND = 2 or 3, +C +C BDZF(I,J) = (d/dZ)U(X(I),Y(J),ZF), I=1,2,...,L+1, +C J=1,2,...,M+1. +C +C When NBDCND has any other value, BDZF is a dummy variable. +C BDZF must be dimensioned at least (L+1)*(M+1). +C +C ELMBDA +C The constant LAMBDA in the Helmholtz equation. If +C LAMBDA .GT. 0, a solution may not exist. However, HW3CRT will +C attempt to find a solution. +C +C F +C A three-dimensional array that specifies the values of the +C right side of the Helmholtz equation and boundary values (if +C any). For I=2,3,...,L, J=2,3,...,M, and K=2,3,...,N +C +C F(I,J,K) = F(X(I),Y(J),Z(K)). +C +C On the boundaries F is defined by +C +C LBDCND F(1,J,K) F(L+1,J,K) +C ------ --------------- --------------- +C +C 0 F(XS,Y(J),Z(K)) F(XS,Y(J),Z(K)) +C 1 U(XS,Y(J),Z(K)) U(XF,Y(J),Z(K)) +C 2 U(XS,Y(J),Z(K)) F(XF,Y(J),Z(K)) J=1,2,...,M+1 +C 3 F(XS,Y(J),Z(K)) F(XF,Y(J),Z(K)) K=1,2,...,N+1 +C 4 F(XS,Y(J),Z(K)) U(XF,Y(J),Z(K)) +C +C MBDCND F(I,1,K) F(I,M+1,K) +C ------ --------------- --------------- +C +C 0 F(X(I),YS,Z(K)) F(X(I),YS,Z(K)) +C 1 U(X(I),YS,Z(K)) U(X(I),YF,Z(K)) +C 2 U(X(I),YS,Z(K)) F(X(I),YF,Z(K)) I=1,2,...,L+1 +C 3 F(X(I),YS,Z(K)) F(X(I),YF,Z(K)) K=1,2,...,N+1 +C 4 F(X(I),YS,Z(K)) U(X(I),YF,Z(K)) +C +C NBDCND F(I,J,1) F(I,J,N+1) +C ------ --------------- --------------- +C +C 0 F(X(I),Y(J),ZS) F(X(I),Y(J),ZS) +C 1 U(X(I),Y(J),ZS) U(X(I),Y(J),ZF) +C 2 U(X(I),Y(J),ZS) F(X(I),Y(J),ZF) I=1,2,...,L+1 +C 3 F(X(I),Y(J),ZS) F(X(I),Y(J),ZF) J=1,2,...,M+1 +C 4 F(X(I),Y(J),ZS) U(X(I),Y(J),ZF) +C +C F must be dimensioned at least (L+1)*(M+1)*(N+1). +C +C NOTE: +C +C If the table calls for both the solution U and the right side F +C on a boundary, then the solution must be specified. +C +C LDIMF +C The row (or first) dimension of the arrays F,BDYS,BDYF,BDZS, +C and BDZF as it appears in the program calling HW3CRT. this +C parameter is used to specify the variable dimension of these +C arrays. LDIMF must be at least L+1. +C +C MDIMF +C The column (or second) dimension of the array F and the row (or +C first) dimension of the arrays BDXS and BDXF as it appears in +C the program calling HW3CRT. This parameter is used to specify +C the variable dimension of these arrays. +C MDIMF must be at least M+1. +C +C W +C A one-dimensional array that must be provided by the user for +C work space. The length of W must be at least 30 + L + M + 5*N +C + MAX(L,M,N) + 7*(INT((L+1)/2) + INT((M+1)/2)) +C +C +C * * * * * * On Output * * * * * * +C +C F +C Contains the solution U(I,J,K) of the finite difference +C approximation for the grid point (X(I),Y(J),Z(K)) for +C I=1,2,...,L+1, J=1,2,...,M+1, and K=1,2,...,N+1. +C +C PERTRB +C If a combination of periodic or derivative boundary conditions +C is specified for a Poisson equation (LAMBDA = 0), a solution +C may not exist. PERTRB is a constant, calculated and subtracted +C from F, which ensures that a solution exists. pwscrt then +C computes this solution, which is a least squares solution to +C the original approximation. This solution is not unique and is +C unnormalized. The value of PERTRB should be small compared to +C the right side F. Otherwise, a solution is obtained to an +C essentially different problem. This comparison should always +C be made to insure that a meaningful solution has been obtained. +C +C IERROR +C An error flag that indicates invalid input parameters. Except +C for numbers 0 and 12, a solution is not attempted. +C +C = 0 No error +C = 1 XS .GE. XF +C = 2 L .LT. 5 +C = 3 LBDCND .LT. 0 .OR. LBDCND .GT. 4 +C = 4 YS .GE. YF +C = 5 M .LT. 5 +C = 6 MBDCND .LT. 0 .OR. MBDCND .GT. 4 +C = 7 ZS .GE. ZF +C = 8 N .LT. 5 +C = 9 NBDCND .LT. 0 .OR. NBDCND .GT. 4 +C = 10 LDIMF .LT. L+1 +C = 11 MDIMF .LT. M+1 +C = 12 LAMBDA .GT. 0 +C +C Since this is the only means of indicating a possibly incorrect +C call to HW3CRT, the user should test IERROR after the call. +C***LONG DESCRIPTION +C +C * * * * * * * Program Specifications * * * * * * * * * * * * +C +C Dimension of BDXS(MDIMF,N+1),BDXF(MDIMF,N+1),BDYS(LDIMF,N+1), +C Arguments BDYF(LDIMF,N+1),BDZS(LDIMF,M+1),BDZF(LDIMF,M+1), +C F(LDIMF,MDIMF,N+1),W(see argument list) +C +C Latest December 1, 1978 +C Revision +C +C Subprograms HW3CRT,POIS3D,POS3D1,TRID,RFFTI,RFFTF,RFFTF1, +C Required RFFTB,RFFTB1,COSTI,COST,SINTI,SINT,COSQI,COSQF, +C COSQF1,COSQB,COSQB1,SINQI,SINQF,SINQB,CFFTI, +C CFFTI1,CFFTB,CFFTB1,PASSB2,PASSB3,PASSB4,PASSB, +C CFFTF,CFFTF1,PASSF1,PASSF2,PASSF3,PASSF4,PASSF, +C PIMACH +C +C Special NONE +C Conditions +C +C Common NONE +C Blocks +C +C I/O NONE +C +C Precision Single +C +C Specialist Roland Sweet +C +C Language FORTRAN +C +C History Written by Roland Sweet at NCAR in July,1977 +C +C Algorithm This subroutine defines the finite difference +C equations, incorporates boundary data, and +C adjusts the right side of singular systems and +C then calls POIS3D to solve the system. +C +C Space 7862(decimal) = 17300(octal) locations on the +C Required NCAR Control Data 7600 +C +C Timing and The execution time T on the NCAR Control Data +C Accuracy 7600 for subroutine HW3CRT is roughly proportional +C to L*M*N*(log2(L)+log2(M)+5), but also depends on +C input parameters LBDCND and MBDCND. Some typical +C values are listed in the table below. +C The solution process employed results in a loss +C of no more than three significant digits for L,M +C and N as large as 32. More detailed information +C about accuracy can be found in the documentation +C for subroutine POIS3D which is the routine that +C actually solves the finite difference equations. +C +C +C L(=M=N) LBDCND(=MBDCND=NBDCND) T(MSECS) +C ------- ---------------------- -------- +C +C 16 0 300 +C 16 1 302 +C 16 3 348 +C 32 0 1925 +C 32 1 1929 +C 32 3 2109 +C +C Portability American National Standards Institute FORTRAN. +C The machine dependent constant PI is defined in +C function PIMACH. +C +C Required COS,SIN,ATAN +C Resident +C Routines +C +C Reference NONE +C +C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +C***REFERENCES (NONE) +C***ROUTINES CALLED POIS3D +C***END PROLOGUE HW3CRT +C +C + DIMENSION BDXS(MDIMF,1) ,BDXF(MDIMF,1) , + 1 BDYS(LDIMF,1) ,BDYF(LDIMF,1) , + 2 BDZS(LDIMF,1) ,BDZF(LDIMF,1) , + 3 F(LDIMF,MDIMF,1) ,W(1) +C***FIRST EXECUTABLE STATEMENT HW3CRT + IERROR = 0 + IF (XF .LE. XS) IERROR = 1 + IF (L .LT. 5) IERROR = 2 + IF (LBDCND.LT.0 .OR. LBDCND.GT.4) IERROR = 3 + IF (YF .LE. YS) IERROR = 4 + IF (M .LT. 5) IERROR = 5 + IF (MBDCND.LT.0 .OR. MBDCND.GT.4) IERROR = 6 + IF (ZF .LE. ZS) IERROR = 7 + IF (N .LT. 5) IERROR = 8 + IF (NBDCND.LT.0 .OR. NBDCND.GT.4) IERROR = 9 + IF (LDIMF .LT. L+1) IERROR = 10 + IF (MDIMF .LT. M+1) IERROR = 11 + IF (IERROR .NE. 0) GO TO 188 + DY = (YF-YS)/FLOAT(M) + TWBYDY = 2./DY + C2 = 1./(DY**2) + MSTART = 1 + MSTOP = M + MP1 = M+1 + MP = MBDCND+1 + GO TO (104,101,101,102,102),MP + 101 MSTART = 2 + 102 GO TO (104,104,103,103,104),MP + 103 MSTOP = MP1 + 104 MUNK = MSTOP-MSTART+1 + DZ = (ZF-ZS)/FLOAT(N) + TWBYDZ = 2./DZ + NP = NBDCND+1 + C3 = 1./(DZ**2) + NP1 = N+1 + NSTART = 1 + NSTOP = N + GO TO (108,105,105,106,106),NP + 105 NSTART = 2 + 106 GO TO (108,108,107,107,108),NP + 107 NSTOP = NP1 + 108 NUNK = NSTOP-NSTART+1 + LP1 = L+1 + DX = (XF-XS)/FLOAT(L) + C1 = 1./(DX**2) + TWBYDX = 2./DX + LP = LBDCND+1 + LSTART = 1 + LSTOP = L +C +C ENTER BOUNDARY DATA FOR X-BOUNDARIES. +C + GO TO (122,109,109,112,112),LP + 109 LSTART = 2 + DO 111 J=MSTART,MSTOP + DO 110 K=NSTART,NSTOP + F(2,J,K) = F(2,J,K)-C1*F(1,J,K) + 110 CONTINUE + 111 CONTINUE + GO TO 115 + 112 DO 114 J=MSTART,MSTOP + DO 113 K=NSTART,NSTOP + F(1,J,K) = F(1,J,K)+TWBYDX*BDXS(J,K) + 113 CONTINUE + 114 CONTINUE + 115 GO TO (122,116,119,119,116),LP + 116 DO 118 J=MSTART,MSTOP + DO 117 K=NSTART,NSTOP + F(L,J,K) = F(L,J,K)-C1*F(LP1,J,K) + 117 CONTINUE + 118 CONTINUE + GO TO 122 + 119 LSTOP = LP1 + DO 121 J=MSTART,MSTOP + DO 120 K=NSTART,NSTOP + F(LP1,J,K) = F(LP1,J,K)-TWBYDX*BDXF(J,K) + 120 CONTINUE + 121 CONTINUE + 122 LUNK = LSTOP-LSTART+1 +C +C ENTER BOUNDARY DATA FOR Y-BOUNDARIES. +C + GO TO (136,123,123,126,126),MP + 123 DO 125 I=LSTART,LSTOP + DO 124 K=NSTART,NSTOP + F(I,2,K) = F(I,2,K)-C2*F(I,1,K) + 124 CONTINUE + 125 CONTINUE + GO TO 129 + 126 DO 128 I=LSTART,LSTOP + DO 127 K=NSTART,NSTOP + F(I,1,K) = F(I,1,K)+TWBYDY*BDYS(I,K) + 127 CONTINUE + 128 CONTINUE + 129 GO TO (136,130,133,133,130),MP + 130 DO 132 I=LSTART,LSTOP + DO 131 K=NSTART,NSTOP + F(I,M,K) = F(I,M,K)-C2*F(I,MP1,K) + 131 CONTINUE + 132 CONTINUE + GO TO 136 + 133 DO 135 I=LSTART,LSTOP + DO 134 K=NSTART,NSTOP + F(I,MP1,K) = F(I,MP1,K)-TWBYDY*BDYF(I,K) + 134 CONTINUE + 135 CONTINUE + 136 CONTINUE +C +C ENTER BOUNDARY DATA FOR Z-BOUNDARIES. +C + GO TO (150,137,137,140,140),NP + 137 DO 139 I=LSTART,LSTOP + DO 138 J=MSTART,MSTOP + F(I,J,2) = F(I,J,2)-C3*F(I,J,1) + 138 CONTINUE + 139 CONTINUE + GO TO 143 + 140 DO 142 I=LSTART,LSTOP + DO 141 J=MSTART,MSTOP + F(I,J,1) = F(I,J,1)+TWBYDZ*BDZS(I,J) + 141 CONTINUE + 142 CONTINUE + 143 GO TO (150,144,147,147,144),NP + 144 DO 146 I=LSTART,LSTOP + DO 145 J=MSTART,MSTOP + F(I,J,N) = F(I,J,N)-C3*F(I,J,NP1) + 145 CONTINUE + 146 CONTINUE + GO TO 150 + 147 DO 149 I=LSTART,LSTOP + DO 148 J=MSTART,MSTOP + F(I,J,NP1) = F(I,J,NP1)-TWBYDZ*BDZF(I,J) + 148 CONTINUE + 149 CONTINUE +C +C DEFINE A,B,C COEFFICIENTS IN W-ARRAY. +C + 150 CONTINUE + IWB = NUNK+1 + IWC = IWB+NUNK + IWW = IWC+NUNK + DO 151 K=1,NUNK + I = IWC+K-1 + W(K) = C3 + W(I) = C3 + I = IWB+K-1 + W(I) = -2.*C3+ELMBDA + 151 CONTINUE + GO TO (155,155,153,152,152),NP + 152 W(IWC) = 2.*C3 + 153 GO TO (155,155,154,154,155),NP + 154 W(IWB-1) = 2.*C3 + 155 CONTINUE + PERTRB = 0. +C +C FOR SINGULAR PROBLEMS ADJUST DATA TO INSURE A SOLUTION WILL EXIST. +C + GO TO (156,172,172,156,172),LP + 156 GO TO (157,172,172,157,172),MP + 157 GO TO (158,172,172,158,172),NP + 158 IF (ELMBDA) 172,160,159 + 159 IERROR = 12 + GO TO 172 + 160 CONTINUE + MSTPM1 = MSTOP-1 + LSTPM1 = LSTOP-1 + NSTPM1 = NSTOP-1 + XLP = (2+LP)/3 + YLP = (2+MP)/3 + ZLP = (2+NP)/3 + S1 = 0. + DO 164 K=2,NSTPM1 + DO 162 J=2,MSTPM1 + DO 161 I=2,LSTPM1 + S1 = S1+F(I,J,K) + 161 CONTINUE + S1 = S1+(F(1,J,K)+F(LSTOP,J,K))/XLP + 162 CONTINUE + S2 = 0. + DO 163 I=2,LSTPM1 + S2 = S2+F(I,1,K)+F(I,MSTOP,K) + 163 CONTINUE + S2 = (S2+(F(1,1,K)+F(1,MSTOP,K)+F(LSTOP,1,K)+F(LSTOP,MSTOP,K))/ + 1 XLP)/YLP + S1 = S1+S2 + 164 CONTINUE + S = (F(1,1,1)+F(LSTOP,1,1)+F(1,1,NSTOP)+F(LSTOP,1,NSTOP)+ + 1 F(1,MSTOP,1)+F(LSTOP,MSTOP,1)+F(1,MSTOP,NSTOP)+ + 2 F(LSTOP,MSTOP,NSTOP))/(XLP*YLP) + DO 166 J=2,MSTPM1 + DO 165 I=2,LSTPM1 + S = S+F(I,J,1)+F(I,J,NSTOP) + 165 CONTINUE + 166 CONTINUE + S2 = 0. + DO 167 I=2,LSTPM1 + S2 = S2+F(I,1,1)+F(I,1,NSTOP)+F(I,MSTOP,1)+F(I,MSTOP,NSTOP) + 167 CONTINUE + S = S2/YLP+S + S2 = 0. + DO 168 J=2,MSTPM1 + S2 = S2+F(1,J,1)+F(1,J,NSTOP)+F(LSTOP,J,1)+F(LSTOP,J,NSTOP) + 168 CONTINUE + S = S2/XLP+S + PERTRB = (S/ZLP+S1)/((FLOAT(LUNK+1)-XLP)*(FLOAT(MUNK+1)-YLP)* + 1 (FLOAT(NUNK+1)-ZLP)) + DO 171 I=1,LUNK + DO 170 J=1,MUNK + DO 169 K=1,NUNK + F(I,J,K) = F(I,J,K)-PERTRB + 169 CONTINUE + 170 CONTINUE + 171 CONTINUE + 172 CONTINUE + NPEROD = 0 + IF (NBDCND .EQ. 0) GO TO 173 + NPEROD = 1 + W(1) = 0. + W(IWW-1) = 0. + 173 CONTINUE + CALL POIS3D (LBDCND,LUNK,C1,MBDCND,MUNK,C2,NPEROD,NUNK,W,W(IWB), + 1 W(IWC),LDIMF,MDIMF,F(LSTART,MSTART,NSTART),IR,W(IWW)) +C +C FILL IN SIDES FOR PERIODIC BOUNDARY CONDITIONS. +C + IF (LP .NE. 1) GO TO 180 + IF (MP .NE. 1) GO TO 175 + DO 174 K=NSTART,NSTOP + F(1,MP1,K) = F(1,1,K) + 174 CONTINUE + MSTOP = MP1 + 175 IF (NP .NE. 1) GO TO 177 + DO 176 J=MSTART,MSTOP + F(1,J,NP1) = F(1,J,1) + 176 CONTINUE + NSTOP = NP1 + 177 DO 179 J=MSTART,MSTOP + DO 178 K=NSTART,NSTOP + F(LP1,J,K) = F(1,J,K) + 178 CONTINUE + 179 CONTINUE + 180 CONTINUE + IF (MP .NE. 1) GO TO 185 + IF (NP .NE. 1) GO TO 182 + DO 181 I=LSTART,LSTOP + F(I,1,NP1) = F(I,1,1) + 181 CONTINUE + NSTOP = NP1 + 182 DO 184 I=LSTART,LSTOP + DO 183 K=NSTART,NSTOP + F(I,MP1,K) = F(I,1,K) + 183 CONTINUE + 184 CONTINUE + 185 CONTINUE + IF (NP .NE. 1) GO TO 188 + DO 187 I=LSTART,LSTOP + DO 186 J=MSTART,MSTOP + F(I,J,NP1) = F(I,J,1) + 186 CONTINUE + 187 CONTINUE + 188 CONTINUE + RETURN + END + SUBROUTINE PASSB(NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA) +C***BEGIN PROLOGUE PASSB +C***REFER TO CFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSB + DIMENSION CH(IDO,L1,IP) ,CC(IDO,IP,L1) , + 1 C1(IDO,L1,IP) ,WA(1) ,C2(IDL1,IP), + 2 CH2(IDL1,IP) +C***FIRST EXECUTABLE STATEMENT PASSB + IDOT = IDO/2 + NT = IP*IDL1 + IPP2 = IP+2 + IPPH = (IP+1)/2 + IDP = IP*IDO +C + IF (IDO .LT. L1) GO TO 106 + DO 103 J=2,IPPH + JC = IPP2-J + DO 102 K=1,L1 +CDIR$ IVDEP + DO 101 I=1,IDO + CH(I,K,J) = CC(I,J,K)+CC(I,JC,K) + CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K) + 101 CONTINUE + 102 CONTINUE + 103 CONTINUE + DO 105 K=1,L1 +CDIR$ IVDEP + DO 104 I=1,IDO + CH(I,K,1) = CC(I,1,K) + 104 CONTINUE + 105 CONTINUE + GO TO 112 + 106 DO 109 J=2,IPPH + JC = IPP2-J + DO 108 I=1,IDO +CDIR$ IVDEP + DO 107 K=1,L1 + CH(I,K,J) = CC(I,J,K)+CC(I,JC,K) + CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K) + 107 CONTINUE + 108 CONTINUE + 109 CONTINUE + DO 111 I=1,IDO +CDIR$ IVDEP + DO 110 K=1,L1 + CH(I,K,1) = CC(I,1,K) + 110 CONTINUE + 111 CONTINUE + 112 IDL = 2-IDO + INC = 0 + DO 116 L=2,IPPH + LC = IPP2-L + IDL = IDL+IDO +CDIR$ IVDEP + DO 113 IK=1,IDL1 + C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2) + C2(IK,LC) = WA(IDL)*CH2(IK,IP) + 113 CONTINUE + IDLJ = IDL + INC = INC+IDO + DO 115 J=3,IPPH + JC = IPP2-J + IDLJ = IDLJ+INC + IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP + WAR = WA(IDLJ-1) + WAI = WA(IDLJ) +CDIR$ IVDEP + DO 114 IK=1,IDL1 + C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J) + C2(IK,LC) = C2(IK,LC)+WAI*CH2(IK,JC) + 114 CONTINUE + 115 CONTINUE + 116 CONTINUE + DO 118 J=2,IPPH +CDIR$ IVDEP + DO 117 IK=1,IDL1 + CH2(IK,1) = CH2(IK,1)+CH2(IK,J) + 117 CONTINUE + 118 CONTINUE + DO 120 J=2,IPPH + JC = IPP2-J +CDIR$ IVDEP + DO 119 IK=2,IDL1,2 + CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC) + CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC) + CH2(IK,J) = C2(IK,J)+C2(IK-1,JC) + CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC) + 119 CONTINUE + 120 CONTINUE + NAC = 1 + IF (IDO .EQ. 2) RETURN + NAC = 0 + DO 121 IK=1,IDL1 + C2(IK,1) = CH2(IK,1) + 121 CONTINUE + DO 123 J=2,IP +CDIR$ IVDEP + DO 122 K=1,L1 + C1(1,K,J) = CH(1,K,J) + C1(2,K,J) = CH(2,K,J) + 122 CONTINUE + 123 CONTINUE + IF (IDOT .GT. L1) GO TO 127 + IDIJ = 0 + DO 126 J=2,IP + IDIJ = IDIJ+2 + DO 125 I=4,IDO,2 + IDIJ = IDIJ+2 +CDIR$ IVDEP + DO 124 K=1,L1 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J) + 124 CONTINUE + 125 CONTINUE + 126 CONTINUE + RETURN + 127 IDJ = 2-IDO + DO 130 J=2,IP + IDJ = IDJ+IDO + DO 129 K=1,L1 + IDIJ = IDJ +CDIR$ IVDEP + DO 128 I=4,IDO,2 + IDIJ = IDIJ+2 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J) + 128 CONTINUE + 129 CONTINUE + 130 CONTINUE + RETURN + END + SUBROUTINE PASSB2(IDO,L1,CC,CH,WA1) +C***BEGIN PROLOGUE PASSB2 +C***REFER TO CFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSB2 + DIMENSION CC(IDO,2,L1) ,CH(IDO,L1,2) , + 1 WA1(1) +C***FIRST EXECUTABLE STATEMENT PASSB2 + IF (IDO .GT. 2) GO TO 102 + DO 101 K=1,L1 + CH(1,K,1) = CC(1,1,K)+CC(1,2,K) + CH(1,K,2) = CC(1,1,K)-CC(1,2,K) + CH(2,K,1) = CC(2,1,K)+CC(2,2,K) + CH(2,K,2) = CC(2,1,K)-CC(2,2,K) + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K) + TR2 = CC(I-1,1,K)-CC(I-1,2,K) + CH(I,K,1) = CC(I,1,K)+CC(I,2,K) + TI2 = CC(I,1,K)-CC(I,2,K) + CH(I,K,2) = WA1(I-1)*TI2+WA1(I)*TR2 + CH(I-1,K,2) = WA1(I-1)*TR2-WA1(I)*TI2 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K) + TR2 = CC(I-1,1,K)-CC(I-1,2,K) + CH(I,K,1) = CC(I,1,K)+CC(I,2,K) + TI2 = CC(I,1,K)-CC(I,2,K) + CH(I,K,2) = WA1(I-1)*TI2+WA1(I)*TR2 + CH(I-1,K,2) = WA1(I-1)*TR2-WA1(I)*TI2 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSB3(IDO,L1,CC,CH,WA1,WA2) +C***BEGIN PROLOGUE PASSB3 +C***REFER TO CFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSB3 + DIMENSION CC(IDO,3,L1) ,CH(IDO,L1,3) , + 1 WA1(1) ,WA2(1) + DATA TAUR,TAUI /-.5,.866025403784439/ +C***FIRST EXECUTABLE STATEMENT PASSB3 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TR2 = CC(1,2,K)+CC(1,3,K) + CR2 = CC(1,1,K)+TAUR*TR2 + CH(1,K,1) = CC(1,1,K)+TR2 + TI2 = CC(2,2,K)+CC(2,3,K) + CI2 = CC(2,1,K)+TAUR*TI2 + CH(2,K,1) = CC(2,1,K)+TI2 + CR3 = TAUI*(CC(1,2,K)-CC(1,3,K)) + CI3 = TAUI*(CC(2,2,K)-CC(2,3,K)) + CH(1,K,2) = CR2-CI3 + CH(1,K,3) = CR2+CI3 + CH(2,K,2) = CI2+CR3 + CH(2,K,3) = CI2-CR3 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TR2 = CC(I-1,2,K)+CC(I-1,3,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,2,K)+CC(I,3,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K)) + CI3 = TAUI*(CC(I,2,K)-CC(I,3,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2 + CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2 + CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3 + CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TR2 = CC(I-1,2,K)+CC(I-1,3,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,2,K)+CC(I,3,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K)) + CI3 = TAUI*(CC(I,2,K)-CC(I,3,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2 + CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2 + CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3 + CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSB4(IDO,L1,CC,CH,WA1,WA2,WA3) +C***BEGIN PROLOGUE PASSB4 +C***REFER TO CFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSB4 + DIMENSION CC(IDO,4,L1) ,CH(IDO,L1,4) , + 1 WA1(1) ,WA2(1) ,WA3(1) +C***FIRST EXECUTABLE STATEMENT PASSB4 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TI1 = CC(2,1,K)-CC(2,3,K) + TI2 = CC(2,1,K)+CC(2,3,K) + TR4 = CC(2,4,K)-CC(2,2,K) + TI3 = CC(2,2,K)+CC(2,4,K) + TR1 = CC(1,1,K)-CC(1,3,K) + TR2 = CC(1,1,K)+CC(1,3,K) + TI4 = CC(1,2,K)-CC(1,4,K) + TR3 = CC(1,2,K)+CC(1,4,K) + CH(1,K,1) = TR2+TR3 + CH(1,K,3) = TR2-TR3 + CH(2,K,1) = TI2+TI3 + CH(2,K,3) = TI2-TI3 + CH(1,K,2) = TR1+TR4 + CH(1,K,4) = TR1-TR4 + CH(2,K,2) = TI1+TI4 + CH(2,K,4) = TI1-TI4 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TI1 = CC(I,1,K)-CC(I,3,K) + TI2 = CC(I,1,K)+CC(I,3,K) + TI3 = CC(I,2,K)+CC(I,4,K) + TR4 = CC(I,4,K)-CC(I,2,K) + TR1 = CC(I-1,1,K)-CC(I-1,3,K) + TR2 = CC(I-1,1,K)+CC(I-1,3,K) + TI4 = CC(I-1,2,K)-CC(I-1,4,K) + TR3 = CC(I-1,2,K)+CC(I-1,4,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1+TR4 + CR4 = TR1-TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-1)*CR2-WA1(I)*CI2 + CH(I,K,2) = WA1(I-1)*CI2+WA1(I)*CR2 + CH(I-1,K,3) = WA2(I-1)*CR3-WA2(I)*CI3 + CH(I,K,3) = WA2(I-1)*CI3+WA2(I)*CR3 + CH(I-1,K,4) = WA3(I-1)*CR4-WA3(I)*CI4 + CH(I,K,4) = WA3(I-1)*CI4+WA3(I)*CR4 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TI1 = CC(I,1,K)-CC(I,3,K) + TI2 = CC(I,1,K)+CC(I,3,K) + TI3 = CC(I,2,K)+CC(I,4,K) + TR4 = CC(I,4,K)-CC(I,2,K) + TR1 = CC(I-1,1,K)-CC(I-1,3,K) + TR2 = CC(I-1,1,K)+CC(I-1,3,K) + TI4 = CC(I-1,2,K)-CC(I-1,4,K) + TR3 = CC(I-1,2,K)+CC(I-1,4,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1+TR4 + CR4 = TR1-TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-1)*CR2-WA1(I)*CI2 + CH(I,K,2) = WA1(I-1)*CI2+WA1(I)*CR2 + CH(I-1,K,3) = WA2(I-1)*CR3-WA2(I)*CI3 + CH(I,K,3) = WA2(I-1)*CI3+WA2(I)*CR3 + CH(I-1,K,4) = WA3(I-1)*CR4-WA3(I)*CI4 + CH(I,K,4) = WA3(I-1)*CI4+WA3(I)*CR4 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSF(NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA) +C***BEGIN PROLOGUE PASSF +C***REFER TO CFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSF + DIMENSION CH(IDO,L1,IP) ,CC(IDO,IP,L1) , + 1 C1(IDO,L1,IP) ,WA(1) ,C2(IDL1,IP), + 2 CH2(IDL1,IP) +C***FIRST EXECUTABLE STATEMENT PASSF + IDOT = IDO/2 + NT = IP*IDL1 + IPP2 = IP+2 + IPPH = (IP+1)/2 + IDP = IP*IDO +C + IF (IDO .LT. L1) GO TO 106 + DO 103 J=2,IPPH + JC = IPP2-J + DO 102 K=1,L1 +CDIR$ IVDEP + DO 101 I=1,IDO + CH(I,K,J) = CC(I,J,K)+CC(I,JC,K) + CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K) + 101 CONTINUE + 102 CONTINUE + 103 CONTINUE + DO 105 K=1,L1 +CDIR$ IVDEP + DO 104 I=1,IDO + CH(I,K,1) = CC(I,1,K) + 104 CONTINUE + 105 CONTINUE + GO TO 112 + 106 DO 109 J=2,IPPH + JC = IPP2-J + DO 108 I=1,IDO +CDIR$ IVDEP + DO 107 K=1,L1 + CH(I,K,J) = CC(I,J,K)+CC(I,JC,K) + CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K) + 107 CONTINUE + 108 CONTINUE + 109 CONTINUE + DO 111 I=1,IDO +CDIR$ IVDEP + DO 110 K=1,L1 + CH(I,K,1) = CC(I,1,K) + 110 CONTINUE + 111 CONTINUE + 112 IDL = 2-IDO + INC = 0 + DO 116 L=2,IPPH + LC = IPP2-L + IDL = IDL+IDO +CDIR$ IVDEP + DO 113 IK=1,IDL1 + C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2) + C2(IK,LC) = -WA(IDL)*CH2(IK,IP) + 113 CONTINUE + IDLJ = IDL + INC = INC+IDO + DO 115 J=3,IPPH + JC = IPP2-J + IDLJ = IDLJ+INC + IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP + WAR = WA(IDLJ-1) + WAI = WA(IDLJ) +CDIR$ IVDEP + DO 114 IK=1,IDL1 + C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J) + C2(IK,LC) = C2(IK,LC)-WAI*CH2(IK,JC) + 114 CONTINUE + 115 CONTINUE + 116 CONTINUE + DO 118 J=2,IPPH +CDIR$ IVDEP + DO 117 IK=1,IDL1 + CH2(IK,1) = CH2(IK,1)+CH2(IK,J) + 117 CONTINUE + 118 CONTINUE + DO 120 J=2,IPPH + JC = IPP2-J +CDIR$ IVDEP + DO 119 IK=2,IDL1,2 + CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC) + CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC) + CH2(IK,J) = C2(IK,J)+C2(IK-1,JC) + CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC) + 119 CONTINUE + 120 CONTINUE + NAC = 1 + IF (IDO .EQ. 2) RETURN + NAC = 0 +CDIR$ IVDEP + DO 121 IK=1,IDL1 + C2(IK,1) = CH2(IK,1) + 121 CONTINUE + DO 123 J=2,IP +CDIR$ IVDEP + DO 122 K=1,L1 + C1(1,K,J) = CH(1,K,J) + C1(2,K,J) = CH(2,K,J) + 122 CONTINUE + 123 CONTINUE + IF (IDOT .GT. L1) GO TO 127 + IDIJ = 0 + DO 126 J=2,IP + IDIJ = IDIJ+2 + DO 125 I=4,IDO,2 + IDIJ = IDIJ+2 +CDIR$ IVDEP + DO 124 K=1,L1 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J) + 124 CONTINUE + 125 CONTINUE + 126 CONTINUE + RETURN + 127 IDJ = 2-IDO + DO 130 J=2,IP + IDJ = IDJ+IDO + DO 129 K=1,L1 + IDIJ = IDJ +CDIR$ IVDEP + DO 128 I=4,IDO,2 + IDIJ = IDIJ+2 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J) + 128 CONTINUE + 129 CONTINUE + 130 CONTINUE + RETURN + END + SUBROUTINE PASSF2(IDO,L1,CC,CH,WA1) +C***BEGIN PROLOGUE PASSF2 +C***REFER TO CFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSF2 + DIMENSION CC(IDO,2,L1) ,CH(IDO,L1,2) , + 1 WA1(1) +C***FIRST EXECUTABLE STATEMENT PASSF2 + IF (IDO .GT. 2) GO TO 102 + DO 101 K=1,L1 + CH(1,K,1) = CC(1,1,K)+CC(1,2,K) + CH(1,K,2) = CC(1,1,K)-CC(1,2,K) + CH(2,K,1) = CC(2,1,K)+CC(2,2,K) + CH(2,K,2) = CC(2,1,K)-CC(2,2,K) + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K) + TR2 = CC(I-1,1,K)-CC(I-1,2,K) + CH(I,K,1) = CC(I,1,K)+CC(I,2,K) + TI2 = CC(I,1,K)-CC(I,2,K) + CH(I,K,2) = WA1(I-1)*TI2-WA1(I)*TR2 + CH(I-1,K,2) = WA1(I-1)*TR2+WA1(I)*TI2 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K) + TR2 = CC(I-1,1,K)-CC(I-1,2,K) + CH(I,K,1) = CC(I,1,K)+CC(I,2,K) + TI2 = CC(I,1,K)-CC(I,2,K) + CH(I,K,2) = WA1(I-1)*TI2-WA1(I)*TR2 + CH(I-1,K,2) = WA1(I-1)*TR2+WA1(I)*TI2 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSF3(IDO,L1,CC,CH,WA1,WA2) +C***BEGIN PROLOGUE PASSF3 +C***REFER TO CFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSF3 + DIMENSION CC(IDO,3,L1) ,CH(IDO,L1,3) , + 1 WA1(1) ,WA2(1) + DATA TAUR,TAUI /-.5,-.866025403784439/ +C***FIRST EXECUTABLE STATEMENT PASSF3 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TR2 = CC(1,2,K)+CC(1,3,K) + CR2 = CC(1,1,K)+TAUR*TR2 + CH(1,K,1) = CC(1,1,K)+TR2 + TI2 = CC(2,2,K)+CC(2,3,K) + CI2 = CC(2,1,K)+TAUR*TI2 + CH(2,K,1) = CC(2,1,K)+TI2 + CR3 = TAUI*(CC(1,2,K)-CC(1,3,K)) + CI3 = TAUI*(CC(2,2,K)-CC(2,3,K)) + CH(1,K,2) = CR2-CI3 + CH(1,K,3) = CR2+CI3 + CH(2,K,2) = CI2+CR3 + CH(2,K,3) = CI2-CR3 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TR2 = CC(I-1,2,K)+CC(I-1,3,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,2,K)+CC(I,3,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K)) + CI3 = TAUI*(CC(I,2,K)-CC(I,3,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2 + CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2 + CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3 + CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TR2 = CC(I-1,2,K)+CC(I-1,3,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,2,K)+CC(I,3,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K)) + CI3 = TAUI*(CC(I,2,K)-CC(I,3,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2 + CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2 + CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3 + CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSF4(IDO,L1,CC,CH,WA1,WA2,WA3) +C***BEGIN PROLOGUE PASSF4 +C***REFER TO CFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSF4 + DIMENSION CC(IDO,4,L1) ,CH(IDO,L1,4) , + 1 WA1(1) ,WA2(1) ,WA3(1) +C***FIRST EXECUTABLE STATEMENT PASSF4 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TI1 = CC(2,1,K)-CC(2,3,K) + TI2 = CC(2,1,K)+CC(2,3,K) + TR4 = CC(2,2,K)-CC(2,4,K) + TI3 = CC(2,2,K)+CC(2,4,K) + TR1 = CC(1,1,K)-CC(1,3,K) + TR2 = CC(1,1,K)+CC(1,3,K) + TI4 = CC(1,4,K)-CC(1,2,K) + TR3 = CC(1,2,K)+CC(1,4,K) + CH(1,K,1) = TR2+TR3 + CH(1,K,3) = TR2-TR3 + CH(2,K,1) = TI2+TI3 + CH(2,K,3) = TI2-TI3 + CH(1,K,2) = TR1+TR4 + CH(1,K,4) = TR1-TR4 + CH(2,K,2) = TI1+TI4 + CH(2,K,4) = TI1-TI4 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TI1 = CC(I,1,K)-CC(I,3,K) + TI2 = CC(I,1,K)+CC(I,3,K) + TI3 = CC(I,2,K)+CC(I,4,K) + TR4 = CC(I,2,K)-CC(I,4,K) + TR1 = CC(I-1,1,K)-CC(I-1,3,K) + TR2 = CC(I-1,1,K)+CC(I-1,3,K) + TI4 = CC(I-1,4,K)-CC(I-1,2,K) + TR3 = CC(I-1,2,K)+CC(I-1,4,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1+TR4 + CR4 = TR1-TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-1)*CR2+WA1(I)*CI2 + CH(I,K,2) = WA1(I-1)*CI2-WA1(I)*CR2 + CH(I-1,K,3) = WA2(I-1)*CR3+WA2(I)*CI3 + CH(I,K,3) = WA2(I-1)*CI3-WA2(I)*CR3 + CH(I-1,K,4) = WA3(I-1)*CR4+WA3(I)*CI4 + CH(I,K,4) = WA3(I-1)*CI4-WA3(I)*CR4 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TI1 = CC(I,1,K)-CC(I,3,K) + TI2 = CC(I,1,K)+CC(I,3,K) + TI3 = CC(I,2,K)+CC(I,4,K) + TR4 = CC(I,2,K)-CC(I,4,K) + TR1 = CC(I-1,1,K)-CC(I-1,3,K) + TR2 = CC(I-1,1,K)+CC(I-1,3,K) + TI4 = CC(I-1,4,K)-CC(I-1,2,K) + TR3 = CC(I-1,2,K)+CC(I-1,4,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1+TR4 + CR4 = TR1-TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-1)*CR2+WA1(I)*CI2 + CH(I,K,2) = WA1(I-1)*CI2-WA1(I)*CR2 + CH(I-1,K,3) = WA2(I-1)*CR3+WA2(I)*CI3 + CH(I,K,3) = WA2(I-1)*CI3-WA2(I)*CR3 + CH(I-1,K,4) = WA3(I-1)*CR4+WA3(I)*CI4 + CH(I,K,4) = WA3(I-1)*CI4-WA3(I)*CR4 + 106 CONTINUE + 107 CONTINUE + RETURN + END + FUNCTION PIMACH(DUM) +C***BEGIN PROLOGUE PIMACH +C***REFER TO HSTCSP,HSTSSP,HWSCSP +C +C This subprogram supplies the value of the constant PI correct to +C machine precision where +C +C PI=3.1415926535897932384626433832795028841971693993751058209749446 +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PIMACH +C +C***FIRST EXECUTABLE STATEMENT PIMACH + PIMACH = 3.14159265358979 + RETURN + END + SUBROUTINE POIS3D(LPEROD,L,C1,MPEROD,M,C2,NPEROD,N,A,B,C,LDIMF, + 1 MDIMF,F,IERROR,W) +C***BEGIN PROLOGUE POIS3D +C***DATE WRITTEN 801001 (YYMMDD) +C***REVISION DATE 830415 (YYMMDD) +C***CATEGORY NO. I2B4B +C***KEYWORDS ELLIPTIC,FISHPACK,HELMHOLTZ,PDE,POISSON +C***AUTHOR ADAMS, J., (NCAR) +C SWARZTRAUBER, P., (NCAR) +C SWEET, R., (NCAR) +C***PURPOSE This subroutine solves three-dimensional block +C tridiagonal linear systems arising from finite +C difference approximations to three-dimensional +C Poisson equations using the Fourier transform +C package SCLRFFTPAK written by Paul Swarztrauber. +C***DESCRIPTION +C +C Subroutine POIS3D solves the linear system of equations +C +C C1*(X(I-1,J,K)-2.*X(I,J,K)+X(I+1,J,K)) +C + C2*(X(I,J-1,K)-2.*X(I,J,K)+X(I,J+1,K)) +C + A(K)*X(I,J,K-1)+B(K)*X(I,J,K)+C(K)*X(I,J,K+1) = F(I,J,K) +C +C for I=1,2,...,L , J=1,2,...,M , and K=1,2,...,N . +C +C The indices K-1 and K+1 are evaluated modulo N, i.e. +C X(I,J,0) = X(I,J,N) and X(I,J,N+1) = X(I,J,1). The unknowns +C X(0,J,K), X(L+1,J,K), X(I,0,K), and X(I,M+1,K) are assumed to take +C on certain prescribed values described below. +C +C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +C +C +C * * * * * * * * Parameter Description * * * * * * * * * * +C +C +C * * * * * * On Input * * * * * * +C +C LPEROD Indicates the values that X(0,J,K) and X(L+1,J,K) are +C assumed to have. +C +C = 0 If X(0,J,K) = X(L,J,K) and X(L+1,J,K) = X(1,J,K). +C = 1 If X(0,J,K) = X(L+1,J,K) = 0. +C = 2 If X(0,J,K) = 0 and X(L+1,J,K) = X(L-1,J,K). +C = 3 If X(0,J,K) = X(2,J,K) and X(L+1,J,K) = X(L-1,J,K). +C = 4 If X(0,J,K) = X(2,J,K) and X(L+1,J,K) = 0. +C +C L The number of unknowns in the I-direction. L must be at +C least 3. +C +C C1 The real constant that appears in the above equation. +C +C MPEROD Indicates the values that X(I,0,K) and X(I,M+1,K) are +C assumed to have. +C +C = 0 If X(I,0,K) = X(I,M,K) and X(I,M+1,K) = X(I,1,K). +C = 1 If X(I,0,K) = X(I,M+1,K) = 0. +C = 2 If X(I,0,K) = 0 and X(I,M+1,K) = X(I,M-1,K). +C = 3 If X(I,0,K) = X(I,2,K) and X(I,M+1,K) = X(I,M-1,K). +C = 4 If X(I,0,K) = X(I,2,K) and X(I,M+1,K) = 0. +C +C M The number of unknowns in the J-direction. M must be at +C least 3. +C +C C2 The real constant which appears in the above equation. +C +C NPEROD = 0 If A(1) and C(N) are not zero. +C = 1 If A(1) = C(N) = 0. +C +C N The number of unknowns in the K-direction. N must be at +C least 3. +C +C +C A,B,C One-dimensional arrays of length N that specify the +C coefficients in the linear equations given above. +C +C If NPEROD = 0 the array elements must not depend upon the +C index K, but must be constant. Specifically,the +C subroutine checks the following condition +C +C A(K) = C(1) +C C(K) = C(1) +C B(K) = B(1) +C +C for K=1,2,...,N. +C +C LDIMF The row (or first) dimension of the three-dimensional +C array F as it appears in the program calling POIS3D. +C This parameter is used to specify the variable dimension +C of F. LDIMF must be at least L. +C +C MDIMF The column (or second) dimension of the three-dimensional +C array F as it appears in the program calling POIS3D. +C This parameter is used to specify the variable dimension +C of F. MDIMF must be at least M. +C +C F A three-dimensional array that specifies the values of +C the right side of the linear system of equations given +C above. F must be dimensioned at least L x M x N. +C +C W A one-dimensional array that must be provided by the +C user for work space. The length of W must be at least +C 30 + L + M + 2*N + MAX(L,M,N) + +C 7*(INT((L+1)/2) + INT((M+1)/2)). +C +C +C * * * * * * On Output * * * * * * +C +C F Contains the solution X. +C +C IERROR An error flag that indicates invalid input parameters. +C Except for number zero, a solution is not attempted. +C = 0 No error +C = 1 If LPEROD .LT. 0 or .GT. 4 +C = 2 If L .LT. 3 +C = 3 If MPEROD .LT. 0 or .GT. 4 +C = 4 If M .LT. 3 +C = 5 If NPEROD .LT. 0 or .GT. 1 +C = 6 If N .LT. 3 +C = 7 If LDIMF .LT. L +C = 8 If MDIMF .LT. M +C = 9 If A(K) .NE. C(1) or C(K) .NE. C(1) or B(I) .NE.B(1) +C for some K=1,2,...,N. +C = 10 If NPEROD = 1 and A(1) .NE. 0 or C(N) .NE. 0 +C +C Since this is the only means of indicating a possibly +C incorrect call to POIS3D, the user should test IERROR +C after the call. +C***LONG DESCRIPTION +C +C * * * * * * * Program Specifications * * * * * * * * * * * * +C +C Dimension of A(N),B(N),C(N),F(LDIMF,MDIMF,N), +C Arguments W(see argument list) +C +C Latest December 1, 1978 +C Revision +C +C Subprograms POIS3D,POS3D1,TRID,RFFTI,RFFTF,RFFTF1,RFFTB, +C Required RFFTB1,COSTI,COST,SINTI,SINT,COSQI,COSQF,COSQF1 +C COSQB,COSQB1,SINQI,SINQF,SINQB,CFFTI,CFFTI1, +C CFFTB,CFFTB1,PASSB2,PASSB3,PASSB4,PASSB,CFFTF, +C CFFTF1,PASSF1,PASSF2,PASSF3,PASSF4,PASSF,PIMACH, +C +C Special NONE +C Conditions +C +C Common NONE +C Blocks +C +C I/O NONE +C +C Precision Single +C +C Specialist Roland Sweet +C +C Language FORTRAN +C +C History Written by Roland Sweet at NCAR in July,1977 +C +C Algorithm This subroutine solves three-dimensional block +C tridiagonal linear systems arising from finite +C difference approximations to three-dimensional +C Poisson equations using the Fourier transform +C package SCLRFFTPAK written by Paul Swarztrauber. +C +C Space 6561(decimal) = 14641(octal) locations on the +C Required NCAR Control Data 7600 +C +C Timing and The execution time T on the NCAR Control Data +C Accuracy 7600 for subroutine POIS3D is roughly proportional +C to L*M*N*(log2(L)+log2(M)+5), but also depends on +C input parameters LPEROD and MPEROD. Some typical +C values are listed in the table below when NPEROD=0. +C To measure the accuracy of the algorithm a +C uniform random number generator was used to create +C a solution array X for the system given in the +C 'PURPOSE' with +C +C A(K) = C(K) = -0.5*B(K) = 1, K=1,2,...,N +C +C and, when NPEROD = 1 +C +C A(1) = C(N) = 0 +C A(N) = C(1) = 2. +C +C The solution X was substituted into the given sys- +C tem and, using double precision, a right side Y was +C computed. Using this array Y subroutine POIS3D was +C called to produce an approximate solution Z. Then +C the relative error, defined as +C +C E = MAX(ABS(Z(I,J,K)-X(I,J,K)))/MAX(ABS(X(I,J,K))) +C +C where the two maxima are taken over I=1,2,...,L, +C J=1,2,...,M and K=1,2,...,N, was computed. The +C value of E is given in the table below for some +C typical values of L,M and N. +C +C +C L(=M=N) LPEROD MPEROD T(MSECS) E +C ------ ------ ------ -------- ------ +C +C 16 0 0 272 1.E-13 +C 15 1 1 287 4.E-13 +C 17 3 3 338 2.E-13 +C 32 0 0 1755 2.E-13 +C 31 1 1 1894 2.E-12 +C 33 3 3 2042 7.E-13 +C +C +C Portability American National Standards Institute FORTRAN. +C The machine dependent constant PI is defined in +C function PIMACH. +C +C Required COS,SIN,ATAN +C Resident +C Routines +C +C Reference NONE +C +C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +C***REFERENCES (NONE) +C***ROUTINES CALLED POS3D1 +C***END PROLOGUE POIS3D +C +C + DIMENSION A(1) ,B(1) ,C(1) , + 1 F(LDIMF,MDIMF,1) ,W(1) ,SAVE(6) +C***FIRST EXECUTABLE STATEMENT POIS3D + LP = LPEROD+1 + MP = MPEROD+1 + NP = NPEROD+1 +C +C CHECK FOR INVALID INPUT. +C + IERROR = 0 + IF (LP.LT.1 .OR. LP.GT.5) IERROR = 1 + IF (L .LT. 3) IERROR = 2 + IF (MP.LT.1 .OR. MP.GT.5) IERROR = 3 + IF (M .LT. 3) IERROR = 4 + IF (NP.LT.1 .OR. NP.GT.2) IERROR = 5 + IF (N .LT. 3) IERROR = 6 + IF (LDIMF .LT. L) IERROR = 7 + IF (MDIMF .LT. M) IERROR = 8 + IF (NP .NE. 1) GO TO 103 + DO 101 K=1,N + IF (A(K) .NE. C(1)) GO TO 102 + IF (C(K) .NE. C(1)) GO TO 102 + IF (B(K) .NE. B(1)) GO TO 102 + 101 CONTINUE + GO TO 104 + 102 IERROR = 9 + 103 IF (NPEROD.EQ.1 .AND. (A(1).NE.0. .OR. C(N).NE.0.)) IERROR = 10 + 104 IF (IERROR .NE. 0) GO TO 122 + IWYRT = L+1 + IWT = IWYRT+M + IWD = IWT+MAX0(L,M,N)+1 + IWBB = IWD+N + IWX = IWBB+N + IWY = IWX+7*((L+1)/2)+15 + GO TO (105,114),NP +C +C REORDER UNKNOWNS WHEN NPEROD = 0. +C + 105 NH = (N+1)/2 + NHM1 = NH-1 + NODD = 1 + IF (2*NH .EQ. N) NODD = 2 + DO 111 I=1,L + DO 110 J=1,M + DO 106 K=1,NHM1 + NHPK = NH+K + NHMK = NH-K + W(K) = F(I,J,NHMK)-F(I,J,NHPK) + W(NHPK) = F(I,J,NHMK)+F(I,J,NHPK) + 106 CONTINUE + W(NH) = 2.*F(I,J,NH) + GO TO (108,107),NODD + 107 W(N) = 2.*F(I,J,N) + 108 DO 109 K=1,N + F(I,J,K) = W(K) + 109 CONTINUE + 110 CONTINUE + 111 CONTINUE + SAVE(1) = C(NHM1) + SAVE(2) = A(NH) + SAVE(3) = C(NH) + SAVE(4) = B(NHM1) + SAVE(5) = B(N) + SAVE(6) = A(N) + C(NHM1) = 0. + A(NH) = 0. + C(NH) = 2.*C(NH) + GO TO (112,113),NODD + 112 B(NHM1) = B(NHM1)-A(NH-1) + B(N) = B(N)+A(N) + GO TO 114 + 113 A(N) = C(NH) + 114 CONTINUE + CALL POS3D1 (LP,L,MP,M,N,A,B,C,LDIMF,MDIMF,F,W,W(IWYRT),W(IWT), + 1 W(IWD),W(IWX),W(IWY),C1,C2,W(IWBB)) + GO TO (115,122),NP + 115 DO 121 I=1,L + DO 120 J=1,M + DO 116 K=1,NHM1 + NHMK = NH-K + NHPK = NH+K + W(NHMK) = .5*(F(I,J,NHPK)+F(I,J,K)) + W(NHPK) = .5*(F(I,J,NHPK)-F(I,J,K)) + 116 CONTINUE + W(NH) = .5*F(I,J,NH) + GO TO (118,117),NODD + 117 W(N) = .5*F(I,J,N) + 118 DO 119 K=1,N + F(I,J,K) = W(K) + 119 CONTINUE + 120 CONTINUE + 121 CONTINUE + C(NHM1) = SAVE(1) + A(NH) = SAVE(2) + C(NH) = SAVE(3) + B(NHM1) = SAVE(4) + B(N) = SAVE(5) + A(N) = SAVE(6) + 122 CONTINUE + RETURN + END + SUBROUTINE POS3D1(LP,L,MP,M,N,A,B,C,LDIMF,MDIMF,F,XRT,YRT,T,D,WX, + 1 WY,C1,C2,BB) +C***BEGIN PROLOGUE POS3D1 +C***REFER TO POIS3D +C***ROUTINES CALLED COSQB,COSQF,COSQI,COST,COSTI,PIMACH,RFFTB,RFFTF, +C RFFTI,SINQB,SINQF,SINQI,SINT,SINTI,TRID +C***END PROLOGUE POS3D1 + DIMENSION A(1) ,B(1) ,C(1) , + 1 F(LDIMF,MDIMF,1) ,XRT(1) ,YRT(1) , + 2 T(1) ,D(1) ,WX(1) ,WY(1) , + 3 BB(1) +C***FIRST EXECUTABLE STATEMENT POS3D1 + PI = PIMACH(DUM) + LR = L + MR = M + NR = N +C +C GENERATE TRANSFORM ROOTS +C + LRDEL = ((LP-1)*(LP-3)*(LP-5))/3 + SCALX = LR+LRDEL + DX = PI/(2.*SCALX) + GO TO (108,103,101,102,101),LP + 101 DI = 0.5 + SCALX = 2.*SCALX + GO TO 104 + 102 DI = 1.0 + GO TO 104 + 103 DI = 0.0 + 104 DO 105 I=1,LR + XRT(I) = -4.*C1*(SIN((FLOAT(I)-DI)*DX))**2 + 105 CONTINUE + SCALX = 2.*SCALX + GO TO (112,106,110,107,111),LP + 106 CALL SINTI (LR,WX) + GO TO 112 + 107 CALL COSTI (LR,WX) + GO TO 112 + 108 XRT(1) = 0. + XRT(LR) = -4.*C1 + DO 109 I=3,LR,2 + XRT(I-1) = -4.*C1*(SIN(FLOAT((I-1))*DX))**2 + XRT(I) = XRT(I-1) + 109 CONTINUE + CALL RFFTI (LR,WX) + GO TO 112 + 110 CALL SINQI (LR,WX) + GO TO 112 + 111 CALL COSQI (LR,WX) + 112 CONTINUE + MRDEL = ((MP-1)*(MP-3)*(MP-5))/3 + SCALY = MR+MRDEL + DY = PI/(2.*SCALY) + GO TO (120,115,113,114,113),MP + 113 DJ = 0.5 + SCALY = 2.*SCALY + GO TO 116 + 114 DJ = 1.0 + GO TO 116 + 115 DJ = 0.0 + 116 DO 117 J=1,MR + YRT(J) = -4.*C2*(SIN((FLOAT(J)-DJ)*DY))**2 + 117 CONTINUE + SCALY = 2.*SCALY + GO TO (124,118,122,119,123),MP + 118 CALL SINTI (MR,WY) + GO TO 124 + 119 CALL COSTI (MR,WY) + GO TO 124 + 120 YRT(1) = 0. + YRT(MR) = -4.*C2 + DO 121 J=3,MR,2 + YRT(J-1) = -4.*C2*(SIN(FLOAT((J-1))*DY))**2 + YRT(J) = YRT(J-1) + 121 CONTINUE + CALL RFFTI (MR,WY) + GO TO 124 + 122 CALL SINQI (MR,WY) + GO TO 124 + 123 CALL COSQI (MR,WY) + 124 CONTINUE + IFWRD = 1 + IS = 1 + 125 CONTINUE +C +C TRANSFORM X +C + DO 141 J=1,MR + DO 140 K=1,NR + DO 126 I=1,LR + T(I) = F(I,J,K) + 126 CONTINUE + GO TO (127,130,131,134,135),LP + 127 GO TO (128,129),IFWRD + 128 CALL RFFTF (LR,T,WX) + GO TO 138 + 129 CALL RFFTB (LR,T,WX) + GO TO 138 + 130 CALL SINT (LR,T,WX) + GO TO 138 + 131 GO TO (132,133),IFWRD + 132 CALL SINQF (LR,T,WX) + GO TO 138 + 133 CALL SINQB (LR,T,WX) + GO TO 138 + 134 CALL COST (LR,T,WX) + GO TO 138 + 135 GO TO (136,137),IFWRD + 136 CALL COSQF (LR,T,WX) + GO TO 138 + 137 CALL COSQB (LR,T,WX) + 138 CONTINUE + DO 139 I=1,LR + F(I,J,K) = T(I) + 139 CONTINUE + 140 CONTINUE + 141 CONTINUE + GO TO (142,164),IFWRD +C +C TRANSFORM Y +C + 142 CONTINUE + DO 158 I=1,LR + DO 157 K=1,NR + DO 143 J=1,MR + T(J) = F(I,J,K) + 143 CONTINUE + GO TO (144,147,148,151,152),MP + 144 GO TO (145,146),IFWRD + 145 CALL RFFTF (MR,T,WY) + GO TO 155 + 146 CALL RFFTB (MR,T,WY) + GO TO 155 + 147 CALL SINT (MR,T,WY) + GO TO 155 + 148 GO TO (149,150),IFWRD + 149 CALL SINQF (MR,T,WY) + GO TO 155 + 150 CALL SINQB (MR,T,WY) + GO TO 155 + 151 CALL COST (MR,T,WY) + GO TO 155 + 152 GO TO (153,154),IFWRD + 153 CALL COSQF (MR,T,WY) + GO TO 155 + 154 CALL COSQB (MR,T,WY) + 155 CONTINUE + DO 156 J=1,MR + F(I,J,K) = T(J) + 156 CONTINUE + 157 CONTINUE + 158 CONTINUE + GO TO (159,125),IFWRD + 159 CONTINUE +C +C SOLVE TRIDIAGONAL SYSTEMS IN Z +C + DO 163 I=1,LR + DO 162 J=1,MR + DO 160 K=1,NR + BB(K) = B(K)+XRT(I)+YRT(J) + T(K) = F(I,J,K) + 160 CONTINUE + CALL TRID (NR,A,BB,C,T,D) + DO 161 K=1,NR + F(I,J,K) = T(K) + 161 CONTINUE + 162 CONTINUE + 163 CONTINUE + IFWRD = 2 + IS = -1 + GO TO 142 + 164 CONTINUE + DO 167 I=1,LR + DO 166 J=1,MR + DO 165 K=1,NR + F(I,J,K) = F(I,J,K)/(SCALX*SCALY) + 165 CONTINUE + 166 CONTINUE + 167 CONTINUE + RETURN + END + SUBROUTINE RADB2(IDO,L1,CC,CH,WA1) +C***BEGIN PROLOGUE RADB2 +C***REFER TO RFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADB2 + DIMENSION CC(IDO,2,L1) ,CH(IDO,L1,2) , + 1 WA1(1) +C***FIRST EXECUTABLE STATEMENT RADB2 + DO 101 K=1,L1 + CH(1,K,1) = CC(1,1,K)+CC(IDO,2,K) + CH(1,K,2) = CC(1,1,K)-CC(IDO,2,K) + 101 CONTINUE + IF (IDO-2) 107,105,102 + 102 IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 108 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=3,IDO,2 + IC = IDP2-I + CH(I-1,K,1) = CC(I-1,1,K)+CC(IC-1,2,K) + TR2 = CC(I-1,1,K)-CC(IC-1,2,K) + CH(I,K,1) = CC(I,1,K)-CC(IC,2,K) + TI2 = CC(I,1,K)+CC(IC,2,K) + CH(I-1,K,2) = WA1(I-2)*TR2-WA1(I-1)*TI2 + CH(I,K,2) = WA1(I-2)*TI2+WA1(I-1)*TR2 + 103 CONTINUE + 104 CONTINUE + GO TO 111 + 108 DO 110 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 109 K=1,L1 + CH(I-1,K,1) = CC(I-1,1,K)+CC(IC-1,2,K) + TR2 = CC(I-1,1,K)-CC(IC-1,2,K) + CH(I,K,1) = CC(I,1,K)-CC(IC,2,K) + TI2 = CC(I,1,K)+CC(IC,2,K) + CH(I-1,K,2) = WA1(I-2)*TR2-WA1(I-1)*TI2 + CH(I,K,2) = WA1(I-2)*TI2+WA1(I-1)*TR2 + 109 CONTINUE + 110 CONTINUE + 111 IF (MOD(IDO,2) .EQ. 1) RETURN + 105 DO 106 K=1,L1 + CH(IDO,K,1) = CC(IDO,1,K)+CC(IDO,1,K) + CH(IDO,K,2) = -(CC(1,2,K)+CC(1,2,K)) + 106 CONTINUE + 107 RETURN + END + SUBROUTINE RADB3(IDO,L1,CC,CH,WA1,WA2) +C***BEGIN PROLOGUE RADB3 +C***REFER TO RFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADB3 + DIMENSION CC(IDO,3,L1) ,CH(IDO,L1,3) , + 1 WA1(1) ,WA2(1) + DATA TAUR,TAUI /-.5,.866025403784439/ +C***FIRST EXECUTABLE STATEMENT RADB3 + DO 101 K=1,L1 + TR2 = CC(IDO,2,K)+CC(IDO,2,K) + CR2 = CC(1,1,K)+TAUR*TR2 + CH(1,K,1) = CC(1,1,K)+TR2 + CI3 = TAUI*(CC(1,3,K)+CC(1,3,K)) + CH(1,K,2) = CR2-CI3 + CH(1,K,3) = CR2+CI3 + 101 CONTINUE + IF (IDO .EQ. 1) RETURN + IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 104 + DO 103 K=1,L1 +CDIR$ IVDEP + DO 102 I=3,IDO,2 + IC = IDP2-I + TR2 = CC(I-1,3,K)+CC(IC-1,2,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,3,K)-CC(IC,2,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,3,K)-CC(IC-1,2,K)) + CI3 = TAUI*(CC(I,3,K)+CC(IC,2,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2 + CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2 + CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3 + CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3 + 102 CONTINUE + 103 CONTINUE + RETURN + 104 DO 106 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 105 K=1,L1 + TR2 = CC(I-1,3,K)+CC(IC-1,2,K) + CR2 = CC(I-1,1,K)+TAUR*TR2 + CH(I-1,K,1) = CC(I-1,1,K)+TR2 + TI2 = CC(I,3,K)-CC(IC,2,K) + CI2 = CC(I,1,K)+TAUR*TI2 + CH(I,K,1) = CC(I,1,K)+TI2 + CR3 = TAUI*(CC(I-1,3,K)-CC(IC-1,2,K)) + CI3 = TAUI*(CC(I,3,K)+CC(IC,2,K)) + DR2 = CR2-CI3 + DR3 = CR2+CI3 + DI2 = CI2+CR3 + DI3 = CI2-CR3 + CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2 + CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2 + CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3 + CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3 + 105 CONTINUE + 106 CONTINUE + RETURN + END + SUBROUTINE RADB4(IDO,L1,CC,CH,WA1,WA2,WA3) +C***BEGIN PROLOGUE RADB4 +C***REFER TO RFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADB4 + DIMENSION CC(IDO,4,L1) ,CH(IDO,L1,4) , + 1 WA1(1) ,WA2(1) ,WA3(1) + DATA SQRT2 /1.414213562373095/ +C***FIRST EXECUTABLE STATEMENT RADB4 + DO 101 K=1,L1 + TR1 = CC(1,1,K)-CC(IDO,4,K) + TR2 = CC(1,1,K)+CC(IDO,4,K) + TR3 = CC(IDO,2,K)+CC(IDO,2,K) + TR4 = CC(1,3,K)+CC(1,3,K) + CH(1,K,1) = TR2+TR3 + CH(1,K,2) = TR1-TR4 + CH(1,K,3) = TR2-TR3 + CH(1,K,4) = TR1+TR4 + 101 CONTINUE + IF (IDO-2) 107,105,102 + 102 IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 108 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=3,IDO,2 + IC = IDP2-I + TI1 = CC(I,1,K)+CC(IC,4,K) + TI2 = CC(I,1,K)-CC(IC,4,K) + TI3 = CC(I,3,K)-CC(IC,2,K) + TR4 = CC(I,3,K)+CC(IC,2,K) + TR1 = CC(I-1,1,K)-CC(IC-1,4,K) + TR2 = CC(I-1,1,K)+CC(IC-1,4,K) + TI4 = CC(I-1,3,K)-CC(IC-1,2,K) + TR3 = CC(I-1,3,K)+CC(IC-1,2,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1-TR4 + CR4 = TR1+TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-2)*CR2-WA1(I-1)*CI2 + CH(I,K,2) = WA1(I-2)*CI2+WA1(I-1)*CR2 + CH(I-1,K,3) = WA2(I-2)*CR3-WA2(I-1)*CI3 + CH(I,K,3) = WA2(I-2)*CI3+WA2(I-1)*CR3 + CH(I-1,K,4) = WA3(I-2)*CR4-WA3(I-1)*CI4 + CH(I,K,4) = WA3(I-2)*CI4+WA3(I-1)*CR4 + 103 CONTINUE + 104 CONTINUE + GO TO 111 + 108 DO 110 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 109 K=1,L1 + TI1 = CC(I,1,K)+CC(IC,4,K) + TI2 = CC(I,1,K)-CC(IC,4,K) + TI3 = CC(I,3,K)-CC(IC,2,K) + TR4 = CC(I,3,K)+CC(IC,2,K) + TR1 = CC(I-1,1,K)-CC(IC-1,4,K) + TR2 = CC(I-1,1,K)+CC(IC-1,4,K) + TI4 = CC(I-1,3,K)-CC(IC-1,2,K) + TR3 = CC(I-1,3,K)+CC(IC-1,2,K) + CH(I-1,K,1) = TR2+TR3 + CR3 = TR2-TR3 + CH(I,K,1) = TI2+TI3 + CI3 = TI2-TI3 + CR2 = TR1-TR4 + CR4 = TR1+TR4 + CI2 = TI1+TI4 + CI4 = TI1-TI4 + CH(I-1,K,2) = WA1(I-2)*CR2-WA1(I-1)*CI2 + CH(I,K,2) = WA1(I-2)*CI2+WA1(I-1)*CR2 + CH(I-1,K,3) = WA2(I-2)*CR3-WA2(I-1)*CI3 + CH(I,K,3) = WA2(I-2)*CI3+WA2(I-1)*CR3 + CH(I-1,K,4) = WA3(I-2)*CR4-WA3(I-1)*CI4 + CH(I,K,4) = WA3(I-2)*CI4+WA3(I-1)*CR4 + 109 CONTINUE + 110 CONTINUE + 111 IF (MOD(IDO,2) .EQ. 1) RETURN + 105 DO 106 K=1,L1 + TI1 = CC(1,2,K)+CC(1,4,K) + TI2 = CC(1,4,K)-CC(1,2,K) + TR1 = CC(IDO,1,K)-CC(IDO,3,K) + TR2 = CC(IDO,1,K)+CC(IDO,3,K) + CH(IDO,K,1) = TR2+TR2 + CH(IDO,K,2) = SQRT2*(TR1-TI1) + CH(IDO,K,3) = TI2+TI2 + CH(IDO,K,4) = -SQRT2*(TR1+TI1) + 106 CONTINUE + 107 RETURN + END + SUBROUTINE RADB5(IDO,L1,CC,CH,WA1,WA2,WA3,WA4) +C***BEGIN PROLOGUE RADB5 +C***REFER TO RFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADB5 + DIMENSION CC(IDO,5,L1) ,CH(IDO,L1,5) , + 1 WA1(1) ,WA2(1) ,WA3(1) ,WA4(1) + DATA TR11,TI11,TR12,TI12 /.309016994374947,.951056516295154, + 1-.809016994374947,.587785252292473/ +C***FIRST EXECUTABLE STATEMENT RADB5 + DO 101 K=1,L1 + TI5 = CC(1,3,K)+CC(1,3,K) + TI4 = CC(1,5,K)+CC(1,5,K) + TR2 = CC(IDO,2,K)+CC(IDO,2,K) + TR3 = CC(IDO,4,K)+CC(IDO,4,K) + CH(1,K,1) = CC(1,1,K)+TR2+TR3 + CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3 + CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3 + CI5 = TI11*TI5+TI12*TI4 + CI4 = TI12*TI5-TI11*TI4 + CH(1,K,2) = CR2-CI5 + CH(1,K,3) = CR3-CI4 + CH(1,K,4) = CR3+CI4 + CH(1,K,5) = CR2+CI5 + 101 CONTINUE + IF (IDO .EQ. 1) RETURN + IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 104 + DO 103 K=1,L1 +CDIR$ IVDEP + DO 102 I=3,IDO,2 + IC = IDP2-I + TI5 = CC(I,3,K)+CC(IC,2,K) + TI2 = CC(I,3,K)-CC(IC,2,K) + TI4 = CC(I,5,K)+CC(IC,4,K) + TI3 = CC(I,5,K)-CC(IC,4,K) + TR5 = CC(I-1,3,K)-CC(IC-1,2,K) + TR2 = CC(I-1,3,K)+CC(IC-1,2,K) + TR4 = CC(I-1,5,K)-CC(IC-1,4,K) + TR3 = CC(I-1,5,K)+CC(IC-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2 + CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2 + CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3 + CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3 + CH(I-1,K,4) = WA3(I-2)*DR4-WA3(I-1)*DI4 + CH(I,K,4) = WA3(I-2)*DI4+WA3(I-1)*DR4 + CH(I-1,K,5) = WA4(I-2)*DR5-WA4(I-1)*DI5 + CH(I,K,5) = WA4(I-2)*DI5+WA4(I-1)*DR5 + 102 CONTINUE + 103 CONTINUE + RETURN + 104 DO 106 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 105 K=1,L1 + TI5 = CC(I,3,K)+CC(IC,2,K) + TI2 = CC(I,3,K)-CC(IC,2,K) + TI4 = CC(I,5,K)+CC(IC,4,K) + TI3 = CC(I,5,K)-CC(IC,4,K) + TR5 = CC(I-1,3,K)-CC(IC-1,2,K) + TR2 = CC(I-1,3,K)+CC(IC-1,2,K) + TR4 = CC(I-1,5,K)-CC(IC-1,4,K) + TR3 = CC(I-1,5,K)+CC(IC-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2 + CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2 + CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3 + CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3 + CH(I-1,K,4) = WA3(I-2)*DR4-WA3(I-1)*DI4 + CH(I,K,4) = WA3(I-2)*DI4+WA3(I-1)*DR4 + CH(I-1,K,5) = WA4(I-2)*DR5-WA4(I-1)*DI5 + CH(I,K,5) = WA4(I-2)*DI5+WA4(I-1)*DR5 + 105 CONTINUE + 106 CONTINUE + RETURN + END + SUBROUTINE RADBG(IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA) +C***BEGIN PROLOGUE RADBG +C***REFER TO RFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADBG + DIMENSION CH(IDO,L1,IP) ,CC(IDO,IP,L1) , + 1 C1(IDO,L1,IP) ,C2(IDL1,IP), + 2 CH2(IDL1,IP) ,WA(1) + DATA TPI/6.28318530717959/ +C***FIRST EXECUTABLE STATEMENT RADBG + ARG = TPI/FLOAT(IP) + DCP = COS(ARG) + DSP = SIN(ARG) + IDP2 = IDO+2 + NBD = (IDO-1)/2 + IPP2 = IP+2 + IPPH = (IP+1)/2 + IF (IDO .LT. L1) GO TO 103 + DO 102 K=1,L1 + DO 101 I=1,IDO + CH(I,K,1) = CC(I,1,K) + 101 CONTINUE + 102 CONTINUE + GO TO 106 + 103 DO 105 I=1,IDO + DO 104 K=1,L1 + CH(I,K,1) = CC(I,1,K) + 104 CONTINUE + 105 CONTINUE + 106 DO 108 J=2,IPPH + JC = IPP2-J + J2 = J+J + DO 107 K=1,L1 + CH(1,K,J) = CC(IDO,J2-2,K)+CC(IDO,J2-2,K) + CH(1,K,JC) = CC(1,J2-1,K)+CC(1,J2-1,K) + 107 CONTINUE + 108 CONTINUE + IF (IDO .EQ. 1) GO TO 116 + IF (NBD .LT. L1) GO TO 112 + DO 111 J=2,IPPH + JC = IPP2-J + DO 110 K=1,L1 +CDIR$ IVDEP + DO 109 I=3,IDO,2 + IC = IDP2-I + CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K) + CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K) + CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K) + CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K) + 109 CONTINUE + 110 CONTINUE + 111 CONTINUE + GO TO 116 + 112 DO 115 J=2,IPPH + JC = IPP2-J +CDIR$ IVDEP + DO 114 I=3,IDO,2 + IC = IDP2-I + DO 113 K=1,L1 + CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K) + CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K) + CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K) + CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K) + 113 CONTINUE + 114 CONTINUE + 115 CONTINUE + 116 AR1 = 1. + AI1 = 0. + DO 120 L=2,IPPH + LC = IPP2-L + AR1H = DCP*AR1-DSP*AI1 + AI1 = DCP*AI1+DSP*AR1 + AR1 = AR1H + DO 117 IK=1,IDL1 + C2(IK,L) = CH2(IK,1)+AR1*CH2(IK,2) + C2(IK,LC) = AI1*CH2(IK,IP) + 117 CONTINUE + DC2 = AR1 + DS2 = AI1 + AR2 = AR1 + AI2 = AI1 + DO 119 J=3,IPPH + JC = IPP2-J + AR2H = DC2*AR2-DS2*AI2 + AI2 = DC2*AI2+DS2*AR2 + AR2 = AR2H + DO 118 IK=1,IDL1 + C2(IK,L) = C2(IK,L)+AR2*CH2(IK,J) + C2(IK,LC) = C2(IK,LC)+AI2*CH2(IK,JC) + 118 CONTINUE + 119 CONTINUE + 120 CONTINUE + DO 122 J=2,IPPH + DO 121 IK=1,IDL1 + CH2(IK,1) = CH2(IK,1)+CH2(IK,J) + 121 CONTINUE + 122 CONTINUE + DO 124 J=2,IPPH + JC = IPP2-J + DO 123 K=1,L1 + CH(1,K,J) = C1(1,K,J)-C1(1,K,JC) + CH(1,K,JC) = C1(1,K,J)+C1(1,K,JC) + 123 CONTINUE + 124 CONTINUE + IF (IDO .EQ. 1) GO TO 132 + IF (NBD .LT. L1) GO TO 128 + DO 127 J=2,IPPH + JC = IPP2-J + DO 126 K=1,L1 +CDIR$ IVDEP + DO 125 I=3,IDO,2 + CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC) + CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC) + CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC) + CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC) + 125 CONTINUE + 126 CONTINUE + 127 CONTINUE + GO TO 132 + 128 DO 131 J=2,IPPH + JC = IPP2-J + DO 130 I=3,IDO,2 + DO 129 K=1,L1 + CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC) + CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC) + CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC) + CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC) + 129 CONTINUE + 130 CONTINUE + 131 CONTINUE + 132 CONTINUE + IF (IDO .EQ. 1) RETURN + DO 133 IK=1,IDL1 + C2(IK,1) = CH2(IK,1) + 133 CONTINUE + DO 135 J=2,IP + DO 134 K=1,L1 + C1(1,K,J) = CH(1,K,J) + 134 CONTINUE + 135 CONTINUE + IF (NBD .GT. L1) GO TO 139 + IS = -IDO + DO 138 J=2,IP + IS = IS+IDO + IDIJ = IS + DO 137 I=3,IDO,2 + IDIJ = IDIJ+2 + DO 136 K=1,L1 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J) + 136 CONTINUE + 137 CONTINUE + 138 CONTINUE + GO TO 143 + 139 IS = -IDO + DO 142 J=2,IP + IS = IS+IDO + DO 141 K=1,L1 + IDIJ = IS +CDIR$ IVDEP + DO 140 I=3,IDO,2 + IDIJ = IDIJ+2 + C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J) + C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J) + 140 CONTINUE + 141 CONTINUE + 142 CONTINUE + 143 RETURN + END + SUBROUTINE RADF2(IDO,L1,CC,CH,WA1) +C***BEGIN PROLOGUE RADF2 +C***REFER TO RFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADF2 + DIMENSION CH(IDO,2,L1) ,CC(IDO,L1,2) , + 1 WA1(1) +C***FIRST EXECUTABLE STATEMENT RADF2 + DO 101 K=1,L1 + CH(1,1,K) = CC(1,K,1)+CC(1,K,2) + CH(IDO,2,K) = CC(1,K,1)-CC(1,K,2) + 101 CONTINUE + IF (IDO-2) 107,105,102 + 102 IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 108 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=3,IDO,2 + IC = IDP2-I + TR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + TI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + CH(I,1,K) = CC(I,K,1)+TI2 + CH(IC,2,K) = TI2-CC(I,K,1) + CH(I-1,1,K) = CC(I-1,K,1)+TR2 + CH(IC-1,2,K) = CC(I-1,K,1)-TR2 + 103 CONTINUE + 104 CONTINUE + GO TO 111 + 108 DO 110 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 109 K=1,L1 + TR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + TI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + CH(I,1,K) = CC(I,K,1)+TI2 + CH(IC,2,K) = TI2-CC(I,K,1) + CH(I-1,1,K) = CC(I-1,K,1)+TR2 + CH(IC-1,2,K) = CC(I-1,K,1)-TR2 + 109 CONTINUE + 110 CONTINUE + 111 IF (MOD(IDO,2) .EQ. 1) RETURN + 105 DO 106 K=1,L1 + CH(1,2,K) = -CC(IDO,K,2) + CH(IDO,1,K) = CC(IDO,K,1) + 106 CONTINUE + 107 RETURN + END + SUBROUTINE RADF3(IDO,L1,CC,CH,WA1,WA2) +C***BEGIN PROLOGUE RADF3 +C***REFER TO RFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADF3 + DIMENSION CH(IDO,3,L1) ,CC(IDO,L1,3) , + 1 WA1(1) ,WA2(1) + DATA TAUR,TAUI /-.5,.866025403784439/ +C***FIRST EXECUTABLE STATEMENT RADF3 + DO 101 K=1,L1 + CR2 = CC(1,K,2)+CC(1,K,3) + CH(1,1,K) = CC(1,K,1)+CR2 + CH(1,3,K) = TAUI*(CC(1,K,3)-CC(1,K,2)) + CH(IDO,2,K) = CC(1,K,1)+TAUR*CR2 + 101 CONTINUE + IF (IDO .EQ. 1) RETURN + IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 104 + DO 103 K=1,L1 +CDIR$ IVDEP + DO 102 I=3,IDO,2 + IC = IDP2-I + DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + CR2 = DR2+DR3 + CI2 = DI2+DI3 + CH(I-1,1,K) = CC(I-1,K,1)+CR2 + CH(I,1,K) = CC(I,K,1)+CI2 + TR2 = CC(I-1,K,1)+TAUR*CR2 + TI2 = CC(I,K,1)+TAUR*CI2 + TR3 = TAUI*(DI2-DI3) + TI3 = TAUI*(DR3-DR2) + CH(I-1,3,K) = TR2+TR3 + CH(IC-1,2,K) = TR2-TR3 + CH(I,3,K) = TI2+TI3 + CH(IC,2,K) = TI3-TI2 + 102 CONTINUE + 103 CONTINUE + RETURN + 104 DO 106 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 105 K=1,L1 + DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + CR2 = DR2+DR3 + CI2 = DI2+DI3 + CH(I-1,1,K) = CC(I-1,K,1)+CR2 + CH(I,1,K) = CC(I,K,1)+CI2 + TR2 = CC(I-1,K,1)+TAUR*CR2 + TI2 = CC(I,K,1)+TAUR*CI2 + TR3 = TAUI*(DI2-DI3) + TI3 = TAUI*(DR3-DR2) + CH(I-1,3,K) = TR2+TR3 + CH(IC-1,2,K) = TR2-TR3 + CH(I,3,K) = TI2+TI3 + CH(IC,2,K) = TI3-TI2 + 105 CONTINUE + 106 CONTINUE + RETURN + END + SUBROUTINE RADF4(IDO,L1,CC,CH,WA1,WA2,WA3) +C***BEGIN PROLOGUE RADF4 +C***REFER TO RFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADF4 + DIMENSION CC(IDO,L1,4) ,CH(IDO,4,L1) , + 1 WA1(1) ,WA2(1) ,WA3(1) + DATA HSQT2 /.7071067811865475/ +C***FIRST EXECUTABLE STATEMENT RADF4 + DO 101 K=1,L1 + TR1 = CC(1,K,2)+CC(1,K,4) + TR2 = CC(1,K,1)+CC(1,K,3) + CH(1,1,K) = TR1+TR2 + CH(IDO,4,K) = TR2-TR1 + CH(IDO,2,K) = CC(1,K,1)-CC(1,K,3) + CH(1,3,K) = CC(1,K,4)-CC(1,K,2) + 101 CONTINUE + IF (IDO-2) 107,105,102 + 102 IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 111 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=3,IDO,2 + IC = IDP2-I + CR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + CI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + CR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + CI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + CR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4) + CI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4) + TR1 = CR2+CR4 + TR4 = CR4-CR2 + TI1 = CI2+CI4 + TI4 = CI2-CI4 + TI2 = CC(I,K,1)+CI3 + TI3 = CC(I,K,1)-CI3 + TR2 = CC(I-1,K,1)+CR3 + TR3 = CC(I-1,K,1)-CR3 + CH(I-1,1,K) = TR1+TR2 + CH(IC-1,4,K) = TR2-TR1 + CH(I,1,K) = TI1+TI2 + CH(IC,4,K) = TI1-TI2 + CH(I-1,3,K) = TI4+TR3 + CH(IC-1,2,K) = TR3-TI4 + CH(I,3,K) = TR4+TI3 + CH(IC,2,K) = TR4-TI3 + 103 CONTINUE + 104 CONTINUE + GO TO 110 + 111 DO 109 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 108 K=1,L1 + CR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + CI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + CR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + CI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + CR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4) + CI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4) + TR1 = CR2+CR4 + TR4 = CR4-CR2 + TI1 = CI2+CI4 + TI4 = CI2-CI4 + TI2 = CC(I,K,1)+CI3 + TI3 = CC(I,K,1)-CI3 + TR2 = CC(I-1,K,1)+CR3 + TR3 = CC(I-1,K,1)-CR3 + CH(I-1,1,K) = TR1+TR2 + CH(IC-1,4,K) = TR2-TR1 + CH(I,1,K) = TI1+TI2 + CH(IC,4,K) = TI1-TI2 + CH(I-1,3,K) = TI4+TR3 + CH(IC-1,2,K) = TR3-TI4 + CH(I,3,K) = TR4+TI3 + CH(IC,2,K) = TR4-TI3 + 108 CONTINUE + 109 CONTINUE + 110 IF (MOD(IDO,2) .EQ. 1) RETURN + 105 DO 106 K=1,L1 + TI1 = -HSQT2*(CC(IDO,K,2)+CC(IDO,K,4)) + TR1 = HSQT2*(CC(IDO,K,2)-CC(IDO,K,4)) + CH(IDO,1,K) = TR1+CC(IDO,K,1) + CH(IDO,3,K) = CC(IDO,K,1)-TR1 + CH(1,2,K) = TI1-CC(IDO,K,3) + CH(1,4,K) = TI1+CC(IDO,K,3) + 106 CONTINUE + 107 RETURN + END + SUBROUTINE RADF5(IDO,L1,CC,CH,WA1,WA2,WA3,WA4) +C***BEGIN PROLOGUE RADF5 +C***REFER TO RFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADF5 + DIMENSION CC(IDO,L1,5) ,CH(IDO,5,L1) , + 1 WA1(1) ,WA2(1) ,WA3(1) ,WA4(1) + DATA TR11,TI11,TR12,TI12 /.309016994374947,.951056516295154, + 1-.809016994374947,.587785252292473/ +C***FIRST EXECUTABLE STATEMENT RADF5 + DO 101 K=1,L1 + CR2 = CC(1,K,5)+CC(1,K,2) + CI5 = CC(1,K,5)-CC(1,K,2) + CR3 = CC(1,K,4)+CC(1,K,3) + CI4 = CC(1,K,4)-CC(1,K,3) + CH(1,1,K) = CC(1,K,1)+CR2+CR3 + CH(IDO,2,K) = CC(1,K,1)+TR11*CR2+TR12*CR3 + CH(1,3,K) = TI11*CI5+TI12*CI4 + CH(IDO,4,K) = CC(1,K,1)+TR12*CR2+TR11*CR3 + CH(1,5,K) = TI12*CI5-TI11*CI4 + 101 CONTINUE + IF (IDO .EQ. 1) RETURN + IDP2 = IDO+2 + IF((IDO-1)/2.LT.L1) GO TO 104 + DO 103 K=1,L1 +CDIR$ IVDEP + DO 102 I=3,IDO,2 + IC = IDP2-I + DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + DR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4) + DI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4) + DR5 = WA4(I-2)*CC(I-1,K,5)+WA4(I-1)*CC(I,K,5) + DI5 = WA4(I-2)*CC(I,K,5)-WA4(I-1)*CC(I-1,K,5) + CR2 = DR2+DR5 + CI5 = DR5-DR2 + CR5 = DI2-DI5 + CI2 = DI2+DI5 + CR3 = DR3+DR4 + CI4 = DR4-DR3 + CR4 = DI3-DI4 + CI3 = DI3+DI4 + CH(I-1,1,K) = CC(I-1,K,1)+CR2+CR3 + CH(I,1,K) = CC(I,K,1)+CI2+CI3 + TR2 = CC(I-1,K,1)+TR11*CR2+TR12*CR3 + TI2 = CC(I,K,1)+TR11*CI2+TR12*CI3 + TR3 = CC(I-1,K,1)+TR12*CR2+TR11*CR3 + TI3 = CC(I,K,1)+TR12*CI2+TR11*CI3 + TR5 = TI11*CR5+TI12*CR4 + TI5 = TI11*CI5+TI12*CI4 + TR4 = TI12*CR5-TI11*CR4 + TI4 = TI12*CI5-TI11*CI4 + CH(I-1,3,K) = TR2+TR5 + CH(IC-1,2,K) = TR2-TR5 + CH(I,3,K) = TI2+TI5 + CH(IC,2,K) = TI5-TI2 + CH(I-1,5,K) = TR3+TR4 + CH(IC-1,4,K) = TR3-TR4 + CH(I,5,K) = TI3+TI4 + CH(IC,4,K) = TI4-TI3 + 102 CONTINUE + 103 CONTINUE + RETURN + 104 DO 106 I=3,IDO,2 + IC = IDP2-I +CDIR$ IVDEP + DO 105 K=1,L1 + DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2) + DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2) + DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3) + DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3) + DR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4) + DI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4) + DR5 = WA4(I-2)*CC(I-1,K,5)+WA4(I-1)*CC(I,K,5) + DI5 = WA4(I-2)*CC(I,K,5)-WA4(I-1)*CC(I-1,K,5) + CR2 = DR2+DR5 + CI5 = DR5-DR2 + CR5 = DI2-DI5 + CI2 = DI2+DI5 + CR3 = DR3+DR4 + CI4 = DR4-DR3 + CR4 = DI3-DI4 + CI3 = DI3+DI4 + CH(I-1,1,K) = CC(I-1,K,1)+CR2+CR3 + CH(I,1,K) = CC(I,K,1)+CI2+CI3 + TR2 = CC(I-1,K,1)+TR11*CR2+TR12*CR3 + TI2 = CC(I,K,1)+TR11*CI2+TR12*CI3 + TR3 = CC(I-1,K,1)+TR12*CR2+TR11*CR3 + TI3 = CC(I,K,1)+TR12*CI2+TR11*CI3 + TR5 = TI11*CR5+TI12*CR4 + TI5 = TI11*CI5+TI12*CI4 + TR4 = TI12*CR5-TI11*CR4 + TI4 = TI12*CI5-TI11*CI4 + CH(I-1,3,K) = TR2+TR5 + CH(IC-1,2,K) = TR2-TR5 + CH(I,3,K) = TI2+TI5 + CH(IC,2,K) = TI5-TI2 + CH(I-1,5,K) = TR3+TR4 + CH(IC-1,4,K) = TR3-TR4 + CH(I,5,K) = TI3+TI4 + CH(IC,4,K) = TI4-TI3 + 105 CONTINUE + 106 CONTINUE + RETURN + END + SUBROUTINE RADFG(IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA) +C***BEGIN PROLOGUE RADFG +C***REFER TO RFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RADFG + DIMENSION CH(IDO,L1,IP) ,CC(IDO,IP,L1) , + 1 C1(IDO,L1,IP) ,C2(IDL1,IP), + 2 CH2(IDL1,IP) ,WA(1) + DATA TPI/6.28318530717959/ +C***FIRST EXECUTABLE STATEMENT RADFG + ARG = TPI/FLOAT(IP) + DCP = COS(ARG) + DSP = SIN(ARG) + IPPH = (IP+1)/2 + IPP2 = IP+2 + IDP2 = IDO+2 + NBD = (IDO-1)/2 + IF (IDO .EQ. 1) GO TO 119 + DO 101 IK=1,IDL1 + CH2(IK,1) = C2(IK,1) + 101 CONTINUE + DO 103 J=2,IP + DO 102 K=1,L1 + CH(1,K,J) = C1(1,K,J) + 102 CONTINUE + 103 CONTINUE + IF (NBD .GT. L1) GO TO 107 + IS = -IDO + DO 106 J=2,IP + IS = IS+IDO + IDIJ = IS + DO 105 I=3,IDO,2 + IDIJ = IDIJ+2 + DO 104 K=1,L1 + CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J) + CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J) + 104 CONTINUE + 105 CONTINUE + 106 CONTINUE + GO TO 111 + 107 IS = -IDO + DO 110 J=2,IP + IS = IS+IDO + DO 109 K=1,L1 + IDIJ = IS +CDIR$ IVDEP + DO 108 I=3,IDO,2 + IDIJ = IDIJ+2 + CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J) + CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J) + 108 CONTINUE + 109 CONTINUE + 110 CONTINUE + 111 IF (NBD .LT. L1) GO TO 115 + DO 114 J=2,IPPH + JC = IPP2-J + DO 113 K=1,L1 +CDIR$ IVDEP + DO 112 I=3,IDO,2 + C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC) + C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC) + C1(I,K,J) = CH(I,K,J)+CH(I,K,JC) + C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J) + 112 CONTINUE + 113 CONTINUE + 114 CONTINUE + GO TO 121 + 115 DO 118 J=2,IPPH + JC = IPP2-J + DO 117 I=3,IDO,2 + DO 116 K=1,L1 + C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC) + C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC) + C1(I,K,J) = CH(I,K,J)+CH(I,K,JC) + C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J) + 116 CONTINUE + 117 CONTINUE + 118 CONTINUE + GO TO 121 + 119 DO 120 IK=1,IDL1 + C2(IK,1) = CH2(IK,1) + 120 CONTINUE + 121 DO 123 J=2,IPPH + JC = IPP2-J + DO 122 K=1,L1 + C1(1,K,J) = CH(1,K,J)+CH(1,K,JC) + C1(1,K,JC) = CH(1,K,JC)-CH(1,K,J) + 122 CONTINUE + 123 CONTINUE +C + AR1 = 1. + AI1 = 0. + DO 127 L=2,IPPH + LC = IPP2-L + AR1H = DCP*AR1-DSP*AI1 + AI1 = DCP*AI1+DSP*AR1 + AR1 = AR1H + DO 124 IK=1,IDL1 + CH2(IK,L) = C2(IK,1)+AR1*C2(IK,2) + CH2(IK,LC) = AI1*C2(IK,IP) + 124 CONTINUE + DC2 = AR1 + DS2 = AI1 + AR2 = AR1 + AI2 = AI1 + DO 126 J=3,IPPH + JC = IPP2-J + AR2H = DC2*AR2-DS2*AI2 + AI2 = DC2*AI2+DS2*AR2 + AR2 = AR2H + DO 125 IK=1,IDL1 + CH2(IK,L) = CH2(IK,L)+AR2*C2(IK,J) + CH2(IK,LC) = CH2(IK,LC)+AI2*C2(IK,JC) + 125 CONTINUE + 126 CONTINUE + 127 CONTINUE + DO 129 J=2,IPPH + DO 128 IK=1,IDL1 + CH2(IK,1) = CH2(IK,1)+C2(IK,J) + 128 CONTINUE + 129 CONTINUE +C + IF (IDO .LT. L1) GO TO 132 + DO 131 K=1,L1 + DO 130 I=1,IDO + CC(I,1,K) = CH(I,K,1) + 130 CONTINUE + 131 CONTINUE + GO TO 135 + 132 DO 134 I=1,IDO + DO 133 K=1,L1 + CC(I,1,K) = CH(I,K,1) + 133 CONTINUE + 134 CONTINUE + 135 DO 137 J=2,IPPH + JC = IPP2-J + J2 = J+J + DO 136 K=1,L1 + CC(IDO,J2-2,K) = CH(1,K,J) + CC(1,J2-1,K) = CH(1,K,JC) + 136 CONTINUE + 137 CONTINUE + IF (IDO .EQ. 1) RETURN + IF (NBD .LT. L1) GO TO 141 + DO 140 J=2,IPPH + JC = IPP2-J + J2 = J+J + DO 139 K=1,L1 +CDIR$ IVDEP + DO 138 I=3,IDO,2 + IC = IDP2-I + CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC) + CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC) + CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC) + CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J) + 138 CONTINUE + 139 CONTINUE + 140 CONTINUE + RETURN + 141 DO 144 J=2,IPPH + JC = IPP2-J + J2 = J+J + DO 143 I=3,IDO,2 + IC = IDP2-I + DO 142 K=1,L1 + CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC) + CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC) + CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC) + CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J) + 142 CONTINUE + 143 CONTINUE + 144 CONTINUE + RETURN + END + SUBROUTINE RFFTB(N,R,WSAVE) +C***BEGIN PROLOGUE RFFTB +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A1 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Backward transform of a real coefficient array. +C***DESCRIPTION +C +C Subroutine RFFTB computes the real perodic sequence from its +C Fourier coefficients (Fourier synthesis). The transform is defined +C below at output parameter R. +C +C Input Parameters +C +C N the length of the array R to be transformed. The method +C is most efficient when N is a product of small primes. +C N may change so long as different work arrays are provided. +C +C R a real array of length N which contains the sequence +C to be transformed +C +C WSAVE a work array which must be dimensioned at least 2*N+15 +C in the program that calls RFFTB. The WSAVE array must be +C initialized by calling subroutine RFFTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C The same WSAVE array can be used by RFFTF and RFFTB. +C +C +C Output Parameters +C +C R For N even and For I = 1,...,N +C +C R(I) = R(1)+(-1)**(I-1)*R(N) +C +C plus the sum from K=2 to K=N/2 of +C +C 2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N) +C +C -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N) +C +C For N odd and For I = 1,...,N +C +C R(I) = R(1) plus the sum from K=2 to K=(N+1)/2 of +C +C 2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N) +C +C -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N) +C +C ***** Note: +C This transform is unnormalized since a call of RFFTF +C followed by a call of RFFTB will multiply the input +C sequence by N. +C +C WSAVE contains results which must not be destroyed between +C calls of RFFTB or RFFTF. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTB1 +C***END PROLOGUE RFFTB + DIMENSION R(1) ,WSAVE(1) +C***FIRST EXECUTABLE STATEMENT RFFTB + IF (N .EQ. 1) RETURN + CALL RFFTB1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1)) + RETURN + END + SUBROUTINE RFFTB1(N,C,CH,WA,IFAC) +C***BEGIN PROLOGUE RFFTB1 +C***REFER TO RFFTB +C***ROUTINES CALLED RADB2,RADB3,RADB4,RADB5,RADBG +C***END PROLOGUE RFFTB1 + DIMENSION CH(1) ,C(1) ,WA(1) ,IFAC(1) +C***FIRST EXECUTABLE STATEMENT RFFTB1 + NF = IFAC(2) + NA = 0 + L1 = 1 + IW = 1 + DO 116 K1=1,NF + IP = IFAC(K1+2) + L2 = IP*L1 + IDO = N/L2 + IDL1 = IDO*L1 + IF (IP .NE. 4) GO TO 103 + IX2 = IW+IDO + IX3 = IX2+IDO + IF (NA .NE. 0) GO TO 101 + CALL RADB4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3)) + GO TO 102 + 101 CALL RADB4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3)) + 102 NA = 1-NA + GO TO 115 + 103 IF (IP .NE. 2) GO TO 106 + IF (NA .NE. 0) GO TO 104 + CALL RADB2 (IDO,L1,C,CH,WA(IW)) + GO TO 105 + 104 CALL RADB2 (IDO,L1,CH,C,WA(IW)) + 105 NA = 1-NA + GO TO 115 + 106 IF (IP .NE. 3) GO TO 109 + IX2 = IW+IDO + IF (NA .NE. 0) GO TO 107 + CALL RADB3 (IDO,L1,C,CH,WA(IW),WA(IX2)) + GO TO 108 + 107 CALL RADB3 (IDO,L1,CH,C,WA(IW),WA(IX2)) + 108 NA = 1-NA + GO TO 115 + 109 IF (IP .NE. 5) GO TO 112 + IX2 = IW+IDO + IX3 = IX2+IDO + IX4 = IX3+IDO + IF (NA .NE. 0) GO TO 110 + CALL RADB5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + GO TO 111 + 110 CALL RADB5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + 111 NA = 1-NA + GO TO 115 + 112 IF (NA .NE. 0) GO TO 113 + CALL RADBG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW)) + GO TO 114 + 113 CALL RADBG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW)) + 114 IF (IDO .EQ. 1) NA = 1-NA + 115 L1 = L2 + IW = IW+(IP-1)*IDO + 116 CONTINUE + IF (NA .EQ. 0) RETURN + DO 117 I=1,N + C(I) = CH(I) + 117 CONTINUE + RETURN + END + SUBROUTINE RFFTF(N,R,WSAVE) +C***BEGIN PROLOGUE RFFTF +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A1 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Forward transform of a real, periodic sequence. +C***DESCRIPTION +C +C Subroutine RFFTF computes the Fourier coefficients of a real +C perodic sequence (Fourier analysis). The transform is defined +C below at output parameter R. +C +C Input Parameters +C +C N the length of the array R to be transformed. The method +C is most efficient when N is a product of small primes. +C N may change so long as different work arrays are provided +C +C R a real array of length N which contains the sequence +C to be transformed +C +C WSAVE a work array which must be dimensioned at least 2*N+15 +C in the program that calls RFFTF. The WSAVE array must be +C initialized by calling subroutine RFFTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C the same WSAVE array can be used by RFFTF and RFFTB. +C +C +C Output Parameters +C +C R R(1) = the sum from I=1 to I=N of R(I) +C +C If N is even set L = N/2; if N is odd set L = (N+1)/2 +C +C then for K = 2,...,L +C +C R(2*K-2) = the sum from I = 1 to I = N of +C +C R(I)*COS((K-1)*(I-1)*2*PI/N) +C +C R(2*K-1) = the sum from I = 1 to I = N of +C +C -R(I)*SIN((K-1)*(I-1)*2*PI/N) +C +C If N is even +C +C R(N) = the sum from I = 1 to I = N of +C +C (-1)**(I-1)*R(I) +C +C ***** Note: +C This transform is unnormalized since a call of RFFTF +C followed by a call of RFFTB will multiply the input +C sequence by N. +C +C WSAVE contains results which must not be destroyed between +C calls of RFFTF or RFFTB. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTF1 +C***END PROLOGUE RFFTF + DIMENSION R(1) ,WSAVE(1) +C***FIRST EXECUTABLE STATEMENT RFFTF + IF (N .EQ. 1) RETURN + CALL RFFTF1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1)) + RETURN + END + SUBROUTINE RFFTF1(N,C,CH,WA,IFAC) +C***BEGIN PROLOGUE RFFTF1 +C***REFER TO RFFTF +C***ROUTINES CALLED RADF2,RADF3,RADF4,RADF5,RADFG +C***END PROLOGUE RFFTF1 + DIMENSION CH(1) ,C(1) ,WA(1) ,IFAC(1) +C***FIRST EXECUTABLE STATEMENT RFFTF1 + NF = IFAC(2) + NA = 1 + L2 = N + IW = N + DO 111 K1=1,NF + KH = NF-K1 + IP = IFAC(KH+3) + L1 = L2/IP + IDO = N/L2 + IDL1 = IDO*L1 + IW = IW-(IP-1)*IDO + NA = 1-NA + IF (IP .NE. 4) GO TO 102 + IX2 = IW+IDO + IX3 = IX2+IDO + IF (NA .NE. 0) GO TO 101 + CALL RADF4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3)) + GO TO 110 + 101 CALL RADF4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3)) + GO TO 110 + 102 IF (IP .NE. 2) GO TO 104 + IF (NA .NE. 0) GO TO 103 + CALL RADF2 (IDO,L1,C,CH,WA(IW)) + GO TO 110 + 103 CALL RADF2 (IDO,L1,CH,C,WA(IW)) + GO TO 110 + 104 IF (IP .NE. 3) GO TO 106 + IX2 = IW+IDO + IF (NA .NE. 0) GO TO 105 + CALL RADF3 (IDO,L1,C,CH,WA(IW),WA(IX2)) + GO TO 110 + 105 CALL RADF3 (IDO,L1,CH,C,WA(IW),WA(IX2)) + GO TO 110 + 106 IF (IP .NE. 5) GO TO 108 + IX2 = IW+IDO + IX3 = IX2+IDO + IX4 = IX3+IDO + IF (NA .NE. 0) GO TO 107 + CALL RADF5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + GO TO 110 + 107 CALL RADF5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4)) + GO TO 110 + 108 IF (IDO .EQ. 1) NA = 1-NA + IF (NA .NE. 0) GO TO 109 + CALL RADFG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW)) + NA = 1 + GO TO 110 + 109 CALL RADFG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW)) + NA = 0 + 110 L2 = L1 + 111 CONTINUE + IF (NA .EQ. 1) RETURN + DO 112 I=1,N + C(I) = CH(I) + 112 CONTINUE + RETURN + END + SUBROUTINE RFFTI(N,WSAVE) +C***BEGIN PROLOGUE RFFTI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A1 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for RFFTF and RFFTB. +C***DESCRIPTION +C +C Subroutine RFFTI initializes the array WSAVE which is used in +C both RFFTF and RFFTB. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the sequence to be transformed. +C +C Output Parameter +C +C WSAVE a work array which must be dimensioned at least 2*N+15. +C The same work array can be used for both RFFTF and RFFTB +C as long as N remains unchanged. Different WSAVE arrays +C are required for different values of N. The contents of +C WSAVE must not be changed between calls of RFFTF or RFFTB. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTI1 +C***END PROLOGUE RFFTI + DIMENSION WSAVE(1) +C***FIRST EXECUTABLE STATEMENT RFFTI + IF (N .EQ. 1) RETURN + CALL RFFTI1 (N,WSAVE(N+1),WSAVE(2*N+1)) + RETURN + END + SUBROUTINE RFFTI1(N,WA,IFAC) +C***BEGIN PROLOGUE RFFTI1 +C***REFER TO RFFTI +C***ROUTINES CALLED (NONE) +C***END PROLOGUE RFFTI1 + DIMENSION WA(1) ,IFAC(1) ,NTRYH(4) + DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/4,2,3,5/ +C***FIRST EXECUTABLE STATEMENT RFFTI1 + NL = N + NF = 0 + J = 0 + 101 J = J+1 + IF (J-4) 102,102,103 + 102 NTRY = NTRYH(J) + GO TO 104 + 103 NTRY = NTRY+2 + 104 NQ = NL/NTRY + NR = NL-NTRY*NQ + IF (NR) 101,105,101 + 105 NF = NF+1 + IFAC(NF+2) = NTRY + NL = NQ + IF (NTRY .NE. 2) GO TO 107 + IF (NF .EQ. 1) GO TO 107 + DO 106 I=2,NF + IB = NF-I+2 + IFAC(IB+2) = IFAC(IB+1) + 106 CONTINUE + IFAC(3) = 2 + 107 IF (NL .NE. 1) GO TO 104 + IFAC(1) = N + IFAC(2) = NF + TPI = 6.28318530717959 + ARGH = TPI/FLOAT(N) + IS = 0 + NFM1 = NF-1 + L1 = 1 + IF (NFM1 .EQ. 0) RETURN + DO 110 K1=1,NFM1 + IP = IFAC(K1+2) + LD = 0 + L2 = L1*IP + IDO = N/L2 + IPM = IP-1 + DO 109 J=1,IPM + LD = LD+L1 + I = IS + ARGLD = FLOAT(LD)*ARGH + FI = 0. + DO 108 II=3,IDO,2 + I = I+2 + FI = FI+1. + ARG = FI*ARGLD + WA(I-1) = COS(ARG) + WA(I) = SIN(ARG) + 108 CONTINUE + IS = IS+IDO + 109 CONTINUE + L1 = L2 + 110 CONTINUE + RETURN + END + SUBROUTINE SINQB(N,X,WSAVE) +C***BEGIN PROLOGUE SINQB +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Unnormalized inverse of SINQF. +C***DESCRIPTION +C +C Subroutine SINQB computes the fast Fourier transform of quarter +C wave data. That is, SINQB computes a sequence from its +C representation in terms of a sine series with odd wave numbers. +C the transform is defined below at output parameter X. +C +C SINQF is the unnormalized inverse of SINQB since a call of SINQB +C followed by a call of SINQF will multiply the input sequence X +C by 4*N. +C +C The array WSAVE which is used by subroutine SINQB must be +C initialized by calling subroutine SINQI(N,WSAVE). +C +C +C Input Parameters +C +C N the length of the array X to be transformed. The method +C is most efficient when N is a product of small primes. +C +C X an array which contains the sequence to be transformed +C +C WSAVE a work array which must be dimensioned at least 3*N+15 +C in the program that calls SINQB. The WSAVE array must be +C initialized by calling subroutine SINQI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X for I=1,...,N +C +C X(I)= the sum from K=1 to K=N of +C +C 4*X(K)*SIN((2k-1)*I*PI/(2*N)) +C +C a call of SINQB followed by a call of +C SINQF will multiply the sequence X by 4*N. +C Therefore SINQF is the unnormalized inverse +C of SINQB. +C +C WSAVE contains initialization calculations which must not +C be destroyed between calls of SINQB or SINQF. +C***REFERENCES (NONE) +C***ROUTINES CALLED COSQB +C***END PROLOGUE SINQB + DIMENSION X(1) ,WSAVE(1) +C***FIRST EXECUTABLE STATEMENT SINQB + IF (N .GT. 1) GO TO 101 + X(1) = 4.*X(1) + RETURN + 101 NS2 = N/2 + DO 102 K=2,N,2 + X(K) = -X(K) + 102 CONTINUE + CALL COSQB (N,X,WSAVE) + DO 103 K=1,NS2 + KC = N-K + XHOLD = X(K) + X(K) = X(KC+1) + X(KC+1) = XHOLD + 103 CONTINUE + RETURN + END + SUBROUTINE SINQF(N,X,WSAVE) +C***BEGIN PROLOGUE SINQF +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Forward sine transform with odd wave numbers. +C***DESCRIPTION +C +C Subroutine SINQF computes the fast Fourier transform of quarter +C wave data. That is, SINQF computes the coefficients in a sine +C series representation with only odd wave numbers. The transform +C is defined below at output parameter X. +C +C SINQB is the unnormalized inverse of SINQF since a call of SINQF +C followed by a call of SINQB will multiply the input sequence X +C by 4*N. +C +C The array WSAVE which is used by subroutine SINQF must be +C initialized by calling subroutine SINQI(N,WSAVE). +C +C +C Input Parameters +C +C N the length of the array X to be transformed. The method +C is most efficient when N is a product of small primes. +C +C X an array which contains the sequence to be transformed +C +C WSAVE a work array which must be dimensioned at least 3*N+15 +C in the program that calls SINQF. The WSAVE array must be +C initialized by calling subroutine SINQI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X For I=1,...,N +C +C X(I) = (-1)**(I-1)*X(N) +C +C + the sum from K=1 to K=N-1 of +C +C 2*X(K)*SIN((2*I-1)*K*PI/(2*N)) +C +C A call of SINQF followed by a call of +C SINQB will multiply the sequence X by 4*N. +C Therefore SINQB is the unnormalized inverse +C of SINQF. +C +C WSAVE contains initialization calculations which must not +C be destroyed between calls of SINQF or SINQB. +C***REFERENCES (NONE) +C***ROUTINES CALLED COSQF +C***END PROLOGUE SINQF + DIMENSION X(1) ,WSAVE(1) +C***FIRST EXECUTABLE STATEMENT SINQF + IF (N .EQ. 1) RETURN + NS2 = N/2 + DO 101 K=1,NS2 + KC = N-K + XHOLD = X(K) + X(K) = X(KC+1) + X(KC+1) = XHOLD + 101 CONTINUE + CALL COSQF (N,X,WSAVE) + DO 102 K=2,N,2 + X(K) = -X(K) + 102 CONTINUE + RETURN + END + SUBROUTINE SINQI(N,WSAVE) +C***BEGIN PROLOGUE SINQI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for SINQF and SINQB. +C***DESCRIPTION +C +C Subroutine SINQI initializes the array WSAVE which is used in +C both SINQF and SINQB. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the sequence to be transformed. The method +C is most efficient when N is a product of small primes. +C +C Output Parameter +C +C WSAVE a work array which must be dimensioned at least 3*N+15. +C The same work array can be used for both SINQF and SINQB +C as long as N remains unchanged. Different WSAVE arrays +C are required for different values of N. The contents of +C WSAVE must not be changed between calls of SINQF or SINQB. +C***REFERENCES (NONE) +C***ROUTINES CALLED COSQI +C***END PROLOGUE SINQI + DIMENSION WSAVE(1) +C***FIRST EXECUTABLE STATEMENT SINQI + CALL COSQI (N,WSAVE) + RETURN + END + SUBROUTINE SINT(N,X,WSAVE) +C***BEGIN PROLOGUE SINT +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Sine transform of a real, odd sequence. +C***DESCRIPTION +C +C Subroutine SINT computes the discrete Fourier sine transform +C of an odd sequence X(I). The transform is defined below at +C output parameter X. +C +C SINT is the unnormalized inverse of itself since a call of SINT +C followed by another call of SINT will multiply the input sequence +C X by 2*(N+1). +C +C The array WSAVE which is used by subroutine SINT must be +C initialized by calling subroutine SINTI(N,WSAVE). +C +C Input Parameters +C +C N the length of the sequence to be transformed. The method +C is most efficient when N+1 is the product of small primes. +C +C X an array which contains the sequence to be transformed +C +C +C WSAVE a work array with dimension at least INT(3.5*N+16) +C in the program that calls SINT. The WSAVE array must be +C initialized by calling subroutine SINTI(N,WSAVE), and a +C different WSAVE array must be used for each different +C value of N. This initialization does not have to be +C repeated so long as N remains unchanged. Thus subsequent +C transforms can be obtained faster than the first. +C +C Output Parameters +C +C X for I=1,...,N +C +C X(I)= the sum from k=1 to k=N +C +C 2*X(K)*SIN(K*I*PI/(N+1)) +C +C A call of SINT followed by another call of +C SINT will multiply the sequence X by 2*(N+1). +C Hence SINT is the unnormalized inverse +C of itself. +C +C WSAVE contains initialization calculations which must not be +C destroyed between calls of SINT. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTF +C***END PROLOGUE SINT + DIMENSION X(1) ,WSAVE(1) + DATA SQRT3 /1.73205080756888/ +C***FIRST EXECUTABLE STATEMENT SINT + IF (N-2) 101,102,103 + 101 X(1) = X(1)+X(1) + RETURN + 102 XH = SQRT3*(X(1)+X(2)) + X(2) = SQRT3*(X(1)-X(2)) + X(1) = XH + RETURN + 103 NP1 = N+1 + NS2 = N/2 + WSAVE(1) = 0. + KW = NP1 + DO 104 K=1,NS2 +1 KW = KW+1 + KC = NP1-K + T1 = X(K)-X(KC) + T2 = WSAVE(KW)*(X(K)+X(KC)) + WSAVE(K+1) = T1+T2 + WSAVE(KC+1) = T2-T1 + 104 CONTINUE + MODN = MOD(N,2) + IF (MODN .NE. 0) WSAVE(NS2+2) = 4.*X(NS2+1) + NF = NP1+NS2+1 + CALL RFFTF (NP1,WSAVE,WSAVE(NF)) + X(1) = .5*WSAVE(1) + DO 105 I=3,N,2 + X(I-1) = -WSAVE(I) + X(I) = X(I-2)+WSAVE(I-1) + 105 CONTINUE + IF (MODN .NE. 0) RETURN + X(N) = -WSAVE(N+1) + RETURN + END + SUBROUTINE SINTI(N,WSAVE) +C***BEGIN PROLOGUE SINTI +C***DATE WRITTEN 790601 (YYMMDD) +C***REVISION DATE 830401 (YYMMDD) +C***CATEGORY NO. J1A3 +C***KEYWORDS FOURIER TRANSFORM +C***AUTHOR SWARZTRAUBER, P. N., (NCAR) +C***PURPOSE Initialize for SINT. +C***DESCRIPTION +C +C Subroutine SINTI initializes the array WSAVE which is used in +C subroutine SINT. The prime factorization of N together with +C a tabulation of the trigonometric functions are computed and +C stored in WSAVE. +C +C Input Parameter +C +C N the length of the sequence to be transformed. The method +C is most efficient when N+1 is a product of small primes. +C +C Output Parameter +C +C WSAVE a work array with at least INT(3.5*N+16) locations. +C Different WSAVE arrays are required for different values +C of N. The contents of WSAVE must not be changed between +C calls of SINT. +C***REFERENCES (NONE) +C***ROUTINES CALLED RFFTI +C***END PROLOGUE SINTI + DIMENSION WSAVE(1) + DATA PI /3.14159265358979/ +C***FIRST EXECUTABLE STATEMENT SINTI + IF (N .LE. 1) RETURN + NP1 = N+1 + NS2 = N/2 + DT = PI/FLOAT(NP1) + KS = N+2 + KF = KS+NS2-1 + FK = 0. + DO 101 K=KS,KF + FK = FK+1. + WSAVE(K) = 2.*SIN(FK*DT) + 101 CONTINUE + CALL RFFTI (NP1,WSAVE(KF+1)) + RETURN + END + SUBROUTINE TRID(MR,A,B,C,Y,D) +C***BEGIN PROLOGUE TRID +C***REFER TO POIS3D +C***ROUTINES CALLED (NONE) +C***END PROLOGUE TRID + DIMENSION A(1) ,B(1) ,C(1) ,Y(1) , + 1 D(1) +C***FIRST EXECUTABLE STATEMENT TRID + M = MR + MM1 = M-1 + Z = 1./B(1) + D(1) = C(1)*Z + Y(1) = Y(1)*Z + DO 101 I=2,MM1 + Z = 1./(B(I)-A(I)*D(I-1)) + D(I) = C(I)*Z + Y(I) = (Y(I)-A(I)*Y(I-1))*Z + 101 CONTINUE + Z = B(M)-A(M)*D(MM1) + IF (Z .NE. 0.) GO TO 102 + Y(M) = 0. + GO TO 103 + 102 Y(M) = (Y(M)-A(M)*Y(MM1))/Z + 103 CONTINUE + DO 104 IP=1,MM1 + I = M-IP + Y(I) = Y(I)-D(I)*Y(I+1) + 104 CONTINUE + RETURN + END + SUBROUTINE PASSB5(IDO,L1,CC,CH,WA1,WA2,WA3,WA4) +C***BEGIN PROLOGUE PASSB5 +C***REFER TO CFFTB +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSB5 + DIMENSION CC(IDO,5,L1) ,CH(IDO,L1,5) , + 1 WA1(1) ,WA2(1) ,WA3(1) ,WA4(1) + DATA TR11,TI11,TR12,TI12 /.309016994374947,.951056516295154, + 1-.809016994374947,.587785252292473/ +C***FIRST EXECUTABLE STATEMENT PASSB5 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TI5 = CC(2,2,K)-CC(2,5,K) + TI2 = CC(2,2,K)+CC(2,5,K) + TI4 = CC(2,3,K)-CC(2,4,K) + TI3 = CC(2,3,K)+CC(2,4,K) + TR5 = CC(1,2,K)-CC(1,5,K) + TR2 = CC(1,2,K)+CC(1,5,K) + TR4 = CC(1,3,K)-CC(1,4,K) + TR3 = CC(1,3,K)+CC(1,4,K) + CH(1,K,1) = CC(1,1,K)+TR2+TR3 + CH(2,K,1) = CC(2,1,K)+TI2+TI3 + CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + CH(1,K,2) = CR2-CI5 + CH(1,K,5) = CR2+CI5 + CH(2,K,2) = CI2+CR5 + CH(2,K,3) = CI3+CR4 + CH(1,K,3) = CR3-CI4 + CH(1,K,4) = CR3+CI4 + CH(2,K,4) = CI3-CR4 + CH(2,K,5) = CI2-CR5 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TI5 = CC(I,2,K)-CC(I,5,K) + TI2 = CC(I,2,K)+CC(I,5,K) + TI4 = CC(I,3,K)-CC(I,4,K) + TI3 = CC(I,3,K)+CC(I,4,K) + TR5 = CC(I-1,2,K)-CC(I-1,5,K) + TR2 = CC(I-1,2,K)+CC(I-1,5,K) + TR4 = CC(I-1,3,K)-CC(I-1,4,K) + TR3 = CC(I-1,3,K)+CC(I-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2 + CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2 + CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3 + CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3 + CH(I-1,K,4) = WA3(I-1)*DR4-WA3(I)*DI4 + CH(I,K,4) = WA3(I-1)*DI4+WA3(I)*DR4 + CH(I-1,K,5) = WA4(I-1)*DR5-WA4(I)*DI5 + CH(I,K,5) = WA4(I-1)*DI5+WA4(I)*DR5 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TI5 = CC(I,2,K)-CC(I,5,K) + TI2 = CC(I,2,K)+CC(I,5,K) + TI4 = CC(I,3,K)-CC(I,4,K) + TI3 = CC(I,3,K)+CC(I,4,K) + TR5 = CC(I-1,2,K)-CC(I-1,5,K) + TR2 = CC(I-1,2,K)+CC(I-1,5,K) + TR4 = CC(I-1,3,K)-CC(I-1,4,K) + TR3 = CC(I-1,3,K)+CC(I-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2 + CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2 + CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3 + CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3 + CH(I-1,K,4) = WA3(I-1)*DR4-WA3(I)*DI4 + CH(I,K,4) = WA3(I-1)*DI4+WA3(I)*DR4 + CH(I-1,K,5) = WA4(I-1)*DR5-WA4(I)*DI5 + CH(I,K,5) = WA4(I-1)*DI5+WA4(I)*DR5 + 106 CONTINUE + 107 CONTINUE + RETURN + END + SUBROUTINE PASSF5(IDO,L1,CC,CH,WA1,WA2,WA3,WA4) +C***BEGIN PROLOGUE PASSF5 +C***REFER TO CFFTF +C***ROUTINES CALLED (NONE) +C***END PROLOGUE PASSF5 + DIMENSION CC(IDO,5,L1) ,CH(IDO,L1,5) , + 1 WA1(1) ,WA2(1) ,WA3(1) ,WA4(1) + DATA TR11,TI11,TR12,TI12 /.309016994374947,-.951056516295154, + 1-.809016994374947,-.587785252292473/ +C***FIRST EXECUTABLE STATEMENT PASSF5 + IF (IDO .NE. 2) GO TO 102 + DO 101 K=1,L1 + TI5 = CC(2,2,K)-CC(2,5,K) + TI2 = CC(2,2,K)+CC(2,5,K) + TI4 = CC(2,3,K)-CC(2,4,K) + TI3 = CC(2,3,K)+CC(2,4,K) + TR5 = CC(1,2,K)-CC(1,5,K) + TR2 = CC(1,2,K)+CC(1,5,K) + TR4 = CC(1,3,K)-CC(1,4,K) + TR3 = CC(1,3,K)+CC(1,4,K) + CH(1,K,1) = CC(1,1,K)+TR2+TR3 + CH(2,K,1) = CC(2,1,K)+TI2+TI3 + CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + CH(1,K,2) = CR2-CI5 + CH(1,K,5) = CR2+CI5 + CH(2,K,2) = CI2+CR5 + CH(2,K,3) = CI3+CR4 + CH(1,K,3) = CR3-CI4 + CH(1,K,4) = CR3+CI4 + CH(2,K,4) = CI3-CR4 + CH(2,K,5) = CI2-CR5 + 101 CONTINUE + RETURN + 102 IF(IDO/2.LT.L1) GO TO 105 + DO 104 K=1,L1 +CDIR$ IVDEP + DO 103 I=2,IDO,2 + TI5 = CC(I,2,K)-CC(I,5,K) + TI2 = CC(I,2,K)+CC(I,5,K) + TI4 = CC(I,3,K)-CC(I,4,K) + TI3 = CC(I,3,K)+CC(I,4,K) + TR5 = CC(I-1,2,K)-CC(I-1,5,K) + TR2 = CC(I-1,2,K)+CC(I-1,5,K) + TR4 = CC(I-1,3,K)-CC(I-1,4,K) + TR3 = CC(I-1,3,K)+CC(I-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2 + CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2 + CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3 + CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3 + CH(I-1,K,4) = WA3(I-1)*DR4+WA3(I)*DI4 + CH(I,K,4) = WA3(I-1)*DI4-WA3(I)*DR4 + CH(I-1,K,5) = WA4(I-1)*DR5+WA4(I)*DI5 + CH(I,K,5) = WA4(I-1)*DI5-WA4(I)*DR5 + 103 CONTINUE + 104 CONTINUE + RETURN + 105 DO 107 I=2,IDO,2 +CDIR$ IVDEP + DO 106 K=1,L1 + TI5 = CC(I,2,K)-CC(I,5,K) + TI2 = CC(I,2,K)+CC(I,5,K) + TI4 = CC(I,3,K)-CC(I,4,K) + TI3 = CC(I,3,K)+CC(I,4,K) + TR5 = CC(I-1,2,K)-CC(I-1,5,K) + TR2 = CC(I-1,2,K)+CC(I-1,5,K) + TR4 = CC(I-1,3,K)-CC(I-1,4,K) + TR3 = CC(I-1,3,K)+CC(I-1,4,K) + CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3 + CH(I,K,1) = CC(I,1,K)+TI2+TI3 + CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3 + CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3 + CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3 + CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3 + CR5 = TI11*TR5+TI12*TR4 + CI5 = TI11*TI5+TI12*TI4 + CR4 = TI12*TR5-TI11*TR4 + CI4 = TI12*TI5-TI11*TI4 + DR3 = CR3-CI4 + DR4 = CR3+CI4 + DI3 = CI3+CR4 + DI4 = CI3-CR4 + DR5 = CR2+CI5 + DR2 = CR2-CI5 + DI5 = CI2-CR5 + DI2 = CI2+CR5 + CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2 + CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2 + CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3 + CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3 + CH(I-1,K,4) = WA3(I-1)*DR4+WA3(I)*DI4 + CH(I,K,4) = WA3(I-1)*DI4-WA3(I)*DR4 + CH(I-1,K,5) = WA4(I-1)*DR5+WA4(I)*DI5 + CH(I,K,5) = WA4(I-1)*DI5-WA4(I)*DR5 + 106 CONTINUE + 107 CONTINUE + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/read.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/read.f new file mode 100644 index 000000000..e9b93d5b9 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/read.f @@ -0,0 +1,71 @@ + program lecture + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + character*30 rota + + pi=3.1415926 + piinv = 1./( pi) + pi2=2.*pi + + nx=32 + ny=32 + nz=32 + + +c rota='rotax'//'0' + open(17,file='rotax0',form='unformatted', + 1 status='unknown') + read(17) (((omg1(i,j,k),i=1,nx),j=1,ny),k=1,nz) + close(17) +c +c rota='rotay'//'0' + open(18,file='rotay0',form='unformatted', + 1 status='unknown') + read(18) (((omg2(i,j,k),i=1,nx),j=1,ny),k=1,nz) + close(18) +c +c rota='rotaz'//'0' + open(19,file='rotaz0',form='unformatted', + 1 status='unknown') + read(19) (((omg3(i,j,k),i=1,nx),j=1,ny),k=1,nz) + close(19) + + + open(17,file='rotax0_asci') + open(18,file='rotay0_asci') + open(19,file='rotaz0_asci') + + do i=1,nx + do j=1,nx + do k=1,nx + write(17,*) omg1(i,j,k) + write(18,*) omg2(i,j,k) + write(19,*) omg3(i,j,k) + enddo + enddo + enddo + + close(17) + close(18) + close(19) + enstro=0. + + do i=1,nx + do j=1,nx + do k=1,nx + enstro=enstro+omg1(i,j,k) +c print*, omg1(i,j,k) + enddo + enddo + enddo + + print*,enstro/(nx**3) + + stop + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_lambda3.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_lambda3.f new file mode 100644 index 000000000..ae4d64e8e --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_lambda3.f @@ -0,0 +1,630 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE remeshdif(npart,circlim,om1,om2,om3, + 1 xp,yp,zp,dv,idif,anu,delt,coef_les,ipoint) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension om1(*),om2(*),om3(*),xp(*),yp(*),zp(*),dv(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + pi=3.1415926 + + do 10 k=1,nz + do 10 j=1,ny + do 10 i=1,nx + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. +10 continue + + dxinv=1./dx + dyinv=1./dy + dzinv=1./dz + + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + +c x0=xmin-.5*dx +c y0=ymin-.5*dy +c z0=zmin-.5*dz + + x0=xmin + y0=ymin + z0=zmin + + xm=xmax-xmin + ym=ymax-ymin + zm=zmax-zmin + + DO 20 n = 1,npart + + g1 = om1(n) + g2 = om2(n) + g3 = om3(n) + x = xp(n) + y = yp(n) + z = zp(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +C Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dy-y0)*dyinv + zz1 = (z - float(kp1)*dz-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + +C +C on repositionne les points de grille par periodicite +C entre 0 et npx-1, puis on numerote de 1 a npx +C + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + + jp1=mod(jp1+ny,ny) +1 + jp0=mod(jp0+ny,ny) +1 + jp2=mod(jp2+ny,ny) +1 + jp3=mod(jp3+ny,ny) +1 + + kp1=mod(kp1+nz,nz) +1 + kp0=mod(kp0+nz,nz) +1 + kp2=mod(kp2+nz,nz) +1 + kp3=mod(kp3+nz,nz) +1 + +C The M'4 scheme +C + + a1 = .5*(1.-xx1**2)*(2.-xx1) + b1 = .5*(1.-yy1**2)*(2.-yy1) + c1 = .5*(1.-zz1**2)*(2.-zz1) + + a0 = (1.-xx0)*(2.-xx0)*(3.-xx0)/6. + b0 = (1.-yy0)*(2.-yy0)*(3.-yy0)/6. + c0 = (1.-zz0)*(2.-zz0)*(3.-zz0)/6. + + a3 = (1.-xx3)*(2.-xx3)*(3.-xx3)/6. + b3 = (1.-yy3)*(2.-yy3)*(3.-yy3)/6. + c3 = (1.-zz3)*(2.-zz3)*(3.-zz3)/6. + + a2 = .5*(1.-xx2**2)*(2.-xx2) + b2 = .5*(1.-yy2**2)*(2.-yy2) + c2 = .5*(1.-zz2**2)*(2.-zz2) + + coef=a0*b0*c0 + omg1(ip0,jp0,kp0) = omg1(ip0,jp0,kp0) + g1*coef + omg2(ip0,jp0,kp0) = omg2(ip0,jp0,kp0) + g2*coef + omg3(ip0,jp0,kp0) = omg3(ip0,jp0,kp0) + g3*coef + + coef=a0*b0*c1 + omg1(ip0,jp0,kp1) = omg1(ip0,jp0,kp1) + g1*coef + omg2(ip0,jp0,kp1) = omg2(ip0,jp0,kp1) + g2*coef + omg3(ip0,jp0,kp1) = omg3(ip0,jp0,kp1) + g3*coef + + coef=a0*b0*c2 + omg1(ip0,jp0,kp2) = omg1(ip0,jp0,kp2) + g1*coef + omg2(ip0,jp0,kp2) = omg2(ip0,jp0,kp2) + g2*coef + omg3(ip0,jp0,kp2) = omg3(ip0,jp0,kp2) + g3*coef + + coef=a0*b0*c3 + omg1(ip0,jp0,kp3) = omg1(ip0,jp0,kp3) + g1*coef + omg2(ip0,jp0,kp3) = omg2(ip0,jp0,kp3) + g2*coef + omg3(ip0,jp0,kp3) = omg3(ip0,jp0,kp3) + g3*coef + +ccc + + coef=a0*b1*c0 + omg1(ip0,jp1,kp0) = omg1(ip0,jp1,kp0) + g1*coef + omg2(ip0,jp1,kp0) = omg2(ip0,jp1,kp0) + g2*coef + omg3(ip0,jp1,kp0) = omg3(ip0,jp1,kp0) + g3*coef + + coef=a0*b1*c1 + omg1(ip0,jp1,kp1) = omg1(ip0,jp1,kp1) + g1*coef + omg2(ip0,jp1,kp1) = omg2(ip0,jp1,kp1) + g2*coef + omg3(ip0,jp1,kp1) = omg3(ip0,jp1,kp1) + g3*coef + + coef=a0*b1*c2 + omg1(ip0,jp1,kp2) = omg1(ip0,jp1,kp2) + g1*coef + omg2(ip0,jp1,kp2) = omg2(ip0,jp1,kp2) + g2*coef + omg3(ip0,jp1,kp2) = omg3(ip0,jp1,kp2) + g3*coef + + coef=a0*b1*c3 + omg1(ip0,jp1,kp3) = omg1(ip0,jp1,kp3) + g1*coef + omg2(ip0,jp1,kp3) = omg2(ip0,jp1,kp3) + g2*coef + omg3(ip0,jp1,kp3) = omg3(ip0,jp1,kp3) + g3*coef + +ccc + + coef=a0*b2*c0 + omg1(ip0,jp2,kp0) = omg1(ip0,jp2,kp0) + g1*coef + omg2(ip0,jp2,kp0) = omg2(ip0,jp2,kp0) + g2*coef + omg3(ip0,jp2,kp0) = omg3(ip0,jp2,kp0) + g3*coef + + coef=a0*b2*c1 + omg1(ip0,jp2,kp1) = omg1(ip0,jp2,kp1) + g1*coef + omg2(ip0,jp2,kp1) = omg2(ip0,jp2,kp1) + g2*coef + omg3(ip0,jp2,kp1) = omg3(ip0,jp2,kp1) + g3*coef + + coef=a0*b2*c2 + omg1(ip0,jp2,kp2) = omg1(ip0,jp2,kp2) + g1*coef + omg2(ip0,jp2,kp2) = omg2(ip0,jp2,kp2) + g2*coef + omg3(ip0,jp2,kp2) = omg3(ip0,jp2,kp2) + g3*coef + + coef=a0*b2*c3 + omg1(ip0,jp2,kp3) = omg1(ip0,jp2,kp3) + g1*coef + omg2(ip0,jp2,kp3) = omg2(ip0,jp2,kp3) + g2*coef + omg3(ip0,jp2,kp3) = omg3(ip0,jp2,kp3) + g3*coef + +ccc + + coef=a0*b3*c0 + omg1(ip0,jp3,kp0) = omg1(ip0,jp3,kp0) + g1*coef + omg2(ip0,jp3,kp0) = omg2(ip0,jp3,kp0) + g2*coef + omg3(ip0,jp3,kp0) = omg3(ip0,jp3,kp0) + g3*coef + + coef=a0*b3*c1 + omg1(ip0,jp3,kp1) = omg1(ip0,jp3,kp1) + g1*coef + omg2(ip0,jp3,kp1) = omg2(ip0,jp3,kp1) + g2*coef + omg3(ip0,jp3,kp1) = omg3(ip0,jp3,kp1) + g3*coef + + coef=a0*b3*c2 + omg1(ip0,jp3,kp2) = omg1(ip0,jp3,kp2) + g1*coef + omg2(ip0,jp3,kp2) = omg2(ip0,jp3,kp2) + g2*coef + omg3(ip0,jp3,kp2) = omg3(ip0,jp3,kp2) + g3*coef + + coef=a0*b3*c3 + omg1(ip0,jp3,kp3) = omg1(ip0,jp3,kp3) + g1*coef + omg2(ip0,jp3,kp3) = omg2(ip0,jp3,kp3) + g2*coef + omg3(ip0,jp3,kp3) = omg3(ip0,jp3,kp3) + g3*coef + +ccc + coef=a1*b0*c0 + omg1(ip1,jp0,kp0) = omg1(ip1,jp0,kp0) + g1*coef + omg2(ip1,jp0,kp0) = omg2(ip1,jp0,kp0) + g2*coef + omg3(ip1,jp0,kp0) = omg3(ip1,jp0,kp0) + g3*coef + + coef=a1*b0*c1 + omg1(ip1,jp0,kp1) = omg1(ip1,jp0,kp1) + g1*coef + omg2(ip1,jp0,kp1) = omg2(ip1,jp0,kp1) + g2*coef + omg3(ip1,jp0,kp1) = omg3(ip1,jp0,kp1) + g3*coef + + coef=a1*b0*c2 + omg1(ip1,jp0,kp2) = omg1(ip1,jp0,kp2) + g1*coef + omg2(ip1,jp0,kp2) = omg2(ip1,jp0,kp2) + g2*coef + omg3(ip1,jp0,kp2) = omg3(ip1,jp0,kp2) + g3*coef + + coef=a1*b0*c3 + omg1(ip1,jp0,kp3) = omg1(ip1,jp0,kp3) + g1*coef + omg2(ip1,jp0,kp3) = omg2(ip1,jp0,kp3) + g2*coef + omg3(ip1,jp0,kp3) = omg3(ip1,jp0,kp3) + g3*coef + +ccc + + coef=a1*b1*c0 + omg1(ip1,jp1,kp0) = omg1(ip1,jp1,kp0) + g1*coef + omg2(ip1,jp1,kp0) = omg2(ip1,jp1,kp0) + g2*coef + omg3(ip1,jp1,kp0) = omg3(ip1,jp1,kp0) + g3*coef + + coef=a1*b1*c1 + omg1(ip1,jp1,kp1) = omg1(ip1,jp1,kp1) + g1*coef + omg2(ip1,jp1,kp1) = omg2(ip1,jp1,kp1) + g2*coef + omg3(ip1,jp1,kp1) = omg3(ip1,jp1,kp1) + g3*coef + + coef=a1*b1*c2 + omg1(ip1,jp1,kp2) = omg1(ip1,jp1,kp2) + g1*coef + omg2(ip1,jp1,kp2) = omg2(ip1,jp1,kp2) + g2*coef + omg3(ip1,jp1,kp2) = omg3(ip1,jp1,kp2) + g3*coef + + coef=a1*b1*c3 + omg1(ip1,jp1,kp3) = omg1(ip1,jp1,kp3) + g1*coef + omg2(ip1,jp1,kp3) = omg2(ip1,jp1,kp3) + g2*coef + omg3(ip1,jp1,kp3) = omg3(ip1,jp1,kp3) + g3*coef + +ccc + + coef=a1*b2*c0 + omg1(ip1,jp2,kp0) = omg1(ip1,jp2,kp0) + g1*coef + omg2(ip1,jp2,kp0) = omg2(ip1,jp2,kp0) + g2*coef + omg3(ip1,jp2,kp0) = omg3(ip1,jp2,kp0) + g3*coef + + coef=a1*b2*c1 + omg1(ip1,jp2,kp1) = omg1(ip1,jp2,kp1) + g1*coef + omg2(ip1,jp2,kp1) = omg2(ip1,jp2,kp1) + g2*coef + omg3(ip1,jp2,kp1) = omg3(ip1,jp2,kp1) + g3*coef + + coef=a1*b2*c2 + omg1(ip1,jp2,kp2) = omg1(ip1,jp2,kp2) + g1*coef + omg2(ip1,jp2,kp2) = omg2(ip1,jp2,kp2) + g2*coef + omg3(ip1,jp2,kp2) = omg3(ip1,jp2,kp2) + g3*coef + + coef=a1*b2*c3 + omg1(ip1,jp2,kp3) = omg1(ip1,jp2,kp3) + g1*coef + omg2(ip1,jp2,kp3) = omg2(ip1,jp2,kp3) + g2*coef + omg3(ip1,jp2,kp3) = omg3(ip1,jp2,kp3) + g3*coef + +ccc + + coef=a1*b3*c0 + omg1(ip1,jp3,kp0) = omg1(ip1,jp3,kp0) + g1*coef + omg2(ip1,jp3,kp0) = omg2(ip1,jp3,kp0) + g2*coef + omg3(ip1,jp3,kp0) = omg3(ip1,jp3,kp0) + g3*coef + + coef=a1*b3*c1 + omg1(ip1,jp3,kp1) = omg1(ip1,jp3,kp1) + g1*coef + omg2(ip1,jp3,kp1) = omg2(ip1,jp3,kp1) + g2*coef + omg3(ip1,jp3,kp1) = omg3(ip1,jp3,kp1) + g3*coef + + coef=a1*b3*c2 + omg1(ip1,jp3,kp2) = omg1(ip1,jp3,kp2) + g1*coef + omg2(ip1,jp3,kp2) = omg2(ip1,jp3,kp2) + g2*coef + omg3(ip1,jp3,kp2) = omg3(ip1,jp3,kp2) + g3*coef + + coef=a1*b3*c3 + omg1(ip1,jp3,kp3) = omg1(ip1,jp3,kp3) + g1*coef + omg2(ip1,jp3,kp3) = omg2(ip1,jp3,kp3) + g2*coef + omg3(ip1,jp3,kp3) = omg3(ip1,jp3,kp3) + g3*coef + +ccc + coef=a2*b0*c0 + omg1(ip2,jp0,kp0) = omg1(ip2,jp0,kp0) + g1*coef + omg2(ip2,jp0,kp0) = omg2(ip2,jp0,kp0) + g2*coef + omg3(ip2,jp0,kp0) = omg3(ip2,jp0,kp0) + g3*coef + + coef=a2*b0*c1 + omg1(ip2,jp0,kp1) = omg1(ip2,jp0,kp1) + g1*coef + omg2(ip2,jp0,kp1) = omg2(ip2,jp0,kp1) + g2*coef + omg3(ip2,jp0,kp1) = omg3(ip2,jp0,kp1) + g3*coef + + coef=a2*b0*c2 + omg1(ip2,jp0,kp2) = omg1(ip2,jp0,kp2) + g1*coef + omg2(ip2,jp0,kp2) = omg2(ip2,jp0,kp2) + g2*coef + omg3(ip2,jp0,kp2) = omg3(ip2,jp0,kp2) + g3*coef + + coef=a2*b0*c3 + omg1(ip2,jp0,kp3) = omg1(ip2,jp0,kp3) + g1*coef + omg2(ip2,jp0,kp3) = omg2(ip2,jp0,kp3) + g2*coef + omg3(ip2,jp0,kp3) = omg3(ip2,jp0,kp3) + g3*coef + +ccc + + coef=a2*b1*c0 + omg1(ip2,jp1,kp0) = omg1(ip2,jp1,kp0) + g1*coef + omg2(ip2,jp1,kp0) = omg2(ip2,jp1,kp0) + g2*coef + omg3(ip2,jp1,kp0) = omg3(ip2,jp1,kp0) + g3*coef + + coef=a2*b1*c1 + omg1(ip2,jp1,kp1) = omg1(ip2,jp1,kp1) + g1*coef + omg2(ip2,jp1,kp1) = omg2(ip2,jp1,kp1) + g2*coef + omg3(ip2,jp1,kp1) = omg3(ip2,jp1,kp1) + g3*coef + + coef=a2*b1*c2 + omg1(ip2,jp1,kp2) = omg1(ip2,jp1,kp2) + g1*coef + omg2(ip2,jp1,kp2) = omg2(ip2,jp1,kp2) + g2*coef + omg3(ip2,jp1,kp2) = omg3(ip2,jp1,kp2) + g3*coef + + coef=a2*b1*c3 + omg1(ip2,jp1,kp3) = omg1(ip2,jp1,kp3) + g1*coef + omg2(ip2,jp1,kp3) = omg2(ip2,jp1,kp3) + g2*coef + omg3(ip2,jp1,kp3) = omg3(ip2,jp1,kp3) + g3*coef + +ccc + + coef=a2*b2*c0 + omg1(ip2,jp2,kp0) = omg1(ip2,jp2,kp0) + g1*coef + omg2(ip2,jp2,kp0) = omg2(ip2,jp2,kp0) + g2*coef + omg3(ip2,jp2,kp0) = omg3(ip2,jp2,kp0) + g3*coef + + coef=a2*b2*c1 + omg1(ip2,jp2,kp1) = omg1(ip2,jp2,kp1) + g1*coef + omg2(ip2,jp2,kp1) = omg2(ip2,jp2,kp1) + g2*coef + omg3(ip2,jp2,kp1) = omg3(ip2,jp2,kp1) + g3*coef + + coef=a2*b2*c2 + omg1(ip2,jp2,kp2) = omg1(ip2,jp2,kp2) + g1*coef + omg2(ip2,jp2,kp2) = omg2(ip2,jp2,kp2) + g2*coef + omg3(ip2,jp2,kp2) = omg3(ip2,jp2,kp2) + g3*coef + + coef=a2*b2*c3 + omg1(ip2,jp2,kp3) = omg1(ip2,jp2,kp3) + g1*coef + omg2(ip2,jp2,kp3) = omg2(ip2,jp2,kp3) + g2*coef + omg3(ip2,jp2,kp3) = omg3(ip2,jp2,kp3) + g3*coef + +ccc + + coef=a2*b3*c0 + omg1(ip2,jp3,kp0) = omg1(ip2,jp3,kp0) + g1*coef + omg2(ip2,jp3,kp0) = omg2(ip2,jp3,kp0) + g2*coef + omg3(ip2,jp3,kp0) = omg3(ip2,jp3,kp0) + g3*coef + + coef=a2*b3*c1 + omg1(ip2,jp3,kp1) = omg1(ip2,jp3,kp1) + g1*coef + omg2(ip2,jp3,kp1) = omg2(ip2,jp3,kp1) + g2*coef + omg3(ip2,jp3,kp1) = omg3(ip2,jp3,kp1) + g3*coef + + coef=a2*b3*c2 + omg1(ip2,jp3,kp2) = omg1(ip2,jp3,kp2) + g1*coef + omg2(ip2,jp3,kp2) = omg2(ip2,jp3,kp2) + g2*coef + omg3(ip2,jp3,kp2) = omg3(ip2,jp3,kp2) + g3*coef + + coef=a2*b3*c3 + omg1(ip2,jp3,kp3) = omg1(ip2,jp3,kp3) + g1*coef + omg2(ip2,jp3,kp3) = omg2(ip2,jp3,kp3) + g2*coef + omg3(ip2,jp3,kp3) = omg3(ip2,jp3,kp3) + g3*coef + +ccc + + coef=a3*b0*c0 + omg1(ip3,jp0,kp0) = omg1(ip3,jp0,kp0) + g1*coef + omg2(ip3,jp0,kp0) = omg2(ip3,jp0,kp0) + g2*coef + omg3(ip3,jp0,kp0) = omg3(ip3,jp0,kp0) + g3*coef + + coef=a3*b0*c1 + omg1(ip3,jp0,kp1) = omg1(ip3,jp0,kp1) + g1*coef + omg2(ip3,jp0,kp1) = omg2(ip3,jp0,kp1) + g2*coef + omg3(ip3,jp0,kp1) = omg3(ip3,jp0,kp1) + g3*coef + + coef=a3*b0*c2 + omg1(ip3,jp0,kp2) = omg1(ip3,jp0,kp2) + g1*coef + omg2(ip3,jp0,kp2) = omg2(ip3,jp0,kp2) + g2*coef + omg3(ip3,jp0,kp2) = omg3(ip3,jp0,kp2) + g3*coef + + coef=a3*b0*c3 + omg1(ip3,jp0,kp3) = omg1(ip3,jp0,kp3) + g1*coef + omg2(ip3,jp0,kp3) = omg2(ip3,jp0,kp3) + g2*coef + omg3(ip3,jp0,kp3) = omg3(ip3,jp0,kp3) + g3*coef + +ccc + + coef=a3*b1*c0 + omg1(ip3,jp1,kp0) = omg1(ip3,jp1,kp0) + g1*coef + omg2(ip3,jp1,kp0) = omg2(ip3,jp1,kp0) + g2*coef + omg3(ip3,jp1,kp0) = omg3(ip3,jp1,kp0) + g3*coef + + coef=a3*b1*c1 + omg1(ip3,jp1,kp1) = omg1(ip3,jp1,kp1) + g1*coef + omg2(ip3,jp1,kp1) = omg2(ip3,jp1,kp1) + g2*coef + omg3(ip3,jp1,kp1) = omg3(ip3,jp1,kp1) + g3*coef + + coef=a3*b1*c2 + omg1(ip3,jp1,kp2) = omg1(ip3,jp1,kp2) + g1*coef + omg2(ip3,jp1,kp2) = omg2(ip3,jp1,kp2) + g2*coef + omg3(ip3,jp1,kp2) = omg3(ip3,jp1,kp2) + g3*coef + + coef=a3*b1*c3 + omg1(ip3,jp1,kp3) = omg1(ip3,jp1,kp3) + g1*coef + omg2(ip3,jp1,kp3) = omg2(ip3,jp1,kp3) + g2*coef + omg3(ip3,jp1,kp3) = omg3(ip3,jp1,kp3) + g3*coef + +ccc + + coef=a3*b2*c0 + omg1(ip3,jp2,kp0) = omg1(ip3,jp2,kp0) + g1*coef + omg2(ip3,jp2,kp0) = omg2(ip3,jp2,kp0) + g2*coef + omg3(ip3,jp2,kp0) = omg3(ip3,jp2,kp0) + g3*coef + + coef=a3*b2*c1 + omg1(ip3,jp2,kp1) = omg1(ip3,jp2,kp1) + g1*coef + omg2(ip3,jp2,kp1) = omg2(ip3,jp2,kp1) + g2*coef + omg3(ip3,jp2,kp1) = omg3(ip3,jp2,kp1) + g3*coef + + coef=a3*b2*c2 + omg1(ip3,jp2,kp2) = omg1(ip3,jp2,kp2) + g1*coef + omg2(ip3,jp2,kp2) = omg2(ip3,jp2,kp2) + g2*coef + omg3(ip3,jp2,kp2) = omg3(ip3,jp2,kp2) + g3*coef + + coef=a3*b2*c3 + omg1(ip3,jp2,kp3) = omg1(ip3,jp2,kp3) + g1*coef + omg2(ip3,jp2,kp3) = omg2(ip3,jp2,kp3) + g2*coef + omg3(ip3,jp2,kp3) = omg3(ip3,jp2,kp3) + g3*coef + +ccc + + coef=a3*b3*c0 + omg1(ip3,jp3,kp0) = omg1(ip3,jp3,kp0) + g1*coef + omg2(ip3,jp3,kp0) = omg2(ip3,jp3,kp0) + g2*coef + omg3(ip3,jp3,kp0) = omg3(ip3,jp3,kp0) + g3*coef + + coef=a3*b3*c1 + omg1(ip3,jp3,kp1) = omg1(ip3,jp3,kp1) + g1*coef + omg2(ip3,jp3,kp1) = omg2(ip3,jp3,kp1) + g2*coef + omg3(ip3,jp3,kp1) = omg3(ip3,jp3,kp1) + g3*coef + + coef=a3*b3*c2 + omg1(ip3,jp3,kp2) = omg1(ip3,jp3,kp2) + g1*coef + omg2(ip3,jp3,kp2) = omg2(ip3,jp3,kp2) + g2*coef + omg3(ip3,jp3,kp2) = omg3(ip3,jp3,kp2) + g3*coef + + coef=a3*b3*c3 + omg1(ip3,jp3,kp3) = omg1(ip3,jp3,kp3) + g1*coef + omg2(ip3,jp3,kp3) = omg2(ip3,jp3,kp3) + g2*coef + omg3(ip3,jp3,kp3) = omg3(ip3,jp3,kp3) + g3*coef + +ccc + +20 CONTINUE + + npart=0 + + do k=1,nz + z=amod(z0-zmin+(k-1)*dz+zm,zm)+zmin + do j=1,ny + y=amod(y0-ymin+(j-1)*dy+ym,ym)+ymin + do i=1,nx + x=amod(x0-xmin+(i-1)*dx+xm,xm)+xmin + vol=dx*dy*dz + strength=abs(omg1(i,j,k))+abs(omg2(i,j,k))+abs(omg3(i,j,k)) + if ((strength.ge.circlim*vol)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp(npart)=x + yp(npart)=y + zp(npart)=z + dv(npart)=vol + om1(npart)=omg1(i,j,k) + om2(npart)=omg2(i,j,k) + om3(npart)=omg3(i,j,k) + endif + enddo + enddo + enddo + + + if (ipoint.eq.0) go to 310 + + +c goto 310 + + if (idif.ne.0) then + +c dans la foulee on fiat la diffusion dans l'espace +c mappee avec formules de diffusion anisotropes + +c pas de temps de diffusion pour CFL + +c coeff aspect ratio pour se mettre dans une grille +c totalement isotrope et coeff de normalisation +c pour kernel 1/(1+r**2) + dzdx=(dz/dx)**2 + dzdy=(dz/dy)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +c boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +c boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx-1,nx)+1 + j2=mod(jj+ly+ny-1,ny)+1 + k2=mod(kk+lz+nz-1,nz)+1 + gammasrc1=omg1(i2,j2,k2) + gammasrc2=omg2(i2,j2,k2) + gammasrc3=omg3(i2,j2,k2) + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + dvx=(vxsrc-vxrcv)/dx + dvy=(vysrc-vyrcv)/dy + dvz=(vzsrc-vzrcv)/dz + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + ales=amax1(0.,dvx*lx+dvy*ly+dvz*lz)/(1.+r)**2 +c ales=abs(dvx*lx+dvy*ly+dvz*lz)/(1.+r)**2 + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + factor=akernel/(dz*dz) + tot2=tot2+akernel + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)* + 1 (anu*factor+coef_les*ales) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)* + 1 (anu*factor+coef_les*ales) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)* + 1 (anu*factor+coef_les*ales) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy*dx*dz/dv(i)) + +c enddo pour caluc de dom sur les particules + enddo + + + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv(i)) + omax0=amax1(omax0,abs(om2(i))/dv(i)) + omax0=amax1(omax0,abs(om3(i))/dv(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv(i)) + omax1=amax1(omax1,abs(om2(i))/dv(i)) + omax1=amax1(omax1,abs(om3(i))/dv(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + + endif + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_m4.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_m4.f new file mode 100644 index 000000000..3dc238365 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/remesh_m4.f @@ -0,0 +1,629 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE remeshdif(npart,circlim,om1,om2,om3, + 1 xp,yp,zp,dv,idif,anu,delt,coef_les,ipoint) + + + +C +C This subroutine asssigns vorticity on a grid +C + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension om1(*),om2(*),om3(*),xp(*),yp(*),zp(*),dv(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + pi=3.1415926 + + do 10 k=1,nz + do 10 j=1,ny + do 10 i=1,nx + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. +10 continue + + dxinv=1./dx + dyinv=1./dy + dzinv=1./dz + + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + +c x0=xmin-.5*dx +c y0=ymin-.5*dy +c z0=zmin-.5*dz + + x0=xmin + y0=ymin + z0=zmin + + xm=xmax-xmin + ym=ymax-ymin + zm=zmax-zmin + + DO 20 n = 1,npart + + g1 = om1(n) + g2 = om2(n) + g3 = om3(n) + x = xp(n) + y = yp(n) + z = zp(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +C Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dy-y0)*dyinv + zz1 = (z - float(kp1)*dz-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + +C +C on repositionne les points de grille par periodicite +C entre 0 et npx-1, puis on numerote de 1 a npx +C + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + + jp1=mod(jp1+ny,ny) +1 + jp0=mod(jp0+ny,ny) +1 + jp2=mod(jp2+ny,ny) +1 + jp3=mod(jp3+ny,ny) +1 + + kp1=mod(kp1+nz,nz) +1 + kp0=mod(kp0+nz,nz) +1 + kp2=mod(kp2+nz,nz) +1 + kp3=mod(kp3+nz,nz) +1 + +C The M'4 scheme +C + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + coef=a0*b0*c0 + omg1(ip0,jp0,kp0) = omg1(ip0,jp0,kp0) + g1*coef + omg2(ip0,jp0,kp0) = omg2(ip0,jp0,kp0) + g2*coef + omg3(ip0,jp0,kp0) = omg3(ip0,jp0,kp0) + g3*coef + + coef=a0*b0*c1 + omg1(ip0,jp0,kp1) = omg1(ip0,jp0,kp1) + g1*coef + omg2(ip0,jp0,kp1) = omg2(ip0,jp0,kp1) + g2*coef + omg3(ip0,jp0,kp1) = omg3(ip0,jp0,kp1) + g3*coef + + coef=a0*b0*c2 + omg1(ip0,jp0,kp2) = omg1(ip0,jp0,kp2) + g1*coef + omg2(ip0,jp0,kp2) = omg2(ip0,jp0,kp2) + g2*coef + omg3(ip0,jp0,kp2) = omg3(ip0,jp0,kp2) + g3*coef + + coef=a0*b0*c3 + omg1(ip0,jp0,kp3) = omg1(ip0,jp0,kp3) + g1*coef + omg2(ip0,jp0,kp3) = omg2(ip0,jp0,kp3) + g2*coef + omg3(ip0,jp0,kp3) = omg3(ip0,jp0,kp3) + g3*coef + +ccc + + coef=a0*b1*c0 + omg1(ip0,jp1,kp0) = omg1(ip0,jp1,kp0) + g1*coef + omg2(ip0,jp1,kp0) = omg2(ip0,jp1,kp0) + g2*coef + omg3(ip0,jp1,kp0) = omg3(ip0,jp1,kp0) + g3*coef + + coef=a0*b1*c1 + omg1(ip0,jp1,kp1) = omg1(ip0,jp1,kp1) + g1*coef + omg2(ip0,jp1,kp1) = omg2(ip0,jp1,kp1) + g2*coef + omg3(ip0,jp1,kp1) = omg3(ip0,jp1,kp1) + g3*coef + + coef=a0*b1*c2 + omg1(ip0,jp1,kp2) = omg1(ip0,jp1,kp2) + g1*coef + omg2(ip0,jp1,kp2) = omg2(ip0,jp1,kp2) + g2*coef + omg3(ip0,jp1,kp2) = omg3(ip0,jp1,kp2) + g3*coef + + coef=a0*b1*c3 + omg1(ip0,jp1,kp3) = omg1(ip0,jp1,kp3) + g1*coef + omg2(ip0,jp1,kp3) = omg2(ip0,jp1,kp3) + g2*coef + omg3(ip0,jp1,kp3) = omg3(ip0,jp1,kp3) + g3*coef + +ccc + + coef=a0*b2*c0 + omg1(ip0,jp2,kp0) = omg1(ip0,jp2,kp0) + g1*coef + omg2(ip0,jp2,kp0) = omg2(ip0,jp2,kp0) + g2*coef + omg3(ip0,jp2,kp0) = omg3(ip0,jp2,kp0) + g3*coef + + coef=a0*b2*c1 + omg1(ip0,jp2,kp1) = omg1(ip0,jp2,kp1) + g1*coef + omg2(ip0,jp2,kp1) = omg2(ip0,jp2,kp1) + g2*coef + omg3(ip0,jp2,kp1) = omg3(ip0,jp2,kp1) + g3*coef + + coef=a0*b2*c2 + omg1(ip0,jp2,kp2) = omg1(ip0,jp2,kp2) + g1*coef + omg2(ip0,jp2,kp2) = omg2(ip0,jp2,kp2) + g2*coef + omg3(ip0,jp2,kp2) = omg3(ip0,jp2,kp2) + g3*coef + + coef=a0*b2*c3 + omg1(ip0,jp2,kp3) = omg1(ip0,jp2,kp3) + g1*coef + omg2(ip0,jp2,kp3) = omg2(ip0,jp2,kp3) + g2*coef + omg3(ip0,jp2,kp3) = omg3(ip0,jp2,kp3) + g3*coef + +ccc + + coef=a0*b3*c0 + omg1(ip0,jp3,kp0) = omg1(ip0,jp3,kp0) + g1*coef + omg2(ip0,jp3,kp0) = omg2(ip0,jp3,kp0) + g2*coef + omg3(ip0,jp3,kp0) = omg3(ip0,jp3,kp0) + g3*coef + + coef=a0*b3*c1 + omg1(ip0,jp3,kp1) = omg1(ip0,jp3,kp1) + g1*coef + omg2(ip0,jp3,kp1) = omg2(ip0,jp3,kp1) + g2*coef + omg3(ip0,jp3,kp1) = omg3(ip0,jp3,kp1) + g3*coef + + coef=a0*b3*c2 + omg1(ip0,jp3,kp2) = omg1(ip0,jp3,kp2) + g1*coef + omg2(ip0,jp3,kp2) = omg2(ip0,jp3,kp2) + g2*coef + omg3(ip0,jp3,kp2) = omg3(ip0,jp3,kp2) + g3*coef + + coef=a0*b3*c3 + omg1(ip0,jp3,kp3) = omg1(ip0,jp3,kp3) + g1*coef + omg2(ip0,jp3,kp3) = omg2(ip0,jp3,kp3) + g2*coef + omg3(ip0,jp3,kp3) = omg3(ip0,jp3,kp3) + g3*coef + +ccc + coef=a1*b0*c0 + omg1(ip1,jp0,kp0) = omg1(ip1,jp0,kp0) + g1*coef + omg2(ip1,jp0,kp0) = omg2(ip1,jp0,kp0) + g2*coef + omg3(ip1,jp0,kp0) = omg3(ip1,jp0,kp0) + g3*coef + + coef=a1*b0*c1 + omg1(ip1,jp0,kp1) = omg1(ip1,jp0,kp1) + g1*coef + omg2(ip1,jp0,kp1) = omg2(ip1,jp0,kp1) + g2*coef + omg3(ip1,jp0,kp1) = omg3(ip1,jp0,kp1) + g3*coef + + coef=a1*b0*c2 + omg1(ip1,jp0,kp2) = omg1(ip1,jp0,kp2) + g1*coef + omg2(ip1,jp0,kp2) = omg2(ip1,jp0,kp2) + g2*coef + omg3(ip1,jp0,kp2) = omg3(ip1,jp0,kp2) + g3*coef + + coef=a1*b0*c3 + omg1(ip1,jp0,kp3) = omg1(ip1,jp0,kp3) + g1*coef + omg2(ip1,jp0,kp3) = omg2(ip1,jp0,kp3) + g2*coef + omg3(ip1,jp0,kp3) = omg3(ip1,jp0,kp3) + g3*coef + +ccc + + coef=a1*b1*c0 + omg1(ip1,jp1,kp0) = omg1(ip1,jp1,kp0) + g1*coef + omg2(ip1,jp1,kp0) = omg2(ip1,jp1,kp0) + g2*coef + omg3(ip1,jp1,kp0) = omg3(ip1,jp1,kp0) + g3*coef + + coef=a1*b1*c1 + omg1(ip1,jp1,kp1) = omg1(ip1,jp1,kp1) + g1*coef + omg2(ip1,jp1,kp1) = omg2(ip1,jp1,kp1) + g2*coef + omg3(ip1,jp1,kp1) = omg3(ip1,jp1,kp1) + g3*coef + + coef=a1*b1*c2 + omg1(ip1,jp1,kp2) = omg1(ip1,jp1,kp2) + g1*coef + omg2(ip1,jp1,kp2) = omg2(ip1,jp1,kp2) + g2*coef + omg3(ip1,jp1,kp2) = omg3(ip1,jp1,kp2) + g3*coef + + coef=a1*b1*c3 + omg1(ip1,jp1,kp3) = omg1(ip1,jp1,kp3) + g1*coef + omg2(ip1,jp1,kp3) = omg2(ip1,jp1,kp3) + g2*coef + omg3(ip1,jp1,kp3) = omg3(ip1,jp1,kp3) + g3*coef + +ccc + + coef=a1*b2*c0 + omg1(ip1,jp2,kp0) = omg1(ip1,jp2,kp0) + g1*coef + omg2(ip1,jp2,kp0) = omg2(ip1,jp2,kp0) + g2*coef + omg3(ip1,jp2,kp0) = omg3(ip1,jp2,kp0) + g3*coef + + coef=a1*b2*c1 + omg1(ip1,jp2,kp1) = omg1(ip1,jp2,kp1) + g1*coef + omg2(ip1,jp2,kp1) = omg2(ip1,jp2,kp1) + g2*coef + omg3(ip1,jp2,kp1) = omg3(ip1,jp2,kp1) + g3*coef + + coef=a1*b2*c2 + omg1(ip1,jp2,kp2) = omg1(ip1,jp2,kp2) + g1*coef + omg2(ip1,jp2,kp2) = omg2(ip1,jp2,kp2) + g2*coef + omg3(ip1,jp2,kp2) = omg3(ip1,jp2,kp2) + g3*coef + + coef=a1*b2*c3 + omg1(ip1,jp2,kp3) = omg1(ip1,jp2,kp3) + g1*coef + omg2(ip1,jp2,kp3) = omg2(ip1,jp2,kp3) + g2*coef + omg3(ip1,jp2,kp3) = omg3(ip1,jp2,kp3) + g3*coef + +ccc + + coef=a1*b3*c0 + omg1(ip1,jp3,kp0) = omg1(ip1,jp3,kp0) + g1*coef + omg2(ip1,jp3,kp0) = omg2(ip1,jp3,kp0) + g2*coef + omg3(ip1,jp3,kp0) = omg3(ip1,jp3,kp0) + g3*coef + + coef=a1*b3*c1 + omg1(ip1,jp3,kp1) = omg1(ip1,jp3,kp1) + g1*coef + omg2(ip1,jp3,kp1) = omg2(ip1,jp3,kp1) + g2*coef + omg3(ip1,jp3,kp1) = omg3(ip1,jp3,kp1) + g3*coef + + coef=a1*b3*c2 + omg1(ip1,jp3,kp2) = omg1(ip1,jp3,kp2) + g1*coef + omg2(ip1,jp3,kp2) = omg2(ip1,jp3,kp2) + g2*coef + omg3(ip1,jp3,kp2) = omg3(ip1,jp3,kp2) + g3*coef + + coef=a1*b3*c3 + omg1(ip1,jp3,kp3) = omg1(ip1,jp3,kp3) + g1*coef + omg2(ip1,jp3,kp3) = omg2(ip1,jp3,kp3) + g2*coef + omg3(ip1,jp3,kp3) = omg3(ip1,jp3,kp3) + g3*coef + +ccc + coef=a2*b0*c0 + omg1(ip2,jp0,kp0) = omg1(ip2,jp0,kp0) + g1*coef + omg2(ip2,jp0,kp0) = omg2(ip2,jp0,kp0) + g2*coef + omg3(ip2,jp0,kp0) = omg3(ip2,jp0,kp0) + g3*coef + + coef=a2*b0*c1 + omg1(ip2,jp0,kp1) = omg1(ip2,jp0,kp1) + g1*coef + omg2(ip2,jp0,kp1) = omg2(ip2,jp0,kp1) + g2*coef + omg3(ip2,jp0,kp1) = omg3(ip2,jp0,kp1) + g3*coef + + coef=a2*b0*c2 + omg1(ip2,jp0,kp2) = omg1(ip2,jp0,kp2) + g1*coef + omg2(ip2,jp0,kp2) = omg2(ip2,jp0,kp2) + g2*coef + omg3(ip2,jp0,kp2) = omg3(ip2,jp0,kp2) + g3*coef + + coef=a2*b0*c3 + omg1(ip2,jp0,kp3) = omg1(ip2,jp0,kp3) + g1*coef + omg2(ip2,jp0,kp3) = omg2(ip2,jp0,kp3) + g2*coef + omg3(ip2,jp0,kp3) = omg3(ip2,jp0,kp3) + g3*coef + +ccc + + coef=a2*b1*c0 + omg1(ip2,jp1,kp0) = omg1(ip2,jp1,kp0) + g1*coef + omg2(ip2,jp1,kp0) = omg2(ip2,jp1,kp0) + g2*coef + omg3(ip2,jp1,kp0) = omg3(ip2,jp1,kp0) + g3*coef + + coef=a2*b1*c1 + omg1(ip2,jp1,kp1) = omg1(ip2,jp1,kp1) + g1*coef + omg2(ip2,jp1,kp1) = omg2(ip2,jp1,kp1) + g2*coef + omg3(ip2,jp1,kp1) = omg3(ip2,jp1,kp1) + g3*coef + + coef=a2*b1*c2 + omg1(ip2,jp1,kp2) = omg1(ip2,jp1,kp2) + g1*coef + omg2(ip2,jp1,kp2) = omg2(ip2,jp1,kp2) + g2*coef + omg3(ip2,jp1,kp2) = omg3(ip2,jp1,kp2) + g3*coef + + coef=a2*b1*c3 + omg1(ip2,jp1,kp3) = omg1(ip2,jp1,kp3) + g1*coef + omg2(ip2,jp1,kp3) = omg2(ip2,jp1,kp3) + g2*coef + omg3(ip2,jp1,kp3) = omg3(ip2,jp1,kp3) + g3*coef + +ccc + + coef=a2*b2*c0 + omg1(ip2,jp2,kp0) = omg1(ip2,jp2,kp0) + g1*coef + omg2(ip2,jp2,kp0) = omg2(ip2,jp2,kp0) + g2*coef + omg3(ip2,jp2,kp0) = omg3(ip2,jp2,kp0) + g3*coef + + coef=a2*b2*c1 + omg1(ip2,jp2,kp1) = omg1(ip2,jp2,kp1) + g1*coef + omg2(ip2,jp2,kp1) = omg2(ip2,jp2,kp1) + g2*coef + omg3(ip2,jp2,kp1) = omg3(ip2,jp2,kp1) + g3*coef + + coef=a2*b2*c2 + omg1(ip2,jp2,kp2) = omg1(ip2,jp2,kp2) + g1*coef + omg2(ip2,jp2,kp2) = omg2(ip2,jp2,kp2) + g2*coef + omg3(ip2,jp2,kp2) = omg3(ip2,jp2,kp2) + g3*coef + + coef=a2*b2*c3 + omg1(ip2,jp2,kp3) = omg1(ip2,jp2,kp3) + g1*coef + omg2(ip2,jp2,kp3) = omg2(ip2,jp2,kp3) + g2*coef + omg3(ip2,jp2,kp3) = omg3(ip2,jp2,kp3) + g3*coef + +ccc + + coef=a2*b3*c0 + omg1(ip2,jp3,kp0) = omg1(ip2,jp3,kp0) + g1*coef + omg2(ip2,jp3,kp0) = omg2(ip2,jp3,kp0) + g2*coef + omg3(ip2,jp3,kp0) = omg3(ip2,jp3,kp0) + g3*coef + + coef=a2*b3*c1 + omg1(ip2,jp3,kp1) = omg1(ip2,jp3,kp1) + g1*coef + omg2(ip2,jp3,kp1) = omg2(ip2,jp3,kp1) + g2*coef + omg3(ip2,jp3,kp1) = omg3(ip2,jp3,kp1) + g3*coef + + coef=a2*b3*c2 + omg1(ip2,jp3,kp2) = omg1(ip2,jp3,kp2) + g1*coef + omg2(ip2,jp3,kp2) = omg2(ip2,jp3,kp2) + g2*coef + omg3(ip2,jp3,kp2) = omg3(ip2,jp3,kp2) + g3*coef + + coef=a2*b3*c3 + omg1(ip2,jp3,kp3) = omg1(ip2,jp3,kp3) + g1*coef + omg2(ip2,jp3,kp3) = omg2(ip2,jp3,kp3) + g2*coef + omg3(ip2,jp3,kp3) = omg3(ip2,jp3,kp3) + g3*coef + +ccc + + coef=a3*b0*c0 + omg1(ip3,jp0,kp0) = omg1(ip3,jp0,kp0) + g1*coef + omg2(ip3,jp0,kp0) = omg2(ip3,jp0,kp0) + g2*coef + omg3(ip3,jp0,kp0) = omg3(ip3,jp0,kp0) + g3*coef + + coef=a3*b0*c1 + omg1(ip3,jp0,kp1) = omg1(ip3,jp0,kp1) + g1*coef + omg2(ip3,jp0,kp1) = omg2(ip3,jp0,kp1) + g2*coef + omg3(ip3,jp0,kp1) = omg3(ip3,jp0,kp1) + g3*coef + + coef=a3*b0*c2 + omg1(ip3,jp0,kp2) = omg1(ip3,jp0,kp2) + g1*coef + omg2(ip3,jp0,kp2) = omg2(ip3,jp0,kp2) + g2*coef + omg3(ip3,jp0,kp2) = omg3(ip3,jp0,kp2) + g3*coef + + coef=a3*b0*c3 + omg1(ip3,jp0,kp3) = omg1(ip3,jp0,kp3) + g1*coef + omg2(ip3,jp0,kp3) = omg2(ip3,jp0,kp3) + g2*coef + omg3(ip3,jp0,kp3) = omg3(ip3,jp0,kp3) + g3*coef + +ccc + + coef=a3*b1*c0 + omg1(ip3,jp1,kp0) = omg1(ip3,jp1,kp0) + g1*coef + omg2(ip3,jp1,kp0) = omg2(ip3,jp1,kp0) + g2*coef + omg3(ip3,jp1,kp0) = omg3(ip3,jp1,kp0) + g3*coef + + coef=a3*b1*c1 + omg1(ip3,jp1,kp1) = omg1(ip3,jp1,kp1) + g1*coef + omg2(ip3,jp1,kp1) = omg2(ip3,jp1,kp1) + g2*coef + omg3(ip3,jp1,kp1) = omg3(ip3,jp1,kp1) + g3*coef + + coef=a3*b1*c2 + omg1(ip3,jp1,kp2) = omg1(ip3,jp1,kp2) + g1*coef + omg2(ip3,jp1,kp2) = omg2(ip3,jp1,kp2) + g2*coef + omg3(ip3,jp1,kp2) = omg3(ip3,jp1,kp2) + g3*coef + + coef=a3*b1*c3 + omg1(ip3,jp1,kp3) = omg1(ip3,jp1,kp3) + g1*coef + omg2(ip3,jp1,kp3) = omg2(ip3,jp1,kp3) + g2*coef + omg3(ip3,jp1,kp3) = omg3(ip3,jp1,kp3) + g3*coef + +ccc + + coef=a3*b2*c0 + omg1(ip3,jp2,kp0) = omg1(ip3,jp2,kp0) + g1*coef + omg2(ip3,jp2,kp0) = omg2(ip3,jp2,kp0) + g2*coef + omg3(ip3,jp2,kp0) = omg3(ip3,jp2,kp0) + g3*coef + + coef=a3*b2*c1 + omg1(ip3,jp2,kp1) = omg1(ip3,jp2,kp1) + g1*coef + omg2(ip3,jp2,kp1) = omg2(ip3,jp2,kp1) + g2*coef + omg3(ip3,jp2,kp1) = omg3(ip3,jp2,kp1) + g3*coef + + coef=a3*b2*c2 + omg1(ip3,jp2,kp2) = omg1(ip3,jp2,kp2) + g1*coef + omg2(ip3,jp2,kp2) = omg2(ip3,jp2,kp2) + g2*coef + omg3(ip3,jp2,kp2) = omg3(ip3,jp2,kp2) + g3*coef + + coef=a3*b2*c3 + omg1(ip3,jp2,kp3) = omg1(ip3,jp2,kp3) + g1*coef + omg2(ip3,jp2,kp3) = omg2(ip3,jp2,kp3) + g2*coef + omg3(ip3,jp2,kp3) = omg3(ip3,jp2,kp3) + g3*coef + +ccc + + coef=a3*b3*c0 + omg1(ip3,jp3,kp0) = omg1(ip3,jp3,kp0) + g1*coef + omg2(ip3,jp3,kp0) = omg2(ip3,jp3,kp0) + g2*coef + omg3(ip3,jp3,kp0) = omg3(ip3,jp3,kp0) + g3*coef + + coef=a3*b3*c1 + omg1(ip3,jp3,kp1) = omg1(ip3,jp3,kp1) + g1*coef + omg2(ip3,jp3,kp1) = omg2(ip3,jp3,kp1) + g2*coef + omg3(ip3,jp3,kp1) = omg3(ip3,jp3,kp1) + g3*coef + + coef=a3*b3*c2 + omg1(ip3,jp3,kp2) = omg1(ip3,jp3,kp2) + g1*coef + omg2(ip3,jp3,kp2) = omg2(ip3,jp3,kp2) + g2*coef + omg3(ip3,jp3,kp2) = omg3(ip3,jp3,kp2) + g3*coef + + coef=a3*b3*c3 + omg1(ip3,jp3,kp3) = omg1(ip3,jp3,kp3) + g1*coef + omg2(ip3,jp3,kp3) = omg2(ip3,jp3,kp3) + g2*coef + omg3(ip3,jp3,kp3) = omg3(ip3,jp3,kp3) + g3*coef + +ccc + +20 CONTINUE + + npart=0 + + do k=1,nz + z=amod(z0-zmin+(k-1)*dz+zm,zm)+zmin + do j=1,ny + y=amod(y0-ymin+(j-1)*dy+ym,ym)+ymin + do i=1,nx + x=amod(x0-xmin+(i-1)*dx+xm,xm)+xmin + vol=dx*dy*dz + strength=abs(omg1(i,j,k))+abs(omg2(i,j,k))+abs(omg3(i,j,k)) + if ((strength.ge.circlim*vol)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp(npart)=x + yp(npart)=y + zp(npart)=z + dv(npart)=vol + om1(npart)=omg1(i,j,k) + om2(npart)=omg2(i,j,k) + om3(npart)=omg3(i,j,k) + endif + enddo + enddo + enddo + + + if (ipoint.eq.0) go to 310 + + +c goto 310 + + if (idif.ne.0) then + +c dans la foulee on fiat la diffusion dans l'espace +c mappee avec formules de diffusion anisotropes + +c pas de temps de diffusion pour CFL + +c coeff aspect ratio pour se mettre dans une grille +c totalement isotrope et coeff de normalisation +c pour kernel 1/(1+r**2) + dzdx=(dz/dx)**2 + dzdy=(dz/dy)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +c boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +c boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx-1,nx)+1 + j2=mod(jj+ly+ny-1,ny)+1 + k2=mod(kk+lz+nz-1,nz)+1 + gammasrc1=omg1(i2,j2,k2) + gammasrc2=omg2(i2,j2,k2) + gammasrc3=omg3(i2,j2,k2) + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + dvx=(vxsrc-vxrcv)/dx + dvy=(vysrc-vyrcv)/dy + dvz=(vzsrc-vzrcv)/dz + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + ales=amax1(0.,dvx*lx+dvy*ly+dvz*lz)/(1.+r)**2 +c ales=abs(dvx*lx+dvy*ly+dvz*lz)/(1.+r)**2 + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + factor=akernel/(dz*dz) + tot2=tot2+akernel + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)* + 1 (anu*factor+coef_les*ales) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)* + 1 (anu*factor+coef_les*ales) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)* + 1 (anu*factor+coef_les*ales) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy*dx*dz/dv(i)) + +c enddo pour caluc de dom sur les particules + enddo + + + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv(i)) + omax0=amax1(omax0,abs(om2(i))/dv(i)) + omax0=amax1(omax0,abs(om3(i))/dv(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv(i)) + omax1=amax1(omax1,abs(om2(i))/dv(i)) + omax1=amax1(omax1,abs(om3(i))/dv(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + + endif + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/stream.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/stream.f new file mode 100644 index 000000000..d3dc29b0a --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/stream.f @@ -0,0 +1,137 @@ + subroutine stream(iper) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + dimension rhs(npgx,npgy,npgz),bdzs(npgx,npgy),bdzf(npgx,npgy) + dimension bdxs(1,1),bdxf(1,1),bdys(npgx,npgz),bdyf(npgx,npgz) + dimension w(10000) + + common/stuff/omg1i(npgx,npgy,npgz), + 1 omg2i(npgx,npgy,npgz),omg3i(npgx,npgy,npgz), + 1 vxgi(npgx,npgy,npgz),vygi(npgx,npgy,npgz),vzgi(npgx,npgy,npgz) + + +c calucl de fonction courants 3d + + + xs=xmin + xf=xmax + ys=ymin + yf=ymax + zs=zmin + zf=zmax + + + w(1)=100000 + lbdcnd=0 + mbdcnd=0 + nbdcnd=0 + beta=0. + ldimf=npgx + mdimf=npgy + elmbda=0. + pertrb=0. + ierror=0 + + do k=1,nz+1 + kk=mod(k-1,nz)+1 + do j=1,ny+1 + do i=1,nx+1 + ii=mod(i-1,nx)+1 + rhs(i,j,k)=-omg1(ii,j,kk)+omg1i(ii,j,kk) + enddo + enddo + enddo + + + call HW3CRT(XS,XF,nx,LBDCND,BDXS,BDXF,yS,yF,ny,MBDCND,BDYS, + 1 BDYF,zS,zF,nz,NBDCND,BDZS,BDZF,ELMBDA,LDIMF,mDIMF,rhs,PERTRB, + 2 IERROR,W) + + + if (ierror.ne.0) print*,'attention sepx ierror=',ierror + + psimax=0. + do i=1,nx+1 + do j=1,ny+1 + do k=1,nz+1 + psi1(i,j,k)=rhs(i,j,k) + psimax=amax1(psimax,abs(psi1(i,j,k))) + enddo + enddo + enddo + + +c 2e composante: + + do k=1,nz+1 + kk=mod(k-1,nz)+1 + do j=1,ny+1 + do i=1,nx+1 + ii=mod(i-1,nx)+1 + rhs(i,j,k)=-omg2(ii,j,kk)+omg2i(ii,j,kk) + + enddo + enddo + enddo + + w(1)=100000 + + call HW3CRT(XS,XF,nx,LBDCND,BDXS,BDXF,yS,yF,ny,MBDCND,BDYS, + 1 BDYF,zS,zF,nz,NBDCND,BDZS,BDZF,ELMBDA,LDIMF,mDIMF,rhs,PERTRB, + 2 IERROR,W) + + + if (ierror.ne.0) print*,'attention sepx ierror=',ierror + + psimax=0. + psitot=0. + do i=1,nx+1 + do j=1,ny+1 + do k=1,nz+1 + psi2(i,j,k)=rhs(i,j,k) + psimax=amax1(psimax,abs(psi2(i,j,k))) + enddo + enddo + enddo + + +c 3E composante + + do k=1,nz+1 + kk=mod(k-1,nz)+1 + do j=1,ny+1 + do i=1,nx+1 + ii=mod(i-1,nx)+1 + rhs(i,j,k)=-omg3(ii,j,kk)+omg3i(ii,j,kk) + enddo + enddo + enddo + + w(1)=100000 + + call HW3CRT(XS,XF,nx,LBDCND,BDXS,BDXF,yS,yF,ny,MBDCND,BDYS, + 1 BDYF,zS,zF,nz,NBDCND,BDZS,BDZF,ELMBDA,LDIMF,mDIMF,rhs,PERTRB, + 2 IERROR,W) + + if (ierror.ne.0) print*,'attention sepx ierror=',ierror + + psimax=0. + do i=1,nx+1 + do j=1,ny+1 + yy=float(j-1)*dx + do k=1,nz+1 + psi3(i,j,k)=rhs(i,j,k) + psimax=amax1(psimax,abs(psi3(i,j,k))) + enddo + enddo + enddo + + + return + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_fft_2ways.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_fft_2ways.f new file mode 100644 index 000000000..3059dbf43 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_fft_2ways.f @@ -0,0 +1,127 @@ + subroutine velox_fft + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension aux3(npg,npg,npg),aux1(npg,npg,npg),aux2(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2), + 1 wk(ngx2+1,npgy,npgz) + + pi=3.1415926 + dxinv=0.5/dx + dyinv=dxinv + dzinv=dxinv + +c calucl de fonction courants 3d + + nx2=nx/2 + ny2=ny/2 + nz2=nz/2 + + + call fftw3d(omg1,cfx,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg2,cfy,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg3,cfz,nx,ny,nz,nx2,ny2,nz2,wk,0) + + +c coeff de normalisation pour laplacien en spectral + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nz2,nz2 + rk=float(k)*ak + do 10 j=1-ny2,ny2 + rj=float(j)*aj + do 10 i=0,nx2 + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) + if (r2.ne.0.) then +c + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + endif +10 continue + + + call fftw3d(aux1,cux,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,cuy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,cuz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + goto 111 + + do k=1,nz + do j=1,ny + do i=1,nx + dvx(i,j,k)=(-aux1(i,j,k)-vxg(i,j,k))/delt + dvy(i,j,k)=(-aux2(i,j,k)-vyg(i,j,k))/delt + dvz(i,j,k)=(-aux2(i,j,k)-vzg(i,j,k))/delt + + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + enddo + enddo + enddo + +c pour terme barotrope : du/dt+(u\nabla)u - g = + do k=1,nz + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + do i=1,nx + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + dvx(i,j,k)=dvx(i,j,k)+vxg(i,j,k)*(vxg(it,j,k)-vxg(ib,j,k))*dxinv + dvx(i,j,k)=dvx(i,j,k)+vyg(i,j,k)*(vxg(i,jt,k)-vxg(i,jb,k))*dyinv + dvx(i,j,k)=dvx(i,j,k)+vzg(i,j,k)*(vxg(i,j,kt)-vxg(i,j,kb))*dyinv + dvy(i,j,k)=dvy(i,j,k)+vxg(i,j,k)*(vyg(it,j,k)-vyg(ib,j,k))*dxinv + dvy(i,j,k)=dvy(i,j,k)+vyg(i,j,k)*(vyg(i,jt,k)-vyg(i,jb,k))*dyinv + dvy(i,j,k)=dvy(i,j,k)+vzg(i,j,k)*(vyg(i,j,kt)-vyg(i,j,kb))*dyinv + dvz(i,j,k)=dvz(i,j,k)+vxg(i,j,k)*(vzg(it,j,k)-vzg(ib,j,k))*dxinv + dvz(i,j,k)=dvz(i,j,k)+vyg(i,j,k)*(vzg(i,jt,k)-vzg(i,jb,k))*dyinv + dvz(i,j,k)=dvz(i,j,k)+vzg(i,j,k)*(vzg(i,j,kt)-vzg(i,j,kb))*dyinv + + enddo + enddo + enddo + +111 continue + + do k=1,nx + do j=1,ny + do i=1,nz + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + enddo + enddo + enddo + + + + + return + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_stream.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_stream.f new file mode 100644 index 000000000..0f831ead2 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/velox_stream.f @@ -0,0 +1,52 @@ + subroutine velox_stream + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + integer indxg(npgx,npgy),indyg(npgx,npgy) + + + + dxinv2=0.5/dx + dyinv2=0.5/dy + dzinv2=0.5/dz + + vnmax=0. + vxmin=1000. + vxmax=-1000. + vymin=100. + vymax=-1000. + do k=1,nz + kt=mod(k,nz)+1 + kb=mod(k-2+nz,nz)+1 + do j=1,ny + jt=mod(j,ny)+1 + jb=mod(j-2+ny,ny)+1 + do i=1,nx + it=mod(i,nx)+1 + ib=mod(i-2+nx,nx)+1 + vxg(i,j,k)=(-psi3(i,jb,k)+psi3(i,jt,k))*dyinv2- + 1 (-psi2(i,j,kb)+psi2(i,j,kt))*dzinv2 + + vyg(i,j,k)=(-psi1(i,j,kb)+psi1(i,j,kt))*dzinv2- + 1 (-psi3(ib,j,k)+psi3(it,j,k))*dxinv2 + + vzg(i,j,k)=(-psi2(ib,j,k)+psi2(it,j,k))*dxinv2- + 1 (-psi1(i,jb,k)+psi1(i,jt,k))*dyinv2 + + vymax=amax1(vymax,(vyg(i,j,k))) + vymin=amin1(vymin,(vyg(i,j,k))) + vxmax=amax1(vxmax,(vxg(i,j,k))) + vxmin=amin1(vxmin,(vxg(i,j,k))) + enddo + enddo + enddo + +c print*,' VXMAX = ',vxmax,vymax + + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/NotUsed/vhat.f b/CodesEnVrac/CodeGH/src-sphere/NotUsed/vhat.f new file mode 100644 index 000000000..f634056c4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/NotUsed/vhat.f @@ -0,0 +1,51 @@ + subroutine vhat(delt) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + pi=3.1415926 + topi=2./pi + eps=dx/1000. + +c calcul vitesse moyenne dans obstacle + + total=0. + aux=0. + do k=1,nz + do j=1,ny + do i=1,nx + arg=phig(i,j,k) + aux=aux+arg*vzg(i,j,k) + total=total+arg + enddo + enddo + enddo + + + aux=aux/total + + do i=1,nx + do j=1,ny + do k=1,nz + dvx(i,j,k)=0. + dvy(i,j,k)=0. + dvz(i,j,k)=(aux-vzh)/delt + enddo + enddo + enddo + + vzh=aux + + zg=zg+delt*vzh + +101 continue + + + return + end + + + diff --git a/CodesEnVrac/CodeGH/src-sphere/arrays.h b/CodesEnVrac/CodeGH/src-sphere/arrays.h new file mode 100644 index 000000000..b76a59abe --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/arrays.h @@ -0,0 +1,7 @@ +common /GRID/ & +omg1(npgx,npgy,npgz),omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz),& + vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz),& + psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz),& + strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz),& + strg3(npgx,npgy,npgz),phig(npgx,npgy,npgz) + diff --git a/CodesEnVrac/CodeGH/src-sphere/dif_om.f90 b/CodesEnVrac/CodeGH/src-sphere/dif_om.f90 new file mode 100644 index 000000000..547622cd4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/dif_om.f90 @@ -0,0 +1,73 @@ +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE dif_om(npart,om1,om2,om3,xp1,yp1,zp1,dv1,anu,dt,omax2) + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) +! +! diffusion sur grille puis initialisation des particules +! + +!---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + anudt=anu*dt/(dx**2) + + circlim=0.001 + + omax1=0. + omax2=0. + + do k=1,nz + kt=mod(k,nz)+1 + kb=mod(k-2+nz,nz)+1 + do j=1,ny + jt=mod(j,nz)+1 + jb=mod(j-2+nz,nz)+1 + do i=1,nx + it=mod(i,nz)+1 + ib=mod(i-2+nz,nz)+1 + psi1(i,j,k)=omg1(it,j,k)+omg1(ib,j,k)+omg1(i,jt,k)+omg1(i,jb,k)+omg1(i,j,kt)+omg1(i,j,kb)-6.*omg1(i,j,k) + psi2(i,j,k)=omg2(it,j,k)+omg2(ib,j,k)+omg2(i,jt,k)+omg2(i,jb,k)+omg2(i,j,kt)+omg2(i,j,kb)-6.*omg2(i,j,k) + psi3(i,j,k)=omg3(it,j,k)+omg3(ib,j,k)+omg3(i,jt,k)+omg3(i,jb,k)+omg3(i,j,kt)+omg3(i,j,kb)-6.*omg3(i,j,k) + omax1=amax1(omax1,abs(omg1(i,j,k))) + omax1=amax1(omax1,abs(omg2(i,j,k))) + omax1=amax1(omax1,abs(omg3(i,j,k))) + enddo + enddo + enddo + + npart=0 + vol=dx**3 + do k=1,nz + z=zmin+(k-1)*dz + do j=1,ny + y=ymin+(j-1)*dy + do i=1,nx + x=xmin+(i-1)*dx + omg1(i,j,k)=omg1(i,j,k)+anudt*psi1(i,j,k) + omg2(i,j,k)=omg2(i,j,k)+anudt*psi2(i,j,k) + omg3(i,j,k)=omg3(i,j,k)+anudt*psi3(i,j,k) + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + omax2=amax1(omax2,abs(omg1(i,j,k))) + omax2=amax1(omax2,abs(omg2(i,j,k))) + omax2=amax1(omax2,abs(omg3(i,j,k))) + enddo + enddo + enddo + + print*, 'OMAX avant et apres DIFF ',omax1,omax2 + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/diff_fft.f90 b/CodesEnVrac/CodeGH/src-sphere/diff_fft.f90 new file mode 100644 index 000000000..60fd7d07c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/diff_fft.f90 @@ -0,0 +1,114 @@ +subroutine diff_fft(npart,anu,delt,xp1,yp1,zp1,om1,om2,om3,dv1,omax2) + + ! calcul fft pour vitesses ET diffusion + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + + dimension aux3(npg,npg,npg),aux1(npg,npg,npg),aux2(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,cox,coy,coz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cox(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + wk(ngx2+1,npgy,npgz) + + pi=3.1415926 + dxinv=0.5/dx + dyinv=dxinv + dzinv=dxinv + + ! calucl de fonction courants 3d + + nx2=nx/2 + ny2=ny/2 + nz2=nz/2 + + + call fftw3d(omg1,cfx,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg2,cfy,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg3,cfz,nx,ny,nz,nx2,ny2,nz2,wk,0) + + + ! coeff de normalisation pour laplacien en spectral + + anudt=anu*delt + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nz2,nz2 + rk=float(k)*ak + do 10 j=1-ny2,ny2 + rj=float(j)*aj + do 10 i=0,nx2 + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + r2b=(1.+r2*anudt) + ! diffusion en fourier + cox(i,j,k)=cfx(i,j,k)/r2b + coy(i,j,k)=cfy(i,j,k)/r2b + coz(i,j,k)=cfz(i,j,k)/r2b +10 continue + + + ! fourier inverse pour vorticite apres difusion + ! et creation de particules + + call fftw3d(aux1,cox,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,coy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,coz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + + circlim=0.0001 + npart=0 + vol=dx**3 + omax1=0. + omax2=0. + do k=1,nx + do j=1,ny + do i=1,nz + omg1(i,j,k)=aux1(i,j,k) + omg2(i,j,k)=aux2(i,j,k) + omg3(i,j,k)=aux3(i,j,k) + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + x=xmin+float(i-1)*dx + y=xmin+float(j-1)*dx + z=xmin+float(k-1)*dx + npart=npart+1 + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + omax2=amax1(omax2,abs(omg1(i,j,k))) + omax2=amax1(omax2,abs(omg2(i,j,k))) + omax2=amax1(omax2,abs(omg3(i,j,k))) + enddo + enddo + enddo + + print*, 'OMAX avant et apres DIFF ',omax1,omax2 + return + + +end subroutine diff_fft + diff --git a/CodesEnVrac/CodeGH/src-sphere/drag.f90 b/CodesEnVrac/CodeGH/src-sphere/drag.f90 new file mode 100644 index 000000000..bba1137fd --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/drag.f90 @@ -0,0 +1,28 @@ + subroutine drag(drag1,drag2,drag3,j1,j2) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + drag1=0. + drag2=0. + drag3=0. + do i=1,nx + DO j=j1,j2-1 + yy=ymin+(float(j)-1.)*dy + DO k=1,nz + zz=zmin+(float(k)-1.)*dz + drag1=drag1+vxg(i,j,k)*(1.-phig(i,j,k)) + drag2=drag2+(zz*omg2(i,j,k)-yy*omg3(i,j,k))*(1.-phig(i,j,k)) + drag3=drag3+vxg(i,j,k)*phig(i,j,k) + enddo + enddo + enddo + + drag1=drag1*dx*dx*dx + drag2=drag2*dx*dx*dx + drag3=drag3*dx*dx*dx + + return + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/drag_surface.f90 b/CodesEnVrac/CodeGH/src-sphere/drag_surface.f90 new file mode 100644 index 000000000..e9ece0ada --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/drag_surface.f90 @@ -0,0 +1,104 @@ +subroutine drag_surface(drag,anu,j1,j2) + +! calcul de force selon x (pour drag) +! termes de surfaces en y= j1 et y=j2 pour la fromule de noca +! poru le drag, en supposant omega = O sur le faces z=+-h +! par rapport a noca : facteur 1/2 a mettre en facteur du tout + + include 'param.i' + include 'param.h' + include 'arrays.h' + + pi=3.1415926 + + j1t=mod(j1+ny,ny)+1 + j1b=mod(j1-2+ny,ny)+1 + j2t=mod(j2+ny,ny)+1 + j2b=mod(j2-2+ny,ny)+1 + y1=ymin+float(j1-1)*dx + y2=ymin+float(j2-1)*dx + drag1=0. + drag2=0. + drag3=0. + drag4=0. + drag5=0. +! faces y=cste (j1 ou j2) + do i=1,nx + ii=mod(i-1+nx,nx)+1 + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + x=xmin+float(i-1)*dx + DO k=1,nz + kk=mod(k-1+nz,nz)+1 + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + z=xmin+float(k-1)*dx +! queqlues derivees aparaissant dans certines integrales +! de surface + dux1dy=vxg(ii,j1t,kk)-vxg(ii,j1b,kk) + duy1dx=vyg(it,j1,kk)-vyg(ib,j1,kk) + dux2dy=vxg(ii,j2t,kk)-vxg(ii,j2b,kk) + duy2dx=vyg(it,j2,kk)-vyg(ib,j2,kk) + deltaux1=vxg(it,j1,kk)+vxg(ib,j1,kk)+vxg(ii,j1t,kk)+& + vxg(ii,j1b,kk)+vxg(ii,j1,kt)+vxg(ii,j1,kb)-6.*vxg(ii,j1,kk) + deltaux2=vxg(it,j2,kk)+vxg(ib,j2,kk)+vxg(ii,j2t,kk)+& + vxg(ii,j2b,kk)+vxg(ii,j2,kt)+vxg(ii,j2,kb)-6.*vxg(ii,j2,kk) +! 1ere + drag1=drag1+2.*vyg(ii,j1,kk)*vxg(ii,j1,kk) + drag1=drag1-2.*vyg(ii,j2,kk)*vxg(ii,j2,kk) +! 2e + drag2=drag2+vyg(ii,j1,kk)*& + (y1*omg3(ii,j1,kk)-z*omg2(ii,j1,kk)) + drag2=drag2-vyg(ii,j2,kk)*& + (y2*omg3(ii,j2,kk)-z*omg2(ii,j2,kk)) +! 3e + drag3=drag3-omg2(ii,j1,kk)*& + (y1*vzg(ii,j1,kk)-z*vyg(ii,j1,kk)) + drag3=drag3+omg2(ii,j2,kk)*& + (y2*vzg(ii,j2,kk)-z*vyg(ii,j2,kk)) +! 4e + drag4=drag4+y1*anu*deltaux1/(dx**2) + drag4=drag4-y2*anu*deltaux2/(dx**2) +! 5e (attention facteur 2 par raport aux autres -> 2dx devient dx) + drag5=drag5-anu*(dux1dy+duy1dx)/(dx) + drag5=drag5+anu*(dux2dy+duy2dx)/(dx) + enddo + enddo + +! faces z=0 et z=1 pour 2e,3e et4e integrale + drag2b=0. + drag3b=0. + drag4b=0. + do i=1,nx + ii=mod(i-1+nx,nx)+1 + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + x=xmin+float(i-1)*dx + do j=j1,j2-1 + jt=mod(j+nz,nz)+1 + jb=mod(j-2+nz,nz)+1 +! queqlues derivees aparaissant dans certines integrales +! de surface + deltaux1=vxg(it,j,1)+vxg(ib,j,1)+vxg(ii,jt,1)+& + vxg(ii,jb,1)+vxg(ii,j,2)+vxg(ii,j,nx)-6.*vxg(ii,j,1) +! 2e integrale + drag2b=drag2b+(xmax-xmin)*vzg(ii,j,1)*omg2(ii,j,1) +! 3e intergral + drag3b=drag3b-(xmax-xmin)*vyg(ii,j,1)*omg3(ii,j,1) +! 4e + drag4b=drag4b-(xmax-xmin)*anu*deltaux1/(dx**2) + enddo + enddo + + drag=drag1+drag2+drag3+drag4+drag5+drag2b+drag3b+drag4b + + drag=drag*dx*dx + + cc=4.*dx*dx/(pi*0.2422*0.2422) + + print*,'DRAGSSS ',cc*drag1,cc*drag2,cc*drag3,cc*drag4,cc*drag5 + print*,'DRAGSSS ',cc*drag2b,cc*drag3b,cc*drag4b + + return + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/init.f90 b/CodesEnVrac/CodeGH/src-sphere/init.f90 new file mode 100644 index 000000000..77b19bc6c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/init.f90 @@ -0,0 +1,63 @@ + subroutine init(npart,xp,yp,zp,omx,omy,omz,dv) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp(*),yp(*),zp(*),dv(*) + dimension omx(*),omy(*),omz(*) + + character*30 rota + + pi=3.1415926 + piinv = 1./( pi) + pi2=2.*pi + + xc=(xmin+xmax)/2. + yc=xc + zc=xc +! rc1=0.1 + rc1=(xmax-xmin)*0.1211 + + eps=dx*width + + npart=0. + do 10 i=1,nx + xx=xmin+(float(i)-1.)*dx + DO 10 j=1,ny + yy=ymin+(float(j)-1.)*dy + DO 10 k=1,nz + zz=zmin+(float(k)-1.)*dz + npart=npart+1 + r1 =sqrt((xx-xc)**2+(yy-yc)**2+(zz-zc)**2)-rc1 + xp(npart)=xx + yp(npart)=yy + zp(npart)=zz + dv(npart)=dx*dy*dz + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. + vxg(i,j,k)=0. + vyg(i,j,k)=0. + vzg(i,j,k)=0. + strg1(i,j,k)=0. + strg2(i,j,k)=0. + strg3(i,j,k)=0. + omx(npart)=0. + omy(npart)=0. + omz(npart)=0. + phig(i,j,k)=amin1(1.,amax1(1.-r1/eps,0.)) + if ((j.le.4).or.(j.ge.nx-3)) phig(i,j,k)=1. +10 continue + print*, 'NPART =', npart + +101 continue + + + return + end + + diff --git a/CodesEnVrac/CodeGH/src-sphere/intersm4.f90 b/CodesEnVrac/CodeGH/src-sphere/intersm4.f90 new file mode 100644 index 000000000..0241ebbdf --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/intersm4.f90 @@ -0,0 +1,365 @@ +! +SUBROUTINE intersm4(npart,g1,g2,g3,xp,yp,zp) + + ! + ! Interpolation routine with M'4 + ! + ! geometry=unit box, periodic in x and y + ! last ponits in z direction assume extension by continuity + ! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + include 'param.i' + include 'param.h' + dimension g1(1),g2(1),g3(1),xp(1),yp(1),zp(1) + + COMMON/GRID/ omg1(npgx,npgy,npgz),& + omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz),& + vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz),& + psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz),& + gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz),& + phig(npgx,npgy,npgz) + + do i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. + end do + + dxinv=1./dx + dyinv=1./dy + dzinv=1./dz + dh3=dx*dy*dz + dhinv3=1./dh3 + + + !-------------------------------------------------------------------- + !- PART II : Determination of the circulation of each particle + !-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + DO i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + + ! get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dy-y0)*dyinv + zz1 = (z - float(kp1)*dz-z0)*dzinv + xx0=xx1+1 + yy0=yy1+1 + zz0=zz1+1 + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + + xx3=2-xx1 + yy3=2-yy1 + zz3=2-zz1 + + + ! + ! on repositionne les points de grille par periodicite + ! entre 0 et m-1, puis on numerote de 1 a m + ! + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + + ! print*,ip0,ip1,ip2,ip3 + + jp1=mod(jp1+ny,ny) +1 + jp0=mod(jp0+ny,ny) +1 + jp2=mod(jp2+ny,ny) +1 + jp3=mod(jp3+ny,ny) +1 + + kp1=mod(kp1+nz,nz) +1 + kp0=mod(kp0+nz,nz) +1 + kp2=mod(kp2+nz,nz) +1 + kp3=mod(kp3+nz,nz) +1 + ! + ! The M'4 scheme + ! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + g1(i)= g1(i) + GG1(ip0,jp0,kp0)*a0*b0*c0 + g1(i)= g1(i) + GG1(ip0,jp1,kp0)*a0*b1*c0 + g1(i)= g1(i) + GG1(ip0,jp2,kp0)*a0*b2*c0 + g1(i)= g1(i) + GG1(ip0,jp3,kp0)*a0*b3*c0 + + g2(i)= g2(i) + GG2(ip0,jp0,kp0)*a0*b0*c0 + g2(i)= g2(i) + GG2(ip0,jp1,kp0)*a0*b1*c0 + g2(i)= g2(i) + GG2(ip0,jp2,kp0)*a0*b2*c0 + g2(i)= g2(i) + GG2(ip0,jp3,kp0)*a0*b3*c0 + + g3(i)= g3(i) + GG3(ip0,jp0,kp0)*a0*b0*c0 + g3(i)= g3(i) + GG3(ip0,jp1,kp0)*a0*b1*c0 + g3(i)= g3(i) + GG3(ip0,jp2,kp0)*a0*b2*c0 + g3(i)= g3(i) + GG3(ip0,jp3,kp0)*a0*b3*c0 + + g1(i)= g1(i) + GG1(ip1,jp0,kp0)*a1*b0*c0 + g1(i)= g1(i) + GG1(ip1,jp1,kp0)*a1*b1*c0 + g1(i)= g1(i) + GG1(ip1,jp2,kp0)*a1*b2*c0 + g1(i)= g1(i) + GG1(ip1,jp3,kp0)*a1*b3*c0 + + g2(i)= g2(i) + GG2(ip1,jp0,kp0)*a1*b0*c0 + g2(i)= g2(i) + GG2(ip1,jp1,kp0)*a1*b1*c0 + g2(i)= g2(i) + GG2(ip1,jp2,kp0)*a1*b2*c0 + g2(i)= g2(i) + GG2(ip1,jp3,kp0)*a1*b3*c0 + + g3(i)= g3(i) + GG3(ip1,jp0,kp0)*a1*b0*c0 + g3(i)= g3(i) + GG3(ip1,jp1,kp0)*a1*b1*c0 + g3(i)= g3(i) + GG3(ip1,jp2,kp0)*a1*b2*c0 + g3(i)= g3(i) + GG3(ip1,jp3,kp0)*a1*b3*c0 + + g1(i)= g1(i) + GG1(ip2,jp0,kp0)*a2*b0*c0 + g1(i)= g1(i) + GG1(ip2,jp1,kp0)*a2*b1*c0 + g1(i)= g1(i) + GG1(ip2,jp2,kp0)*a2*b2*c0 + g1(i)= g1(i) + GG1(ip2,jp3,kp0)*a2*b3*c0 + + g2(i)= g2(i) + GG2(ip2,jp0,kp0)*a2*b0*c0 + g2(i)= g2(i) + GG2(ip2,jp1,kp0)*a2*b1*c0 + g2(i)= g2(i) + GG2(ip2,jp2,kp0)*a2*b2*c0 + g2(i)= g2(i) + GG2(ip2,jp3,kp0)*a2*b3*c0 + + g3(i)= g3(i) + GG3(ip2,jp0,kp0)*a2*b0*c0 + g3(i)= g3(i) + GG3(ip2,jp1,kp0)*a2*b1*c0 + g3(i)= g3(i) + GG3(ip2,jp2,kp0)*a2*b2*c0 + g3(i)= g3(i) + GG3(ip2,jp3,kp0)*a2*b3*c0 + + g1(i)= g1(i) + GG1(ip3,jp0,kp0)*a3*b0*c0 + g1(i)= g1(i) + GG1(ip3,jp1,kp0)*a3*b1*c0 + g1(i)= g1(i) + GG1(ip3,jp2,kp0)*a3*b2*c0 + g1(i)= g1(i) + GG1(ip3,jp3,kp0)*a3*b3*c0 + + g2(i)= g2(i) + GG2(ip3,jp0,kp0)*a3*b0*c0 + g2(i)= g2(i) + GG2(ip3,jp1,kp0)*a3*b1*c0 + g2(i)= g2(i) + GG2(ip3,jp2,kp0)*a3*b2*c0 + g2(i)= g2(i) + GG2(ip3,jp3,kp0)*a3*b3*c0 + + g3(i)= g3(i) + GG3(ip3,jp0,kp0)*a3*b0*c0 + g3(i)= g3(i) + GG3(ip3,jp1,kp0)*a3*b1*c0 + g3(i)= g3(i) + GG3(ip3,jp2,kp0)*a3*b2*c0 + g3(i)= g3(i) + GG3(ip3,jp3,kp0)*a3*b3*c0 + + g1(i)= g1(i) + GG1(ip0,jp0,kp1)*a0*b0*c1 + g1(i)= g1(i) + GG1(ip0,jp1,kp1)*a0*b1*c1 + g1(i)= g1(i) + GG1(ip0,jp2,kp1)*a0*b2*c1 + g1(i)= g1(i) + GG1(ip0,jp3,kp1)*a0*b3*c1 + + g2(i)= g2(i) + GG2(ip0,jp0,kp1)*a0*b0*c1 + g2(i)= g2(i) + GG2(ip0,jp1,kp1)*a0*b1*c1 + g2(i)= g2(i) + GG2(ip0,jp2,kp1)*a0*b2*c1 + g2(i)= g2(i) + GG2(ip0,jp3,kp1)*a0*b3*c1 + + g3(i)= g3(i) + GG3(ip0,jp0,kp1)*a0*b0*c1 + g3(i)= g3(i) + GG3(ip0,jp1,kp1)*a0*b1*c1 + g3(i)= g3(i) + GG3(ip0,jp2,kp1)*a0*b2*c1 + g3(i)= g3(i) + GG3(ip0,jp3,kp1)*a0*b3*c1 + + g1(i)= g1(i) + GG1(ip1,jp0,kp1)*a1*b0*c1 + g1(i)= g1(i) + GG1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + GG1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + GG1(ip1,jp3,kp1)*a1*b3*c1 + + g2(i)= g2(i) + GG2(ip1,jp0,kp1)*a1*b0*c1 + g2(i)= g2(i) + GG2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + GG2(ip1,jp2,kp1)*a1*b2*c1 + g2(i)= g2(i) + GG2(ip1,jp3,kp1)*a1*b3*c1 + + g3(i)= g3(i) + GG3(ip1,jp0,kp1)*a1*b0*c1 + g3(i)= g3(i) + GG3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + GG3(ip1,jp2,kp1)*a1*b2*c1 + g3(i)= g3(i) + GG3(ip1,jp3,kp1)*a1*b3*c1 + + g1(i)= g1(i) + GG1(ip2,jp0,kp1)*a2*b0*c1 + g1(i)= g1(i) + GG1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + GG1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + GG1(ip2,jp3,kp1)*a2*b3*c1 + + g2(i)= g2(i) + GG2(ip2,jp0,kp1)*a2*b0*c1 + g2(i)= g2(i) + GG2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + GG2(ip2,jp2,kp1)*a2*b2*c1 + g2(i)= g2(i) + GG2(ip2,jp3,kp1)*a2*b3*c1 + + g3(i)= g3(i) + GG3(ip2,jp0,kp1)*a2*b0*c1 + g3(i)= g3(i) + GG3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + GG3(ip2,jp2,kp1)*a2*b2*c1 + g3(i)= g3(i) + GG3(ip2,jp3,kp1)*a2*b3*c1 + + g1(i)= g1(i) + GG1(ip3,jp0,kp1)*a3*b0*c1 + g1(i)= g1(i) + GG1(ip3,jp1,kp1)*a3*b1*c1 + g1(i)= g1(i) + GG1(ip3,jp2,kp1)*a3*b2*c1 + g1(i)= g1(i) + GG1(ip3,jp3,kp1)*a3*b3*c1 + + g2(i)= g2(i) + GG2(ip3,jp0,kp1)*a3*b0*c1 + g2(i)= g2(i) + GG2(ip3,jp1,kp1)*a3*b1*c1 + g2(i)= g2(i) + GG2(ip3,jp2,kp1)*a3*b2*c1 + g2(i)= g2(i) + GG2(ip3,jp3,kp1)*a3*b3*c1 + + g3(i)= g3(i) + GG3(ip3,jp0,kp1)*a3*b0*c1 + g3(i)= g3(i) + GG3(ip3,jp1,kp1)*a3*b1*c1 + g3(i)= g3(i) + GG3(ip3,jp2,kp1)*a3*b2*c1 + g3(i)= g3(i) + GG3(ip3,jp3,kp1)*a3*b3*c1 + + g1(i)= g1(i) + GG1(ip0,jp0,kp2)*a0*b0*c2 + g1(i)= g1(i) + GG1(ip0,jp1,kp2)*a0*b1*c2 + g1(i)= g1(i) + GG1(ip0,jp2,kp2)*a0*b2*c2 + g1(i)= g1(i) + GG1(ip0,jp3,kp2)*a0*b3*c2 + + g2(i)= g2(i) + GG2(ip0,jp0,kp2)*a0*b0*c2 + g2(i)= g2(i) + GG2(ip0,jp1,kp2)*a0*b1*c2 + g2(i)= g2(i) + GG2(ip0,jp2,kp2)*a0*b2*c2 + g2(i)= g2(i) + GG2(ip0,jp3,kp2)*a0*b3*c2 + + g3(i)= g3(i) + GG3(ip0,jp0,kp2)*a0*b0*c2 + g3(i)= g3(i) + GG3(ip0,jp1,kp2)*a0*b1*c2 + g3(i)= g3(i) + GG3(ip0,jp2,kp2)*a0*b2*c2 + g3(i)= g3(i) + GG3(ip0,jp3,kp2)*a0*b3*c2 + + g1(i)= g1(i) + GG1(ip1,jp0,kp2)*a1*b0*c2 + g1(i)= g1(i) + GG1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + GG1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + GG1(ip1,jp3,kp2)*a1*b3*c2 + + g2(i)= g2(i) + GG2(ip1,jp0,kp2)*a1*b0*c2 + g2(i)= g2(i) + GG2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + GG2(ip1,jp2,kp2)*a1*b2*c2 + g2(i)= g2(i) + GG2(ip1,jp3,kp2)*a1*b3*c2 + + g3(i)= g3(i) + GG3(ip1,jp0,kp2)*a1*b0*c2 + g3(i)= g3(i) + GG3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + GG3(ip1,jp2,kp2)*a1*b2*c2 + g3(i)= g3(i) + GG3(ip1,jp3,kp2)*a1*b3*c2 + + g1(i)= g1(i) + GG1(ip2,jp0,kp2)*a2*b0*c2 + g1(i)= g1(i) + GG1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + GG1(ip2,jp2,kp2)*a2*b2*c2 + g1(i)= g1(i) + GG1(ip2,jp3,kp2)*a2*b3*c2 + + g2(i)= g2(i) + GG2(ip2,jp0,kp2)*a2*b0*c2 + g2(i)= g2(i) + GG2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + GG2(ip2,jp2,kp2)*a2*b2*c2 + g2(i)= g2(i) + GG2(ip2,jp3,kp2)*a2*b3*c2 + + g3(i)= g3(i) + GG3(ip2,jp0,kp2)*a2*b0*c2 + g3(i)= g3(i) + GG3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + GG3(ip2,jp2,kp2)*a2*b2*c2 + g3(i)= g3(i) + GG3(ip2,jp3,kp2)*a2*b3*c2 + + g1(i)= g1(i) + GG1(ip3,jp0,kp2)*a3*b0*c2 + g1(i)= g1(i) + GG1(ip3,jp1,kp2)*a3*b1*c2 + g1(i)= g1(i) + GG1(ip3,jp2,kp2)*a3*b2*c2 + g1(i)= g1(i) + GG1(ip3,jp3,kp2)*a3*b3*c2 + + g2(i)= g2(i) + GG2(ip3,jp0,kp2)*a3*b0*c2 + g2(i)= g2(i) + GG2(ip3,jp1,kp2)*a3*b1*c2 + g2(i)= g2(i) + GG2(ip3,jp2,kp2)*a3*b2*c2 + g2(i)= g2(i) + GG2(ip3,jp3,kp2)*a3*b3*c2 + + g3(i)= g3(i) + GG3(ip3,jp0,kp2)*a3*b0*c2 + g3(i)= g3(i) + GG3(ip3,jp1,kp2)*a3*b1*c2 + g3(i)= g3(i) + GG3(ip3,jp2,kp2)*a3*b2*c2 + g3(i)= g3(i) + GG3(ip3,jp3,kp2)*a3*b3*c2 + + g1(i)= g1(i) + GG1(ip0,jp0,kp3)*a0*b0*c3 + g1(i)= g1(i) + GG1(ip0,jp1,kp3)*a0*b1*c3 + g1(i)= g1(i) + GG1(ip0,jp2,kp3)*a0*b2*c3 + g1(i)= g1(i) + GG1(ip0,jp3,kp3)*a0*b3*c3 + + g2(i)= g2(i) + GG2(ip0,jp0,kp3)*a0*b0*c3 + g2(i)= g2(i) + GG2(ip0,jp1,kp3)*a0*b1*c3 + g2(i)= g2(i) + GG2(ip0,jp2,kp3)*a0*b2*c3 + g2(i)= g2(i) + GG2(ip0,jp3,kp3)*a0*b3*c3 + + g3(i)= g3(i) + GG3(ip0,jp0,kp3)*a0*b0*c3 + g3(i)= g3(i) + GG3(ip0,jp1,kp3)*a0*b1*c3 + g3(i)= g3(i) + GG3(ip0,jp2,kp3)*a0*b2*c3 + g3(i)= g3(i) + GG3(ip0,jp3,kp3)*a0*b3*c3 + + g1(i)= g1(i) + GG1(ip1,jp0,kp3)*a1*b0*c3 + g1(i)= g1(i) + GG1(ip1,jp1,kp3)*a1*b1*c3 + g1(i)= g1(i) + GG1(ip1,jp2,kp3)*a1*b2*c3 + g1(i)= g1(i) + GG1(ip1,jp3,kp3)*a1*b3*c3 + + g2(i)= g2(i) + GG2(ip1,jp0,kp3)*a1*b0*c3 + g2(i)= g2(i) + GG2(ip1,jp1,kp3)*a1*b1*c3 + g2(i)= g2(i) + GG2(ip1,jp2,kp3)*a1*b2*c3 + g2(i)= g2(i) + GG2(ip1,jp3,kp3)*a1*b3*c3 + + g3(i)= g3(i) + GG3(ip1,jp0,kp3)*a1*b0*c3 + g3(i)= g3(i) + GG3(ip1,jp1,kp3)*a1*b1*c3 + g3(i)= g3(i) + GG3(ip1,jp2,kp3)*a1*b2*c3 + g3(i)= g3(i) + GG3(ip1,jp3,kp3)*a1*b3*c3 + + g1(i)= g1(i) + GG1(ip2,jp0,kp3)*a2*b0*c3 + g1(i)= g1(i) + GG1(ip2,jp1,kp3)*a2*b1*c3 + g1(i)= g1(i) + GG1(ip2,jp2,kp3)*a2*b2*c3 + g1(i)= g1(i) + GG1(ip2,jp3,kp3)*a2*b3*c3 + + g2(i)= g2(i) + GG2(ip2,jp0,kp3)*a2*b0*c3 + g2(i)= g2(i) + GG2(ip2,jp1,kp3)*a2*b1*c3 + g2(i)= g2(i) + GG2(ip2,jp2,kp3)*a2*b2*c3 + g2(i)= g2(i) + GG2(ip2,jp3,kp3)*a2*b3*c3 + + g3(i)= g3(i) + GG3(ip2,jp0,kp3)*a2*b0*c3 + g3(i)= g3(i) + GG3(ip2,jp1,kp3)*a2*b1*c3 + g3(i)= g3(i) + GG3(ip2,jp2,kp3)*a2*b2*c3 + g3(i)= g3(i) + GG3(ip2,jp3,kp3)*a2*b3*c3 + + g1(i)= g1(i) + GG1(ip3,jp0,kp3)*a3*b0*c3 + g1(i)= g1(i) + GG1(ip3,jp1,kp3)*a3*b1*c3 + g1(i)= g1(i) + GG1(ip3,jp2,kp3)*a3*b2*c3 + g1(i)= g1(i) + GG1(ip3,jp3,kp3)*a3*b3*c3 + + g2(i)= g2(i) + GG2(ip3,jp0,kp3)*a3*b0*c3 + g2(i)= g2(i) + GG2(ip3,jp1,kp3)*a3*b1*c3 + g2(i)= g2(i) + GG2(ip3,jp2,kp3)*a3*b2*c3 + g2(i)= g2(i) + GG2(ip3,jp3,kp3)*a3*b3*c3 + + g3(i)= g3(i) + GG3(ip3,jp0,kp3)*a3*b0*c3 + g3(i)= g3(i) + GG3(ip3,jp1,kp3)*a3*b1*c3 + g3(i)= g3(i) + GG3(ip3,jp2,kp3)*a3*b2*c3 + g3(i)= g3(i) + GG3(ip3,jp3,kp3)*a3*b3*c3 + + end DO + +end SUBROUTINE intersm4 diff --git a/CodesEnVrac/CodeGH/src-sphere/intervm4.f90 b/CodesEnVrac/CodeGH/src-sphere/intervm4.f90 new file mode 100644 index 000000000..61456d17c --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/intervm4.f90 @@ -0,0 +1,377 @@ +! + SUBROUTINE intervm4(npart,g1,g2,g3,xp,yp,zp) + +! +! Interpolation routine with M'4 +! +! geometry=unit box, periodic in x and y +! last ponits in z direction assume extension by continuity +! that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +!---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + dimension g1(*),g2(*),g3(*),xp(*),yp(*),zp(*) + + COMMON/GRID/ omg1(npgx,npgy,npgz),& + omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz),& + gg1(npgx,npgy,npgz),gg2(npgx,npgy,npgz),gg3(npgx,npgy,npgz),& + psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz),& + strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz),& + strg3(npgx,npgy,npgz),phig(npgx,npgy,npgz) + + + + do 10 i=1,npart + g1(i)=0. + g2(i)=0. + g3(i)=0. +10 continue + + dxinv=1./dx + dyinv=1./dy + dzinv=1./dz + dh3=dx*dy*dz + dhinv3=1./dh3 + + +!-------------------------------------------------------------------- +!- PART II : Determination of the circulation of each particle +!-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + + DO 20 i = 1,npart + + x = XP(i) + y = YP(i) + z = ZP(i) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + +! get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dy-y0)*dyinv + zz1 = (z - float(kp1)*dz-z0)*dzinv + + xx0=xx1+1 + yy0=yy1+1 + zz0=zz1+1 + + xx2=1-xx1 + yy2=1-yy1 + zz2=1-zz1 + + xx3=2-xx1 + yy3=2-yy1 + zz3=2-zz1 + + +! +! on repositionne les points de grille par periodicite +! entre 0 et m-1, puis on numerote de 1 a m +! + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + +! print*,ip0,ip1,ip2,ip3 + + jp1=mod(jp1+ny,ny) +1 + jp0=mod(jp0+ny,ny) +1 + jp2=mod(jp2+ny,ny) +1 + jp3=mod(jp3+ny,ny) +1 + + kp1=mod(kp1+nz,nz) +1 + kp0=mod(kp0+nz,nz) +1 + kp2=mod(kp2+nz,nz) +1 + kp3=mod(kp3+nz,nz) +1 + +! +! The M'4 scheme +! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + g1(i)= g1(i) + GG1(ip0,jp0,kp0)*a0*b0*c0 + g1(i)= g1(i) + GG1(ip0,jp1,kp0)*a0*b1*c0 + g1(i)= g1(i) + GG1(ip0,jp2,kp0)*a0*b2*c0 + g1(i)= g1(i) + GG1(ip0,jp3,kp0)*a0*b3*c0 + + g2(i)= g2(i) + GG2(ip0,jp0,kp0)*a0*b0*c0 + g2(i)= g2(i) + GG2(ip0,jp1,kp0)*a0*b1*c0 + g2(i)= g2(i) + GG2(ip0,jp2,kp0)*a0*b2*c0 + g2(i)= g2(i) + GG2(ip0,jp3,kp0)*a0*b3*c0 + + g3(i)= g3(i) + GG3(ip0,jp0,kp0)*a0*b0*c0 + g3(i)= g3(i) + GG3(ip0,jp1,kp0)*a0*b1*c0 + g3(i)= g3(i) + GG3(ip0,jp2,kp0)*a0*b2*c0 + g3(i)= g3(i) + GG3(ip0,jp3,kp0)*a0*b3*c0 + + g1(i)= g1(i) + GG1(ip1,jp0,kp0)*a1*b0*c0 + g1(i)= g1(i) + GG1(ip1,jp1,kp0)*a1*b1*c0 + g1(i)= g1(i) + GG1(ip1,jp2,kp0)*a1*b2*c0 + g1(i)= g1(i) + GG1(ip1,jp3,kp0)*a1*b3*c0 + + g2(i)= g2(i) + GG2(ip1,jp0,kp0)*a1*b0*c0 + g2(i)= g2(i) + GG2(ip1,jp1,kp0)*a1*b1*c0 + g2(i)= g2(i) + GG2(ip1,jp2,kp0)*a1*b2*c0 + g2(i)= g2(i) + GG2(ip1,jp3,kp0)*a1*b3*c0 + + g3(i)= g3(i) + GG3(ip1,jp0,kp0)*a1*b0*c0 + g3(i)= g3(i) + GG3(ip1,jp1,kp0)*a1*b1*c0 + g3(i)= g3(i) + GG3(ip1,jp2,kp0)*a1*b2*c0 + g3(i)= g3(i) + GG3(ip1,jp3,kp0)*a1*b3*c0 + + g1(i)= g1(i) + GG1(ip2,jp0,kp0)*a2*b0*c0 + g1(i)= g1(i) + GG1(ip2,jp1,kp0)*a2*b1*c0 + g1(i)= g1(i) + GG1(ip2,jp2,kp0)*a2*b2*c0 + g1(i)= g1(i) + GG1(ip2,jp3,kp0)*a2*b3*c0 + + g2(i)= g2(i) + GG2(ip2,jp0,kp0)*a2*b0*c0 + g2(i)= g2(i) + GG2(ip2,jp1,kp0)*a2*b1*c0 + g2(i)= g2(i) + GG2(ip2,jp2,kp0)*a2*b2*c0 + g2(i)= g2(i) + GG2(ip2,jp3,kp0)*a2*b3*c0 + + g3(i)= g3(i) + GG3(ip2,jp0,kp0)*a2*b0*c0 + g3(i)= g3(i) + GG3(ip2,jp1,kp0)*a2*b1*c0 + g3(i)= g3(i) + GG3(ip2,jp2,kp0)*a2*b2*c0 + g3(i)= g3(i) + GG3(ip2,jp3,kp0)*a2*b3*c0 + + g1(i)= g1(i) + GG1(ip3,jp0,kp0)*a3*b0*c0 + g1(i)= g1(i) + GG1(ip3,jp1,kp0)*a3*b1*c0 + g1(i)= g1(i) + GG1(ip3,jp2,kp0)*a3*b2*c0 + g1(i)= g1(i) + GG1(ip3,jp3,kp0)*a3*b3*c0 + + g2(i)= g2(i) + GG2(ip3,jp0,kp0)*a3*b0*c0 + g2(i)= g2(i) + GG2(ip3,jp1,kp0)*a3*b1*c0 + g2(i)= g2(i) + GG2(ip3,jp2,kp0)*a3*b2*c0 + g2(i)= g2(i) + GG2(ip3,jp3,kp0)*a3*b3*c0 + + g3(i)= g3(i) + GG3(ip3,jp0,kp0)*a3*b0*c0 + g3(i)= g3(i) + GG3(ip3,jp1,kp0)*a3*b1*c0 + g3(i)= g3(i) + GG3(ip3,jp2,kp0)*a3*b2*c0 + g3(i)= g3(i) + GG3(ip3,jp3,kp0)*a3*b3*c0 + + g1(i)= g1(i) + GG1(ip0,jp0,kp1)*a0*b0*c1 + g1(i)= g1(i) + GG1(ip0,jp1,kp1)*a0*b1*c1 + g1(i)= g1(i) + GG1(ip0,jp2,kp1)*a0*b2*c1 + g1(i)= g1(i) + GG1(ip0,jp3,kp1)*a0*b3*c1 + + g2(i)= g2(i) + GG2(ip0,jp0,kp1)*a0*b0*c1 + g2(i)= g2(i) + GG2(ip0,jp1,kp1)*a0*b1*c1 + g2(i)= g2(i) + GG2(ip0,jp2,kp1)*a0*b2*c1 + g2(i)= g2(i) + GG2(ip0,jp3,kp1)*a0*b3*c1 + + g3(i)= g3(i) + GG3(ip0,jp0,kp1)*a0*b0*c1 + g3(i)= g3(i) + GG3(ip0,jp1,kp1)*a0*b1*c1 + g3(i)= g3(i) + GG3(ip0,jp2,kp1)*a0*b2*c1 + g3(i)= g3(i) + GG3(ip0,jp3,kp1)*a0*b3*c1 + + g1(i)= g1(i) + GG1(ip1,jp0,kp1)*a1*b0*c1 + g1(i)= g1(i) + GG1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + GG1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + GG1(ip1,jp3,kp1)*a1*b3*c1 + + g2(i)= g2(i) + GG2(ip1,jp0,kp1)*a1*b0*c1 + g2(i)= g2(i) + GG2(ip1,jp1,kp1)*a1*b1*c1 + g2(i)= g2(i) + GG2(ip1,jp2,kp1)*a1*b2*c1 + g2(i)= g2(i) + GG2(ip1,jp3,kp1)*a1*b3*c1 + + g3(i)= g3(i) + GG3(ip1,jp0,kp1)*a1*b0*c1 + g3(i)= g3(i) + GG3(ip1,jp1,kp1)*a1*b1*c1 + g3(i)= g3(i) + GG3(ip1,jp2,kp1)*a1*b2*c1 + g3(i)= g3(i) + GG3(ip1,jp3,kp1)*a1*b3*c1 + + g1(i)= g1(i) + GG1(ip2,jp0,kp1)*a2*b0*c1 + g1(i)= g1(i) + GG1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + GG1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + GG1(ip2,jp3,kp1)*a2*b3*c1 + + g2(i)= g2(i) + GG2(ip2,jp0,kp1)*a2*b0*c1 + g2(i)= g2(i) + GG2(ip2,jp1,kp1)*a2*b1*c1 + g2(i)= g2(i) + GG2(ip2,jp2,kp1)*a2*b2*c1 + g2(i)= g2(i) + GG2(ip2,jp3,kp1)*a2*b3*c1 + + g3(i)= g3(i) + GG3(ip2,jp0,kp1)*a2*b0*c1 + g3(i)= g3(i) + GG3(ip2,jp1,kp1)*a2*b1*c1 + g3(i)= g3(i) + GG3(ip2,jp2,kp1)*a2*b2*c1 + g3(i)= g3(i) + GG3(ip2,jp3,kp1)*a2*b3*c1 + + g1(i)= g1(i) + GG1(ip3,jp0,kp1)*a3*b0*c1 + g1(i)= g1(i) + GG1(ip3,jp1,kp1)*a3*b1*c1 + g1(i)= g1(i) + GG1(ip3,jp2,kp1)*a3*b2*c1 + g1(i)= g1(i) + GG1(ip3,jp3,kp1)*a3*b3*c1 + + g2(i)= g2(i) + GG2(ip3,jp0,kp1)*a3*b0*c1 + g2(i)= g2(i) + GG2(ip3,jp1,kp1)*a3*b1*c1 + g2(i)= g2(i) + GG2(ip3,jp2,kp1)*a3*b2*c1 + g2(i)= g2(i) + GG2(ip3,jp3,kp1)*a3*b3*c1 + + g3(i)= g3(i) + GG3(ip3,jp0,kp1)*a3*b0*c1 + g3(i)= g3(i) + GG3(ip3,jp1,kp1)*a3*b1*c1 + g3(i)= g3(i) + GG3(ip3,jp2,kp1)*a3*b2*c1 + g3(i)= g3(i) + GG3(ip3,jp3,kp1)*a3*b3*c1 + + g1(i)= g1(i) + GG1(ip0,jp0,kp2)*a0*b0*c2 + g1(i)= g1(i) + GG1(ip0,jp1,kp2)*a0*b1*c2 + g1(i)= g1(i) + GG1(ip0,jp2,kp2)*a0*b2*c2 + g1(i)= g1(i) + GG1(ip0,jp3,kp2)*a0*b3*c2 + + g2(i)= g2(i) + GG2(ip0,jp0,kp2)*a0*b0*c2 + g2(i)= g2(i) + GG2(ip0,jp1,kp2)*a0*b1*c2 + g2(i)= g2(i) + GG2(ip0,jp2,kp2)*a0*b2*c2 + g2(i)= g2(i) + GG2(ip0,jp3,kp2)*a0*b3*c2 + + g3(i)= g3(i) + GG3(ip0,jp0,kp2)*a0*b0*c2 + g3(i)= g3(i) + GG3(ip0,jp1,kp2)*a0*b1*c2 + g3(i)= g3(i) + GG3(ip0,jp2,kp2)*a0*b2*c2 + g3(i)= g3(i) + GG3(ip0,jp3,kp2)*a0*b3*c2 + + g1(i)= g1(i) + GG1(ip1,jp0,kp2)*a1*b0*c2 + g1(i)= g1(i) + GG1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + GG1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + GG1(ip1,jp3,kp2)*a1*b3*c2 + + g2(i)= g2(i) + GG2(ip1,jp0,kp2)*a1*b0*c2 + g2(i)= g2(i) + GG2(ip1,jp1,kp2)*a1*b1*c2 + g2(i)= g2(i) + GG2(ip1,jp2,kp2)*a1*b2*c2 + g2(i)= g2(i) + GG2(ip1,jp3,kp2)*a1*b3*c2 + + g3(i)= g3(i) + GG3(ip1,jp0,kp2)*a1*b0*c2 + g3(i)= g3(i) + GG3(ip1,jp1,kp2)*a1*b1*c2 + g3(i)= g3(i) + GG3(ip1,jp2,kp2)*a1*b2*c2 + g3(i)= g3(i) + GG3(ip1,jp3,kp2)*a1*b3*c2 + + g1(i)= g1(i) + GG1(ip2,jp0,kp2)*a2*b0*c2 + g1(i)= g1(i) + GG1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + GG1(ip2,jp2,kp2)*a2*b2*c2 + g1(i)= g1(i) + GG1(ip2,jp3,kp2)*a2*b3*c2 + + g2(i)= g2(i) + GG2(ip2,jp0,kp2)*a2*b0*c2 + g2(i)= g2(i) + GG2(ip2,jp1,kp2)*a2*b1*c2 + g2(i)= g2(i) + GG2(ip2,jp2,kp2)*a2*b2*c2 + g2(i)= g2(i) + GG2(ip2,jp3,kp2)*a2*b3*c2 + + g3(i)= g3(i) + GG3(ip2,jp0,kp2)*a2*b0*c2 + g3(i)= g3(i) + GG3(ip2,jp1,kp2)*a2*b1*c2 + g3(i)= g3(i) + GG3(ip2,jp2,kp2)*a2*b2*c2 + g3(i)= g3(i) + GG3(ip2,jp3,kp2)*a2*b3*c2 + + g1(i)= g1(i) + GG1(ip3,jp0,kp2)*a3*b0*c2 + g1(i)= g1(i) + GG1(ip3,jp1,kp2)*a3*b1*c2 + g1(i)= g1(i) + GG1(ip3,jp2,kp2)*a3*b2*c2 + g1(i)= g1(i) + GG1(ip3,jp3,kp2)*a3*b3*c2 + + g2(i)= g2(i) + GG2(ip3,jp0,kp2)*a3*b0*c2 + g2(i)= g2(i) + GG2(ip3,jp1,kp2)*a3*b1*c2 + g2(i)= g2(i) + GG2(ip3,jp2,kp2)*a3*b2*c2 + g2(i)= g2(i) + GG2(ip3,jp3,kp2)*a3*b3*c2 + + g3(i)= g3(i) + GG3(ip3,jp0,kp2)*a3*b0*c2 + g3(i)= g3(i) + GG3(ip3,jp1,kp2)*a3*b1*c2 + g3(i)= g3(i) + GG3(ip3,jp2,kp2)*a3*b2*c2 + g3(i)= g3(i) + GG3(ip3,jp3,kp2)*a3*b3*c2 + + g1(i)= g1(i) + GG1(ip0,jp0,kp3)*a0*b0*c3 + g1(i)= g1(i) + GG1(ip0,jp1,kp3)*a0*b1*c3 + g1(i)= g1(i) + GG1(ip0,jp2,kp3)*a0*b2*c3 + g1(i)= g1(i) + GG1(ip0,jp3,kp3)*a0*b3*c3 + + g2(i)= g2(i) + GG2(ip0,jp0,kp3)*a0*b0*c3 + g2(i)= g2(i) + GG2(ip0,jp1,kp3)*a0*b1*c3 + g2(i)= g2(i) + GG2(ip0,jp2,kp3)*a0*b2*c3 + g2(i)= g2(i) + GG2(ip0,jp3,kp3)*a0*b3*c3 + + g3(i)= g3(i) + GG3(ip0,jp0,kp3)*a0*b0*c3 + g3(i)= g3(i) + GG3(ip0,jp1,kp3)*a0*b1*c3 + g3(i)= g3(i) + GG3(ip0,jp2,kp3)*a0*b2*c3 + g3(i)= g3(i) + GG3(ip0,jp3,kp3)*a0*b3*c3 + + g1(i)= g1(i) + GG1(ip1,jp0,kp3)*a1*b0*c3 + g1(i)= g1(i) + GG1(ip1,jp1,kp3)*a1*b1*c3 + g1(i)= g1(i) + GG1(ip1,jp2,kp3)*a1*b2*c3 + g1(i)= g1(i) + GG1(ip1,jp3,kp3)*a1*b3*c3 + + g2(i)= g2(i) + GG2(ip1,jp0,kp3)*a1*b0*c3 + g2(i)= g2(i) + GG2(ip1,jp1,kp3)*a1*b1*c3 + g2(i)= g2(i) + GG2(ip1,jp2,kp3)*a1*b2*c3 + g2(i)= g2(i) + GG2(ip1,jp3,kp3)*a1*b3*c3 + + g3(i)= g3(i) + GG3(ip1,jp0,kp3)*a1*b0*c3 + g3(i)= g3(i) + GG3(ip1,jp1,kp3)*a1*b1*c3 + g3(i)= g3(i) + GG3(ip1,jp2,kp3)*a1*b2*c3 + g3(i)= g3(i) + GG3(ip1,jp3,kp3)*a1*b3*c3 + + g1(i)= g1(i) + GG1(ip2,jp0,kp3)*a2*b0*c3 + g1(i)= g1(i) + GG1(ip2,jp1,kp3)*a2*b1*c3 + g1(i)= g1(i) + GG1(ip2,jp2,kp3)*a2*b2*c3 + g1(i)= g1(i) + GG1(ip2,jp3,kp3)*a2*b3*c3 + + g2(i)= g2(i) + GG2(ip2,jp0,kp3)*a2*b0*c3 + g2(i)= g2(i) + GG2(ip2,jp1,kp3)*a2*b1*c3 + g2(i)= g2(i) + GG2(ip2,jp2,kp3)*a2*b2*c3 + g2(i)= g2(i) + GG2(ip2,jp3,kp3)*a2*b3*c3 + + g3(i)= g3(i) + GG3(ip2,jp0,kp3)*a2*b0*c3 + g3(i)= g3(i) + GG3(ip2,jp1,kp3)*a2*b1*c3 + g3(i)= g3(i) + GG3(ip2,jp2,kp3)*a2*b2*c3 + g3(i)= g3(i) + GG3(ip2,jp3,kp3)*a2*b3*c3 + + g1(i)= g1(i) + GG1(ip3,jp0,kp3)*a3*b0*c3 + g1(i)= g1(i) + GG1(ip3,jp1,kp3)*a3*b1*c3 + g1(i)= g1(i) + GG1(ip3,jp2,kp3)*a3*b2*c3 + g1(i)= g1(i) + GG1(ip3,jp3,kp3)*a3*b3*c3 + + g2(i)= g2(i) + GG2(ip3,jp0,kp3)*a3*b0*c3 + g2(i)= g2(i) + GG2(ip3,jp1,kp3)*a3*b1*c3 + g2(i)= g2(i) + GG2(ip3,jp2,kp3)*a3*b2*c3 + g2(i)= g2(i) + GG2(ip3,jp3,kp3)*a3*b3*c3 + + g3(i)= g3(i) + GG3(ip3,jp0,kp3)*a3*b0*c3 + g3(i)= g3(i) + GG3(ip3,jp1,kp3)*a3*b1*c3 + g3(i)= g3(i) + GG3(ip3,jp2,kp3)*a3*b2*c3 + g3(i)= g3(i) + GG3(ip3,jp3,kp3)*a3*b3*c3 + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/main.f90 b/CodesEnVrac/CodeGH/src-sphere/main.f90 new file mode 100644 index 000000000..1c2beea85 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/main.f90 @@ -0,0 +1,300 @@ +program cylindre + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp(npm),yp(npm),zp(npm),dv(npm) + dimension omx(npm),omy(npm),omz(npm) + dimension vx(npm),vy(npm),vz(npm) + dimension strx(npm),stry(npm),strz(npm) + + dimension domx(npm),domy(npm),domz(npm) + ! tableuax supplementaries pour RK + dimension xp0(npm),yp0(npm),zp0(npm) + dimension om1(npm),om2(npm),om3(npm) + dimension strxv(4,npm),stryv(4,npm),strzv(4,npm) + dimension vxv(4,npm),vyv(4,npm),vzv(4,npm) + dimension para(4) + dimension enstrophy(0:1000),energy(0:1000),divergence(0:1000) + + data (para(i),i=1,4)/0.5,0.5,1.,0./ + + character*30 filevelx,filevely,filevelz + + + pi=3.1415926 + pi2=2.*pi + + + + OPEN(1,file='C_IN.DAT',status='OLD') + READ(1,*) + read(1,*) nx + READ(1,*) + read(1,*)tstop + READ(1,*) + read(1,*)coef_pen + READ(1,*) + read(1,*)reynolds + READ(1,*) + read(1,*)coef_les + READ(1,*) + read(1,*)tvisu + READ(1,*) + read(1,*) width + + + anu=0.5*0.4844/reynolds + coef_drag=8./(pi*0.2422*0.2422) + nit=50000 + + close(1) + tvisu=0.3 + idif=1 + + xmin=-0. + xmax=1. + ymin=0. + ymax=1. + zmin=xmin + zmax=xmax + + ! dialetre de la spher selon Folke + diam=(xmax-xmin)*0.2422 + + ny=nx + nz=nx + dx=(xmax-xmin)/(nx) + dy=(ymax-ymin)/(ny) + dz=(zmax-zmin)/(nz) + + delt=0.01 + + + call init(npart,xp,yp,zp,omx,omy,omz,dv) + time=0. + go to 222 + call reinit(npart,xp,yp,zp,omx,omy,omz,dv) + time=10. + call velox_fft + call vfix + call stretch +222 continue + + OPEN(35,file='DRAGd',status='unknown') + + ! debut des iterations + + tcompt=0. + istep=0 + + do 20 kk=1,nit + + if (kk.gt.1) delt=amin1(0.01,0.25/omax2) + time=time+delt + + j1=16 + if (nx.eq.256) j1=32 + j2=nx-j1 + call drag(drag1,drag2,drag3,j1,j2) + call drag_surface(drag4,anu,j1,j2) + if (kk.gt.1) then + drag_dudt=(drag1-drag1_0)/delt + drag_dwdt=0.5*coef_drag*(drag2-drag2_0)/delt + print*,'DRAGdwdt ',drag_dwdt + drag_dwdt=drag_dwdt+0.5*coef_drag*drag4 + drag_poreux=2.*coef_pen*drag3/diam + endif + print*,' time, DRAGs ',kk,time,drag_dwdt,drag_poreux + write(35,*) time,drag_dwdt + drag2_0=drag2 + + deltconv=delt + delt1=delt/6. + + ! on fait les sous-iterations R.K. + + do 10 i=1,npart + xp0(i)=xp(i) + yp0(i)=yp(i) + zp0(i)=zp(i) + om1(i)=omx(i) + om2(i)=omy(i) + om3(i)=omz(i) +10 continue + + do 550 ll=1,4 + + call intervm4(npart,vx,vy,vz,xp,yp,zp) + call intersm4(npart,strx,stry,strz,xp,yp,zp) + + ! increment des positions et poids correspondant aux sous-ite + ! RK + !********************** + + vxmax=0. + vxmax=-10000. + vxmin=10000. + vymax=-10000. + vymin=10000. + vzmax=-10000. + vzmin=10000. + vzmax=0. + do 520 i=1,npart + vxv(ll,i)=vx(i) + vyv(ll,i)=vy(i) + vzv(ll,i)=vz(i) + strxv(ll,i)=dv(i)*strx(i) + stryv(ll,i)=dv(i)*stry(i) + strzv(ll,i)=dv(i)*strz(i) + xp(i)=xp0(i)+para(ll)*deltconv*vx(i) + if (xp(i).lt.xmin) xp(i)=xp(i)+xmax-xmin + if (xp(i).gt.xmax) xp(i)=xp(i)-xmax+xmin + yp(i)=yp0(i)+para(ll)*deltconv*vy(i) + if (yp(i).lt.ymin) yp(i)=yp(i)+ymax-ymin + if (yp(i).gt.ymax) yp(i)=yp(i)-ymax+ymin + zp(i)=zp0(i)+para(ll)*deltconv*vz(i) + if (zp(i).lt.zmin) zp(i)=zp(i)+zmax-zmin + if (zp(i).gt.zmax) zp(i)=zp(i)-zmax+zmin + omx(i)=om1(i)+para(ll)*deltconv*dv(i)*strx(i) + omy(i)=om2(i)+para(ll)*deltconv*dv(i)*stry(i) + omz(i)=om3(i)+para(ll)*deltconv*dv(i)*strz(i) + vxmax=amax1(vxmax,(vx(i))) + vxmin=amin1(vxmin,(vx(i))) + vymax=amax1(vymax,(vy(i))) + vymin=amin1(vymin,(vy(i))) + vzmax=amax1(vzmax,(vz(i))) + vzmin=amin1(vzmin,(vz(i))) +520 continue + ! print*,' vitesses max ',vxmax,vxmin,vymax,vymin,vzmax,vzmin + +550 continue + + ! FIN des sous-ite RK + !********************** + + ! Increments des positions et poids pour + ! la partie transport-deformation du tourbillon + + + xleft=xmax + xright=xmin + yleft=ymax + yright=ymin + zleft=zmax + zright=zmin + do 900 i=1,npart + xp(i)=xp0(i)+delt1*(vxv(1,i)+2.*vxv(2,i)+2.*vxv(3,i)+vxv(4,i)) + yp(i)=yp0(i)+delt1*(vyv(1,i)+2.*vyv(2,i)+2.*vyv(3,i)+vyv(4,i)) + zp(i)=zp0(i)+delt1*(vzv(1,i)+2.*vzv(2,i)+2.*vzv(3,i)+vzv(4,i)) + if (xp(i).lt.xmin) xp(i)=xp(i)+xmax-xmin + if (xp(i).gt.xmax) xp(i)=xp(i)-xmax+xmin + if (yp(i).lt.ymin) yp(i)=yp(i)+ymax-ymin + if (yp(i).gt.ymax) yp(i)=yp(i)-ymax+ymin + if (zp(i).lt.zmin) zp(i)=zp(i)+zmax-zmin + if (zp(i).gt.zmax) zp(i)=zp(i)-zmax+zmin + omx(i)=om1(i)+delt1*(strxv(1,i)+2.*strxv(2,i)+& + 2.*strxv(3,i)+strxv(4,i)) + omy(i)=om2(i)+delt1*(stryv(1,i)+2.*stryv(2,i)+& + 2.*stryv(3,i)+stryv(4,i)) + omz(i)=om3(i)+delt1*(strzv(1,i)+2.*strzv(2,i)+& + 2.*strzv(3,i)+strzv(4,i)) +900 continue + + + + + ! Remshing + Diffusion + !********************** + + ! circlim=0.0001 + ! circulation mimimum pour troncature de la vorticite dans remaillage + circlim=-10. + + call remesh_om(npart,omx,omy,omz,xp,yp,zp,dv) + + call velox_fft + call vfix + + if (time.ge.tstop) then + OPEN(33,file='SPEEDz',status='unknown') + OPEN(34,file='SPEEDy',status='unknown') + do k=1,nx + write(33,*) (k-1)*dx,vxg(nx/2,nx/2,k),vxg(1,k,1) + write(34,*) (k-1)*dx,vxg(nx/2,k,nx/2),vxg(1,k,nx/2),vxg(1,k,1) + enddo + endif + + + ! call pen(coef_pen,delt) + call pen_diff_fft(coef_pen,npart,anu,delt,xp,yp,zp,omx,omy,omz,dv,omax2) + + call stretch + + ! call dif_om(npart,omx,omy,omz, + ! 1 xp,yp,zp,dv,anu,delt,omax2) + + ! call diff_fft(npart,anu,delt, + ! 1 xp,yp,zp,omx,omy,omz,dv,omax2) + + print *,' Npart ',npart + + + if (time.ge.tstop) then + + ! OPEN(33,file='SPEEDz',status='unknown') + ! OPEN(34,file='SPEEDy',status='unknown') + ! do k=1,nx + ! write(33,*) (k-1)*dx,vxg(nx/2,nx/2,k),vxg(1,k,1) + ! write(34,*) (k-1)*dx,vxg(nx/2,k,nx/2),vxg(1,k,nx/2), + ! 1 vxg(1,k,1) + ! enddo + open(24,file='fileom') + umax=0. + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx," ",nx," ",nx + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dx," ",dx + WRITE(24,*) "POINT_DATA ",nx*nx*nx + WRITE(24,'(A)') "SCALARS omg float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nx + do j=1,nx + do i=1,nx + strength=sqrt(omg1(i,j,k)**2+omg2(i,j,k)**2+omg3(i,j,k)**2) + ! strength=sqrt(vxg(i,j,k)**2+vyg(i,j,k)**2+vzg(i,j,k)**2) + ! umax=amax1(umax,abs(ug(i,j,k))) + write(24,*) amax1(0.00001,strength) + enddo + enddo + enddo + close(24) + close(33) + close(34) + ! goto 201 + ! endif + + open(2,file='fileomx',form='unformatted',convert='big_endian',status='unknown') + open(3,file='fileomy',form='unformatted',convert='big_endian',status='unknown') + open(4,file='fileomz',form='unformatted',convert='big_endian',status='unknown') + + write(2) ((((omg1(i,j,k)),i=1,nx),j=1,ny),k=1,nz) + write(3) ((((omg2(i,j,k)),i=1,nx),j=1,ny),k=1,nz) + write(4) (((omg3(i,j,k),i=1,nx),j=1,ny),k=1,nz) + close(2) + close(3) + close(4) + goto 201 + + endif + +20 continue + +201 continue + stop + +end program cylindre diff --git a/CodesEnVrac/CodeGH/src-sphere/param.h b/CodesEnVrac/CodeGH/src-sphere/param.h new file mode 100644 index 000000000..edb596f8f --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/param.h @@ -0,0 +1,5 @@ + common xmin,xmax,ymin,ymax,zmin,zmax,nx,ny,nz,nt,dx,dy,dz,ifft + common width + common vzh,zg + + diff --git a/CodesEnVrac/CodeGH/src-sphere/pen.f90 b/CodesEnVrac/CodeGH/src-sphere/pen.f90 new file mode 100644 index 000000000..0a889d0c3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/pen.f90 @@ -0,0 +1,69 @@ + subroutine pen(coef_pen,delt) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + +!condition limite v=vh par penalisation implicite en vorticite + + cdelt=coef_pen*delt + + vxh=0. + vyh=0. + vzh=0. + +!penalisation sous forme : +!omega_n+1=curl[(u_n+coef_pen*delt*vh)/(1+coef_pen)] + + do k=1,nz + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + do i=1,nx + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + arg=phig(i,j,k) + argt=phig(i,jt,k) + argb=phig(i,jb,k) + argu=phig(i,j,kt) + argd=phig(i,j,kb) + argr=phig(it,j,k) + argl=phig(ib,j,k) + +!x-component: + term1=(vzg(i,jt,k)+argt*cdelt*vzh)/(1.+cdelt*argt) + term2=(vzg(i,jb,k)+argb*cdelt*vzh)/(1.+cdelt*argb) + omg1(i,j,k)=(term1-term2)/(2.*dx) + term1=(vyg(i,j,kt)+argu*cdelt*vyh)/(1.+cdelt*argu) + term2=(vyg(i,j,kb)+argd*cdelt*vyh)/(1.+cdelt*argd) + omg1(i,j,k)=omg1(i,j,k)-(term1-term2)/(2.*dx) + +!y-component: + term1=(vxg(i,j,kt)+argu*cdelt*vxh)/(1.+cdelt*argu) + term2=(vxg(i,j,kb)+argd*cdelt*vxh)/(1.+cdelt*argd) + omg2(i,j,k)=(term1-term2)/(2.*dx) + term1=(vzg(it,j,k)+argr*cdelt*vzh)/(1.+cdelt*argr) + term2=(vzg(ib,j,k)+argl*cdelt*vzh)/(1.+cdelt*argl) + omg2(i,j,k)=omg2(i,j,k)-(term1-term2)/(2.*dx) + +!z-component: + term1=(vyg(it,j,k)+argu*cdelt*vyh)/(1.+cdelt*argr) + term2=(vyg(ib,j,k)+argd*cdelt*vyh)/(1.+cdelt*argl) + omg3(i,j,k)=(term1-term2)/(2.*dx) + term1=(vxg(i,jt,k)+argr*cdelt*vxh)/(1.+cdelt*argt) + term2=(vxg(i,jb,k)+argl*cdelt*vxh)/(1.+cdelt*argb) + omg3(i,j,k)=omg3(i,j,k)-(term1-term2)/(2.*dx) + +111 continue + enddo + enddo + enddo + + + + + return + end diff --git a/CodesEnVrac/CodeGH/src-sphere/pen_dif_fft.f90 b/CodesEnVrac/CodeGH/src-sphere/pen_dif_fft.f90 new file mode 100644 index 000000000..a84b2da1d --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/pen_dif_fft.f90 @@ -0,0 +1,138 @@ +subroutine pen_diff_fft(coef_pen,npart,anu,delt,xp1,yp1,zp1,om1,om2,om3,dv1,omax2) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + !condition limite v=vh par penalisation implicite en vorticite + !penalisation sur v, puis fft, puis om en fourier + !puis diff implicite en fourier, puis retour omg + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + + dimension aux3(npg,npg,npg),aux1(npg,npg,npg),aux2(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,cox,coy,coz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cox(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + wk(ngx2+1,npgy,npgz) + + pi=3.1415926 + dxinv=0.5/dx + dyinv=dxinv + dzinv=dxinv + + ! calucl de fonction courants 3d + + nx2=nx/2 + ny2=ny/2 + nz2=nz/2 + + cdelt=coef_pen*delt + + vxh=0. + vyh=0. + vzh=0. + + !penalisation sous forme : + !u_n+1=[(u_n+coef_pen*delt*vh*phi)/(1+coef_pen*delt*phi)] + + do k=1,nz + do j=1,ny + do i=1,nx + arg=phig(i,j,k) + + !x-component: + vxg(i,j,k)=(vxg(i,j,k)+arg*cdelt*vxh)/(1.+cdelt*arg) + vyg(i,j,k)=(vyg(i,j,k)+arg*cdelt*vyh)/(1.+cdelt*arg) + vzg(i,j,k)=(vzg(i,j,k)+arg*cdelt*vzh)/(1.+cdelt*arg) + enddo + enddo + enddo + + call fftw3d(vxg,cfx,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(vyg,cfy,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(vzg,cfz,nx,ny,nz,nx2,ny2,nz2,wk,0) + + ! calcul rotationnel et difusion implicite + ! sur omega + + anudt=anu*delt + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do k=1-nz2,nz2 + rk=float(k)*ak + do j=1-ny2,ny2 + rj=float(j)*aj + do i=0,nx2 + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + r2b=(1.+r2*anudt) + ! diffusion en fourier + cox(i,j,k)=cmplx(0.0,1.0)*(+rj*cfz(i,j,k)-rk*cfy(i,j,k))/r2b + coy(i,j,k)=cmplx(0.0,1.0)*(+rk*cfx(i,j,k)-ri*cfz(i,j,k))/r2b + coz(i,j,k)=cmplx(0.0,1.0)*(+ri*cfy(i,j,k)-rj*cfx(i,j,k))/r2b + end do + end do + end do + + + ! fourier inverse pour vorticite apres difusion + ! et creation de particules + + call fftw3d(aux1,cox,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,coy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,coz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + circlim=0.0001 + npart=0 + vol=dx**3 + omax1=0. + omax2=0. + do k=1,nx + do j=1,ny + do i=1,nz + omg1(i,j,k)=aux1(i,j,k) + omg2(i,j,k)=aux2(i,j,k) + omg3(i,j,k)=aux3(i,j,k) + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + x=xmin+float(i-1)*dx + y=xmin+float(j-1)*dx + z=xmin+float(k-1)*dx + npart=npart+1 + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + omax2=amax1(omax2,abs(omg1(i,j,k))) + omax2=amax1(omax2,abs(omg2(i,j,k))) + omax2=amax1(omax2,abs(omg3(i,j,k))) + enddo + enddo + enddo + + print*, 'OMAX avant et apres DIFF ',omax1,omax2 + + return + +end subroutine pen_diff_fft diff --git a/CodesEnVrac/CodeGH/src-sphere/reinit.f90 b/CodesEnVrac/CodeGH/src-sphere/reinit.f90 new file mode 100644 index 000000000..6f7542697 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/reinit.f90 @@ -0,0 +1,68 @@ +subroutine reinit(npart,xp,yp,zp,omx,omy,omz,dv) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp(*),yp(*),zp(*),dv(*) + dimension omx(*),omy(*),omz(*) + + character*30 rota + + pi=3.1415926 + piinv = 1./( pi) + pi2=2.*pi + + xc=(xmin+xmax)/2. + yc=xc + zc=xc + ! rc1=0.1 + rc1=(xmax-xmin)*0.1211 + + open(2,file='fileomx',form='unformatted',convert='big_endian',status='unknown') + open(3,file='fileomy',form='unformatted',convert='big_endian',status='unknown') + open(4,file='fileomz',form='unformatted',convert='big_endian',status='unknown') + + read(2,*) (((omg1(i,j,k),i=1,nx),j=1,ny),k=1,nz) + read(3,*) (((omg2(i,j,k),i=1,nx),j=1,ny),k=1,nz) + read(4,*) (((omg3(i,j,k),i=1,nx),j=1,ny),k=1,nz) + close(2) + close(3) + close(4) + + eps=dx*width + vol=dx**3 + circlim=0.0001 + + npart=0. + do i=1,nx + xx=xmin+(float(i)-1.)*dx + DO j=1,ny + yy=ymin+(float(j)-1.)*dy + DO k=1,nz + zz=zmin+(float(k)-1.)*dz + r1 =sqrt((xx-xc)**2+(yy-yc)**2+(zz-zc)**2)-rc1 + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + npart=npart+1 + xp(npart)=xx + yp(npart)=yy + zp(npart)=zz + dv(npart)=dx**3 + omx(npart)=omg1(i,j,k)*vol + omy(npart)=omg2(i,j,k)*vol + omz(npart)=omg3(i,j,k)*vol + endif + phig(i,j,k)=amin1(1.,amax1(1.-r1/eps,0.)) + if ((j.le.4).or.(j.ge.nx-3)) phig(i,j,k)=1. + end DO + end DO + end do + print*, 'NPART =', npart + return +end subroutine reinit + + diff --git a/CodesEnVrac/CodeGH/src-sphere/remesh.f90 b/CodesEnVrac/CodeGH/src-sphere/remesh.f90 new file mode 100644 index 000000000..2bbed6937 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/remesh.f90 @@ -0,0 +1,579 @@ + SUBROUTINE remeshdif(npart,circlim,om1,om2,om3,xp,yp,zp,dv,anu,delt) + +! This subroutine asssigns vorticity on a grid +!---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension om1(*),om2(*),om3(*),xp(*),yp(*),zp(*),dv(*) + dimension dom1(npm),dom2(npm),dom3(npm) + integer indx(npm),indy(npm),indz(npm) + + + + pi=3.1415926 + + do 10 k=1,nz + do 10 j=1,ny + do 10 i=1,nx + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. +10 continue + + dxinv=1./dx + dyinv=1./dy + dzinv=1./dz + + + +!-------------------------------------------------------------------- +!- PART II : Determination of the circulation of each particle +!-------------------------------------------------------------------- + +!x0=xmin-.5*dx +!y0=ymin-.5*dy +!z0=zmin-.5*dz + + x0=xmin + y0=ymin + z0=zmin + + xm=xmax-xmin + ym=ymax-ymin + zm=zmax-zmin + + DO 20 n = 1,npart + + g1 = om1(n) + g2 = om2(n) + g3 = om3(n) + x = xp(n) + y = yp(n) + z = zp(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + +!Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx-x0)*dxinv + yy1 = (y - float(jp1)*dy-y0)*dyinv + zz1 = (z - float(kp1)*dz-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + +! on repositionne les points de grille par periodicite +!entre 0 et npx-1, puis on numerote de 1 a npx + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 + ip3=mod(ip3+nx,nx) +1 + + jp1=mod(jp1+ny,ny) +1 + jp0=mod(jp0+ny,ny) +1 + jp2=mod(jp2+ny,ny) +1 + jp3=mod(jp3+ny,ny) +1 + + kp1=mod(kp1+nz,nz) +1 + kp0=mod(kp0+nz,nz) +1 + kp2=mod(kp2+nz,nz) +1 + kp3=mod(kp3+nz,nz) +1 + +!The M'4 scheme + + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + coef=a0*b0*c0 + omg1(ip0,jp0,kp0) = omg1(ip0,jp0,kp0) + g1*coef + omg2(ip0,jp0,kp0) = omg2(ip0,jp0,kp0) + g2*coef + omg3(ip0,jp0,kp0) = omg3(ip0,jp0,kp0) + g3*coef + + coef=a0*b0*c1 + omg1(ip0,jp0,kp1) = omg1(ip0,jp0,kp1) + g1*coef + omg2(ip0,jp0,kp1) = omg2(ip0,jp0,kp1) + g2*coef + omg3(ip0,jp0,kp1) = omg3(ip0,jp0,kp1) + g3*coef + + coef=a0*b0*c2 + omg1(ip0,jp0,kp2) = omg1(ip0,jp0,kp2) + g1*coef + omg2(ip0,jp0,kp2) = omg2(ip0,jp0,kp2) + g2*coef + omg3(ip0,jp0,kp2) = omg3(ip0,jp0,kp2) + g3*coef + + coef=a0*b0*c3 + omg1(ip0,jp0,kp3) = omg1(ip0,jp0,kp3) + g1*coef + omg2(ip0,jp0,kp3) = omg2(ip0,jp0,kp3) + g2*coef + omg3(ip0,jp0,kp3) = omg3(ip0,jp0,kp3) + g3*coef + + + coef=a0*b1*c0 + omg1(ip0,jp1,kp0) = omg1(ip0,jp1,kp0) + g1*coef + omg2(ip0,jp1,kp0) = omg2(ip0,jp1,kp0) + g2*coef + omg3(ip0,jp1,kp0) = omg3(ip0,jp1,kp0) + g3*coef + + coef=a0*b1*c1 + omg1(ip0,jp1,kp1) = omg1(ip0,jp1,kp1) + g1*coef + omg2(ip0,jp1,kp1) = omg2(ip0,jp1,kp1) + g2*coef + omg3(ip0,jp1,kp1) = omg3(ip0,jp1,kp1) + g3*coef + + coef=a0*b1*c2 + omg1(ip0,jp1,kp2) = omg1(ip0,jp1,kp2) + g1*coef + omg2(ip0,jp1,kp2) = omg2(ip0,jp1,kp2) + g2*coef + omg3(ip0,jp1,kp2) = omg3(ip0,jp1,kp2) + g3*coef + + coef=a0*b1*c3 + omg1(ip0,jp1,kp3) = omg1(ip0,jp1,kp3) + g1*coef + omg2(ip0,jp1,kp3) = omg2(ip0,jp1,kp3) + g2*coef + omg3(ip0,jp1,kp3) = omg3(ip0,jp1,kp3) + g3*coef + + coef=a0*b2*c0 + omg1(ip0,jp2,kp0) = omg1(ip0,jp2,kp0) + g1*coef + omg2(ip0,jp2,kp0) = omg2(ip0,jp2,kp0) + g2*coef + omg3(ip0,jp2,kp0) = omg3(ip0,jp2,kp0) + g3*coef + + coef=a0*b2*c1 + omg1(ip0,jp2,kp1) = omg1(ip0,jp2,kp1) + g1*coef + omg2(ip0,jp2,kp1) = omg2(ip0,jp2,kp1) + g2*coef + omg3(ip0,jp2,kp1) = omg3(ip0,jp2,kp1) + g3*coef + + coef=a0*b2*c2 + omg1(ip0,jp2,kp2) = omg1(ip0,jp2,kp2) + g1*coef + omg2(ip0,jp2,kp2) = omg2(ip0,jp2,kp2) + g2*coef + omg3(ip0,jp2,kp2) = omg3(ip0,jp2,kp2) + g3*coef + + coef=a0*b2*c3 + omg1(ip0,jp2,kp3) = omg1(ip0,jp2,kp3) + g1*coef + omg2(ip0,jp2,kp3) = omg2(ip0,jp2,kp3) + g2*coef + omg3(ip0,jp2,kp3) = omg3(ip0,jp2,kp3) + g3*coef + + coef=a0*b3*c0 + omg1(ip0,jp3,kp0) = omg1(ip0,jp3,kp0) + g1*coef + omg2(ip0,jp3,kp0) = omg2(ip0,jp3,kp0) + g2*coef + omg3(ip0,jp3,kp0) = omg3(ip0,jp3,kp0) + g3*coef + + coef=a0*b3*c1 + omg1(ip0,jp3,kp1) = omg1(ip0,jp3,kp1) + g1*coef + omg2(ip0,jp3,kp1) = omg2(ip0,jp3,kp1) + g2*coef + omg3(ip0,jp3,kp1) = omg3(ip0,jp3,kp1) + g3*coef + + coef=a0*b3*c2 + omg1(ip0,jp3,kp2) = omg1(ip0,jp3,kp2) + g1*coef + omg2(ip0,jp3,kp2) = omg2(ip0,jp3,kp2) + g2*coef + omg3(ip0,jp3,kp2) = omg3(ip0,jp3,kp2) + g3*coef + + coef=a0*b3*c3 + omg1(ip0,jp3,kp3) = omg1(ip0,jp3,kp3) + g1*coef + omg2(ip0,jp3,kp3) = omg2(ip0,jp3,kp3) + g2*coef + omg3(ip0,jp3,kp3) = omg3(ip0,jp3,kp3) + g3*coef + + coef=a1*b0*c0 + omg1(ip1,jp0,kp0) = omg1(ip1,jp0,kp0) + g1*coef + omg2(ip1,jp0,kp0) = omg2(ip1,jp0,kp0) + g2*coef + omg3(ip1,jp0,kp0) = omg3(ip1,jp0,kp0) + g3*coef + + coef=a1*b0*c1 + omg1(ip1,jp0,kp1) = omg1(ip1,jp0,kp1) + g1*coef + omg2(ip1,jp0,kp1) = omg2(ip1,jp0,kp1) + g2*coef + omg3(ip1,jp0,kp1) = omg3(ip1,jp0,kp1) + g3*coef + + coef=a1*b0*c2 + omg1(ip1,jp0,kp2) = omg1(ip1,jp0,kp2) + g1*coef + omg2(ip1,jp0,kp2) = omg2(ip1,jp0,kp2) + g2*coef + omg3(ip1,jp0,kp2) = omg3(ip1,jp0,kp2) + g3*coef + + coef=a1*b0*c3 + omg1(ip1,jp0,kp3) = omg1(ip1,jp0,kp3) + g1*coef + omg2(ip1,jp0,kp3) = omg2(ip1,jp0,kp3) + g2*coef + omg3(ip1,jp0,kp3) = omg3(ip1,jp0,kp3) + g3*coef + + coef=a1*b1*c0 + omg1(ip1,jp1,kp0) = omg1(ip1,jp1,kp0) + g1*coef + omg2(ip1,jp1,kp0) = omg2(ip1,jp1,kp0) + g2*coef + omg3(ip1,jp1,kp0) = omg3(ip1,jp1,kp0) + g3*coef + + coef=a1*b1*c1 + omg1(ip1,jp1,kp1) = omg1(ip1,jp1,kp1) + g1*coef + omg2(ip1,jp1,kp1) = omg2(ip1,jp1,kp1) + g2*coef + omg3(ip1,jp1,kp1) = omg3(ip1,jp1,kp1) + g3*coef + + coef=a1*b1*c2 + omg1(ip1,jp1,kp2) = omg1(ip1,jp1,kp2) + g1*coef + omg2(ip1,jp1,kp2) = omg2(ip1,jp1,kp2) + g2*coef + omg3(ip1,jp1,kp2) = omg3(ip1,jp1,kp2) + g3*coef + + coef=a1*b1*c3 + omg1(ip1,jp1,kp3) = omg1(ip1,jp1,kp3) + g1*coef + omg2(ip1,jp1,kp3) = omg2(ip1,jp1,kp3) + g2*coef + omg3(ip1,jp1,kp3) = omg3(ip1,jp1,kp3) + g3*coef + + + coef=a1*b2*c0 + omg1(ip1,jp2,kp0) = omg1(ip1,jp2,kp0) + g1*coef + omg2(ip1,jp2,kp0) = omg2(ip1,jp2,kp0) + g2*coef + omg3(ip1,jp2,kp0) = omg3(ip1,jp2,kp0) + g3*coef + + coef=a1*b2*c1 + omg1(ip1,jp2,kp1) = omg1(ip1,jp2,kp1) + g1*coef + omg2(ip1,jp2,kp1) = omg2(ip1,jp2,kp1) + g2*coef + omg3(ip1,jp2,kp1) = omg3(ip1,jp2,kp1) + g3*coef + + coef=a1*b2*c2 + omg1(ip1,jp2,kp2) = omg1(ip1,jp2,kp2) + g1*coef + omg2(ip1,jp2,kp2) = omg2(ip1,jp2,kp2) + g2*coef + omg3(ip1,jp2,kp2) = omg3(ip1,jp2,kp2) + g3*coef + + coef=a1*b2*c3 + omg1(ip1,jp2,kp3) = omg1(ip1,jp2,kp3) + g1*coef + omg2(ip1,jp2,kp3) = omg2(ip1,jp2,kp3) + g2*coef + omg3(ip1,jp2,kp3) = omg3(ip1,jp2,kp3) + g3*coef + + coef=a1*b3*c0 + omg1(ip1,jp3,kp0) = omg1(ip1,jp3,kp0) + g1*coef + omg2(ip1,jp3,kp0) = omg2(ip1,jp3,kp0) + g2*coef + omg3(ip1,jp3,kp0) = omg3(ip1,jp3,kp0) + g3*coef + + coef=a1*b3*c1 + omg1(ip1,jp3,kp1) = omg1(ip1,jp3,kp1) + g1*coef + omg2(ip1,jp3,kp1) = omg2(ip1,jp3,kp1) + g2*coef + omg3(ip1,jp3,kp1) = omg3(ip1,jp3,kp1) + g3*coef + + coef=a1*b3*c2 + omg1(ip1,jp3,kp2) = omg1(ip1,jp3,kp2) + g1*coef + omg2(ip1,jp3,kp2) = omg2(ip1,jp3,kp2) + g2*coef + omg3(ip1,jp3,kp2) = omg3(ip1,jp3,kp2) + g3*coef + + coef=a1*b3*c3 + omg1(ip1,jp3,kp3) = omg1(ip1,jp3,kp3) + g1*coef + omg2(ip1,jp3,kp3) = omg2(ip1,jp3,kp3) + g2*coef + omg3(ip1,jp3,kp3) = omg3(ip1,jp3,kp3) + g3*coef + + coef=a2*b0*c0 + omg1(ip2,jp0,kp0) = omg1(ip2,jp0,kp0) + g1*coef + omg2(ip2,jp0,kp0) = omg2(ip2,jp0,kp0) + g2*coef + omg3(ip2,jp0,kp0) = omg3(ip2,jp0,kp0) + g3*coef + + coef=a2*b0*c1 + omg1(ip2,jp0,kp1) = omg1(ip2,jp0,kp1) + g1*coef + omg2(ip2,jp0,kp1) = omg2(ip2,jp0,kp1) + g2*coef + omg3(ip2,jp0,kp1) = omg3(ip2,jp0,kp1) + g3*coef + + coef=a2*b0*c2 + omg1(ip2,jp0,kp2) = omg1(ip2,jp0,kp2) + g1*coef + omg2(ip2,jp0,kp2) = omg2(ip2,jp0,kp2) + g2*coef + omg3(ip2,jp0,kp2) = omg3(ip2,jp0,kp2) + g3*coef + + coef=a2*b0*c3 + omg1(ip2,jp0,kp3) = omg1(ip2,jp0,kp3) + g1*coef + omg2(ip2,jp0,kp3) = omg2(ip2,jp0,kp3) + g2*coef + omg3(ip2,jp0,kp3) = omg3(ip2,jp0,kp3) + g3*coef + + coef=a2*b1*c0 + omg1(ip2,jp1,kp0) = omg1(ip2,jp1,kp0) + g1*coef + omg2(ip2,jp1,kp0) = omg2(ip2,jp1,kp0) + g2*coef + omg3(ip2,jp1,kp0) = omg3(ip2,jp1,kp0) + g3*coef + + coef=a2*b1*c1 + omg1(ip2,jp1,kp1) = omg1(ip2,jp1,kp1) + g1*coef + omg2(ip2,jp1,kp1) = omg2(ip2,jp1,kp1) + g2*coef + omg3(ip2,jp1,kp1) = omg3(ip2,jp1,kp1) + g3*coef + + coef=a2*b1*c2 + omg1(ip2,jp1,kp2) = omg1(ip2,jp1,kp2) + g1*coef + omg2(ip2,jp1,kp2) = omg2(ip2,jp1,kp2) + g2*coef + omg3(ip2,jp1,kp2) = omg3(ip2,jp1,kp2) + g3*coef + + coef=a2*b1*c3 + omg1(ip2,jp1,kp3) = omg1(ip2,jp1,kp3) + g1*coef + omg2(ip2,jp1,kp3) = omg2(ip2,jp1,kp3) + g2*coef + omg3(ip2,jp1,kp3) = omg3(ip2,jp1,kp3) + g3*coef + + coef=a2*b2*c0 + omg1(ip2,jp2,kp0) = omg1(ip2,jp2,kp0) + g1*coef + omg2(ip2,jp2,kp0) = omg2(ip2,jp2,kp0) + g2*coef + omg3(ip2,jp2,kp0) = omg3(ip2,jp2,kp0) + g3*coef + + coef=a2*b2*c1 + omg1(ip2,jp2,kp1) = omg1(ip2,jp2,kp1) + g1*coef + omg2(ip2,jp2,kp1) = omg2(ip2,jp2,kp1) + g2*coef + omg3(ip2,jp2,kp1) = omg3(ip2,jp2,kp1) + g3*coef + + coef=a2*b2*c2 + omg1(ip2,jp2,kp2) = omg1(ip2,jp2,kp2) + g1*coef + omg2(ip2,jp2,kp2) = omg2(ip2,jp2,kp2) + g2*coef + omg3(ip2,jp2,kp2) = omg3(ip2,jp2,kp2) + g3*coef + + coef=a2*b2*c3 + omg1(ip2,jp2,kp3) = omg1(ip2,jp2,kp3) + g1*coef + omg2(ip2,jp2,kp3) = omg2(ip2,jp2,kp3) + g2*coef + omg3(ip2,jp2,kp3) = omg3(ip2,jp2,kp3) + g3*coef + + coef=a2*b3*c0 + omg1(ip2,jp3,kp0) = omg1(ip2,jp3,kp0) + g1*coef + omg2(ip2,jp3,kp0) = omg2(ip2,jp3,kp0) + g2*coef + omg3(ip2,jp3,kp0) = omg3(ip2,jp3,kp0) + g3*coef + + coef=a2*b3*c1 + omg1(ip2,jp3,kp1) = omg1(ip2,jp3,kp1) + g1*coef + omg2(ip2,jp3,kp1) = omg2(ip2,jp3,kp1) + g2*coef + omg3(ip2,jp3,kp1) = omg3(ip2,jp3,kp1) + g3*coef + + coef=a2*b3*c2 + omg1(ip2,jp3,kp2) = omg1(ip2,jp3,kp2) + g1*coef + omg2(ip2,jp3,kp2) = omg2(ip2,jp3,kp2) + g2*coef + omg3(ip2,jp3,kp2) = omg3(ip2,jp3,kp2) + g3*coef + + coef=a2*b3*c3 + omg1(ip2,jp3,kp3) = omg1(ip2,jp3,kp3) + g1*coef + omg2(ip2,jp3,kp3) = omg2(ip2,jp3,kp3) + g2*coef + omg3(ip2,jp3,kp3) = omg3(ip2,jp3,kp3) + g3*coef + + coef=a3*b0*c0 + omg1(ip3,jp0,kp0) = omg1(ip3,jp0,kp0) + g1*coef + omg2(ip3,jp0,kp0) = omg2(ip3,jp0,kp0) + g2*coef + omg3(ip3,jp0,kp0) = omg3(ip3,jp0,kp0) + g3*coef + + coef=a3*b0*c1 + omg1(ip3,jp0,kp1) = omg1(ip3,jp0,kp1) + g1*coef + omg2(ip3,jp0,kp1) = omg2(ip3,jp0,kp1) + g2*coef + omg3(ip3,jp0,kp1) = omg3(ip3,jp0,kp1) + g3*coef + + coef=a3*b0*c2 + omg1(ip3,jp0,kp2) = omg1(ip3,jp0,kp2) + g1*coef + omg2(ip3,jp0,kp2) = omg2(ip3,jp0,kp2) + g2*coef + omg3(ip3,jp0,kp2) = omg3(ip3,jp0,kp2) + g3*coef + + coef=a3*b0*c3 + omg1(ip3,jp0,kp3) = omg1(ip3,jp0,kp3) + g1*coef + omg2(ip3,jp0,kp3) = omg2(ip3,jp0,kp3) + g2*coef + omg3(ip3,jp0,kp3) = omg3(ip3,jp0,kp3) + g3*coef + + coef=a3*b1*c0 + omg1(ip3,jp1,kp0) = omg1(ip3,jp1,kp0) + g1*coef + omg2(ip3,jp1,kp0) = omg2(ip3,jp1,kp0) + g2*coef + omg3(ip3,jp1,kp0) = omg3(ip3,jp1,kp0) + g3*coef + + coef=a3*b1*c1 + omg1(ip3,jp1,kp1) = omg1(ip3,jp1,kp1) + g1*coef + omg2(ip3,jp1,kp1) = omg2(ip3,jp1,kp1) + g2*coef + omg3(ip3,jp1,kp1) = omg3(ip3,jp1,kp1) + g3*coef + + coef=a3*b1*c2 + omg1(ip3,jp1,kp2) = omg1(ip3,jp1,kp2) + g1*coef + omg2(ip3,jp1,kp2) = omg2(ip3,jp1,kp2) + g2*coef + omg3(ip3,jp1,kp2) = omg3(ip3,jp1,kp2) + g3*coef + + coef=a3*b1*c3 + omg1(ip3,jp1,kp3) = omg1(ip3,jp1,kp3) + g1*coef + omg2(ip3,jp1,kp3) = omg2(ip3,jp1,kp3) + g2*coef + omg3(ip3,jp1,kp3) = omg3(ip3,jp1,kp3) + g3*coef + + coef=a3*b2*c0 + omg1(ip3,jp2,kp0) = omg1(ip3,jp2,kp0) + g1*coef + omg2(ip3,jp2,kp0) = omg2(ip3,jp2,kp0) + g2*coef + omg3(ip3,jp2,kp0) = omg3(ip3,jp2,kp0) + g3*coef + + coef=a3*b2*c1 + omg1(ip3,jp2,kp1) = omg1(ip3,jp2,kp1) + g1*coef + omg2(ip3,jp2,kp1) = omg2(ip3,jp2,kp1) + g2*coef + omg3(ip3,jp2,kp1) = omg3(ip3,jp2,kp1) + g3*coef + + coef=a3*b2*c2 + omg1(ip3,jp2,kp2) = omg1(ip3,jp2,kp2) + g1*coef + omg2(ip3,jp2,kp2) = omg2(ip3,jp2,kp2) + g2*coef + omg3(ip3,jp2,kp2) = omg3(ip3,jp2,kp2) + g3*coef + + coef=a3*b2*c3 + omg1(ip3,jp2,kp3) = omg1(ip3,jp2,kp3) + g1*coef + omg2(ip3,jp2,kp3) = omg2(ip3,jp2,kp3) + g2*coef + omg3(ip3,jp2,kp3) = omg3(ip3,jp2,kp3) + g3*coef + + coef=a3*b3*c0 + omg1(ip3,jp3,kp0) = omg1(ip3,jp3,kp0) + g1*coef + omg2(ip3,jp3,kp0) = omg2(ip3,jp3,kp0) + g2*coef + omg3(ip3,jp3,kp0) = omg3(ip3,jp3,kp0) + g3*coef + + coef=a3*b3*c1 + omg1(ip3,jp3,kp1) = omg1(ip3,jp3,kp1) + g1*coef + omg2(ip3,jp3,kp1) = omg2(ip3,jp3,kp1) + g2*coef + omg3(ip3,jp3,kp1) = omg3(ip3,jp3,kp1) + g3*coef + + coef=a3*b3*c2 + omg1(ip3,jp3,kp2) = omg1(ip3,jp3,kp2) + g1*coef + omg2(ip3,jp3,kp2) = omg2(ip3,jp3,kp2) + g2*coef + omg3(ip3,jp3,kp2) = omg3(ip3,jp3,kp2) + g3*coef + + coef=a3*b3*c3 + omg1(ip3,jp3,kp3) = omg1(ip3,jp3,kp3) + g1*coef + omg2(ip3,jp3,kp3) = omg2(ip3,jp3,kp3) + g2*coef + omg3(ip3,jp3,kp3) = omg3(ip3,jp3,kp3) + g3*coef + +20 CONTINUE + + npart=0 + + do k=1,nz + z=amod(z0-zmin+(k-1)*dz+zm,zm)+zmin + do j=1,ny + y=amod(y0-ymin+(j-1)*dy+ym,ym)+ymin + do i=1,nx + x=amod(x0-xmin+(i-1)*dx+xm,xm)+xmin + vol=dx*dy*dz + strength=abs(omg1(i,j,k))+abs(omg2(i,j,k))+abs(omg3(i,j,k)) + if ((strength.ge.circlim*vol)) then + npart=npart+1 + indx(npart)=i + indy(npart)=j + indz(npart)=k + xp(npart)=x + yp(npart)=y + zp(npart)=z + dv(npart)=vol + om1(npart)=omg1(i,j,k) + om2(npart)=omg2(i,j,k) + om3(npart)=omg3(i,j,k) + endif + enddo + enddo + enddo + + +! goto 310 + + +! dans la foulee on fiat la diffusion dans l'espace +! mappee avec formules de diffusion anisotropes + +! pas de temps de diffusion pour CFL + +! coeff aspect ratio pour se mettre dans une grille +! totalement isotrope et coeff de normalisation +! pour kernel 1/(1+r**2) + dzdx=(dz/dx)**2 + dzdy=(dz/dy)**2 + trace=dzdx+dzdy+1. + + alpha=3.333333 + beta=5.666667 + alambda=2./(beta-alpha) + amu=-2.*alpha/((beta-alpha)*(2.*alpha+beta)) + +! boucle sur les receveurs + + + tot=0. + + do i=1,npart + dom1(i)=0. + dom2(i)=0. + dom3(i)=0. + tot2=0. + + ii=indx(i) + jj=indy(i) + kk=indz(i) + gammarcv1=om1(i) + gammarcv2=om2(i) + gammarcv3=om3(i) + vxrcv=vxg(ii,jj,kk) + vyrcv=vyg(ii,jj,kk) + vzrcv=vzg(ii,jj,kk) + +! boucle sur les 27 sources + do lx=-1,1 + do ly=-1,1 + do lz=-1,1 + i2=mod(ii+lx+nx-1,nx)+1 + j2=mod(jj+ly+ny-1,ny)+1 + k2=mod(kk+lz+nz-1,nz)+1 + gammasrc1=omg1(i2,j2,k2) + gammasrc2=omg2(i2,j2,k2) + gammasrc3=omg3(i2,j2,k2) + vxsrc=vxg(i2,j2,k2) + vysrc=vyg(i2,j2,k2) + vzsrc=vzg(i2,j2,k2) + r=lx**2+ly**2+lz**2 + am1=alambda*dzdx+amu*trace + am2=alambda*dzdy+amu*trace + am3=alambda+amu*trace + akernel=((lx**2)*am1+(ly**2)*am2+(lz**2)*am3)/(1.+r) + factor=akernel/(dz*dz) + tot2=tot2+akernel + dom1(i)=dom1(i)+(gammasrc1-gammarcv1)*(anu*factor) + dom2(i)=dom2(i)+(gammasrc2-gammarcv2)*(anu*factor) + dom3(i)=dom3(i)+(gammasrc3-gammarcv3)*(anu*factor) + + enddo + enddo + enddo + tot=amax1(tot,tot2*dy*dx*dz/dv(i)) + +! enddo pour caluc de dom sur les particules + enddo + + + + omax0=0. + omax1=0. + + do i=1,npart + omax0=amax1(omax0,abs(om1(i))/dv(i)) + omax0=amax1(omax0,abs(om2(i))/dv(i)) + omax0=amax1(omax0,abs(om3(i))/dv(i)) + om1(i)=om1(i)+delt*dom1(i) + om2(i)=om2(i)+delt*dom2(i) + om3(i)=om3(i)+delt*dom3(i) + omax1=amax1(omax1,abs(om1(i))/dv(i)) + omax1=amax1(omax1,abs(om2(i))/dv(i)) + omax1=amax1(omax1,abs(om3(i))/dv(i)) + enddo + + print*, 'OMAX avant et apres diff ', omax0,omax1 + if (omax1.gt.omax0) print*, '****** ATTENTION DIFFUSION' + + +310 continue + + RETURN + END diff --git a/CodesEnVrac/CodeGH/src-sphere/remesh_om.f90 b/CodesEnVrac/CodeGH/src-sphere/remesh_om.f90 new file mode 100644 index 000000000..296a55f09 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/remesh_om.f90 @@ -0,0 +1,470 @@ +!================================================================ +SUBROUTINE remesh_om(npart,om1,om2,om3,xp1,yp1,zp1,dv1) + ! This subroutine asssigns vorticity on a grid + !---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + + nx1=nx + ny1=nx + nz1=nx + dx1=dx + + + do i=1,nx1 + do j=1,ny1 + do k=1,nz1 + omg1(i,j,k)=0. + omg2(i,j,k)=0. + omg3(i,j,k)=0. + end do + end do + end do + + dy1=dx1 + dz1=dx1 + + dxinv=1./(dx1) + dyinv=dxinv + dzinv=dxinv + + + + !-------------------------------------------------------------------- + !- PART II : Determination of the circulation of each particle + !-------------------------------------------------------------------- + + x0=0. + y0=0. + z0=0. + + vol=dx1*dx1*dx1 + + DO n = 1,npart + + g2 = om1(n)/vol + g3 = om2(n)/vol + g4 = om3(n)/vol + + x = xp1(n) + y = yp1(n) + z = zp1(n) + + ip1 = int((x-x0)*dxinv) + jp1 = int((y-y0)*dyinv) + kp1 = int((z-z0)*dzinv) + + ip0 = ip1 - 1 + jp0 = jp1 - 1 + kp0 = kp1 - 1 + + ip2 = ip1 + 1 + jp2 = jp1 + 1 + kp2 = kp1 + 1 + + ip3 = ip1 + 2 + jp3 = jp1 + 2 + kp3 = kp1 + 2 + + ! Assign the circulations to the nine neighboring cells + + xx1 = (x - float(ip1)*dx1-x0)*dxinv + yy1 = (y - float(jp1)*dy1-y0)*dyinv + zz1 = (z - float(kp1)*dz1-z0)*dzinv + + xx0=xx1+1. + yy0=yy1+1. + zz0=zz1+1. + + xx2=1.-xx1 + yy2=1.-yy1 + zz2=1.-zz1 + + xx3=2.-xx1 + yy3=2.-yy1 + zz3=2.-zz1 + + + ! + ! on repositionne les points de grille par periodicite + ! entre 0 et npx-1, puis on numerote de 1 a npx + ! + + ip1=mod(ip1+nx1,nx1) +1 + ip0=mod(ip0+nx1,nx1) +1 + ip2=mod(ip2+nx1,nx1) +1 + ip3=mod(ip3+nx1,nx1) +1 + + jp1=mod(jp1+ny1,ny1) +1 + jp0=mod(jp0+ny1,ny1) +1 + jp2=mod(jp2+ny1,ny1) +1 + jp3=mod(jp3+ny1,ny1) +1 + + kp1=mod(kp1+nz1,nz1) +1 + kp0=mod(kp0+nz1,nz1) +1 + kp2=mod(kp2+nz1,nz1) +1 + kp3=mod(kp3+nz1,nz1) +1 + + ! The M'4 scheme + ! + a0 = .5*((2.-xx0)**2)*(1.-xx0) + b0 = .5*((2.-yy0)**2)*(1.-yy0) + c0 = .5*((2.-zz0)**2)*(1.-zz0) + + a1 = 1.-2.5*xx1*xx1 + 1.5*xx1*xx1*xx1 + b1 = 1.-2.5*yy1*yy1 + 1.5*yy1*yy1*yy1 + c1 = 1.-2.5*zz1*zz1 + 1.5*zz1*zz1*zz1 + + a2 = 1.-2.5*xx2*xx2 + 1.5*xx2*xx2*xx2 + b2 = 1.-2.5*yy2*yy2 + 1.5*yy2*yy2*yy2 + c2 = 1.-2.5*zz2*zz2 + 1.5*zz2*zz2*zz2 + + a3 = .5*((2.-xx3)**2)*(1.-xx3) + b3 = .5*((2.-yy3)**2)*(1.-yy3) + c3 = .5*((2.-zz3)**2)*(1.-zz3) + + ! b1=1. + ! b0=0. + ! b2=0. + ! b3=0. + ! a1=1. + ! a0=0. + ! a2=0. + ! a3=0. + ! c1=1. + ! c0=0. + ! c2=0. + ! c3=0. + + + coef=a0*b0*c0 + omg1(ip0,jp0,kp0) = omg1(ip0,jp0,kp0) + g2*coef + omg2(ip0,jp0,kp0) = omg2(ip0,jp0,kp0) + g3*coef + omg3(ip0,jp0,kp0) = omg3(ip0,jp0,kp0) + g4*coef + + coef=a0*b0*c1 + omg1(ip0,jp0,kp1) = omg1(ip0,jp0,kp1) + g2*coef + omg2(ip0,jp0,kp1) = omg2(ip0,jp0,kp1) + g3*coef + omg3(ip0,jp0,kp1) = omg3(ip0,jp0,kp1) + g4*coef + + coef=a0*b0*c2 + omg1(ip0,jp0,kp2) = omg1(ip0,jp0,kp2) + g2*coef + omg2(ip0,jp0,kp2) = omg2(ip0,jp0,kp2) + g3*coef + omg3(ip0,jp0,kp2) = omg3(ip0,jp0,kp2) + g4*coef + + coef=a0*b0*c3 + omg1(ip0,jp0,kp3) = omg1(ip0,jp0,kp3) + g2*coef + omg2(ip0,jp0,kp3) = omg2(ip0,jp0,kp3) + g3*coef + omg3(ip0,jp0,kp3) = omg3(ip0,jp0,kp3) + g4*coef + + coef=a0*b1*c0 + omg1(ip0,jp1,kp0) = omg1(ip0,jp1,kp0) + g2*coef + omg2(ip0,jp1,kp0) = omg2(ip0,jp1,kp0) + g3*coef + omg3(ip0,jp1,kp0) = omg3(ip0,jp1,kp0) + g4*coef + + coef=a0*b1*c1 + omg1(ip0,jp1,kp1) = omg1(ip0,jp1,kp1) + g2*coef + omg2(ip0,jp1,kp1) = omg2(ip0,jp1,kp1) + g3*coef + omg3(ip0,jp1,kp1) = omg3(ip0,jp1,kp1) + g4*coef + + coef=a0*b1*c2 + omg1(ip0,jp1,kp2) = omg1(ip0,jp1,kp2) + g2*coef + omg2(ip0,jp1,kp2) = omg2(ip0,jp1,kp2) + g3*coef + omg3(ip0,jp1,kp2) = omg3(ip0,jp1,kp2) + g4*coef + + coef=a0*b1*c3 + omg1(ip0,jp1,kp3) = omg1(ip0,jp1,kp3) + g2*coef + omg2(ip0,jp1,kp3) = omg2(ip0,jp1,kp3) + g3*coef + omg3(ip0,jp1,kp3) = omg3(ip0,jp1,kp3) + g4*coef + + coef=a0*b2*c0 + omg1(ip0,jp2,kp0) = omg1(ip0,jp2,kp0) + g2*coef + omg2(ip0,jp2,kp0) = omg2(ip0,jp2,kp0) + g3*coef + omg3(ip0,jp2,kp0) = omg3(ip0,jp2,kp0) + g4*coef + + coef=a0*b2*c1 + omg1(ip0,jp2,kp1) = omg1(ip0,jp2,kp1) + g2*coef + omg2(ip0,jp2,kp1) = omg2(ip0,jp2,kp1) + g3*coef + omg3(ip0,jp2,kp1) = omg3(ip0,jp2,kp1) + g4*coef + + coef=a0*b2*c2 + omg1(ip0,jp2,kp2) = omg1(ip0,jp2,kp2) + g2*coef + omg2(ip0,jp2,kp2) = omg2(ip0,jp2,kp2) + g3*coef + omg3(ip0,jp2,kp2) = omg3(ip0,jp2,kp2) + g4*coef + + + coef=a0*b2*c3 + omg1(ip0,jp2,kp3) = omg1(ip0,jp2,kp3) + g2*coef + omg2(ip0,jp2,kp3) = omg2(ip0,jp2,kp3) + g3*coef + omg3(ip0,jp2,kp3) = omg3(ip0,jp2,kp3) + g4*coef + + coef=a0*b3*c0 + omg1(ip0,jp3,kp0) = omg1(ip0,jp3,kp0) + g2*coef + omg2(ip0,jp3,kp0) = omg2(ip0,jp3,kp0) + g3*coef + omg3(ip0,jp3,kp0) = omg3(ip0,jp3,kp0) + g4*coef + + coef=a0*b3*c1 + omg1(ip0,jp3,kp1) = omg1(ip0,jp3,kp1) + g2*coef + omg2(ip0,jp3,kp1) = omg2(ip0,jp3,kp1) + g3*coef + omg3(ip0,jp3,kp1) = omg3(ip0,jp3,kp1) + g4*coef + + coef=a0*b3*c2 + omg1(ip0,jp3,kp2) = omg1(ip0,jp3,kp2) + g2*coef + omg2(ip0,jp3,kp2) = omg2(ip0,jp3,kp2) + g3*coef + omg3(ip0,jp3,kp2) = omg3(ip0,jp3,kp2) + g4*coef + + coef=a0*b3*c3 + omg1(ip0,jp3,kp3) = omg1(ip0,jp3,kp3) + g2*coef + omg2(ip0,jp3,kp3) = omg2(ip0,jp3,kp3) + g3*coef + omg3(ip0,jp3,kp3) = omg3(ip0,jp3,kp3) + g4*coef + + coef=a1*b0*c0 + omg1(ip1,jp0,kp0) = omg1(ip1,jp0,kp0) + g2*coef + omg2(ip1,jp0,kp0) = omg2(ip1,jp0,kp0) + g3*coef + omg3(ip1,jp0,kp0) = omg3(ip1,jp0,kp0) + g4*coef + + coef=a1*b0*c1 + omg1(ip1,jp0,kp1) = omg1(ip1,jp0,kp1) + g2*coef + omg2(ip1,jp0,kp1) = omg2(ip1,jp0,kp1) + g3*coef + omg3(ip1,jp0,kp1) = omg3(ip1,jp0,kp1) + g4*coef + + coef=a1*b0*c2 + omg1(ip1,jp0,kp2) = omg1(ip1,jp0,kp2) + g2*coef + omg2(ip1,jp0,kp2) = omg2(ip1,jp0,kp2) + g3*coef + omg3(ip1,jp0,kp2) = omg3(ip1,jp0,kp2) + g4*coef + + coef=a1*b0*c3 + omg1(ip1,jp0,kp3) = omg1(ip1,jp0,kp3) + g2*coef + omg2(ip1,jp0,kp3) = omg2(ip1,jp0,kp3) + g3*coef + omg3(ip1,jp0,kp3) = omg3(ip1,jp0,kp3) + g4*coef + + coef=a1*b1*c0 + omg1(ip1,jp1,kp0) = omg1(ip1,jp1,kp0) + g2*coef + omg2(ip1,jp1,kp0) = omg2(ip1,jp1,kp0) + g3*coef + omg3(ip1,jp1,kp0) = omg3(ip1,jp1,kp0) + g4*coef + + coef=a1*b1*c1 + omg1(ip1,jp1,kp1) = omg1(ip1,jp1,kp1) + g2*coef + omg2(ip1,jp1,kp1) = omg2(ip1,jp1,kp1) + g3*coef + omg3(ip1,jp1,kp1) = omg3(ip1,jp1,kp1) + g4*coef + + coef=a1*b1*c2 + omg1(ip1,jp1,kp2) = omg1(ip1,jp1,kp2) + g2*coef + omg2(ip1,jp1,kp2) = omg2(ip1,jp1,kp2) + g3*coef + omg3(ip1,jp1,kp2) = omg3(ip1,jp1,kp2) + g4*coef + + coef=a1*b1*c3 + omg1(ip1,jp1,kp3) = omg1(ip1,jp1,kp3) + g2*coef + omg2(ip1,jp1,kp3) = omg2(ip1,jp1,kp3) + g3*coef + omg3(ip1,jp1,kp3) = omg3(ip1,jp1,kp3) + g4*coef + + coef=a1*b2*c0 + omg1(ip1,jp2,kp0) = omg1(ip1,jp2,kp0) + g2*coef + omg2(ip1,jp2,kp0) = omg2(ip1,jp2,kp0) + g3*coef + omg3(ip1,jp2,kp0) = omg3(ip1,jp2,kp0) + g4*coef + + coef=a1*b2*c1 + omg1(ip1,jp2,kp1) = omg1(ip1,jp2,kp1) + g2*coef + omg2(ip1,jp2,kp1) = omg2(ip1,jp2,kp1) + g3*coef + omg3(ip1,jp2,kp1) = omg3(ip1,jp2,kp1) + g4*coef + + coef=a1*b2*c2 + omg1(ip1,jp2,kp2) = omg1(ip1,jp2,kp2) + g2*coef + omg2(ip1,jp2,kp2) = omg2(ip1,jp2,kp2) + g3*coef + omg3(ip1,jp2,kp2) = omg3(ip1,jp2,kp2) + g4*coef + + coef=a1*b2*c3 + omg1(ip1,jp2,kp3) = omg1(ip1,jp2,kp3) + g2*coef + omg2(ip1,jp2,kp3) = omg2(ip1,jp2,kp3) + g3*coef + omg3(ip1,jp2,kp3) = omg3(ip1,jp2,kp3) + g4*coef + + coef=a1*b3*c0 + omg1(ip1,jp3,kp0) = omg1(ip1,jp3,kp0) + g2*coef + omg2(ip1,jp3,kp0) = omg2(ip1,jp3,kp0) + g3*coef + omg3(ip1,jp3,kp0) = omg3(ip1,jp3,kp0) + g4*coef + + coef=a1*b3*c1 + omg1(ip1,jp3,kp1) = omg1(ip1,jp3,kp1) + g2*coef + omg2(ip1,jp3,kp1) = omg2(ip1,jp3,kp1) + g3*coef + omg3(ip1,jp3,kp1) = omg3(ip1,jp3,kp1) + g4*coef + + coef=a1*b3*c2 + omg1(ip1,jp3,kp2) = omg1(ip1,jp3,kp2) + g2*coef + omg2(ip1,jp3,kp2) = omg2(ip1,jp3,kp2) + g3*coef + omg3(ip1,jp3,kp2) = omg3(ip1,jp3,kp2) + g4*coef + + coef=a1*b3*c3 + omg1(ip1,jp3,kp3) = omg1(ip1,jp3,kp3) + g2*coef + omg2(ip1,jp3,kp3) = omg2(ip1,jp3,kp3) + g3*coef + omg3(ip1,jp3,kp3) = omg3(ip1,jp3,kp3) + g4*coef + + coef=a2*b0*c0 + omg1(ip2,jp0,kp0) = omg1(ip2,jp0,kp0) + g2*coef + omg2(ip2,jp0,kp0) = omg2(ip2,jp0,kp0) + g3*coef + omg3(ip2,jp0,kp0) = omg3(ip2,jp0,kp0) + g4*coef + + coef=a2*b0*c1 + omg1(ip2,jp0,kp1) = omg1(ip2,jp0,kp1) + g2*coef + omg2(ip2,jp0,kp1) = omg2(ip2,jp0,kp1) + g3*coef + omg3(ip2,jp0,kp1) = omg3(ip2,jp0,kp1) + g4*coef + + coef=a2*b0*c2 + omg1(ip2,jp0,kp2) = omg1(ip2,jp0,kp2) + g2*coef + omg2(ip2,jp0,kp2) = omg2(ip2,jp0,kp2) + g3*coef + omg3(ip2,jp0,kp2) = omg3(ip2,jp0,kp2) + g4*coef + + coef=a2*b0*c3 + omg1(ip2,jp0,kp3) = omg1(ip2,jp0,kp3) + g2*coef + omg2(ip2,jp0,kp3) = omg2(ip2,jp0,kp3) + g3*coef + omg3(ip2,jp0,kp3) = omg3(ip2,jp0,kp3) + g4*coef + + coef=a2*b1*c0 + omg1(ip2,jp1,kp0) = omg1(ip2,jp1,kp0) + g2*coef + omg2(ip2,jp1,kp0) = omg2(ip2,jp1,kp0) + g3*coef + omg3(ip2,jp1,kp0) = omg3(ip2,jp1,kp0) + g4*coef + + coef=a2*b1*c1 + omg1(ip2,jp1,kp1) = omg1(ip2,jp1,kp1) + g2*coef + omg2(ip2,jp1,kp1) = omg2(ip2,jp1,kp1) + g3*coef + omg3(ip2,jp1,kp1) = omg3(ip2,jp1,kp1) + g4*coef + + coef=a2*b1*c2 + omg1(ip2,jp1,kp2) = omg1(ip2,jp1,kp2) + g2*coef + omg2(ip2,jp1,kp2) = omg2(ip2,jp1,kp2) + g3*coef + omg3(ip2,jp1,kp2) = omg3(ip2,jp1,kp2) + g4*coef + + coef=a2*b1*c3 + omg1(ip2,jp1,kp3) = omg1(ip2,jp1,kp3) + g2*coef + omg2(ip2,jp1,kp3) = omg2(ip2,jp1,kp3) + g3*coef + omg3(ip2,jp1,kp3) = omg3(ip2,jp1,kp3) + g4*coef + + coef=a2*b2*c0 + omg1(ip2,jp2,kp0) = omg1(ip2,jp2,kp0) + g2*coef + omg2(ip2,jp2,kp0) = omg2(ip2,jp2,kp0) + g3*coef + omg3(ip2,jp2,kp0) = omg3(ip2,jp2,kp0) + g4*coef + + coef=a2*b2*c1 + omg1(ip2,jp2,kp1) = omg1(ip2,jp2,kp1) + g2*coef + omg2(ip2,jp2,kp1) = omg2(ip2,jp2,kp1) + g3*coef + omg3(ip2,jp2,kp1) = omg3(ip2,jp2,kp1) + g4*coef + + coef=a2*b2*c2 + omg1(ip2,jp2,kp2) = omg1(ip2,jp2,kp2) + g2*coef + omg2(ip2,jp2,kp2) = omg2(ip2,jp2,kp2) + g3*coef + omg3(ip2,jp2,kp2) = omg3(ip2,jp2,kp2) + g4*coef + + coef=a2*b2*c3 + omg1(ip2,jp2,kp3) = omg1(ip2,jp2,kp3) + g2*coef + omg2(ip2,jp2,kp3) = omg2(ip2,jp2,kp3) + g3*coef + omg3(ip2,jp2,kp3) = omg3(ip2,jp2,kp3) + g4*coef + + coef=a2*b3*c0 + omg1(ip2,jp3,kp0) = omg1(ip2,jp3,kp0) + g2*coef + omg2(ip2,jp3,kp0) = omg2(ip2,jp3,kp0) + g3*coef + omg3(ip2,jp3,kp0) = omg3(ip2,jp3,kp0) + g4*coef + + coef=a2*b3*c1 + omg1(ip2,jp3,kp1) = omg1(ip2,jp3,kp1) + g2*coef + omg2(ip2,jp3,kp1) = omg2(ip2,jp3,kp1) + g3*coef + omg3(ip2,jp3,kp1) = omg3(ip2,jp3,kp1) + g4*coef + + coef=a2*b3*c2 + omg1(ip2,jp3,kp2) = omg1(ip2,jp3,kp2) + g2*coef + omg2(ip2,jp3,kp2) = omg2(ip2,jp3,kp2) + g3*coef + omg3(ip2,jp3,kp2) = omg3(ip2,jp3,kp2) + g4*coef + + coef=a2*b3*c3 + omg1(ip2,jp3,kp3) = omg1(ip2,jp3,kp3) + g2*coef + omg2(ip2,jp3,kp3) = omg2(ip2,jp3,kp3) + g3*coef + omg3(ip2,jp3,kp3) = omg3(ip2,jp3,kp3) + g4*coef + + coef=a3*b0*c0 + omg1(ip3,jp0,kp0) = omg1(ip3,jp0,kp0) + g2*coef + omg2(ip3,jp0,kp0) = omg2(ip3,jp0,kp0) + g3*coef + omg3(ip3,jp0,kp0) = omg3(ip3,jp0,kp0) + g4*coef + + coef=a3*b0*c1 + omg1(ip3,jp0,kp1) = omg1(ip3,jp0,kp1) + g2*coef + omg2(ip3,jp0,kp1) = omg2(ip3,jp0,kp1) + g3*coef + omg3(ip3,jp0,kp1) = omg3(ip3,jp0,kp1) + g4*coef + + coef=a3*b0*c2 + omg1(ip3,jp0,kp2) = omg1(ip3,jp0,kp2) + g2*coef + omg2(ip3,jp0,kp2) = omg2(ip3,jp0,kp2) + g3*coef + omg3(ip3,jp0,kp2) = omg3(ip3,jp0,kp2) + g4*coef + + coef=a3*b0*c3 + omg1(ip3,jp0,kp3) = omg1(ip3,jp0,kp3) + g2*coef + omg2(ip3,jp0,kp3) = omg2(ip3,jp0,kp3) + g3*coef + omg3(ip3,jp0,kp3) = omg3(ip3,jp0,kp3) + g4*coef + + coef=a3*b1*c0 + omg1(ip3,jp1,kp0) = omg1(ip3,jp1,kp0) + g2*coef + omg2(ip3,jp1,kp0) = omg2(ip3,jp1,kp0) + g3*coef + omg3(ip3,jp1,kp0) = omg3(ip3,jp1,kp0) + g4*coef + + coef=a3*b1*c1 + omg1(ip3,jp1,kp1) = omg1(ip3,jp1,kp1) + g2*coef + omg2(ip3,jp1,kp1) = omg2(ip3,jp1,kp1) + g3*coef + omg3(ip3,jp1,kp1) = omg3(ip3,jp1,kp1) + g4*coef + + coef=a3*b1*c2 + omg1(ip3,jp1,kp2) = omg1(ip3,jp1,kp2) + g2*coef + omg2(ip3,jp1,kp2) = omg2(ip3,jp1,kp2) + g3*coef + omg3(ip3,jp1,kp2) = omg3(ip3,jp1,kp2) + g4*coef + + coef=a3*b1*c3 + omg1(ip3,jp1,kp3) = omg1(ip3,jp1,kp3) + g2*coef + omg2(ip3,jp1,kp3) = omg2(ip3,jp1,kp3) + g3*coef + omg3(ip3,jp1,kp3) = omg3(ip3,jp1,kp3) + g4*coef + + coef=a3*b2*c0 + omg1(ip3,jp2,kp0) = omg1(ip3,jp2,kp0) + g2*coef + omg2(ip3,jp2,kp0) = omg2(ip3,jp2,kp0) + g3*coef + omg3(ip3,jp2,kp0) = omg3(ip3,jp2,kp0) + g4*coef + + coef=a3*b2*c1 + omg1(ip3,jp2,kp1) = omg1(ip3,jp2,kp1) + g2*coef + omg2(ip3,jp2,kp1) = omg2(ip3,jp2,kp1) + g3*coef + omg3(ip3,jp2,kp1) = omg3(ip3,jp2,kp1) + g4*coef + + coef=a3*b2*c2 + omg1(ip3,jp2,kp2) = omg1(ip3,jp2,kp2) + g2*coef + omg2(ip3,jp2,kp2) = omg2(ip3,jp2,kp2) + g3*coef + omg3(ip3,jp2,kp2) = omg3(ip3,jp2,kp2) + g4*coef + + coef=a3*b2*c3 + omg1(ip3,jp2,kp3) = omg1(ip3,jp2,kp3) + g2*coef + omg2(ip3,jp2,kp3) = omg2(ip3,jp2,kp3) + g3*coef + omg3(ip3,jp2,kp3) = omg3(ip3,jp2,kp3) + g4*coef + + coef=a3*b3*c0 + omg1(ip3,jp3,kp0) = omg1(ip3,jp3,kp0) + g2*coef + omg2(ip3,jp3,kp0) = omg2(ip3,jp3,kp0) + g3*coef + omg3(ip3,jp3,kp0) = omg3(ip3,jp3,kp0) + g4*coef + + coef=a3*b3*c1 + omg1(ip3,jp3,kp1) = omg1(ip3,jp3,kp1) + g2*coef + omg2(ip3,jp3,kp1) = omg2(ip3,jp3,kp1) + g3*coef + omg3(ip3,jp3,kp1) = omg3(ip3,jp3,kp1) + g4*coef + + coef=a3*b3*c2 + omg1(ip3,jp3,kp2) = omg1(ip3,jp3,kp2) + g2*coef + omg2(ip3,jp3,kp2) = omg2(ip3,jp3,kp2) + g3*coef + omg3(ip3,jp3,kp2) = omg3(ip3,jp3,kp2) + g4*coef + + coef=a3*b3*c3 + omg1(ip3,jp3,kp3) = omg1(ip3,jp3,kp3) + g2*coef + omg2(ip3,jp3,kp3) = omg2(ip3,jp3,kp3) + g3*coef + omg3(ip3,jp3,kp3) = omg3(ip3,jp3,kp3) + g4*coef + + end DO + +end SUBROUTINE remesh_om diff --git a/CodesEnVrac/CodeGH/src-sphere/stretch.f90 b/CodesEnVrac/CodeGH/src-sphere/stretch.f90 new file mode 100644 index 000000000..9350e91c3 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/stretch.f90 @@ -0,0 +1,64 @@ +subroutine stretch + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dxinv=1./(12.*dx) + dyinv=1./(12.*dy) + dzinv=1./(12.*dz) + + do k=1,nz + kt=mod(k+nz,nz)+1 + kb=mod(k-2+nz,nz)+1 + ktt=mod(k+1+nz,nz)+1 + kbb=mod(k-3+nz,nz)+1 + ! + do j=1,ny + jt=mod(j+ny,ny)+1 + jb=mod(j-2+ny,ny)+1 + jtt=mod(j+1+ny,ny)+1 + jbb=mod(j-3+ny,ny)+1 + ! + do i=1,nx + it=mod(i+nx,nx)+1 + ib=mod(i-2+nx,nx)+1 + itt=mod(i+1+nx,nx)+1 + ibb=mod(i-3+nx,nx)+1 + + aux1=omg1(itt,j,k)*vxg(itt,j,k)+8.*(omg1(ib,j,k)*vxg(ib,j,k)-& + omg1(it,j,k)*vxg(it,j,k))-omg1(ibb,j,k)*vxg(ibb,j,k) + aux2=omg2(i,jtt,k)*vxg(i,jtt,k)+8.*(omg2(i,jb,k)*vxg(i,jb,k)-& + omg2(i,jt,k)*vxg(i,jt,k))-omg2(i,jbb,k)*vxg(i,jbb,k) + aux3=omg3(i,j,ktt)*vxg(i,j,ktt)+8.*(omg3(i,j,kb)*vxg(i,j,kb)-& + omg3(i,j,kt)*vxg(i,j,kt))-omg3(i,j,kbb)*vxg(i,j,kbb) + + ! strg1(i,j,k)=strg1(i,j,k)-aux1*dxinv-aux2*dyinv-aux3*dzinv + strg1(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv + + aux1=omg1(itt,j,k)*vyg(itt,j,k)+8.*(omg1(ib,j,k)*vyg(ib,j,k)-& + omg1(it,j,k)*vyg(it,j,k))-omg1(ibb,j,k)*vyg(ibb,j,k) + aux2=omg2(i,jtt,k)*vyg(i,jtt,k)+8.*(omg2(i,jb,k)*vyg(i,jb,k)-& + omg2(i,jt,k)*vyg(i,jt,k))-omg2(i,jbb,k)*vyg(i,jbb,k) + aux3=omg3(i,j,ktt)*vyg(i,j,ktt)+8.*(omg3(i,j,kb)*vyg(i,j,kb)-& + omg3(i,j,kt)*vyg(i,j,kt))-omg3(i,j,kbb)*vyg(i,j,kbb) + + ! strg2(i,j,k)=strg2(i,j,k)-aux1*dxinv-aux2*dyinv-aux3*dzinv + strg2(i,j,k)=-aux1*dxinv-aux2*dyinv-aux3*dzinv + ! + aux1=omg1(itt,j,k)*vzg(itt,j,k)+8.*(omg1(ib,j,k)*vzg(ib,j,k)-& + omg1(it,j,k)*vzg(it,j,k))-omg1(ibb,j,k)*vzg(ibb,j,k) + aux2=omg2(i,jtt,k)*vzg(i,jtt,k)+8.*(omg2(i,jb,k)*vzg(i,jb,k)-& + omg2(i,jt,k)*vzg(i,jt,k))-omg2(i,jbb,k)*vzg(i,jbb,k) + aux3=omg3(i,j,ktt)*vzg(i,j,ktt)+8.*(omg3(i,j,kb)*vzg(i,j,kb)-& + omg3(i,j,kt)*vzg(i,j,kt))-omg3(i,j,kbb)*vzg(i,j,kbb) + + ! strg3(i,j,k)=strg3(i,j,k)-aux1*dxinv-aux2*dyinv-aux3*dzinv + strg3(i,j,k)=aux1*dxinv-aux2*dyinv-aux3*dzinv + + enddo + enddo + enddo + + return +end subroutine stretch diff --git a/CodesEnVrac/CodeGH/src-sphere/velox_dif.f90 b/CodesEnVrac/CodeGH/src-sphere/velox_dif.f90 new file mode 100644 index 000000000..f26b70778 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/velox_dif.f90 @@ -0,0 +1,144 @@ + subroutine velox_dif(npart,anu,delt,xp1,yp1,zp1,om1,om2,om3,dv1,omax2) + +! calcul fft pour vitesses ET diffusion + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),yp1(*),zp1(*),dv1(*) + dimension om1(*),om2(*),om3(*) + + + dimension aux3(npg,npg,npg),aux1(npg,npg,npg),aux2(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,cox,coy,coz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cox(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + coz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + wk(ngx2+1,npgy,npgz) + + pi=3.1415926 + dxinv=0.5/dx + dyinv=dxinv + dzinv=dxinv + +! calucl de fonction courants 3d + + nx2=nx/2 + ny2=ny/2 + nz2=nz/2 + + + call fftw3d(omg1,cfx,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg2,cfy,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg3,cfz,nx,ny,nz,nx2,ny2,nz2,wk,0) + + +! coeff de normalisation pour laplacien en spectral + + anudt=anu*delt + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nz2,nz2 + rk=float(k)*ak + do 10 j=1-ny2,ny2 + rj=float(j)*aj + do 10 i=0,nx2 + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + r2b=(1.+r2*anudt) + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) +! diffusion en fourier + cox(i,j,k)=cfx(i,j,k)/r2b + coy(i,j,k)=cfy(i,j,k)/r2b + coz(i,j,k)=cfz(i,j,k)/r2b + if (r2.ne.0.) then +! vitesses en fourier + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + endif +10 continue + +! fourrier inverse pour vitesses + call fftw3d(aux1,cux,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,cuy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,cuz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + + do k=1,nx + do j=1,ny + do i=1,nz + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + enddo + enddo + enddo + +! fourier inverse pour vorticite apres difusion +! et creation de particules + + call fftw3d(aux1,cox,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,coy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,coz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + + circlim=0.0001 + npart=0 + vol=dx**3 + omax1=0. + omax2=0. + do k=1,nx + do j=1,ny + do i=1,nz + omg1(i,j,k)=aux1(i,j,k) + omg2(i,j,k)=aux2(i,j,k) + omg3(i,j,k)=aux3(i,j,k) + strength=abs(omg2(i,j,k))+abs(omg1(i,j,k))+abs(omg3(i,j,k)) + if ((strength.gt.circlim)) then + x=xmin+float(i-1)*dx + y=xmin+float(j-1)*dx + z=xmin+float(k-1)*dx + npart=npart+1 + xp1(npart)=x + yp1(npart)=y + zp1(npart)=z + dv1(npart)=dx**3 + om1(npart)=omg1(i,j,k)*vol + om2(npart)=omg2(i,j,k)*vol + om3(npart)=omg3(i,j,k)*vol + endif + omax2=amax1(omax2,abs(omg1(i,j,k))) + omax2=amax1(omax2,abs(omg2(i,j,k))) + omax2=amax1(omax2,abs(omg3(i,j,k))) + enddo + enddo + enddo + + print*, 'OMAX avant et apres DIFF ',omax1,omax2 + + + + + return + end + diff --git a/CodesEnVrac/CodeGH/src-sphere/velox_fft.f90 b/CodesEnVrac/CodeGH/src-sphere/velox_fft.f90 new file mode 100644 index 000000000..c6513cdb4 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/velox_fft.f90 @@ -0,0 +1,86 @@ +subroutine velox_fft + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension aux3(npg,npg,npg),aux1(npg,npg,npg),aux2(npg,npg,npg) + + parameter(ngx2=npgx/2,ngy2=npgy/2,ngz2=npgz/2) + + complex cfx,cfy,cfz,cux,cuy,cuz,wk + common/fft/cfx(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cfz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cux(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cuy(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + cuz(0:ngx2,1-ngy2:ngy2,1-ngz2:ngz2),& + wk(ngx2+1,npgy,npgz) + + pi=3.1415926 + dxinv=0.5/dx + dyinv=dxinv + dzinv=dxinv + + ! calucl de fonction courants 3d + + nx2=nx/2 + ny2=ny/2 + nz2=nz/2 + + + call fftw3d(omg1,cfx,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg2,cfy,nx,ny,nz,nx2,ny2,nz2,wk,0) + call fftw3d(omg3,cfz,nx,ny,nz,nx2,ny2,nz2,wk,0) + + + ! coeff de normalisation pour laplacien en spectral + + ai=2.*pi/(xmax-xmin) + aj=2.*pi/(ymax-ymin) + ak=2.*pi/(zmax-zmin) + + ai2=ai**2 + aj2=aj**2 + ak2=ak**2 + + do 10 k=1-nz2,nz2 + rk=float(k)*ak + do 10 j=1-ny2,ny2 + rj=float(j)*aj + do 10 i=0,nx2 + ri=float(i)*ai + r2=ri**2+rj**2+rk**2 + cux(i,j,k)=cmplx(0.0,0.0) + cuy(i,j,k)=cmplx(0.0,0.0) + cuz(i,j,k)=cmplx(0.0,0.0) + if (r2.ne.0.) then + ! + cux(i,j,k)=cmplx(0.0,1.0)*(-rj*cfz(i,j,k)+rk*cfy(i,j,k))/r2 + cuy(i,j,k)=cmplx(0.0,1.0)*(-rk*cfx(i,j,k)+ri*cfz(i,j,k))/r2 + cuz(i,j,k)=cmplx(0.0,1.0)*(-ri*cfy(i,j,k)+rj*cfx(i,j,k))/r2 + endif +10 continue + + + call fftw3d(aux1,cux,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux2,cuy,nx,ny,nz,nx2,ny2,nz2,wk,1) + call fftw3d(aux3,cuz,nx,ny,nz,nx2,ny2,nz2,wk,1) + + + do k=1,nx + do j=1,ny + do i=1,nz + vxg(i,j,k)=-aux1(i,j,k) + vyg(i,j,k)=-aux2(i,j,k) + vzg(i,j,k)=-aux3(i,j,k) + enddo + enddo + enddo + + + + + return + end do + diff --git a/CodesEnVrac/CodeGH/src-sphere/vfix.f90 b/CodesEnVrac/CodeGH/src-sphere/vfix.f90 new file mode 100644 index 000000000..d1909a857 --- /dev/null +++ b/CodesEnVrac/CodeGH/src-sphere/vfix.f90 @@ -0,0 +1,46 @@ + subroutine vfix + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + + pi=3.1415926 + topi=2./pi + eps=dx/1000. + +! calcul vitesse moyenne dans obstacle + + aire=(xmax-xmin)**2 + total=0. + aux=0. + do k=1,nz + do j=1,ny + aux=aux+vxg(1,j,k)*dx*dx + enddo + enddo + + corec=(aux-1.)/aire + + aux=aux/total + + vmax=0. + do i=1,nx + do j=1,ny + do k=1,nz + vxg(i,j,k)=vxg(i,j,k)-corec + vmax=amax1(vmax,abs(vxg(i,j,k))) + enddo + enddo + enddo + +101 continue + + print*,' VMAX = ',vmax + + return + end + + + diff --git a/CodesEnVrac/CodesAdrien/split_2d/Makefile b/CodesEnVrac/CodesAdrien/split_2d/Makefile new file mode 100644 index 000000000..b2ad1583c --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/Makefile @@ -0,0 +1,25 @@ +# +# Makefile +# +#Compilateur = ifort +Compilateur = ifort -pg +#Compilateur = ifort -O0 -debug extended +Programme = split_2d +FILES = donnees_mod.f90 donnees_limit_mod.f90 tab_mod.f90 init_mod.f90 remaillage_mod.f90 interpolation_mod.f90 advection_mod.f90 utile_mod.f90 resultats_mod.f90 main.f90 +OBJS = $(patsubst %.f90, %.o, $(FILES)) + +$(Programme): $(OBJS) + @echo edition de liens + @$(Compilateur) $(OBJS) -o $@ + +%.o: %.f90 + @echo compilation de $? + @$(Compilateur) -c $? + +clean: + @rm -f *.o *~ *.mod + @echo nettoyage + +clean_all: + @rm -f *.o *~ *.mod *exe *.out + @echo nettoyage diff --git a/CodesEnVrac/CodesAdrien/split_2d/Makefile_old b/CodesEnVrac/CodesAdrien/split_2d/Makefile_old new file mode 100644 index 000000000..a3cce3640 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/Makefile_old @@ -0,0 +1,27 @@ +# +# Makefile +# +Compilateur = ifort +Programme = limit_flux +OBJS = donnees_mod.f90 donnees_limit_mod.f90 tab_mod.f90 init_mod.f90 advection_mod.f90 remaillage_mod.f90 resultats_mod.f90 utile_mod.f90 interpolation_mod.f90 v_moy_mod.f90 main.f90 + +#interpolation_mod.f90 derives_mod.f90 + +$(Programme): $(OBJS) + @echo edition de liens + @$(Compilateur) $(OBJS) -o $@ + +.f90.o: + @echo compilation de $? + @$(Compilateur) -c -O $? + +.c.o: + @c -c -O $? + @echo compilation de $? +clean: + @rm -f *.o *~ *.mod + @echo nettoyage + +clean_all: + @rm -f *.o *~ *.mod *exe *.out + @echo nettoyage diff --git a/CodesEnVrac/CodesAdrien/split_2d/advection_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/advection_mod.f90 new file mode 100644 index 000000000..de5209262 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/advection_mod.f90 @@ -0,0 +1,555 @@ +module advection_mod + use donnees_mod + use tab_mod + use remaillage_mod + use interpolation_mod +contains + + subroutine def_v_advec (vitx,vity,tps) + implicit none + real(kind=8),dimension(1:nx_gro,1:ny_gro),intent(out) :: vitx,vity + real(kind=8),intent(in) :: tps + integer :: i,j + real(kind=8) :: x,y,r2,tmp,cte,r,alpha,beta,rint,rext,w1,w2,w3,t1,t4,t5 + + + do j=1,ny_gro + do i=1,nx_gro + + x=xg+(i-1)*dx_gro + y=yb+(j-1)*dy_gro + + +!!$ !rotation avec chgmt signe +!!$ !------------------------- +!!$ r2=x**2+y**2 +!!$ !tmp=1 +!!$ tmp=cos(3.*0.5*pi*sqrt(r2)) +!!$ !tmp=cos(10.*sqrt(r2)) +!!$ vitx(i,j)=-tmp*y +!!$ vity(i,j)=tmp*x + +!!$ !test Staniforth sur [0,100]**2 +!!$ !---- +!!$ vitx(i,j)=8.*pi*sin(pi*x/25.)*sin(pi*y/25.)/25. +!!$ vity(i,j)=8.*pi*cos(pi*x/25.)*cos(pi*y/25.)/25. + + !Staniforth sur [0,1] avec retour pour t=0.5 + !-------------------------------------------- +!!$ vitx(i,j)=0.08*pi*sin(4.*pi*x)*sin(4.*pi*y)/(cos(2.*pi*tps)/4.) +!!$ vity(i,j)=0.08*pi*cos(4.*pi*x)*cos(4.*pi*y)/(cos(2.*pi*tps)/4.) +!!$ + + !filaments + !---------- +!!$ t1=10. +!!$ +!!$ vitx(i,j)=-2.*sin(pi*x)**2*sin(pi*y)*cos(pi*y) !*cos(pi*tps/t1) +!!$ vity(i,j)=2.*sin(pi*y)**2*sin(pi*x)*cos(pi*x) !*cos(pi*tps/t1) + + + + !test instationaire + !-------------------- + +!!$ t1=1. +!!$ t4=0.3 +!!$ t5=1. +!!$ +!!$ vitx(i,j)=t5*sin(2.*pi*x/t1)*sin(2.*pi*y/t1)*cos(pi*tps/t4) +!!$ vity(i,j)=t5*cos(2.*pi*x/t1)*cos(2.*pi*y/t1)*cos(pi*tps/t4) + + + !vitesse radiale + !---------------- + r=sqrt(x**2+y**2) + vitx(i,j)=x/r + vity(i,j)=y/r + + if (r<0.4) then + vitx(i,j)=x/0.4 + vity(i,j)=y/0.4 + end if + + + + end do + end do + +end subroutine def_v_advec + + +subroutine evalv (vitx,vity,tps,x,y) + implicit none + real(kind=8),intent(in) :: tps,x,y + real(kind=8),intent(out) :: vitx,vity + integer :: i,j + real(kind=8) :: r2,tmp,cte,r,alpha,beta,rint,rext,w1,w2,w3,t1,t4,t5 + + + t1=1. + t4=0.3 + t5=1. + + vitx=t5*sin(2.*pi*x/t1)*sin(2.*pi*y/t1)*cos(pi*tps/t4) + vity=t5*cos(2.*pi*x/t1)*cos(2.*pi*y/t1)*cos(pi*tps/t4) + +end subroutine evalv + + + + + + + + + subroutine crea_part_x + implicit none + integer :: i,j + real(kind=8) :: x,y,m + + m=cutoff*maxval(abs(qg)) + npart=0 + numpg=0 + do j=1,ny + do i=1,nx + x=xtab(i,j) + y=ytab(i,j) + + if (abs(qg(i,j))>=m) then + npart=npart+1 + numpg(i,j)=npart + xp(npart)=x + yp(npart)=y + vx(npart)=vxg(i,j) + vy(npart)=vyg(i,j) + !vx(npart)=interpol_v_l3(vxg,x,y) + !vy(npart)=interpol_v_l3(vyg,x,y) + qp(npart)=qg(i,j) + end if + end do + end do + + end subroutine crea_part_x + + subroutine crea_part_y + implicit none + integer :: i,j + real(kind=8) :: x,y,m + + m=cutoff*maxval(abs(qg)) + npart=0 + numpg=0 + do i=1,nx + do j=1,ny + x=xtab(i,j) + y=ytab(i,j) + + if (abs(qg(i,j))>=m) then + npart=npart+1 + numpg(i,j)=npart + xp(npart)=x + yp(npart)=y + vx(npart)=vxg(i,j) + vy(npart)=vyg(i,j) + !vx(npart)=interpol_v_l3(vxg,x,y) + !vy(npart)=interpol_v_l3(vyg,x,y) + qp(npart)=qg(i,j) + end if + end do + end do + + end subroutine crea_part_y + + + !================== + !TENSORIEL + !================== + + subroutine ad_tenso_euler + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + xp(i)=xp(i)+dt*vx(i) + yp(i)=yp(i)+dt*vy(i) + end do + + end subroutine ad_tenso_euler + + subroutine ad_tenso_rk2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + + call interpo_l2_2d(vxg,xp1,yp1,vx) + call interpo_l2_2d(vyg,xp1,yp1,vy) + + !call interpo_l3_2d(vxg1,xp1,yp1,vx) + !call interpo_l3_2d(vyg1,xp1,yp1,vy) + + do ib=1,npart + xp(ib)=xp(ib)+dt*vx(ib) + yp(ib)=yp(ib)+dt*vy(ib) + end do + + deallocate(xp1,yp1) + + end subroutine ad_tenso_rk2 + + + + + + + subroutine ad_tenso_rk3 + implicit none + integer :: ib + + + allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vy1(1:npart),vy2(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + + call interpo_l3_2d(vxg1,xp1,yp1,vx1) + call interpo_l3_2d(vyg1,xp1,yp1,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)-dt*vx(ib)+2.*dt*vx1(ib) + yp2(ib)=yp(ib)-dt*vy(ib)+2.*dt*vy1(ib) + end do + + call interpo_l3_2d(vxg2,xp2,yp2,vx2) + call interpo_l3_2d(vyg2,xp2,yp2,vy2) + + do ib=1,npart + xp(ib)=xp(ib)+dt*(vx(ib)/6.+2.*vx1(ib)/3.+vx2(ib)/6.) + yp(ib)=yp(ib)+dt*(vy(ib)/6.+2.*vy1(ib)/3.+vy2(ib)/6.) + end do + + deallocate (xp1,xp2,yp1,yp2) + deallocate (vx1,vx2,vy1,vy2) + + + end subroutine ad_tenso_rk3 + + + subroutine ad_tenso_rk4 + implicit none + integer :: ib + + + allocate (xp1(1:npart),xp2(1:npart),xp3(1:npart),yp1(1:npart),yp2(1:npart),yp3(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vx3(1:npart),vy1(1:npart),vy2(1:npart),vy3(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + + call interpo_l4_2d(vxg1,xp1,yp1,vx1) + call interpo_l4_2d(vyg1,xp1,yp1,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)+0.5*dt*vx1(ib) + yp2(ib)=yp(ib)+0.5*dt*vy1(ib) + end do + + call interpo_l4_2d(vxg1,xp2,yp2,vx2) + call interpo_l4_2d(vyg1,xp2,yp2,vy2) + + do ib=1,npart + xp3(ib)=xp(ib)+dt*vx2(ib) + yp3(ib)=yp(ib)+dt*vy2(ib) + end do + + call interpo_l4_2d(vxg2,xp3,yp3,vx3) + call interpo_l4_2d(vyg2,xp3,yp3,vy3) + + do ib=1,npart + xp(ib)=xp(ib)+dt*(vx(ib)+2.*vx1(ib)+2.*vx2(ib)+vx3(ib))/6. + yp(ib)=yp(ib)+dt*(vy(ib)+2.*vy1(ib)+2.*vy2(ib)+vy3(ib))/6. + end do + + deallocate (xp1,xp2,xp3,yp1,yp2,yp3) + deallocate (vx1,vx2,vx3,vy1,vy2,vy3) + + + end subroutine ad_tenso_rk4 + + + !=============================== + !ADVECTION non tensoriel + !=============================== + + subroutine ad_euler_x + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + xp(i)=xp(i)+dt*vx(i) + end do + + end subroutine ad_euler_x + + subroutine ad_euler_y + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + yp(i)=yp(i)+dt*vy(i) + end do + + end subroutine ad_euler_y + + + !=============================== + !SPLITTING + !calcul de la vitesse pour une advection d'euler à l'ordre 2 ou 3 + !=============================== + + subroutine update_vx_2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + !call interpo_l2_2d(vxg1,xp1,yp1,vx) + call interpo_l2_2d(vxg,xp1,yp1,vx) + deallocate(xp1,yp1) + + end subroutine update_vx_2 + + subroutine update_vy_2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)-0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + !call interpo_l2_2d(vyg1,xp1,yp1,vy) + call interpo_l2_2d(vyg,xp1,yp1,vy) + deallocate(xp1,yp1) + + end subroutine update_vy_2 + + + + subroutine update_vx_3 + implicit none + integer :: ib + + + allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vy1(1:npart),vy2(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+2.*dt*vx(ib)/3. + yp1(ib)=yp(ib)+2.*dt*vy(ib)/3. + end do + + !call interpo_l3_2d(vxg2,xp1,yp1,vx1) + !call interpo_l3_2d(vyg2,xp1,yp1,vy1) + call interpo_l3_2d(vxg,xp1,yp1,vx1) + call interpo_l3_2d(vyg,xp1,yp1,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)/4.+vx1(ib)/4.) + yp2(ib)=yp(ib)+dt*(-vy(ib)+vy1(ib)) + end do + + !call interpo_l3_2d(vxg,xp2,yp,vx2) + !call interpo_l3_2d(vxg,xp,yp2,vy2) + call interpo_l3_2d(vxg,xp2,yp,vx2) + call interpo_l3_2d(vxg,xp,yp2,vy2) + + do ib=1,npart + vx(ib)=-vx(ib)+3.*vx1(ib)/4.+vx2(ib)+vy2(ib)/4. + end do + + deallocate (xp1,xp2,yp1,yp2) + deallocate (vx1,vx2,vy1,vy2) + + + end subroutine update_vx_3 + + subroutine update_vy_3 + implicit none + integer :: ib,i,j + + allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart)) + allocate (xp0(1:npart)) + allocate (vx1(1:npart),vy1(1:npart),vy2(1:npart),vy3(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)-2.*dt*vx(ib)/3. + yp1(ib)=yp(ib)+dt*vy(ib)/3. + xp0(ib)=xp(ib)-dt*vx(ib)/6. + end do + + !call interpo_l3_2d(vxg1,xp0,yp1,vx1) + !call interpo_l3_2d(vyg1,xp1,yp1,vy1) + call interpo_l3_2d(vxg,xp0,yp1,vx1) + call interpo_l3_2d(vyg,xp1,yp1,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(vx(ib)-vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+2.*vy1(ib)) + end do + + !call interpo_l3_2d(vyg,xp2,yp,vy2) + !call interpo_l3_2d(vyg3,xp,yp2,vy3) + call interpo_l3_2d(vyg,xp2,yp,vy2) + call interpo_l3_2d(vyg,xp,yp2,vy3) + + do ib=1,npart + vy(ib)=-vy(ib)+3.*vy1(ib)/4.+vy2(ib)+vy3(ib)/4. + end do + + + deallocate (xp1,xp2,yp1,yp2) + deallocate (xp0) + deallocate (vx1,vy1,vy2,vy3) + + end subroutine update_vy_3 + + + + + + !================================== + !STRANG + !================================== + + subroutine update_vx_strang + implicit none + integer :: ib + + allocate (xp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+dt*vx(ib)/2. + end do + !call interpo_l3_2d(vxg1,xp1,yp,vx) + call interpo_l3_2d(vxg,xp1,yp,vx) + deallocate(xp1) + + end subroutine update_vx_strang + + subroutine update_vy_strang + implicit none + integer :: ib + + allocate (yp1(1:npart)) + do ib=1,npart + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + !call interpo_l3_2d(vyg1,xp,yp1,vy) + call interpo_l3_2d(vyg,xp,yp1,vy) + deallocate(yp1) + + end subroutine update_vy_strang + + + !================================== + !ordre 4 + !================================== + + subroutine update_vx_4 + implicit none + integer :: ib + + + allocate (xp1(1:npart),xp2(1:npart),xp3(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vx3(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + end do + + call interpo_l5_2d(vxg,xp1,yp,vx1) + + do ib=1,npart + xp2(ib)=xp(ib)+0.5*dt*vx1(ib) + end do + + call interpo_l5_2d(vxg,xp2,yp,vx2) + + do ib=1,npart + xp3(ib)=xp(ib)+dt*vx2(ib) + end do + + call interpo_l5_2d(vxg,xp3,yp,vx3) + + do ib=1,npart + vx(ib)=(vx(ib)+2.*vx1(ib)+2.*vx2(ib)+vx3(ib))/6. + end do + + deallocate (xp1,xp2,xp3) + deallocate (vx1,vx2,vx3) + + end subroutine update_vx_4 + + + subroutine update_vy_4 + implicit none + integer :: ib + + + allocate (yp1(1:npart),yp2(1:npart),yp3(1:npart)) + allocate (vy1(1:npart),vy2(1:npart),vy3(1:npart)) + + do ib=1,npart + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + + call interpo_l5_2d(vyg,xp,yp1,vy1) + + do ib=1,npart + yp2(ib)=yp(ib)+0.5*dt*vy1(ib) + end do + + call interpo_l5_2d(vyg,xp,yp2,vy2) + + do ib=1,npart + yp3(ib)=yp(ib)+dt*vy2(ib) + end do + + call interpo_l5_2d(vyg,xp,yp3,vy3) + + do ib=1,npart + vy(ib)=(vy(ib)+2.*vy1(ib)+2.*vy2(ib)+vy3(ib))/6. + end do + + deallocate (yp1,yp2,yp3) + deallocate (vy1,vy2,vy3) + + + end subroutine update_vy_4 + + + + +end module advection_mod + + diff --git a/CodesEnVrac/CodesAdrien/split_2d/donnees_limit_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/donnees_limit_mod.f90 new file mode 100644 index 000000000..ba181a33c --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/donnees_limit_mod.f90 @@ -0,0 +1,5 @@ +module donnees_limit_mod + + real(kind=8),dimension(-6:6):: q_tab,q_tab_p,q_tab_m,v_tab_m,v_tab_p,l_tab_p,l_tab_m,h_tab_p,h_tab_m + +end module donnees_limit_mod diff --git a/CodesEnVrac/CodesAdrien/split_2d/donnees_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/donnees_mod.f90 new file mode 100644 index 000000000..aff193869 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/donnees_mod.f90 @@ -0,0 +1,9 @@ +module donnees_mod + + integer :: nx,ny,nx_gro,ny_gro,npart,type_b,long_bloc,int_limit + real(kind=8) :: time,dx,xd_f,xd_g,xg,dt,dt_sauv,tfin,cfl,pi,dt_b + real(kind=8) :: yb,yh_f,yh_g,dy,cutoff,dx_gro,dy_gro + character(len=50) :: nom_fich_vtk + + +end module donnees_mod diff --git a/CodesEnVrac/CodesAdrien/split_2d/init_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/init_mod.f90 new file mode 100644 index 000000000..a3e1ce4e8 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/init_mod.f90 @@ -0,0 +1,144 @@ +module init_mod + ! + !initialisation des valeurs sur la grille + ! +contains + subroutine init_grille + use donnees_mod + use tab_mod + implicit none + integer :: i,j + real(kind=8) :: x,y,xt,yt,beta,t1,t2,t3,r + + !---gaussienne--------- + !----------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=(1.-(x**2+y**2))**6 +!!$ if ((x**2+y**2)>1.) qg(i,j)=0. +!!$ +!!$ +!!$ end do +!!$ end do + + !---gaussienne pour Staniford sur [0,1]^2----------- + !---------------------------------------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=0. +!!$ +!!$ qg(i,j)=(1.-((x-0.5)**2+(y-0.5)**2))**6 +!!$ if (((x-0.5)**2+(y-0.5)**2)>1.) qg(i,j)=0. +!!$ +!!$ end do +!!$ end do +!!$ +!!$ !---test sur [0,1]^2----------- +!!$ !---------------------------------------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=0. +!!$ +!!$ qg(i,j)=(1.-((x-0.5)**2+(y-0.5)**2))**2 +!!$ if (((x-0.5)**2+(y-0.5)**2)>1.) qg(i,j)=0. +!!$ +!!$ end do +!!$ end do +!!$ + !---constante----------- + !----------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=1. +!!$ if ((x**2+y**2)>1.) qg(i,j)=0. +!!$ end do +!!$ end do +!!$ +!!$ !---gaussienne pour filaments sur [0,1]^2----------- +!!$ !---------------------------------------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=0. +!!$ +!!$ qg(i,j)=(1.-((x-0.5)**2+(y-0.8)**2))**6 +!!$ if (((x-0.5)**2+(y-0.5)**2)>1.) qg(i,j)=0. +!!$ +!!$ end do +!!$ end do + + + !---cercle pour filaments sur [0,1]^2----------- + !---------------------------------------------------- + +!!$ do j=1,ny +!!$ do i=1,nx +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=0. +!!$ +!!$ if (sqrt((x-0.5)**2+(y-0.75)**2)<=0.15) qg(i,j)=1. +!!$ +!!$ end do +!!$ end do + + + !-----------Analytique en cos-------------------------- + !------------------------------------------------------ +!!$ t1=1. +!!$ t2=1. +!!$ t3=0.2 +!!$ do j=1,ny +!!$ do i=1,nx +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ qg(i,j)=cos(pi*time/t3)*cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ end do +!!$ end do + + !---anneau----------- + !----------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ r=sqrt(x**2+y**2) +!!$ qg(i,j)=0. +!!$ !if ( (r>0.5).and.(r<1.4) ) qg(i,j)=1. +!!$ !if ( (r>0.).and.(r<0.8) ) qg(i,j)=1. +!!$ !if ( (r>=1.).and.(r<1.5) ) qg(i,j)=1. +!!$ if ( (r>0.5).and.(r<1.) ) qg(i,j)=1. +!!$ end do +!!$ end do + + !---anneau- regulier---------- + !----------------------- + do i=1,nx + do j=1,ny + x=xtab(i,j) + y=ytab(i,j) + r=sqrt(x**2+y**2) + qg(i,j)=0. + if ( (r>0.4).and.(r<0.6) ) qg(i,j)=-512.+5400.*r-22500.*r**2+46250*r**3-46875*r**4+18750*r**5 + if ( (r>=0.6).and.(r<=0.8) ) qg(i,j)=1. + if ( (r>0.8).and.(r<1.) ) qg(i,j)=10625.-60000*r+135000*r**2-151250*r**3+84375*r**4-18750*r**5 + + !if ( (r>0.4).and.(r<1.) ) qg(i,j)=1. + end do + end do + + + end subroutine init_grille + + + +end module init_mod diff --git a/CodesEnVrac/CodesAdrien/split_2d/interpolation_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/interpolation_mod.f90 new file mode 100644 index 000000000..a3b4048dc --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/interpolation_mod.f90 @@ -0,0 +1,634 @@ +module interpolation_mod + use donnees_mod + contains + + + subroutine interpo_l4_2d(tab_grille,posx,posy,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb + integer,dimension(0:5) :: ip,jp + real(kind=8),dimension(0:5) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy_gro-yb)/dy_gro !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + if (yy1<=0.5) then + poidy(0)=(2.*yy1-y2-2*y3+y4)/24. + poidy(1)=(-4.*yy1+4.*y2+y3-y4)/6. + poidy(2)=1.+(-5.*y2+y4)/4. + poidy(3)=(4.*yy1+4.*y2-y3-y4)/6. + poidy(4)=(-2.*yy1-y2+2*y3+y4)/24. + poidy(5)=0. + else + poidy(0)=0. + poidy(1)=(-6.*yy1+11.*y2-6.*y3+y4)/24. + poidy(2)=1.+(-5.*yy1-5.*y2+5.*y3-y4)/6. + poidy(3)=(6.*yy1+y2-4.*y3+y4)/4. + poidy(4)=(-3.*yy1+y2+3.*y3-y4)/6. + poidy(5)=(2.*yy1-y2-2.*y3+y4)/24. + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + do d=0,5 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine interpo_l4_2d + + subroutine interpo_l5_2d(tab_grille,posx,posy,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb + integer,dimension(0:5) :: ip,jp + real(kind=8),dimension(0:5) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy_gro-yb)/dy_gro !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + poidy(0)=yy1/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(1)=-yy1/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(2)=1.-yy1/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(3)=yy1+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(4)=-yy1/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(5)=yy1/30.-y3/24.+y5/120. + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + do d=0,5 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine interpo_l5_2d + + + + subroutine interpo_l3_2d(tab_grille,posx,posy,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb + integer,dimension(0:3) :: ip,jp + real(kind=8),dimension(0:3) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + poidy(0)=-1./6.*yy1*(yy1-1.)*(yy1-2.) + poidy(1)=0.5*(1.-yy1)*(1.+yy1)*(2.-yy1) + poidy(2)=-0.5*yy1*(yy1+1.)*(yy1-2.) + poidy(3)=1/6.*yy1*(1.+yy1)*(yy1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + do d=0,3 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine interpo_l3_2d + + + subroutine interpo_l2_2d(tab_grille,posx,posy,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb + integer,dimension(0:2) :: ip,jp + real(kind=8),dimension(0:2) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=0.5*xx1*(xx1-1.) + poidx(1)=1.-xx1**2 + poidx(2)=0.5*xx1*(1.+xx1) + + poidy(0)=0.5*yy1*(yy1-1.) + poidy(1)=1.-yy1**2 + poidy(2)=0.5*yy1*(1.+yy1) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,2 + do d=0,2 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine interpo_l2_2d + + subroutine interpo_l1_2d(tab_grille,posx,posy,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb + integer,dimension(1:2) :: ip,jp + real(kind=8),dimension(1:2) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + tab_part=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(2) = ip(1) + 1 + + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(2) = jp(1) + 1 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro !relatif + + !conditions au bord + !------------------ + !periodique: + do c=1,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=1,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + poidx(1)=1.-xx1 + poidx(2)=xx1 + + poidy(1)=1.-yy1 + poidy(2)=yy1 + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,2 + do d=1,2 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine interpo_l1_2d + + + + + + !=========================================================================== + !pour interpoler le champ de vitesse de la grille grossiere à la grille fine + !=========================================================================== + + + function interpol_v_l1(tab_gro,posx,posy) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy + real(kind=8) :: v + integer,dimension(0:1) :: ip,jp + real(kind=8),dimension(0:1) :: poidx,poidy + real(kind=8) :: xx,yy + integer :: c,d + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(1) = ip(0)+1 + + jp(0) = floor((posy-yb)/dy_gro) + jp(1) = jp(0)+1 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + + !conditions au bord + !------------------ + !periodique: + do c=0,1 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,1 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=1.-xx + poidx(1)=xx + + poidy(0)=1.-yy + poidy(1)=yy + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,1 + do d=0,1 + v=v+tab_gro(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + + end function interpol_v_l1 + + function interpol_v_l3(tab_gro,posx,posy) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy + real(kind=8) :: v + integer,dimension(-1:2) :: ip,jp + real(kind=8),dimension(-1:2) :: poidx,poidy + real(kind=8) :: xx,yy + integer :: c,d + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-1,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + poidx(-1)=-1./6.*xx*(xx-1.)*(xx-2.) + poidx(0)=0.5*(1.-xx)*(1.+xx)*(2.-xx) + poidx(1)=-0.5*xx*(xx+1.)*(xx-2.) + poidx(2)=1/6.*xx*(1.+xx)*(xx-1.) + + poidy(-1)=-1./6.*yy*(yy-1.)*(yy-2.) + poidy(0)=0.5*(1.-yy)*(1.+yy)*(2.-yy) + poidy(1)=-0.5*yy*(yy+1.)*(yy-2.) + poidy(2)=1/6.*yy*(1.+yy)*(yy-1.) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-1,2 + do d=-1,2 + v=v+tab_gro(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + + end function interpol_v_l3 + + function interpol_v_l5(tab_gro,posx,posy) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy + real(kind=8) :: v + integer,dimension(-2:3) :: ip,jp + real(kind=8),dimension(-2:3) :: poidx,poidy + real(kind=8) :: xx,yy + integer :: c,d + real(kind=8) :: x2,x3,x4,x5,y2,y3,y4,y5 + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-2) = ip(0)-2 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + ip(3) = ip(0)+3 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-2) = jp(0)-2 + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + jp(3) = jp(0)+3 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + + !conditions au bord + !------------------ + !periodique: + do c=-2,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-2,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + !calcul des poids + !---------------- + x2=xx**2 + x3=xx**3 + x4=xx**4 + x5=xx**5 + y2=yy**2 + y3=yy**3 + y4=yy**4 + y5=yy**5 + + poidx(-2)=xx/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(-1)=-xx/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(0)=1.-xx/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(1)=xx+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(2)=-xx/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(3)=xx/30.-x3/24.+x5/120. + + poidy(-2)=yy/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(-1)=-yy/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(0)=1.-yy/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(1)=yy+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(2)=-yy/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(3)=yy/30.-y3/24.+y5/120. + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,3 + do d=-2,3 + v=v+tab_gro(ip(c)+1,jp(d)+1)*poidx(c)*poidy(d) + end do + end do + + end function interpol_v_l5 + + + + + + + end module interpolation_mod diff --git a/CodesEnVrac/CodesAdrien/split_2d/main.f90 b/CodesEnVrac/CodesAdrien/split_2d/main.f90 new file mode 100644 index 000000000..84d6afbd7 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/main.f90 @@ -0,0 +1,1253 @@ +program split + !-------------------------------------------------------------------------- + !etude de l'ordre pour splitting + ! + !-------------------------------------------------------------------------- + use donnees_mod ! donnees + use tab_mod ! donnees dans tableaux + use init_mod ! init_grille + use advection_mod ! crea_part,advection + use remaillage_mod ! remaill_4m_centre (formules de remaillage) + use interpolation_mod ! formules d'interpolation (pour range kutta) + use resultats_mod ! res_grille_tps,res_grille_freq + use utile_mod ! fonctions en tout genre + + real(kind=8) :: x,y,dt_deb,dt_boucle,dtsauv,maxv + character(len=50) :: name_err,name_coupe + integer :: i,j,cpt_ite,ib,jb,nx_boucle + + real(kind=8) :: deb,masse,t1,t2,t3 + + + !lecture données + !--------------- + open(unit=10,file="parameter",form="formatted") + read(10,*) xg,xd,yb,yh + read(10,*) tfin + read(10,*) cutoff + read(10,*) type_b + read(10,*) long_bloc + read(10,*) int_limit + read(10,*) nom_fich_vtk + read(10,*) name_err,name_coupe + close(10) + + + erreur:do nx_boucle=201,201 + !erreur:do nx_boucle=10,5000,30 + !erreur:do nx_boucle=10,5000,100 + !nx=(long_bloc+1)*k+1 => bloc bord de bonne taille + + open(unit=10,file="parameter",form="formatted") + read(10,*) xg,xd,yb,yh + close (10) + + nx=nx_boucle + ny=nx_boucle + + !nx_gro=nx/2 + nx_gro=nx + ny_gro=nx_gro + + dx=(xd-xg)/(nx-1.) + dy=(yh-yb)/(ny-1.) + + dx_gro=(xd-xg)/(nx_gro-1.) + dy_gro=(yh-yb)/(ny_gro-1.) + + maxv=1. + !maxv=2. + cfl=3. + + dt=cfl*dx/maxv + !dt=0.0001 + dt_deb=dt + + +!!$ +!!$ +!!$ +!!$ erreur:do dt_b=0.2,0.01,-0.01 +!!$ !nx=(long_bloc+1)*k+1 => bloc bord de bonne taille +!!$ +!!$ open(unit=10,file="parameter",form="formatted") +!!$ read(10,*) xg,xd,yb,yh +!!$ close (10) +!!$ +!!$ nx_boucle=400 +!!$ +!!$ nx=nx_boucle +!!$ ny=nx_boucle +!!$ +!!$ !nx_gro=nx/2 +!!$ nx_gro=nx +!!$ ny_gro=nx_gro +!!$ +!!$ dx=(xd-xg)/(nx-1.) +!!$ dy=(yh-yb)/(ny-1.) +!!$ +!!$ dx_gro=(xd-xg)/(nx_gro-1.) +!!$ dy_gro=(yh-yb)/(ny_gro-1.) +!!$ +!!$ +!!$ dt=dt_b + + + + + + ! + !calcul init + !----------- + cpt_ite=0 + time=0. + + + npart=nx*ny + + xd_f=xd-dx !pour conditions periodiques + yh_f=yh-dy + + xd_g=xd-dx_gro + yh_g=yh-dy_gro + + nx=nx-1 + ny=ny-1 + + nx_gro=nx_gro-1 + ny_gro=ny_gro-1 + + + pi=4.*atan(1.) + + + + + + ! + !alloc tableaux: ici npart est une taille maximale, on pourrait rallouer apres la creation des part. + !-------------- + allocate (exa(1:nx,1:ny),qg(1:nx,1:ny),vxg(1:nx_gro,1:ny_gro),vyg(1:nx_gro,1:ny_gro)) + allocate (xtab(1:nx,1:ny),ytab(1:nx,1:ny)) + allocate (numpg(1:nx,1:ny)) + !allocate (Nblocg(1:max(nx,ny))) + + allocate (xp(1:npart),qp(1:npart),vx(1:npart),yp(1:npart),vy(1:npart)) + allocate (blocg(0:npart),blocd(0:npart),Nbloc(0:npart)) + + open(unit=29,file=name_err,form="formatted") + open(unit=30,file=name_coupe,form="formatted") + + call cpu_time(t1) + + ! + !initialisation + !-------------- + call make_grille + call init_grille() + masse=dx*dy*sum(qg) + + call def_v_advec(vxg,vyg,time) + + ! + !boucle temps + !------------ + temps: do while(time<tfin) + + !print*,"cflmax:",dt*max(maxval(vxg),maxval(vyg))/dx + + if ((time+dt)>tfin) dt=tfin-time + + if (time<=2.*dt) dt_deb=dt + + + !call def_v_advec(vxg,vyg,time) !inutile de le garder dans la boucle quand depend pas du temps. + + call crea_part_x() + + + + + !================================ + !si remaillage tenso en espace + !================================ + +!!$ !champ de vitesse +!!$ !----------------- +!!$ !allocate(vxg1(1:nx_gro,1:ny_gro),vyg1(1:nx_gro,1:ny_gro)) +!!$ !rk2 +!!$ !call def_v_advec(vxg1,vyg1,time+0.5*dt) +!!$ !vxg1=vxg +!!$ !vyg1=vyg +!!$ +!!$ !rk3 +!!$ !allocate(vxg2(1:nx_gro,1:ny_gro),vyg2(1:nx_gro,1:ny_gro)) +!!$ !call def_v_advec(vxg1,vyg1,time+0.5*dt) +!!$ !call def_v_advec(vxg2,vyg2,time+dt) +!!$ !vxg2=vxg +!!$ !vyg2=vyg +!!$ +!!$ !rk4 +!!$ !allocate(vxg3(1:nx_gro,1:ny_gro),vyg3(1:nx_gro,1:ny_gro)) +!!$ !vxg3=vxg +!!$ !vyg3=vyg +!!$ +!!$ +!!$ !t source:rk4 +!!$ !------------ +!!$ !call source_rk4 +!!$ +!!$ !advection +!!$ !--------- +!!$ !call ad_tenso_euler +!!$ call ad_tenso_rk2 +!!$ !call ad_tenso_rk3 +!!$ !call ad_tenso_rk4 +!!$ +!!$ +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l2(qp,xp,yp,qg) +!!$ call remaill_l3(qp,xp,yp,qg) +!!$ !call remaill_l4(qp,xp,yp,qg) +!!$ !call remaill_l6(qp,xp,yp,qg) +!!$ !call remaill_mp4(qp,xp,yp,qg) +!!$ !call remaill_mppp6(qp,xp,yp,qg) +!!$ +!!$ !deallocate(vxg1,vyg1) +!!$ !deallocate(vxg2,vyg2) +!!$ !deallocate(vxg3,vyg3) + + !===================== + !splitting en espace + !===================== + + !champ de vitesse + !----------------- + !allocate(vxg1(1:nx_gro,1:ny_gro),vyg1(1:nx_gro,1:ny_gro)) + !rk2 + !call def_v_advec(vxg1,vyg1,time+0.5*dt) + !vxg1=vxg + !vyg1=vyg ! attention sinon modifier dans les update vitesses d'advection + + !rk3 + !allocate(vxg2(1:nx_gro,1:ny_gro),vxg3(1:nx_gro,1:ny_gro),vyg2(1:nx_gro,1:ny_gro),vyg3(1:nx_gro,1:ny_gro)) + !call def_v_advec(vxg1,vyg1,time+dt/3.) + !call def_v_advec(vxg2,vyg2,time+2.*dt/3.) + !call def_v_advec(vxg3,vyg3,time+dt) !que le vyg3 qui nous interesse + !vxg2=vxg;vxg3=vxg + !vyg2=vyg;vyg3=vyg + + + !t source + !--------- + !call source_split_1 + + !update v + !-------- + !call update_vx_2 + call update_vx_3 + + + !test cfl + !-------- + !print*,"test cfl en x " + !print*,"cfl part, cfl",dt/dx*maxval(abs(vx)),dt/dx*maxval(abs(vxg)) + + !print*,"max vx",maxval(vx) + +! ainf=0. +! do j=1,ny +! do i=1,nx-1 +! if ( (numpg(i+1,j)/=0).and.(numpg(i,j)/=0) ) ainf=max(ainf,abs(vx(numpg(i+1,j))-vx(numpg(i,j)))) +! end do +! end do +! if (dt>(0.5*dx/(ainf))) then +! print*,"" +! print*,"cfl l2 viole" ,dt,0.5*dx/(ainf),0.5*dx/(2.*ainf) +! print*,"" +! end if +! if (dt>(0.5*dx/(2.*ainf))) then +! print*,"" +! print*,"cfl l4 viole" ,dt,0.5*dx/(ainf),0.5*dx/(2.*ainf) +! print*,"dx,dt",dx,dt +! print*,"" +! end if +! if (dt>(dx/(2.*ainf/(sqrt(3.)-1.)))) then +! print*,"" +! print*,"TSC gauche pas TVD (l2)" ,dt,dx/(2.*ainf/(sqrt(3.)-1.)) +! print*,"" +! end if +! if (dt>(dx/(5.4641*ainf))) then +! print*,"" +! print*,"TSC gauche pas TVD (l4)" ,dt,dx/(2.*ainf/(sqrt(3.)-1.)) +! print*,"" +! end if +! print*,"ainf",ainf/dx +! print*,"max",maxval(vx) + !fin test + !-------- + + + !bloc x + !------- + if ((type_b==2).or.(type_b==4)) then + !call make_bloc(1) + call make_bloc_v2(1) + else + blocg=0 + blocd=0 + end if + + !advection + !---------- + call ad_euler_x + + + !remaillage + !---------- + if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) + if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) + if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) + if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) + if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) + if (type_b==70)call remaill_mp4_x(qp,xp,yp,qg) + !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) + !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) + if (type_b==2) then + if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) + if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) + end if + if (type_b==4) then + if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) + if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) + end if + + if (type_b==200)call remaill_l2_limit_x(qp,xp,yp,qg) + if (type_b==400)call remaill_l4_limit_x(qp,xp,yp,qg) + + !y + !-- + call crea_part_y() + + !update v + !-------- + !call update_vy_2 + call update_vy_3 + + + !test cfl + !-------- + !print*,"test cfl en y " + !print*,"cfl part, cfl",dt/dy*maxval(abs(vy)),dt/dy*maxval(abs(vyg)) +! ainf=0. +! do j=1,ny-1 +! do i=1,nx +! if ( (numpg(i,j+1)/=0).and.(numpg(i,j)/=0) ) ainf=max(ainf,abs(vy(numpg(i,j+1))-vy(numpg(i,j)))) +! end do +! end do +! if (dt>(0.5*dy/(ainf))) then +! print*,"" +! print*,"cfl l2 viole" ,dt,0.5*dy/(ainf),0.5*dy/(2.*ainf) +! print*,"" +! end if +! if (dt>(0.5*dy/(2.*ainf))) then +! print*,"" +! print*,"cfl l4 viole" ,dt,0.5*dy/(ainf),0.5*dy/(2.*ainf) +! print*,"" +! end if + !fin test + !-------- + + !bloc y + !------- + if ((type_b==2).or.(type_b==4)) then + !call make_bloc(2) + call make_bloc_v2(2) + else + blocg=0 + blocd=0 + end if + + !advection + !---------- + call ad_euler_y + + + +!-------test---------------------------------------- +! if (cpt_ite <=1) then +! +! !trace la position des particules +! open(unit=28,file="RES/pos_part.deb",form="formatted") +! open(unit=29,file="RES/pos_part_2.deb",form="formatted") +! do ib=1,nx +! x=xg+(ib-1)*dx +! if ( (x>0.8).and.(x<0.81) ) then +! do jb=1,(ny+10) +! y=yb+(jb-1)*dy +! write(28,'(2(f35.20,2x))') y,0.5 +! end do +! end if +! end do +! +! do ib=1,npart +! if ((xp(ib)>0.8).and.(xp(ib)<0.81)) then +! write(29,'(4(f35.20,2x))') yp(ib),0.5,blocg(ib)*0.1 ,blocd(ib)*0.1 +! end if +! end do +! +! close (28) +! close (29) +! +! end if +!-------test---------------------------------------- + +!!$ + !remaillage + !---------- + if (type_b==30)call remaill_l3_y(qp,xp,yp,qg) + if (type_b==40)call remaill_l4_y(qp,xp,yp,qg) + if (type_b==20)call remaill_l2_y(qp,xp,yp,qg) + if (type_b==50)call remaill_l5_y(qp,xp,yp,qg) + if (type_b==60)call remaill_l6_y(qp,xp,yp,qg) + if (type_b==70)call remaill_mp4_y(qp,xp,yp,qg) + !if (type_b==2)call remaill_l2_bloc_y(qp,xp,yp,qg) + !if (type_b==4)call remaill_l4_bloc_y(qp,xp,yp,qg) + if (type_b==2) then + if (int_limit==0)call remaill_l2_bloc_v2_y(qp,xp,yp,qg) + if (int_limit==1)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) + end if + if (type_b==4) then + if (int_limit==0)call remaill_l4_bloc_v2_y(qp,xp,yp,qg) + if (int_limit==1)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) + end if + + if (type_b==200)call remaill_l2_limit_y(qp,xp,yp,qg) + if (type_b==400)call remaill_l4_limit_y(qp,xp,yp,qg) + + !t source + !--------- + !call source_split_2 + + + !deallocate(vxg1,vyg1) + !deallocate(vxg2,vxg3,vyg2,vyg3) + + + + !================= + !splitting strang + !================= +!!$ +!!$ !champ de vitesse: +!!$ !----------------- +!!$ allocate(vxg1(1:nx_gro,1:ny_gro),vyg1(1:nx_gro,1:ny_gro)) +!!$ !call def_v_advec(vxg1,vyg1,time+0.5*dt) +!!$ vxg1=vxg +!!$ vyg1=vyg +!!$ +!!$ !t source +!!$ !-------- +!!$ !call source_split_1 +!!$ +!!$ dt_sauv=dt +!!$ dt=0.5*dt +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_strang +!!$ +!!$ +!!$ !bloc x +!!$ !------- +!!$ !call make_bloc_x +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ call remaill_l3_x(qp,xp,yp,qg) +!!$ !call remaill_l5_x(qp,xp,yp,qg) +!!$ !call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2)call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ +!!$ !y +!!$ !-- +!!$ call crea_part_y() +!!$ +!!$ +!!$ dt=dt_sauv +!!$ !update v +!!$ !-------- +!!$ call update_vy_strang +!!$ +!!$ !test cfl +!!$ !-------- +!!$ !ainf=0. +!!$ !do i=1,nx +!!$ ! do j=1,ny-1 +!!$ ! ainf=max(ainf,abs(vyg(i,j+1)-vyg(i,j))) +!!$ ! end do +!!$ !end do +!!$ !print*,"dt,limit vg",dt,dy/(4.*ainf),dy/(6.*ainf) +!!$ !ainf=0. +!!$ !do i=1,nx +!!$ ! do j=1,ny-1 +!!$ ! ainf=max(ainf,abs(vy(numpg(i,j+1))-vy(numpg(i,j)))) +!!$ ! end do +!!$ !end do +!!$ !print*,"dt,limit v",dt,dy/(4.*ainf),dy/(6.*ainf) +!!$ +!!$ +!!$ !bloc y +!!$ !------- +!!$ !call make_bloc_y +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ call remaill_l3_y(qp,xp,yp,qg) +!!$ !call remaill_l5_y(qp,xp,yp,qg) +!!$ !call remaill_l6_y(qp,xp,yp,qg) +!!$ !if (type_b==2)call remaill_l2_bloc_y(qp,xp,yp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_y(qp,xp,yp,qg) +!!$ +!!$ !x +!!$ !-- +!!$ call crea_part_x() +!!$ +!!$ dt_sauv=dt +!!$ dt=0.5*dt +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_strang +!!$ +!!$ !bloc x +!!$ !------- +!!$ !call make_bloc_x +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ call remaill_l3_x(qp,xp,yp,qg) +!!$ !call remaill_l5_x(qp,xp,yp,qg) +!!$ !call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2)call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ +!!$ dt=dt_sauv +!!$ !t source +!!$ !--------- +!!$ !call source_split_2 +!!$ +!!$ +!!$ deallocate(vxg1,vyg1) + + + + + + + + + !============================= + !splitting ordre 4 en temps + !============================== +!!$ allocate(qg_init(1:nx,1:ny),qg_tmp(1:nx,1:ny)) +!!$ qg_init=qg +!!$!==================== +!!$! x: dt/4 +!!$!==================== +!!$ +!!$ dt_sauv=dt +!!$ dt=0.25*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_4 +!!$ +!!$ +!!$ +!!$ !test cfl +!!$ !-------- +!!$ !print*,"test cfl en x " +!!$ !ainf=0. +!!$ !do j=1,ny +!!$ ! do i=1,nx-1 +!!$ ! if ( (numpg(i+1,j)/=0).and.(numpg(i,j)/=0) ) ainf=max(ainf,abs(vx(numpg(i+1,j))-vx(numpg(i,j)))) +!!$ ! end do +!!$ !end do +!!$ !print*,"ainf",ainf +!!$ !fin test +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! y: dt/2 +!!$!==================== +!!$ call crea_part_y() +!!$ +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_4 +!!$ +!!$ !test cfl +!!$ !-------- +!!$ !print*,"test cfl en y " +!!$ !ainf=0. +!!$ !do i=1,nx +!!$ ! do j=1,ny-1 +!!$ ! if ( (numpg(i,j+1)/=0).and.(numpg(i,j)/=0) ) ainf=max(ainf,abs(vy(numpg(i,j+1))-vy(numpg(i,j)))) +!!$ ! end do +!!$ !end do +!!$ !print*,"ainf",ainf +!!$ !fin test +!!$ +!!$ !bloc +!!$ !----- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(2) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_y(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_y(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_y(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_y(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_y(qp,xp,yp,qg) +!!$ +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! x: dt/2 +!!$!==================== +!!$ call crea_part_x() +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_4 +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! y: dt/2 +!!$!==================== +!!$ call crea_part_y() +!!$ +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_4 +!!$ +!!$ !bloc +!!$ !----- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(2) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_y(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_y(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_y(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_y(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_y(qp,xp,yp,qg) +!!$ +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$!==================== +!!$! x: dt/4 +!!$!==================== +!!$ call crea_part_x() +!!$ dt=0.25*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_4 +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$ +!!$ qg_tmp=qg +!!$ qg=qg_init +!!$ +!!$ +!!$!==================== +!!$! x: dt/2 +!!$!==================== +!!$ call crea_part_x() +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_4 +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! y: dt +!!$!==================== +!!$ call crea_part_y() +!!$ +!!$ dt=dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_4 +!!$ +!!$ !bloc +!!$ !----- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(2) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_y(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_y(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_y(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_y(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_y(qp,xp,yp,qg) +!!$ +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! x: dt/2 +!!$!==================== +!!$ call crea_part_x() +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_4 +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$ qg=(-qg+4.*qg_tmp)/3. +!!$ +!!$ +!!$ dt=dt_sauv +!!$ deallocate(qg_init,qg_tmp) +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ +!!$ + !============================= + ! STRANG + !============================== +!!$ allocate(qg_init(1:nx,1:ny),qg_tmp(1:nx,1:ny)) +!!$ qg_init=qg +!!$!==================== +!!$! x: dt/2 +!!$!==================== +!!$ +!!$ dt_sauv=dt +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ !call update_vx_4 +!!$ call update_vx_strang +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! y: dt +!!$!==================== +!!$ call crea_part_y() +!!$ +!!$ dt=dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ !call update_vy_4 +!!$ call update_vy_strang +!!$ +!!$ !bloc +!!$ !----- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(2) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_y(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_y(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_y(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_y(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_y(qp,xp,yp,qg) +!!$ +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_y(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_y(qp,xp,yp,qg) +!!$ +!!$!==================== +!!$! x: dt/2 +!!$!==================== +!!$ call crea_part_x() +!!$ dt=0.5*dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ !call update_vx_4 +!!$ call update_vx_strang +!!$ +!!$ !bloc x +!!$ !------- +!!$ if ((type_b==2).or.(type_b==4)) then +!!$ call make_bloc_v2(1) +!!$ else +!!$ blocg=0 +!!$ blocd=0 +!!$ end if +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ if (type_b==30) call remaill_l3_x(qp,xp,yp,qg) +!!$ if (type_b==40) call remaill_l4_x(qp,xp,yp,qg) +!!$ if (type_b==20) call remaill_l2_x(qp,xp,yp,qg) +!!$ if (type_b==50)call remaill_l5_x(qp,xp,yp,qg) +!!$ if (type_b==60)call remaill_l6_x(qp,xp,yp,qg) +!!$ !if (type_b==2) call remaill_l2_bloc_x(qp,xp,yp,qg) +!!$ !if (type_b==4) call remaill_l4_bloc_x(qp,xp,yp,qg) +!!$ if (type_b==2) then +!!$ if (int_limit==0)call remaill_l2_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ if (type_b==4) then +!!$ if (int_limit==0)call remaill_l4_bloc_v2_x(qp,xp,yp,qg) +!!$ if (int_limit==1)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ end if +!!$ +!!$ if (type_b==200)call remaill_l2_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ if (type_b==400)call remaill_l4_bloc_v2_limit_x(qp,xp,yp,qg) +!!$ +!!$ +!!$ +!!$ dt=dt_sauv +!!$ deallocate(qg_init,qg_tmp) + + + + + + + + + + + + + + time=time+dt + cpt_ite=cpt_ite+1 + + + end do temps + + !------------------------------ + !sol exacte: + !-------------------------------- + + !erreur pour sol init gaussienne + !-------------------------------- +!!$ do i=1,nx +!!$ do j=1,ny +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ exa(i,j)=0. +!!$ +!!$ !exa(i,j)=(1.-((x-0.5)**2+(y-0.5)**2))**6 +!!$ !if (((x-0.5)**2+(y-0.5)**2)>1.) exa(i,j)=0. +!!$ +!!$ exa(i,j)=(1.-((x)**2+(y)**2))**6 +!!$ if (((x)**2+(y)**2)>1.) exa(i,j)=0. +!!$ +!!$ !exa(i,j)=1. +!!$ +!!$ +!!$ end do +!!$ end do +!!$ +!!$ !-----------Analytique en cos-------------------------- +!!$ !------------------------------------------------------ +!!$ t1=1. +!!$ t2=1. +!!$ t3=0.2 +!!$ do j=1,ny +!!$ do i=1,nx +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ exa(i,j)=cos(pi*time/t3)*cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ end do +!!$ end do + + !---cercle pour filaments sur [0,1]^2----------- + !---------------------------------------------------- +!!$ +!!$ do j=1,ny +!!$ do i=1,nx +!!$ x=xtab(i,j) +!!$ y=ytab(i,j) +!!$ exa(i,j)=0. +!!$ +!!$ if (sqrt((x-0.5)**2+(y-0.75)**2)<=0.15) exa(i,j)=1. +!!$ +!!$ end do +!!$ end do + + + !write(29,'(4(e18.10,2x))') dt_deb,dx,dx*dy*sum(abs(exa-qg)),sqrt(dx*dy*sum((exa-qg)**2)) + + !COUPE en y=1.5 + !-------------- + j=(1.5-yb)/dy+1 + do i=1,nx + write(30,'(2(e18.10,2x))') xg+(i-1)*dx,qg(i,j) + end do + + + end do erreur + call cpu_time(t2) + + !resultat final + !-------------- + print*,"tps final",time + print*,"nbre d'ite",cpt_ite + print*,"nart final",npart + print*,"dt,dx,dy",dt_deb,dx,dy + print*,"max vx",maxval(abs(vxg)),maxloc(abs(vxg)) + print*,"max vy",maxval(abs(vyg)),maxloc(abs(vxg)) + print*,"perte masse",masse-dx*dy*sum(qg) + print*,"tps dexecution",t2-t1 + + + + call res_vtk("RES/vtk/"//nom_fich_vtk) + + + + ! + !dealloc fermeture + !----------------- + close(50) + close(51) + close(52) + close(53) + close(66) + close(67) + close(29) + close(30) + + deallocate (xp,qp,vx,vy,yp) + deallocate (qg,vxg,vyg,exa) + deallocate (xtab,ytab) + deallocate (blocg,blocd) + deallocate (numpg,Nbloc) + !deallocate (Nblocg) + + + +end program split + + + + + + + diff --git a/CodesEnVrac/CodesAdrien/split_2d/parameter b/CodesEnVrac/CodesAdrien/split_2d/parameter new file mode 100644 index 000000000..1998801ab --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/parameter @@ -0,0 +1,8 @@ +-2 2 -2 2 ! xg xd yb yh +0.8 2. 5. 0.05 ! TFin +0.00001 !cutoff +70 !type bloc +1 !longeur des blocs +0 ! limitation 0=non 1=oui +"anregu_o3_cfl3_200_t08_cutm5_mp4.vtk" ! sortie fin vtk +"RES/test.er" "RES/anregu_o3_cfl3_200_t08_cutm5_mp4.co" ! fichier erreur /coupe \ No newline at end of file diff --git a/CodesEnVrac/CodesAdrien/split_2d/remaillage_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/remaillage_mod.f90 new file mode 100644 index 000000000..bbbd60860 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/remaillage_mod.f90 @@ -0,0 +1,5365 @@ +module remaillage_mod + use donnees_mod + use tab_mod +contains + + + + + subroutine remaill_l3 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:3) :: ip,jp + real(kind=8),dimension(0:3) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy + + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + poidy(0)=-1./6.*yy1*(yy1-1.)*(yy1-2.) + poidy(1)=0.5*(1.-yy1)*(1.+yy1)*(2.-yy1) + poidy(2)=-0.5*yy1*(yy1+1.)*(yy1-2.) + poidy(3)=1/6.*yy1*(1.+yy1)*(yy1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + do d=0,3 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_l3 + + subroutine remaill_l4 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:5) :: ip,jp + real(kind=8),dimension(0:5) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,y2,y3,y4 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + if (yy1<=0.5) then + poidy(0)=(2.*yy1-y2-2*y3+y4)/24. + poidy(1)=(-4.*yy1+4.*y2+y3-y4)/6. + poidy(2)=1.+(-5.*y2+y4)/4. + poidy(3)=(4.*yy1+4.*y2-y3-y4)/6. + poidy(4)=(-2.*yy1-y2+2*y3+y4)/24. + poidy(5)=0. + else + poidy(0)=0. + poidy(1)=(-6.*yy1+11.*y2-6.*y3+y4)/24. + poidy(2)=1.+(-5.*yy1-5.*y2+5.*y3-y4)/6. + poidy(3)=(6.*yy1+y2-4.*y3+y4)/4. + poidy(4)=(-3.*yy1+y2+3.*y3-y4)/6. + poidy(5)=(2.*yy1-y2-2.*y3+y4)/24. + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + do d=0,5 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine remaill_l4 + + subroutine remaill_mppp6 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:5) :: ip,jp + real(kind=8),dimension(0:5) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,y2,y3,y4 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1*x2 + x4=xx1*x3 + + poidx(0)=9./88.*xx1-3./16.*x2+27./176.*x4-3./44.*xx1**5 + poidx(1)=-31./44.*xx1+19./16.*x2-1./44.*x3-141./176.*x4+15./44.*xx1**5 + poidx(2)=147./88.*x4-175./88.*x2+1.-15./22.*xx1**5 + poidx(3)=31./44.*xx1+107./88.*x2+3./22.*x3-153./88.*x4+15./22.*xx1**5 + poidx(4)=-9./88.*xx1-49./176.*x2-2./11.*x3+159./176.*x4-15./44.*xx1**5 + poidx(5)=9./176.*x2+3./44.*x3-3./16.*x4+3./44.*xx1**5 + + y2=yy1**2 + y3=yy1*y2 + y4=yy1*y3 + + poidy(0)=9./88.*yy1-3./16.*y2+27./176.*y4-3./44.*yy1**5 + poidy(1)=-31./44.*yy1+19./16.*y2-1./44.*y3-141./176.*y4+15./44.*yy1**5 + poidy(2)=147./88.*y4-175./88.*y2+1.-15./22.*yy1**5 + poidy(3)=31./44.*yy1+107./88.*y2+3./22.*y3-153./88.*y4+15./22.*yy1**5 + poidy(4)=-9./88.*yy1-49./176.*y2-2./11.*y3+159./176.*y4-15./44.*yy1**5 + poidy(5)=9./176.*y2+3./44.*y3-3./16.*y4+3./44.*yy1**5 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + do d=0,5 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + end subroutine remaill_mppp6 + + subroutine remaill_l5 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:5) :: ip,jp + real(kind=8),dimension(0:5) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + poidy(0)=yy1/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(1)=-yy1/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(2)=1.-yy1/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(3)=yy1+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(4)=-yy1/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(5)=yy1/30.-y3/24.+y5/120. + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + do d=0,5 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_l5 + + subroutine remaill_l6 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(-3:4) :: ip,jp + real(kind=8),dimension(-3:4) :: poidx,poidy + real(kind=8) :: xx,yy,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + jp(0) = floor((posy(i)-yb)/dy) + jp(-1) = jp(0) - 1 + jp(-2) = jp(0) - 2 + jp(-3) = jp(0) - 3 + jp(1) = jp(0) + 1 + jp(2) = jp(0) + 2 + jp(3) = jp(0) + 3 + jp(4) = jp(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + yy = (posy(i) - real(jp(0),kind=8)*dy-yb)/dy !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=-3,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-3)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/720. + poidx(-2)=-(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+3.)/120. + poidx(-1)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+2.)*(xx+3.)/48. + poidx(0)=-(xx-3.)*(xx-2.)*(xx-1.)*(xx+1.)*(xx+2.)*(xx+3.)/36. + poidx(1)=(xx-3.)*(xx-2.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/48. + poidx(2)=-(xx-3.)*(xx-1.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/120. + poidx(3)=(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/720. + poidx(4)=0. + else + poidx(-3)=0. + poidx(-2)=(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)/720. + poidx(-1)=-(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+2.)/120. + poidx(0)=(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*(xx-3.)*(xx-2.)*xx*(xx+1.)*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/48. + poidx(3)=-(xx-4.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/120. + poidx(4)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/720. + end if + + if (yy<=0.5) then + poidy(-3)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/720. + poidy(-2)=-(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+3.)/120. + poidy(-1)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+2.)*(yy+3.)/48. + poidy(0)=-(yy-3.)*(yy-2.)*(yy-1.)*(yy+1.)*(yy+2.)*(yy+3.)/36. + poidy(1)=(yy-3.)*(yy-2.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/48. + poidy(2)=-(yy-3.)*(yy-1.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/120. + poidy(3)=(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/720. + poidy(4)=0. + else + poidy(-3)=0. + poidy(-2)=(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)/720. + poidy(-1)=-(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+2.)/120. + poidy(0)=(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*(yy+1.)*(yy+2.)/48. + poidy(1)=-(yy-4.)*(yy-3.)*(yy-2.)*yy*(yy+1.)*(yy+2.)/36. + poidy(2)=(yy-4.)*(yy-3.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/48. + poidy(3)=-(yy-4.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/120. + poidy(4)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/720. + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + do d=-3,4 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_l6 + + subroutine remaill_mp4 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:3) :: ip,jp + real(kind=8),dimension(0:3) :: poidx,poidy + real(kind=8) :: xx1,yy1,x2,x3,x4,x5,y2,y3,y4,y5 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy + + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=-0.5*xx1+x2-0.5*x3 + poidx(1)=1-5./2.*x2+3.*0.5*x3 + poidx(2)=0.5*xx1+2.*x2-3.*0.5*x3 + poidx(3)=-0.5*x2+0.5*x3 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + poidy(0)=-0.5*yy1+y2-0.5*y3 + poidy(1)=1-5./2.*y2+3.*0.5*y3 + poidy(2)=0.5*yy1+2.*y2-3.*0.5*y3 + poidy(3)=-0.5*y2+0.5*y3 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + do d=0,3 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_mp4 + + subroutine remaill_l2_g (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(0:3) :: ip,jp + real(kind=8),dimension(0:3) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + poidx(0)=-0.5*xx1*(1.-xx1) + poidx(1)=1.-xx1**2 + poidx(2)=0.5*xx1*(1.+xx1) + poidx(3)=0. + + poidy(0)=-0.5*yy1*(1.-yy1) + poidy(1)=1.-yy1**2 + poidy(2)=0.5*yy1*(1.+yy1) + poidy(3)=0. + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + do d=0,3 + if ((ip(c)>-1).and.(ip(c)<nx).and.(jp(d)>-1).and.(jp(d)<ny)) then + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end if + end do + end do + end do + + end subroutine remaill_l2_g + + subroutine remaill_l2 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(1:4) :: ip,jp + real(kind=8),dimension(1:4) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + + jp(2) = floor((posy(i)-yb)/dy) + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + !periodique: + do c=1,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=1,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + if (xx1<=0.5) then + + poidx(1)=-0.5*xx1*(1.-xx1) + poidx(2)=1.-xx1**2 + poidx(3)=0.5*xx1*(1.+xx1) + poidx(4)=0. + + else + + poidx(1)=0. + poidx(2)=0.5*(xx1-1.)*(xx1-2.) + poidx(3)=xx1*(2.-xx1) + poidx(4)=0.5*xx1*(xx1-1.) + + end if + + if (yy1<=0.5) then + + poidy(1)=-0.5*yy1*(1.-yy1) + poidy(2)=1.-yy1**2 + poidy(3)=0.5*yy1*(1.+yy1) + poidy(4)=0. + + else + + poidy(1)=0. + poidy(2)=0.5*(yy1-1.)*(yy1-2.) + poidy(3)=yy1*(2.-yy1) + poidy(4)=0.5*yy1*(yy1-1.) + + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,4 + do d=1,4 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_l2 + + subroutine remaill_l1 (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(1:2) :: ip,jp + real(kind=8),dimension(0:3) :: poidx,poidy + real(kind=8) :: xx1,yy1 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(2) = ip(1) + 1 + + + jp(1) = floor((posy(i)-yb)/dy) + jp(2) = jp(1) + 1 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids: + !---------------- + poidx(1)=(1.-xx1) + poidx(2)=xx1 + + poidy(1)=(1.-yy1) + poidy(2)=yy1 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,2 + do d=1,2 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + + end do + + end subroutine remaill_l1 + + subroutine remaill_tsc (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb + integer,dimension(1:4) :: ip,jp + real(kind=8),dimension(1:4) :: poidx,poidy + real(kind=8) :: xx1,yy1,alpha + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + + jp(2) = floor((posy(i)-yb)/dy) + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + !periodique: + do c=1,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=1,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + alpha=1./8. + + !calcul des poids + !---------------- + if (xx1<=0.5) then + + poidx(1)=alpha-0.5*xx1+0.5*xx1**2 + poidx(2)=(1.-2.*alpha)-xx1**2 + poidx(3)=alpha+0.5*xx1+0.5*xx1**2 + poidx(4)=0. + + else + + poidx(1)=0. + poidx(2)=1.+alpha-3.*0.5*xx1+0.5*xx1**2 + poidx(3)=-2.*alpha+2.*xx1-xx1**2 + poidx(4)=alpha-0.5*xx1+0.5*xx1**2 + + end if + + if (yy1<=0.5) then + + poidy(1)=alpha-0.5*yy1+0.5*yy1**2 + poidy(2)=(1.-2.*alpha)-yy1**2 + poidy(3)=alpha+0.5*yy1+0.5*yy1**2 + poidy(4)=0. + + else + + poidy(1)=0. + poidy(2)=1.+alpha-3.*0.5*yy1+0.5*yy1**2 + poidy(3)=-2.*alpha+2.*yy1-yy1**2 + poidy(4)=alpha-0.5*yy1+0.5*yy1**2 + + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,4 + do d=1,4 + remaille(ip(c)+1,jp(d)+1)=remaille(ip(c)+1,jp(d)+1)+donne(i)*poidx(c)*poidy(d) + end do + end do + end do + + end subroutine remaill_tsc + + + + + + + + + + + + + + + + + + + + + + + + + + subroutine remaill_l3_x(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:3) :: ip + real(kind=8),dimension(0:3) :: poidx + real(kind=8) :: xx1,tmp_pos + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l3_x + + + subroutine remaill_l3_y(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:3) :: ip + real(kind=8),dimension(0:3) :: poidx + real(kind=8) :: xx1,tmp_pos + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posy(i)-yb)/dy) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(1),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l3_y + + + + + + + subroutine remaill_mp4_x(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:3) :: ip + real(kind=8),dimension(0:3) :: poidx + real(kind=8) :: xx1,tmp_pos + real(kind=8) :: x2,x3,x4,x5 + + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=-0.5*xx1+x2-0.5*x3 + poidx(1)=1-5./2.*x2+3.*0.5*x3 + poidx(2)=0.5*xx1+2.*x2-3.*0.5*x3 + poidx(3)=-0.5*x2+0.5*x3 + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_mp4_x + + + subroutine remaill_mp4_y(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:3) :: ip + real(kind=8),dimension(0:3) :: poidx + real(kind=8) :: xx1,tmp_pos + real(kind=8) :: x2,x3,x4,x5 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posy(i)-yb)/dy) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(1),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=-0.5*xx1+x2-0.5*x3 + poidx(1)=1-5./2.*x2+3.*0.5*x3 + poidx(2)=0.5*xx1+2.*x2-3.*0.5*x3 + poidx(3)=-0.5*x2+0.5*x3 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,3 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_mp4_y + + + + + + + subroutine remaill_l4_x(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l4_x + + + subroutine remaill_l4_y(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posy(i)-yb)/dy) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(2),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l4_y + + subroutine remaill_l6_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb,j + integer,dimension(-3:4) :: ip,jp + real(kind=8),dimension(-3:4) :: poidx,poidy + real(kind=8) :: xx,yy,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-3)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/720. + poidx(-2)=-(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+3.)/120. + poidx(-1)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+2.)*(xx+3.)/48. + poidx(0)=-(xx-3.)*(xx-2.)*(xx-1.)*(xx+1.)*(xx+2.)*(xx+3.)/36. + poidx(1)=(xx-3.)*(xx-2.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/48. + poidx(2)=-(xx-3.)*(xx-1.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/120. + poidx(3)=(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)*(xx+3.)/720. + poidx(4)=0. + else + poidx(-3)=0. + poidx(-2)=(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)/720. + poidx(-1)=-(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+2.)/120. + poidx(0)=(xx-4.)*(xx-3.)*(xx-2.)*(xx-1.)*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*(xx-3.)*(xx-2.)*xx*(xx+1.)*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/48. + poidx(3)=-(xx-4.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/120. + poidx(4)=(xx-3.)*(xx-2.)*(xx-1.)*xx*(xx+1.)*(xx+2.)/720. + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + end do + + end subroutine remaill_l6_x + + subroutine remaill_l6_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,jb,ivar + integer,dimension(-3:4) :: ip,jp + real(kind=8),dimension(-3:4) :: poidx,poidy + real(kind=8) :: xx,yy,x2,x3,x4,x5,y1,y2,y3,y4,y5 + + remaille=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + + + jp(0) = floor((posy(i)-yb)/dy) + jp(-1) = jp(0) - 1 + jp(-2) = jp(0) - 2 + jp(-3) = jp(0) - 3 + jp(1) = jp(0) + 1 + jp(2) = jp(0) + 2 + jp(3) = jp(0) + 3 + jp(4) = jp(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + yy = (posy(i) - real(jp(0),kind=8)*dy-yb)/dy !relatif + + + + !conditions au bord + !------------------ + !periodique: + + do c=-3,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + + if (yy<=0.5) then + poidy(-3)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/720. + poidy(-2)=-(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+3.)/120. + poidy(-1)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+2.)*(yy+3.)/48. + poidy(0)=-(yy-3.)*(yy-2.)*(yy-1.)*(yy+1.)*(yy+2.)*(yy+3.)/36. + poidy(1)=(yy-3.)*(yy-2.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/48. + poidy(2)=-(yy-3.)*(yy-1.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/120. + poidy(3)=(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)*(yy+3.)/720. + poidy(4)=0. + else + poidy(-3)=0. + poidy(-2)=(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)/720. + poidy(-1)=-(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+2.)/120. + poidy(0)=(yy-4.)*(yy-3.)*(yy-2.)*(yy-1.)*(yy+1.)*(yy+2.)/48. + poidy(1)=-(yy-4.)*(yy-3.)*(yy-2.)*yy*(yy+1.)*(yy+2.)/36. + poidy(2)=(yy-4.)*(yy-3.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/48. + poidy(3)=-(yy-4.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/120. + poidy(4)=(yy-3.)*(yy-2.)*(yy-1.)*yy*(yy+1.)*(yy+2.)/720. + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do d=-3,4 + remaille(ivar,jp(d)+1)=remaille(ivar,jp(d)+1)+donne(i)*poidy(d) + end do + + end do + + end subroutine remaill_l6_y + + + + subroutine remaill_l2_x(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = int((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + if ((posx(i)-xg)<0) then + do c=0,5 + ip(c)=ip(c)-1 + end do + end if + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx !relatif + + !conditions au bord + !------------------ + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + !calcul des poids + !---------------- + if (xx1<=0.5) then + poidx(1)=0.5*xx1*(xx1-1.) + poidx(2)=1.-xx1**2 + poidx(3)=0.5*xx1*(1.+xx1) + poidx(4)=0. + else + poidx(1)=0. + poidx(2)=0.5*(1.-xx1)*(2.-xx1) + poidx(3)=2.*xx1-xx1**2 + poidx(4)=0.5*(xx1-1.)*xx1 + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,4 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l2_x + + + + subroutine remaill_l2_y(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = int((posy(i)-yb)/dy) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + if ((posy(i)-yb)<0) then + do c=0,5 + ip(c)=ip(c)-1 + end do + end if + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(2),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + + do c=0,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + if (xx1<=0.5) then + poidx(1)=0.5*xx1*(xx1-1.) + poidx(2)=1.-xx1**2 + poidx(3)=0.5*xx1*(1.+xx1) + poidx(4)=0. + else + poidx(1)=0. + poidx(2)=0.5*(1.-xx1)*(2.-xx1) + poidx(3)=2.*xx1-xx1**2 + poidx(4)=0.5*(xx1-1.)*xx1 + end if + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,4 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l2_y + + + subroutine remaill_l5_x(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4,x5 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_x + + + subroutine remaill_l5_y(donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,tmp_pos,x2,x3,x4,x5 + + remaille=0. + + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posy(i)-yb)/dy) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(2),kind=8)*dy-yb)/dy !relatif + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_y + + +!!$ subroutine remaill_m6kernel_x (donne,posx,posy,remaille) +!!$ implicit none +!!$ real(kind=8),dimension(:),intent(in) :: donne +!!$ real(kind=8),dimension(:),intent(in) :: posx,posy +!!$ real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille +!!$ integer :: i,c,d,j,per +!!$ integer,dimension(-3:3) :: ip +!!$ real(kind=8),dimension(-3:3) :: xx +!!$ +!!$ +!!$ remaille=0. +!!$ +!!$ do i=1,npart +!!$ +!!$ j=nint((posy(i)-yb)/dy)+1 +!!$ +!!$ !numero des points sur le maillage +!!$ !-------------------------------- +!!$ ip(0) = floor((posx(i)-xg)/dx) +!!$ ip(-1) = ip(0) - 1 +!!$ ip(-2) = ip(0) - 2 +!!$ ip(1) = ip(0) + 1 +!!$ ip(2) = ip(0) + 2 +!!$ ip(3) = ip(0) + 3 +!!$ +!!$ +!!$ +!!$ !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) +!!$ !---------------------------------------------------- +!!$ per=mod(i -partxun(j) +ndimx(j),ndimx(j)) + partxun(j) +!!$ do c=-2,3 +!!$ xx(c) = (-posx(per) + real(ip(c),kind=8)*dx+xg)/dx +!!$ end do +!!$ +!!$ !conditions au bord +!!$ !------------------ +!!$ !periodique: +!!$ do c=-2,3 +!!$ ip(c)=mod(ip(c)+nx,nx) +!!$ end do +!!$ +!!$ +!!$ !remaillage à l'interrieur domaine +!!$ !--------------------------------- +!!$ do c=-2,3 +!!$ remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(xx(c)) +!!$ end do +!!$ +!!$ end do +!!$ contains +!!$ function poids(x) result(p) +!!$ implicit none +!!$ real(kind=8) :: x +!!$ real(kind=8) :: p +!!$ +!!$ !mp4 +!!$ !if (abs(x)<=1.) p=1.-5.*x*x/2.+3.*abs(x)**3/2. +!!$ !if ((abs(x)>1.).and.(abs(x)<=2.)) p=(2.-abs(x))**2*(1.-abs(x))/2. +!!$ !if (abs(x)>=2.) p=0. +!!$ +!!$ !lambda 3 +!!$ !if (abs(x)<=1.) p=(1.-x*x)*(2.-abs(x))/2. +!!$ !if ((abs(x)>1.).and.(abs(x)<=2.)) p=(1.-abs(x))*(2.-abs(x))*(3.-abs(x))/6. +!!$ !if (abs(x)>=2.) p=0. +!!$ +!!$ !M6* +!!$ !if (abs(x)<1.) p=-1./12.*(abs(x)-1.)*(24.*abs(x)**4+38.*abs(x)**3-3.*abs(x)**2+12.*abs(x)+12.) +!!$ !if ((abs(x)>=1.).and.(abs(x)<2.)) p=1./24.*(abs(x)-1.)*(abs(x)-2.)*(25.*abs(x)**3-114.*abs(x)**2+153.*abs(x)-48.) +!!$ !if ((abs(x)>=2.).and.(abs(x)<3.)) p=-1./24.*(abs(x)-2.)*(abs(x)-3.)**3*(5.*abs(x)-8.) +!!$ !if (abs(x)>=3.) p=0. +!!$ +!!$ !M6''' +!!$ if (abs(x)<1.) p=-1./88.*(abs(x)-1.)*(60.*abs(x)**4-87.*abs(x)**3-87.*abs(x)**2+88.*abs(x)+88.) +!!$ if ((abs(x)>=1.).and.(abs(x)<2.)) p=1./176.*(abs(x)-1.)*(abs(x)-2.)*(60.*abs(x)**3-261.*abs(x)**2+257.*abs(x)+68.) +!!$ if ((abs(x)>=2.).and.(abs(x)<3.)) p=-3./176.*(abs(x)-2.)*(4.*abs(x)**2-17.*abs(x)+12.)*(abs(x)-3.)**2 +!!$ if (abs(x)>=3.) p=0. +!!$ +!!$ end function poids +!!$ +!!$ end subroutine remaill_m6kernel_x +!!$ +!!$ +!!$ +!!$ subroutine remaill_m6kernel_y (donne,posx,posy,remaille) +!!$ implicit none +!!$ real(kind=8),dimension(:),intent(in) :: donne +!!$ real(kind=8),dimension(:),intent(in) :: posx,posy +!!$ real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille +!!$ integer :: i,c,d,ivar,per +!!$ integer,dimension(-3:3) :: ip +!!$ real(kind=8),dimension(-3:3) :: xx +!!$ +!!$ +!!$ remaille=0. +!!$ +!!$ do i=1,npart +!!$ +!!$ ivar=nint((posx(i)-xg)/dx)+1 +!!$ +!!$ !numero des points sur le maillage +!!$ !-------------------------------- +!!$ ip(0) = floor((posy(i)-yb)/dy) +!!$ ip(-1) = ip(0) - 1 +!!$ ip(-2) = ip(0) - 2 +!!$ ip(1) = ip(0) + 1 +!!$ ip(2) = ip(0) + 2 +!!$ ip(3) = ip(0) + 3 +!!$ +!!$ +!!$ +!!$ !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) +!!$ !---------------------------------------------------- +!!$ per=mod(i -partyun(ivar) +ndimy(ivar),ndimy(ivar)) + partyun(ivar) +!!$ do c=-2,3 +!!$ xx(c) = (-posy(per) + real(ip(c),kind=8)*dy+yb)/dy +!!$ end do +!!$ +!!$ !conditions au bord +!!$ !------------------ +!!$ do c=-2,3 +!!$ ip(c)=mod(ip(c)+ny,ny) +!!$ end do +!!$ +!!$ +!!$ !remaillage à l'interrieur domaine +!!$ !--------------------------------- +!!$ do c=-2,3 +!!$ remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(xx(c)) +!!$ end do +!!$ +!!$ end do +!!$ contains +!!$ function poids(x) result(p) +!!$ implicit none +!!$ real(kind=8) :: x +!!$ real(kind=8) :: p +!!$ +!!$ !mp4 +!!$ !if (abs(x)<=1.) p=1.-5.*x*x/2.+3.*abs(x)**3/2. +!!$ !if ((abs(x)>1.).and.(abs(x)<=2.)) p=(2.-abs(x))**2*(1.-abs(x))/2. +!!$ !if (abs(x)>=2.) p=0. +!!$ +!!$ !lambda 3 +!!$ !if (abs(x)<=1.) p=(1.-x*x)*(2.-abs(x))/2. +!!$ !if ((abs(x)>1.).and.(abs(x)<=2.)) p=(1.-abs(x))*(2.-abs(x))*(3.-abs(x))/6. +!!$ !if (abs(x)>=2.) p=0. +!!$ +!!$ !M6* +!!$ !if (abs(x)<1.) p=-1./12.*(abs(x)-1.)*(24.*abs(x)**4+38.*abs(x)**3-3.*abs(x)**2+12.*abs(x)+12.) +!!$ !if ((abs(x)>=1.).and.(abs(x)<2.)) p=1./24.*(abs(x)-1.)*(abs(x)-2.)*(25.*abs(x)**3-114.*abs(x)**2+153.*abs(x)-48.) +!!$ !if ((abs(x)>=2.).and.(abs(x)<3.)) p=-1./24.*(abs(x)-2.)*(abs(x)-3.)**3*(5.*abs(x)-8.) +!!$ !if (abs(x)>=3.) p=0. +!!$ +!!$ !M6''' +!!$ if (abs(x)<1.) p=-1./88.*(abs(x)-1.)*(60.*abs(x)**4-87.*abs(x)**3-87.*abs(x)**2+88.*abs(x)+88.) +!!$ if ((abs(x)>=1.).and.(abs(x)<2.)) p=1./176.*(abs(x)-1.)*(abs(x)-2.)*(60.*abs(x)**3-261.*abs(x)**2+257.*abs(x)+68.) +!!$ if ((abs(x)>=2.).and.(abs(x)<3.)) p=-3./176.*(abs(x)-2.)*(4.*abs(x)**2-17.*abs(x)+12.)*(abs(x)-3.)**2 +!!$ if (abs(x)>=3.) p=0. +!!$ +!!$ end function poids +!!$ +!!$ end subroutine remaill_m6kernel_y + + + + + + + + + + + + + subroutine remaill_l2_bloc_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + else + poids(0)=0.5*(1.-xx)*(2.-xx) + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + case(2) + poids(0)=1.-0.5*xx*(1.+xx) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + case(4) + poids(-2)=0.5*xx*(1.+xx) + poids(-1)=-xx + poids(0)=1.-xx**2 + case(5) + poids(-1)=-0.5*xx+0.5*xx**2 + poids(0)=1.-poids(-1) + + end select + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + poids(1)=0.5*xx*(1.+xx) + else + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + end if + case(1) + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(1)=xx + poids(2)=0.5*xx*(xx-1) + case(3) + poids(1)=3.*0.5*xx-0.5*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_x + + + subroutine remaill_l2_bloc_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + else + poids(0)=0.5*(1.-xx)*(2.-xx) + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + case(2) + poids(0)=1.-0.5*xx*(1.+xx) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + case(4) + poids(-2)=0.5*xx*(1.+xx) + poids(-1)=-xx + poids(0)=1.-xx**2 + case(5) + poids(-1)=-0.5*xx+0.5*xx**2 + poids(0)=1.-poids(-1) + + end select + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + poids(1)=0.5*xx*(1.+xx) + else + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + end if + case(1) + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(1)=xx + poids(2)=0.5*xx*(xx-1) + case(3) + poids(1)=3.*0.5*xx-0.5*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_y + + + subroutine remaill_l4_bloc_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + else + t1=(xx-1.)*(xx-2.)*(xx-3.) + poids(-1)=t1*xx/24. + poids(0)=-t1*(xx+1.)/6. + end if + case(1) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + + case(2) + t1=(xx-1.)*(xx-2.)/12. + poids(-1)=t1*xx*(xx-3)/2. + poids(0)=t1*(xx+6.)*(xx+1.) + case(3) + t1=0.5*(xx-1.)*(xx-2.) + poids(-2)=t1*xx/12.*(xx+1.) + poids(-1)=-t1*xx/3.*(xx+2.) + poids(0)=t1*(xx+1.) + case(4) + t2=(xx**2-1.) + t1=xx*(xx+2.)*0.5 + poids(-3)=t2*t1/12. + poids(-2)=-t2*xx/6.*(xx+3.) + poids(-1)=t1*(xx-1.) + poids(0)=t2*(xx**2-4.)/4. + case(5) + t1=(xx-2.)*(xx-1.)/4. + poids(-1)=-t1*xx/6.*(3*xx+7.) + poids(0)=t1*(xx+2.)*(xx+1.) + case(6) + t1= (xx-1.)*(xx-2.)/6. + t2=t1*(xx+1.) + poids(-2)=t2*xx/4. + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.) + case(7) + t1=(xx-1.)*(xx+2.) + t2=xx*(xx+1)/6. + poids(-3)=t1*t2/4. + poids(-2)=-t2*(xx-1.) + poids(-1)=-xx*t1/6.*(xx-2.) + poids(0)=t1*(xx-2.)/4.*(xx+1.) + case(8) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=(xx-6.)*(xx+2.)*(xx**2-1.)/12. + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + else + t1=xx*(xx+1.)*(xx-3.) + poids(1)=t1*(xx-2.)/4. + poids(2)=-t1*(xx-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + end if + case(1) + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + case(2) + t1=xx*(xx+1.)*0.5 + t2=t1*(xx-1.) + poids(1)=-t1*(xx-2.) + poids(2)=-t2/3.*(xx-3.) + poids(3)=t2*(xx-2.)/12. + case(3) + t1=xx*(xx+1.)/12. + poids(1)=t1*(xx-2.)*(xx-7.) + poids(2)=t1*(xx+2.)*(xx-1.)/2. + case(4) + t1=xx*(xx+1.) + t2=t1*(xx-1.)/6. + poids(1)=-t1*(xx+2.)*(xx-2.)/6. + poids(2)=t2 + poids(3)=t2*(xx-2.)/4. + case(5) + poids(1)=-xx/24.*(3.*xx-7.)*(xx+2.)*(xx+1.) + case(6) + t1=xx*(xx+1.)/4. + poids(1)=t1*(xx-3.)*(xx-2.) + poids(2)=-t1*(3.*xx-10.)*(xx-1.)/6. + case(7) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_x + + + subroutine remaill_l4_bloc_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + else + t1=(xx-1.)*(xx-2.)*(xx-3.) + poids(-1)=t1*xx/24. + poids(0)=-t1*(xx+1.)/6. + end if + case(1) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + + case(2) + t1=(xx-1.)*(xx-2.)/12. + poids(-1)=t1*xx*(xx-3)/2. + poids(0)=t1*(xx+6.)*(xx+1.) + case(3) + t1=0.5*(xx-1.)*(xx-2.) + poids(-2)=t1*xx/12.*(xx+1.) + poids(-1)=-t1*xx/3.*(xx+2.) + poids(0)=t1*(xx+1.) + case(4) + t2=(xx**2-1.) + t1=xx*(xx+2.)*0.5 + poids(-3)=t2*t1/12. + poids(-2)=-t2*xx/6.*(xx+3.) + poids(-1)=t1*(xx-1.) + poids(0)=t2*(xx**2-4.)/4. + case(5) + t1=(xx-2.)*(xx-1.)/4. + poids(-1)=-t1*xx/6.*(3*xx+7.) + poids(0)=t1*(xx+2.)*(xx+1.) + case(6) + t1= (xx-1.)*(xx-2.)/6. + t2=t1*(xx+1.) + poids(-2)=t2*xx/4. + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.) + case(7) + t1=(xx-1.)*(xx+2.) + t2=xx*(xx+1)/6. + poids(-3)=t1*t2/4. + poids(-2)=-t2*(xx-1.) + poids(-1)=-xx*t1/6.*(xx-2.) + poids(0)=t1*(xx-2.)/4.*(xx+1.) + case(8) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=(xx-6.)*(xx+2.)*(xx**2-1.)/12. + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + else + t1=xx*(xx+1.)*(xx-3.) + poids(1)=t1*(xx-2.)/4. + poids(2)=-t1*(xx-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + end if + case(1) + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + case(2) + t1=xx*(xx+1.)*0.5 + t2=t1*(xx-1.) + poids(1)=-t1*(xx-2.) + poids(2)=-t2/3.*(xx-3.) + poids(3)=t2*(xx-2.)/12. + case(3) + t1=xx*(xx+1.)/12. + poids(1)=t1*(xx-2.)*(xx-7.) + poids(2)=t1*(xx+2.)*(xx-1.)/2. + case(4) + t1=xx*(xx+1.) + t2=t1*(xx-1.)/6. + poids(1)=-t1*(xx+2.)*(xx-2.)/6. + poids(2)=t2 + poids(3)=t2*(xx-2.)/4. + case(5) + poids(1)=-xx/24.*(3.*xx-7.)*(xx+2.)*(xx+1.) + case(6) + t1=xx*(xx+1.)/4. + poids(1)=t1*(xx-3.)*(xx-2.) + poids(2)=-t1*(3.*xx-10.)*(xx-1.)/6. + case(7) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_y + + + + + + + + + + subroutine remaill_l2_bloc_v2_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) !alpha + poids(0)=1.-xx**2 !beta + poids(1)=0.5*xx*(1.+xx) !gamma + else + poids(0)=0.5*(1.-xx)*(2.-xx) !alpha' + poids(1)=2.*xx-xx**2 !beta' + poids(2)=0.5*(xx-1.)*xx !gamma' + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(0)=0.5*(1.-xx)*(2.-xx) + poids(1)=1.-poids(0) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-poids(-1) + case(4) + poids(0)=-0.5*xx*(xx+1.)+1. + poids(1)=1.-poids(0) + case(5) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=xx + poids(2)=0.5*xx*(xx-1.) + case(6) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + case(7) + poids(-2)=0.5*xx*(xx+1) + poids(-1)=-xx + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + end select + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_v2_x + + subroutine remaill_l2_bloc_v2_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) !alpha + poids(0)=1.-xx**2 !beta + poids(1)=0.5*xx*(1.+xx) !gamma + else + poids(0)=0.5*(1.-xx)*(2.-xx) !alpha' + poids(1)=2.*xx-xx**2 !beta' + poids(2)=0.5*(xx-1.)*xx !gamma' + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(0)=0.5*(1.-xx)*(2.-xx) + poids(1)=1.-poids(0) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-poids(-1) + case(4) + poids(0)=-0.5*xx*(xx+1.)+1. + poids(1)=1.-poids(0) + case(5) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=xx + poids(2)=0.5*xx*(xx-1.) + case(6) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + case(7) + poids(-2)=0.5*xx*(xx+1) + poids(-1)=-xx + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_v2_y + + + subroutine remaill_l4_bloc_v2_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + select case (blocg(i)) + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + end if + case(1) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx**4/12.-2.*xx**3/3.+5.*xx**2/12.+7.*xx/6. + case(3) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=1.+xx**4/12.-13.*xx**2/12.-xx**3/3.+xx/3. + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=xx*(xx-1.)*(xx-2.)*(xx-3.)/24. + poids(0)=xx**4/12.+xx**3/3.-13.*xx**2/12.-xx/3.+1. + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=1.-xx**4/8.+7.*xx**3/12.-3.*xx**2/8.-13.*xx/12. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=-xx**4/8.+xx**3/12.+5.*xx**2/8.-7.*xx/12. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(7) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=0.5*xx**3-xx**2-0.5*xx+1. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(8) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=-xx*(xx+3.)*(xx**2-1.)/6. + poids(-1)=0.5*xx**3+0.5*xx**2-xx + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(9) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx**3/6.+0.5*xx**2-xx/3. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(10) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=xx*(1.-xx**2)/6. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + else + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + poids(4)=0. + end if + case(1) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=-xx**4/8.+5.*xx**3/12.+xx**2/8.-5.*xx/12. + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=-xx**4/8.-xx**3/12.+5.*xx**2/8.+7.*xx/12. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=xx*(xx+2.)*(xx**2-1.)/24. + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. + poids(3)=xx**3/6.-0.5*xx*2+xx/3. + poids(4)=xx*(xx-1)*(xx-2.)*(xx-3.)/24. + case(7) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. + poids(2)=xx*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + case(8) + poids(1)=-0.5*xx**3+0.5*xx**2+xx + poids(2)=-xx*(xx-3)*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + end select + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_v2_x + + + + + subroutine remaill_l4_bloc_v2_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + select case (blocg(i)) + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + end if + case(1) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx**4/12.-2.*xx**3/3.+5.*xx**2/12.+7.*xx/6. + case(3) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=1.+xx**4/12.-13.*xx**2/12.-xx**3/3.+xx/3. + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=xx*(xx-1.)*(xx-2.)*(xx-3.)/24. + poids(0)=xx**4/12.+xx**3/3.-13.*xx**2/12.-xx/3.+1. + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=1.-xx**4/8.+7.*xx**3/12.-3.*xx**2/8.-13.*xx/12. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=-xx**4/8.+xx**3/12.+5.*xx**2/8.-7.*xx/12. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(7) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=0.5*xx**3-xx**2-0.5*xx+1. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(8) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=-xx*(xx+3.)*(xx**2-1.)/6. + poids(-1)=0.5*xx**3+0.5*xx**2-xx + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(9) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx**3/6.+0.5*xx**2-xx/3. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(10) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=xx*(1.-xx**2)/6. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + else + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + poids(4)=0. + end if + case(1) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=-xx**4/8.+5.*xx**3/12.+xx**2/8.-5.*xx/12. + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=-xx**4/8.-xx**3/12.+5.*xx**2/8.+7.*xx/12. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=xx*(xx+2.)*(xx**2-1.)/24. + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. + poids(3)=xx**3/6.-0.5*xx*2+xx/3. + poids(4)=xx*(xx-1)*(xx-2.)*(xx-3.)/24. + case(7) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. + poids(2)=xx*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + case(8) + poids(1)=-0.5*xx**3+0.5*xx**2+xx + poids(2)=-xx*(xx-3)*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + end select + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_v2_y + + + + subroutine remaill_l2_bloc_v2_limit_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2) :: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1) :: phi + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + else + + poids(0)=ca(xx-1.,1) + if (test (i,1) ) then + poids(1)=cb(xx-1.,1,1) + poids(2)=cc(xx-1.,1) + else + poids(1)=cb(xx-1.,1,0) + poids(2)=cc(xx-1.,0) + end if + + end if + + case(1) + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + + case(2) + poids(0)=ca(xx-1.,1) + poids(1)=cb(xx-1.,1,0)+cc(xx-1.,0) + case(3) + poids(-1)=ca(xx,0) + poids(0)=cb(xx,0)+cc(xx,0) + case(4) + poids(0)=ca(xx,1)+cb(xx,1,0) + poids(1)=cc(xx,0) + + + + case(5) + poids(-1)=ca(xx,0) + poids(0)=cb(xx,0) + poids(1)=cc(xx,0)-cc(xx-1.,1) + poids(2)=cc(xx-1.,1) + + case(6) + poids(-1)=ca(xx,0) + poids(0)=ca(xx-1.,1)-ca(xx,0) + poids(1)=cb(xx-1.,1) + poids(2)=cc(xx-1.,1) + + + case(7) + poids(-2)=ca(xx+1.,0) + poids(-1)=ca(xx,0)-ca(xx+1.,0) + poids(0)=cb(xx,0) + poids(1)=cc(xx,0) + end select + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. ! +1./6. + case(0) + c=-x**2+1. -2./8. !-2./6. + case(1) + c=0.5*x*(1.+x) +1./8. ! +1./6. + end select + + end function coeff_tscg + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posx(mod(ipart-1+vois+npart,npart)+1) - real( floor((posx(mod(ipart-1+vois+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + + + end subroutine remaill_l2_bloc_v2_limit_x + + subroutine remaill_l2_bloc_v2_limit_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2):: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1):: phi + + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + else + + poids(0)=ca(xx-1.,1) + if (test (i,1) ) then + poids(1)=cb(xx-1.,1,1) + poids(2)=cc(xx-1.,1) + else + poids(1)=cb(xx-1.,1,0) + poids(2)=cc(xx-1.,0) + end if + + end if + + case(1) + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + + case(2) + poids(0)=ca(xx-1.,1) + poids(1)=cb(xx-1.,1,0)+cc(xx-1.,0) + case(3) + poids(-1)=ca(xx,0) + poids(0)=cb(xx,0)+cc(xx,0) + case(4) + poids(0)=ca(xx,1)+cb(xx,1,0) + poids(1)=cc(xx,0) + + + + case(5) + poids(-1)=ca(xx,0) + poids(0)=cb(xx,0) + poids(1)=cc(xx,0)-cc(xx-1.,1) + poids(2)=cc(xx-1.,1) + + case(6) + poids(-1)=ca(xx,0) + poids(0)=ca(xx-1.,1)-ca(xx,0) + poids(1)=cb(xx-1.,1) + poids(2)=cc(xx-1.,1) + + + case(7) + poids(-2)=ca(xx+1.,0) + poids(-1)=ca(xx,0)-ca(xx+1.,0) + poids(0)=cb(xx,0) + poids(1)=cc(xx,0) + end select + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. ! +1./6. + case(0) + c=-x**2+1. -2./8. !-2./6. + case(1) + c=0.5*x*(1.+x) +1./8. ! +1./6. + end select + + end function coeff_tscg + + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posy(mod(ipart-1+vois+npart,npart)+1) - real( floor((posy(mod(ipart-1+vois+npart,npart)+1)-yb)/dy) ,kind=8)*dy-yb)/dy + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + end subroutine remaill_l2_bloc_v2_limit_y + + + subroutine remaill_l2_limit_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2) :: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1) :: phi + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + if (xx<=0.5) then + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + else + + poids(0)=ca(xx-1.,1) + if (test (i,1) ) then + poids(1)=cb(xx-1.,1,1) + poids(2)=cc(xx-1.,1) + else + poids(1)=cb(xx-1.,1,0) + poids(2)=cc(xx-1.,0) + end if + + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. ! +1./6. + case(0) + c=-x**2+1. -2./8. !-2./6. + case(1) + c=0.5*x*(1.+x) +1./8. ! +1./6. + end select + + end function coeff_tscg + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posx(mod(ipart-1+vois+npart,npart)+1) - real( floor((posx(mod(ipart-1+vois+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + + + end subroutine remaill_l2_limit_x + + subroutine remaill_l2_limit_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2):: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1):: phi + + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + + if (xx<=0.5) then + + poids(-1)=ca(xx,0) + if (test (i,1) ) then + poids(0)=cb(xx,0,1) + poids(1)=cc(xx,1) + else + poids(0)=cb(xx,0,0) + poids(1)=cc(xx,0) + end if + + else + + poids(0)=ca(xx-1.,1) + if (test (i,1) ) then + poids(1)=cb(xx-1.,1,1) + poids(2)=cc(xx-1.,1) + else + poids(1)=cb(xx-1.,1,0) + poids(2)=cc(xx-1.,0) + end if + + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. ! +1./6. + case(0) + c=-x**2+1. -2./8. !-2./6. + case(1) + c=0.5*x*(1.+x) +1./8. ! +1./6. + end select + + end function coeff_tscg + + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posy(mod(ipart-1+vois+npart,npart)+1) - real( floor((posy(mod(ipart-1+vois+npart,npart)+1)-yb)/dy) ,kind=8)*dy-yb)/dy + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + end subroutine remaill_l2_limit_y + + + + + + subroutine remaill_l4_bloc_v2_limit_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + real(kind=8) :: phi_m3demi,phi_mdemi,phi_pdemi,phi_p3demi + real(kind=8),dimension(-1:2) :: phi + + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + call calcul_phi_minmax(phi) + phi_m3demi=phi(-1) + phi_mdemi=phi(0) + phi_pdemi=phi(1) + phi_p3demi=phi(2) + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + end if + case(1) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1.)+cd(xx-1.)+ce(xx-1.)-ce(xx) + case(3) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx)+cd(xx)+ce(xx)-ce(xx+1.) + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=ca(xx)-ca(xx-1.)+cb(xx)+cc(xx) + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=ca(xx-1.)+cb(xx-1.) + poids(1)=cc(xx-1.) + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx)+cb(xx) + poids(0)=cc(xx) + case(7) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=ca(xx-1.)-ca(xx)+cb(xx-1.)-cb(xx) + poids(1)=cc(xx-1) + case(8) + poids(-3)=ca(xx+1.) + poids(-2)=cb(xx+1.) + poids(-1)=ca(xx)-ca(xx+1.)+cb(xx)-cb(xx+1.) + poids(0)=cc(xx) + case(9) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=ca(xx-1.)-ca(xx) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + case(10) + poids(-3)=ca(xx+1.) + poids(-2)=ca(xx)-ca(xx+1.) + poids(-1)=cb(xx) + poids(0)=cc(xx) + + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + else + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + end if + case(1) + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=cd(xx-1.)+ce(xx-1.) + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=cd(xx)+ce(xx) + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=ce(xx+1.) + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.)-ce(xx-2.) + poids(4)=ce(xx-2.) + case(7) + poids(1)=cd(xx) + poids(2)=ce(xx)-ce(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + case(8) + poids(1)=cd(xx)-cd(xx-1.)+ce(xx)-ce(xx-1.) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + contains + + function ca(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ca + !ca=x*(x-1.)*(x-2.)*(x+1.)/24. + ca=coeff_M5g(-2,x)+phi_m3demi*coeff_l4mM5g(-2,x) + end function ca + function cb(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cb + !cb=-x*(x-1.)*(x**2-4.)/6. + cb=coeff_M5g(-1,x)-phi_m3demi*coeff_l4mM5g(-2,x)+phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x)) + end function cb + function cc(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cc + !cc=(x**2-4.)*(x**2-1.)/4. + cc=coeff_M5g(0,x)-phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x))-phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x)) + end function cc + function cd(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cd + !cd=-x*(x+1.)*(x+2.)*(x-2.)/6. + cd=coeff_M5g(1,x)+phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x))-phi_p3demi*coeff_l4mM5g(2,x) + end function cd + function ce(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ce + !ce=x*(x+1.)*(x+2.)*(x-1.)/24. + ce=coeff_M5g(2,x)+phi_p3demi*coeff_l4mM5g(2,x) + end function ce + + + function coeff_l4g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=x*(x-1)*(x-2)*(x+1)/24. + case(-1) + c=-x*(x-1)*(x-2)*(x+2)/6. + case(0) + c=(x-2)*(x-1)*(x+1)*(x+2)/4. + case(1) + c=-x*(x-2)*(x+1)*(x+2)/6. + case(2) + c=x*(x-1)*(x+1)*(x+2)/24. + end select + + end function coeff_l4g + + function coeff_M5g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=(2.*x-1.)**4/384. + case(-1) + c=19./96.-11/24.*x+x**2/4.+x**3/6.-x**4/6. + case(0) + c=115./192.-5./8.*x**2+x**4/4. + case(1) + c=19./96.+11/24.*x-x**3/6.+x**2/4.-x**4/6. + case(2) + c=(2.*x+1.)**4/384. + end select + + end function coeff_M5g + + function coeff_l4mM5g (num,x) result(c) + !lambda4 - M5 gauche + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=5.*x/48.*(1.-x)-1./384. + case(-1) + c=-5.*x/24.*(1.-2.*x)-19/96. + case(0) + c=-5.*x**2/8.+77./192. + case(1) + c=5.*x/24.*(1.+2.*x)-19./96. + case(2) + c=-5.*x/48.*(1.+x)-1./384. + end select + + end function coeff_l4mM5g + + + + + subroutine calcul_phi_minmax(phi_out) + implicit none + real(kind=8),dimension(-1:2),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u,bmin,bmax,x,xx_vois + real(kind=8),dimension(-5:5,-5:5) :: ej,fj + real(kind=8) :: tp1,tp2,phi1,phi2 + integer :: ib,jb + + + !particules voisines + !------------------- + do ib=-4,5 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + !coeff decentre droite = coeff decentre gauche -1 + !------------------------------------------------- + do ib=-4,3 + xx_vois(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + + if ((xx_vois(ib)>0.5).and.((blocg(mod(i-1+ib+npart,npart)+1)==0).or.(blocd(mod(i-1+ib+npart,npart)+1)==0))) then + x(ib)=xx_vois(ib)-1. + else + x(ib)=xx_vois(ib) + end if + end do + + + do ib=-4,3 + + bmin(ib)=min(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + bmax(ib)=max(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + + + do jb=-4,3 + ej(ib,jb)=coeff_M5g(-2,x(jb))*u(ib+2)+coeff_M5g(-1,x(jb))*u(ib+1)+coeff_M5g(0,x(jb))*u(ib)+coeff_M5g(1,x(jb))*u(ib-1)+coeff_M5g(2,x(jb))*u(ib-2) + fj(ib,jb)=coeff_l4mM5g(-2,x(jb))*u(ib+1)+(coeff_l4mM5g(-2,x(jb))+coeff_l4mM5g(-1,x(jb)))*u(ib)-(coeff_l4mM5g(1,x(jb))+coeff_l4mM5g(2,x(jb)))*u(ib-1)-coeff_l4mM5g(2,x(jb))*u(ib-2) + end do + + end do + + + do ib=-1,2 + + tp1=(bmin(ib-1)-ej(ib-1,ib)+max(0.,fj(ib-1,ib)))/fj(ib,ib) + tp2=(bmax(ib-1)-ej(ib-1,ib)+min(0.,fj(ib-1,ib)))/fj(ib,ib) + !phi1=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi1=max(0.,min(1.,max(tp1,tp2))) + + tp1=(bmin(ib)-ej(ib,ib-1)+max(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + tp2=(bmax(ib)-ej(ib,ib-1)+min(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + !phi2=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi2=max(0.,min(1.,max(tp1,tp2))) + + phi_out(ib)=min(phi1,phi2) + + if(abs(fj(ib,ib))<0.0000001) phi_out(ib)=0. + if(abs(fj(ib,ib-1))<0.0000001) phi_out(ib)=0. + + end do + + + end subroutine calcul_phi_minmax + + + end subroutine remaill_l4_bloc_v2_limit_x + + + + + subroutine remaill_l4_bloc_v2_limit_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + real(kind=8) :: phi_m3demi,phi_mdemi,phi_pdemi,phi_p3demi + real(kind=8),dimension(-1:2) :: phi + + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + call calcul_phi_minmax(phi) + phi_m3demi=phi(-1) + phi_mdemi=phi(0) + phi_pdemi=phi(1) + phi_p3demi=phi(2) + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + end if + case(1) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1.)+cd(xx-1.)+ce(xx-1.)-ce(xx) + case(3) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx)+cd(xx)+ce(xx)-ce(xx+1.) + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=ca(xx)-ca(xx-1.)+cb(xx)+cc(xx) + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=ca(xx-1.)+cb(xx-1.) + poids(1)=cc(xx-1.) + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx)+cb(xx) + poids(0)=cc(xx) + case(7) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=ca(xx-1.)-ca(xx)+cb(xx-1.)-cb(xx) + poids(1)=cc(xx-1) + case(8) + poids(-3)=ca(xx+1.) + poids(-2)=cb(xx+1.) + poids(-1)=ca(xx)-ca(xx+1.)+cb(xx)-cb(xx+1.) + poids(0)=cc(xx) + case(9) + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=ca(xx-1.)-ca(xx) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + case(10) + poids(-3)=ca(xx+1.) + poids(-2)=ca(xx)-ca(xx+1.) + poids(-1)=cb(xx) + poids(0)=cc(xx) + + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + else + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + end if + case(1) + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=cd(xx-1.)+ce(xx-1.) + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=cd(xx)+ce(xx) + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=ce(xx+1.) + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.)-ce(xx-2.) + poids(4)=ce(xx-2.) + case(7) + poids(1)=cd(xx) + poids(2)=ce(xx)-ce(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + case(8) + poids(1)=cd(xx)-cd(xx-1.)+ce(xx)-ce(xx-1.) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + + + end select + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + contains + + function ca(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ca + !ca=x*(x-1.)*(x-2.)*(x+1.)/24. + ca=coeff_M5g(-2,x)+phi_m3demi*coeff_l4mM5g(-2,x) + end function ca + function cb(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cb + !cb=-x*(x-1.)*(x**2-4.)/6. + cb=coeff_M5g(-1,x)-phi_m3demi*coeff_l4mM5g(-2,x)+phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x)) + end function cb + function cc(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cc + !cc=(x**2-4.)*(x**2-1.)/4. + cc=coeff_M5g(0,x)-phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x))-phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x)) + end function cc + function cd(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cd + !cd=-x*(x+1.)*(x+2.)*(x-2.)/6. + cd=coeff_M5g(1,x)+phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x))-phi_p3demi*coeff_l4mM5g(2,x) + end function cd + function ce(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ce + !ce=x*(x+1.)*(x+2.)*(x-1.)/24. + ce=coeff_M5g(2,x)+phi_p3demi*coeff_l4mM5g(2,x) + end function ce + + + function coeff_l4g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=x*(x-1)*(x-2)*(x+1)/24. + case(-1) + c=-x*(x-1)*(x-2)*(x+2)/6. + case(0) + c=(x-2)*(x-1)*(x+1)*(x+2)/4. + case(1) + c=-x*(x-2)*(x+1)*(x+2)/6. + case(2) + c=x*(x-1)*(x+1)*(x+2)/24. + end select + + end function coeff_l4g + + function coeff_M5g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=(2.*x-1.)**4/384. + case(-1) + c=19./96.-11/24.*x+x**2/4.+x**3/6.-x**4/6. + case(0) + c=115./192.-5./8.*x**2+x**4/4. + case(1) + c=19./96.+11/24.*x-x**3/6.+x**2/4.-x**4/6. + case(2) + c=(2.*x+1.)**4/384. + end select + + end function coeff_M5g + + function coeff_l4mM5g (num,x) result(c) + !lambda4 - M5 gauche + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=5.*x/48.*(1.-x)-1./384. + case(-1) + c=-5.*x/24.*(1.-2.*x)-19/96. + case(0) + c=-5.*x**2/8.+77./192. + case(1) + c=5.*x/24.*(1.+2.*x)-19./96. + case(2) + c=-5.*x/48.*(1.+x)-1./384. + end select + + end function coeff_l4mM5g + + + + + subroutine calcul_phi_minmax(phi_out) + implicit none + real(kind=8),dimension(-1:2),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u,bmin,bmax,x,xx_vois + real(kind=8),dimension(-5:5,-5:5) :: ej,fj + real(kind=8) :: tp1,tp2,phi1,phi2 + integer :: ib,jb + + + !particules voisines + !------------------- + do ib=-4,5 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + !coeff decentre droite = coeff decentre gauche -1 + !------------------------------------------------- + do ib=-4,3 + xx_vois(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + + if ((xx_vois(ib)>0.5).and.((blocg(mod(i-1+ib+npart,npart)+1)==0).or.(blocd(mod(i-1+ib+npart,npart)+1)==0))) then + x(ib)=xx_vois(ib)-1. + else + x(ib)=xx_vois(ib) + end if + end do + + + do ib=-4,3 + + bmin(ib)=min(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + bmax(ib)=max(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + + + do jb=-4,3 + ej(ib,jb)=coeff_M5g(-2,x(jb))*u(ib+2)+coeff_M5g(-1,x(jb))*u(ib+1)+coeff_M5g(0,x(jb))*u(ib)+coeff_M5g(1,x(jb))*u(ib-1)+coeff_M5g(2,x(jb))*u(ib-2) + fj(ib,jb)=coeff_l4mM5g(-2,x(jb))*u(ib+1)+(coeff_l4mM5g(-2,x(jb))+coeff_l4mM5g(-1,x(jb)))*u(ib)-(coeff_l4mM5g(1,x(jb))+coeff_l4mM5g(2,x(jb)))*u(ib-1)-coeff_l4mM5g(2,x(jb))*u(ib-2) + end do + + end do + + + do ib=-1,2 + + tp1=(bmin(ib-1)-ej(ib-1,ib)+max(0.,fj(ib-1,ib)))/fj(ib,ib) + tp2=(bmax(ib-1)-ej(ib-1,ib)+min(0.,fj(ib-1,ib)))/fj(ib,ib) + !phi1=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi1=max(0.,min(1.,max(tp1,tp2))) + + tp1=(bmin(ib)-ej(ib,ib-1)+max(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + tp2=(bmax(ib)-ej(ib,ib-1)+min(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + !phi2=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi2=max(0.,min(1.,max(tp1,tp2))) + + phi_out(ib)=min(phi1,phi2) + + if(abs(fj(ib,ib))<0.0000001) phi_out(ib)=0. + if(abs(fj(ib,ib-1))<0.0000001) phi_out(ib)=0. + + end do + + + end subroutine calcul_phi_minmax + + end subroutine remaill_l4_bloc_v2_limit_y + + + + + subroutine remaill_l4_limit_x (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,j,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + real(kind=8) :: phi_m3demi,phi_mdemi,phi_pdemi,phi_p3demi + real(kind=8),dimension(-1:2) :: phi + + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + call calcul_phi_minmax(phi) + phi_m3demi=phi(-1) + phi_mdemi=phi(0) + phi_pdemi=phi(1) + phi_p3demi=phi(2) + + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,j)=remaille(ip(c)+1,j)+donne(i)*poids(c) + end do + + + end do + + contains + + function ca(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ca + !ca=x*(x-1.)*(x-2.)*(x+1.)/24. + ca=coeff_M5g(-2,x)+phi_m3demi*coeff_l4mM5g(-2,x) + end function ca + function cb(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cb + !cb=-x*(x-1.)*(x**2-4.)/6. + cb=coeff_M5g(-1,x)-phi_m3demi*coeff_l4mM5g(-2,x)+phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x)) + end function cb + function cc(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cc + !cc=(x**2-4.)*(x**2-1.)/4. + cc=coeff_M5g(0,x)-phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x))-phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x)) + end function cc + function cd(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cd + !cd=-x*(x+1.)*(x+2.)*(x-2.)/6. + cd=coeff_M5g(1,x)+phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x))-phi_p3demi*coeff_l4mM5g(2,x) + end function cd + function ce(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ce + !ce=x*(x+1.)*(x+2.)*(x-1.)/24. + ce=coeff_M5g(2,x)+phi_p3demi*coeff_l4mM5g(2,x) + end function ce + + + function coeff_l4g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=x*(x-1)*(x-2)*(x+1)/24. + case(-1) + c=-x*(x-1)*(x-2)*(x+2)/6. + case(0) + c=(x-2)*(x-1)*(x+1)*(x+2)/4. + case(1) + c=-x*(x-2)*(x+1)*(x+2)/6. + case(2) + c=x*(x-1)*(x+1)*(x+2)/24. + end select + + end function coeff_l4g + + function coeff_M5g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=(2.*x-1.)**4/384. + case(-1) + c=19./96.-11/24.*x+x**2/4.+x**3/6.-x**4/6. + case(0) + c=115./192.-5./8.*x**2+x**4/4. + case(1) + c=19./96.+11/24.*x-x**3/6.+x**2/4.-x**4/6. + case(2) + c=(2.*x+1.)**4/384. + end select + + end function coeff_M5g + + function coeff_l4mM5g (num,x) result(c) + !lambda4 - M5 gauche + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=5.*x/48.*(1.-x)-1./384. + case(-1) + c=-5.*x/24.*(1.-2.*x)-19/96. + case(0) + c=-5.*x**2/8.+77./192. + case(1) + c=5.*x/24.*(1.+2.*x)-19./96. + case(2) + c=-5.*x/48.*(1.+x)-1./384. + end select + + end function coeff_l4mM5g + + + + + subroutine calcul_phi_minmax(phi_out) + implicit none + real(kind=8),dimension(-1:2),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u,bmin,bmax,x,xx_vois + real(kind=8),dimension(-5:5,-5:5) :: ej,fj + real(kind=8) :: tp1,tp2,phi1,phi2 + integer :: ib,jb + + + !particules voisines + !------------------- + do ib=-4,5 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + !coeff decentre droite = coeff decentre gauche -1 + !------------------------------------------------- + do ib=-4,3 + xx_vois(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + + if ((xx_vois(ib)>0.5).and.((blocg(mod(i-1+ib+npart,npart)+1)==0).or.(blocd(mod(i-1+ib+npart,npart)+1)==0))) then + x(ib)=xx_vois(ib)-1. + else + x(ib)=xx_vois(ib) + end if + end do + + + do ib=-4,3 + + bmin(ib)=min(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + bmax(ib)=max(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + + + do jb=-4,3 + ej(ib,jb)=coeff_M5g(-2,x(jb))*u(ib+2)+coeff_M5g(-1,x(jb))*u(ib+1)+coeff_M5g(0,x(jb))*u(ib)+coeff_M5g(1,x(jb))*u(ib-1)+coeff_M5g(2,x(jb))*u(ib-2) + fj(ib,jb)=coeff_l4mM5g(-2,x(jb))*u(ib+1)+(coeff_l4mM5g(-2,x(jb))+coeff_l4mM5g(-1,x(jb)))*u(ib)-(coeff_l4mM5g(1,x(jb))+coeff_l4mM5g(2,x(jb)))*u(ib-1)-coeff_l4mM5g(2,x(jb))*u(ib-2) + end do + + end do + + + do ib=-1,2 + + tp1=(bmin(ib-1)-ej(ib-1,ib)+max(0.,fj(ib-1,ib)))/fj(ib,ib) + tp2=(bmax(ib-1)-ej(ib-1,ib)+min(0.,fj(ib-1,ib)))/fj(ib,ib) + !phi1=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi1=max(0.,min(1.,max(tp1,tp2))) + + tp1=(bmin(ib)-ej(ib,ib-1)+max(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + tp2=(bmax(ib)-ej(ib,ib-1)+min(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + !phi2=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi2=max(0.,min(1.,max(tp1,tp2))) + + phi_out(ib)=min(phi1,phi2) + + if(abs(fj(ib,ib))<0.0000001) phi_out(ib)=0. + if(abs(fj(ib,ib-1))<0.0000001) phi_out(ib)=0. + + end do + + + end subroutine calcul_phi_minmax + + + end subroutine remaill_l4_limit_x + + + + + subroutine remaill_l4_limit_y (donne,posx,posy,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy + real(kind=8),dimension(1:nx,1:ny),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + real(kind=8) :: phi_m3demi,phi_mdemi,phi_pdemi,phi_p3demi + real(kind=8),dimension(-1:2) :: phi + + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + call calcul_phi_minmax(phi) + phi_m3demi=phi(-1) + phi_mdemi=phi(0) + phi_pdemi=phi(1) + phi_p3demi=phi(2) + + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=ca(xx) + poids(-1)=cb(xx) + poids(0)=cc(xx) + poids(1)=cd(xx) + poids(2)=ce(xx) + poids(3)=0. + poids(4)=0. + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=ca(xx-1.) + poids(0)=cb(xx-1.) + poids(1)=cc(xx-1) + poids(2)=cd(xx-1.) + poids(3)=ce(xx-1.) + poids(4)=0. + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ivar,ip(c)+1)=remaille(ivar,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + contains + + function ca(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ca + !ca=x*(x-1.)*(x-2.)*(x+1.)/24. + ca=coeff_M5g(-2,x)+phi_m3demi*coeff_l4mM5g(-2,x) + end function ca + function cb(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cb + !cb=-x*(x-1.)*(x**2-4.)/6. + cb=coeff_M5g(-1,x)-phi_m3demi*coeff_l4mM5g(-2,x)+phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x)) + end function cb + function cc(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cc + !cc=(x**2-4.)*(x**2-1.)/4. + cc=coeff_M5g(0,x)-phi_mdemi*(coeff_l4mM5g(-2,x)+coeff_l4mM5g(-1,x))-phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x)) + end function cc + function cd(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: cd + !cd=-x*(x+1.)*(x+2.)*(x-2.)/6. + cd=coeff_M5g(1,x)+phi_pdemi*(coeff_l4mM5g(1,x)+coeff_l4mM5g(2,x))-phi_p3demi*coeff_l4mM5g(2,x) + end function cd + function ce(x) + implicit none + real(kind=8),intent(in) :: x + real(kind=8) :: ce + !ce=x*(x+1.)*(x+2.)*(x-1.)/24. + ce=coeff_M5g(2,x)+phi_p3demi*coeff_l4mM5g(2,x) + end function ce + + + function coeff_l4g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=x*(x-1)*(x-2)*(x+1)/24. + case(-1) + c=-x*(x-1)*(x-2)*(x+2)/6. + case(0) + c=(x-2)*(x-1)*(x+1)*(x+2)/4. + case(1) + c=-x*(x-2)*(x+1)*(x+2)/6. + case(2) + c=x*(x-1)*(x+1)*(x+2)/24. + end select + + end function coeff_l4g + + function coeff_M5g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=(2.*x-1.)**4/384. + case(-1) + c=19./96.-11/24.*x+x**2/4.+x**3/6.-x**4/6. + case(0) + c=115./192.-5./8.*x**2+x**4/4. + case(1) + c=19./96.+11/24.*x-x**3/6.+x**2/4.-x**4/6. + case(2) + c=(2.*x+1.)**4/384. + end select + + end function coeff_M5g + + function coeff_l4mM5g (num,x) result(c) + !lambda4 - M5 gauche + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-2) + c=5.*x/48.*(1.-x)-1./384. + case(-1) + c=-5.*x/24.*(1.-2.*x)-19/96. + case(0) + c=-5.*x**2/8.+77./192. + case(1) + c=5.*x/24.*(1.+2.*x)-19./96. + case(2) + c=-5.*x/48.*(1.+x)-1./384. + end select + + end function coeff_l4mM5g + + + + + subroutine calcul_phi_minmax(phi_out) + implicit none + real(kind=8),dimension(-1:2),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u,bmin,bmax,x,xx_vois + real(kind=8),dimension(-5:5,-5:5) :: ej,fj + real(kind=8) :: tp1,tp2,phi1,phi2 + integer :: ib,jb + + + !particules voisines + !------------------- + do ib=-4,5 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + !coeff decentre droite = coeff decentre gauche -1 + !------------------------------------------------- + do ib=-4,3 + xx_vois(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + + if ((xx_vois(ib)>0.5).and.((blocg(mod(i-1+ib+npart,npart)+1)==0).or.(blocd(mod(i-1+ib+npart,npart)+1)==0))) then + x(ib)=xx_vois(ib)-1. + else + x(ib)=xx_vois(ib) + end if + end do + + + do ib=-4,3 + + bmin(ib)=min(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + bmax(ib)=max(u(ib-2),u(ib-1),u(ib),u(ib+1),u(ib+2)) + + + do jb=-4,3 + ej(ib,jb)=coeff_M5g(-2,x(jb))*u(ib+2)+coeff_M5g(-1,x(jb))*u(ib+1)+coeff_M5g(0,x(jb))*u(ib)+coeff_M5g(1,x(jb))*u(ib-1)+coeff_M5g(2,x(jb))*u(ib-2) + fj(ib,jb)=coeff_l4mM5g(-2,x(jb))*u(ib+1)+(coeff_l4mM5g(-2,x(jb))+coeff_l4mM5g(-1,x(jb)))*u(ib)-(coeff_l4mM5g(1,x(jb))+coeff_l4mM5g(2,x(jb)))*u(ib-1)-coeff_l4mM5g(2,x(jb))*u(ib-2) + end do + + end do + + + do ib=-1,2 + + tp1=(bmin(ib-1)-ej(ib-1,ib)+max(0.,fj(ib-1,ib)))/fj(ib,ib) + tp2=(bmax(ib-1)-ej(ib-1,ib)+min(0.,fj(ib-1,ib)))/fj(ib,ib) + !phi1=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi1=max(0.,min(1.,max(tp1,tp2))) + + tp1=(bmin(ib)-ej(ib,ib-1)+max(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + tp2=(bmax(ib)-ej(ib,ib-1)+min(0.,-fj(ib+1,ib-1)))/(-fj(ib,ib-1)) + !phi2=max(0.,min(tp1,tp2),min(1.,max(tp1,tp2))) + phi2=max(0.,min(1.,max(tp1,tp2))) + + phi_out(ib)=min(phi1,phi2) + + if(abs(fj(ib,ib))<0.0000001) phi_out(ib)=0. + if(abs(fj(ib,ib-1))<0.0000001) phi_out(ib)=0. + + end do + + + end subroutine calcul_phi_minmax + + end subroutine remaill_l4_limit_y + + + + +end module remaillage_mod + + diff --git a/CodesEnVrac/CodesAdrien/split_2d/resultats_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/resultats_mod.f90 new file mode 100644 index 000000000..f56ed9a74 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/resultats_mod.f90 @@ -0,0 +1,255 @@ +module resultats_mod + use donnees_mod + use tab_mod + contains + + subroutine res_qg (nom_fich) + use donnees_mod + use tab_mod + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j + real(kind=8) :: x,y + + open(unit=11,file=nom_fich,form="formatted") + do i=1,nx + do j=1,ny + x=xg+(i-1)*dx + y=yb+(j-1)*dy + write(11,'(3(f35.20,2x))') x,y,qg(i,j) + end do + end do + write(11,*) "" + write(11,*) "" + close (11) + end subroutine res_qg + + subroutine res_vxg (nom_fich) + use donnees_mod + use tab_mod + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j + real(kind=8) :: x,y + + open(unit=11,file=nom_fich,form="formatted") + do i=1,nx + do j=1,ny + x=xg+(i-1)*dx + y=yb+(j-1)*dy + write(11,'(3(f35.20,2x))') x,y,vxg(i,j) + end do + end do + write(11,*) "" + write(11,*) "" + close (11) + end subroutine res_vxg + + subroutine res_vyg (nom_fich) + use donnees_mod + use tab_mod + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j + real(kind=8) :: x,y + + open(unit=11,file=nom_fich,form="formatted") + do i=1,nx + do j=1,ny + x=xg+(i-1)*dx + y=yb+(j-1)*dy + write(11,'(3(f35.20,2x))') x,y,vyg(i,j) + end do + end do + write(11,*) "" + write(11,*) "" + close (11) + end subroutine res_vyg + + subroutine res_brut (nom_fich) + use donnees_mod + use tab_mod + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j + real(kind=8) :: x,y + + open(unit=11,file=nom_fich,form="formatted") + do i=1,nx + do j=1,ny + x=xg+(i-1)*dx + y=yb+(j-1)*dy + write(11,'(1(f35.20,2x))') qg(i,j) + end do + end do + write(11,*) "" + write(11,*) "" + close (11) + end subroutine res_brut + + +!!$ subroutine res_qg_freq (dossier,nom_fich) +!!$ implicit none +!!$ character(len=*),intent(in) :: dossier +!!$ character(len=*),intent(in) :: nom_fich +!!$ integer :: i,j,cpt_num +!!$ +!!$ if ((time<=cpt_fich_sauv).and.(time+dt>cpt_fich_sauv))then +!!$ cpt_fich_sauv=cpt_fich_sauv+frequ_fich_sauv +!!$ +!!$ if (int(time)==0) call res_vtk_q(dossier//nom_fich//char(48)//"_"//char(int(time*10.)+48)//".vtk") +!!$ do i=1,9 +!!$ if (int(time)==i) call res_vtk_q(dossier//nom_fich//char(48+i)//"_"//char(int(mod(time,float(i))*10.)+48)//".vtk") +!!$ end do +!!$ cpt_num=49 +!!$ do j=10,80,10 +!!$ do i=j,j+9 +!!$ if (int(time)==i) call res_vtk_q(dossier//nom_fich//char(cpt_num)//char(48+i-j)//"_"//char(int(mod(time,float(i))*10.)+48)//".vtk") +!!$ end do +!!$ cpt_num=cpt_num+1 +!!$ end do +!!$ end if +!!$ +!!$ end subroutine res_qg_freq + + + + + + + subroutine res_vtk_q (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"scalaire" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,1 + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,0 + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,0 + + write(11,'(A10,i10)') "POINT_DATA",nx*ny + write(11,'(A15)') "SCALARS Q FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + do j=1,ny + do i=1,nx + write(11,'(f20.9)') real(qg(i,j)) + end do + end do + + close (11) + end subroutine res_vtk_q + + + + subroutine res_vtk_tab (nom_fich,tab) + implicit none + character(len=*),intent(in) :: nom_fich + real(kind=8),dimension(:,:),intent(in) :: tab + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"scalaire" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,1 + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,0 + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,0 + + write(11,'(A10,i10)') "POINT_DATA",nx*ny + write(11,'(A15)') "SCALARS Q FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + do j=1,ny + do i=1,nx + write(11,'(f20.9)') real(tab(i,j)) + end do + end do + + close (11) + + end subroutine res_vtk_tab + + subroutine res_vtk_v (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,1 + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,0 + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,0 + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny + write(11,'(A21)') "VECTORS VITESSE FLOAT" + + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j)),real(vyg(i,j)),0. + end do + end do + close (11) + end subroutine res_vtk_v + + subroutine res_vtk (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,1 + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,0 + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,0 + + write(11,'(A10,i10)') "POINT_DATA",nx*ny + write(11,'(A15)') "SCALARS U FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + do j=1,ny + do i=1,nx + write(11,'(f20.9)') real(qg(i,j)) + end do + end do + + write(11,'(A21)') "" + write(11,'(A21)') "VECTORS VITESSE FLOAT" + + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j)),real(vyg(i,j)),0. + end do + end do + + close (11) + + end subroutine res_vtk + + + +end module resultats_mod + diff --git a/CodesEnVrac/CodesAdrien/split_2d/tab_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/tab_mod.f90 new file mode 100644 index 000000000..c1b406a3f --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/tab_mod.f90 @@ -0,0 +1,19 @@ +module tab_mod + + !grille + real(kind=8),dimension(:,:),pointer :: qg,vxg,vyg,xtab,ytab,exa,qg_init,qg_tmp + real(kind=8),dimension(:,:),pointer :: vxg1,vyg1,vxg2,vyg2,vxg3,vyg3 + integer,dimension(:,:),pointer :: numpg + + !particule + real(kind=8),dimension(:),pointer :: xp,yp,qp,vx,vy + real(kind=8),dimension(:),pointer :: xp0,yp0,xp1,xp2,yp1,yp2,xp3,yp3,vx0,vy0,vx1,vx2,vx3,vy1,vy2,vy3 + integer,dimension(:),pointer :: blocg,blocd,Nbloc,Nblocg + + !debug + real(kind=8),dimension(:),pointer ::deb_part1 + real(kind=8),dimension(:,:),pointer ::deb_g1 + + + +end module tab_mod diff --git a/CodesEnVrac/CodesAdrien/split_2d/utile_mod.f90 b/CodesEnVrac/CodesAdrien/split_2d/utile_mod.f90 new file mode 100644 index 000000000..e8ca610bb --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_2d/utile_mod.f90 @@ -0,0 +1,758 @@ +module utile_mod + use donnees_mod + use tab_mod + use interpolation_mod + use advection_mod +contains + + + subroutine make_grille + implicit none + integer :: i,j + + do j=1,ny + do i=1,nx + xtab(i,j)=xg+(i-1)*dx + ytab(i,j)=yb+(j-1)*dy + end do + end do + + end subroutine make_grille + + + function tsource(t,x,y) + implicit none + real(kind=8),intent(in) :: t,x,y + real(kind=8) :: tsource,t1,t2,t3,t4,t5 + + t1=1. + t2=1. + t3=0.2 + t4=0.3 + t5=1. + + + !u=u(t,x,y) + !---------- + tsource=-( pi*sin(pi*t/t3)*cos(2.*pi*x/t1)*cos(2.*pi*y/t2) )/t3 - (2.*pi*t5*sin(2.*pi*x/t1)**2*sin(2.*pi*y/t1)*cos(pi*t/t4)*cos(pi*t/t3)*cos(2.*pi*y/t2) )/t1 -(2.*pi*t5*cos(2.*pi*x/t1)**2*cos(2.*pi*y/t1)*cos(pi*t/t4)*cos(pi*t/t3)*sin(2.*pi*y/t2))/t2 + + !tsource=0. + + + end function tsource + + + + subroutine source_rk4 + implicit none + integer :: i + real(kind=8) :: rk1,rk2,rk3,rk4,t1,t2,t3 + real(kind=8) :: x1,x2,x3,y1,y2,y3,v1x,v2x,v3x,v1y,v2y,v3y + + + + do i=1,npart + + !euler + !------ + ! qp(i)=qp(i)+dt*tsource(time,xp(i),yp(i)) + + !rk2 + !---- + !qp(i)=qp(i)+dt*tsource(time+0.5*dt,xp(i)+0.5*dt*vx(i),yp(i)+0.5*dt*vy(i)) + + !rk3 + !--- +!!$ rk1=tsource(time,xp(i),yp(i)) +!!$ x1=xp(i)+0.5*dt*vx(i) +!!$ y1=yp(i)+0.5*dt*vy(i) +!!$ rk2=tsource(time+0.5*dt,x1,y1) +!!$ call evalv (v1x,v1y,time+0.5*dt,x1,y1) +!!$ x2=xp(i)-dt*vx(i)+2.*dt*v1x +!!$ y2=yp(i)-dt*vy(i)+2.*dt*v1y +!!$ rk3=tsource(time+dt,x2,y2) +!!$ +!!$ qp(i)=qp(i)+dt*(rk1/6.+2.*rk2/3.+rk3/6.) + + !rk4 + !--- + rk1=tsource(time,xp(i),yp(i)) + x1=xp(i)+0.5*dt*vx(i) + y1=yp(i)+0.5*dt*vy(i) + rk2=tsource(time+0.5*dt,x1,y1) + call evalv (v1x,v1y,time+0.5*dt,x1,y1) + x2=xp(i)+0.5*dt*v1x + y2=yp(i)+0.5*dt*v1y + rk3=tsource(time+0.5*dt,x2,y2) + call evalv (v2x,v2y,time+0.5*dt,x2,y2) + x3=xp(i)+dt*v2x + y3=yp(i)+dt*v2y + rk4=tsource(time+dt,x3,y3) + + qp(i)=qp(i)+dt*(rk1+2.*rk2+2.*rk3+rk4)/6. + + end do + + + end subroutine source_rk4 + + + subroutine source_split_1 + implicit none + integer :: i,j + real(kind=8) :: rk1,rk2,rk3,rk4,t1,t2,t3 + real(kind=8) :: x1,x2,x3,y1,y2,y3,v1x,v2x,v3x,v1y,v2y,v3y + real(kind=8) :: x,y + + + !ordre2 + !------ + do i=1,npart + qp(i)=qp(i)+0.5*dt*tsource(time,xp(i),yp(i)) + end do + + + end subroutine source_split_1 + + subroutine source_split_2 + implicit none + integer :: i,j + real(kind=8) :: rk1,rk2,rk3,rk4,t1,t2,t3 + real(kind=8) :: x0,x1,x2,x3,y1,y2,y3,v1x,v2x,v3x,v1y,v2y,v3y + real(kind=8) :: x,y + + + !ordre2 + !------ + do j=1,ny + do i=1,nx + x=xtab(i,j) + y=ytab(i,j) + + qg(i,j)=qg(i,j)+0.5*dt*tsource(time+dt,x,y) + + end do + end do + + + end subroutine source_split_2 + + + subroutine make_bloc(esp) + use donnees_mod + implicit none + integer,intent(in) :: esp + integer :: fin,ib,i,j,k,im,ip,dim1,dim2 + logical :: zero + real(kind=8) :: pas + + select case(esp) + case(1) + dim1=nx + dim2=ny + pas=dx + case(2) + dim1=ny + dim2=nx + pas=dy + end select + + + !----------------------------------------------------------------------------------------- + !Determine la nature des blocs + !Donne un flag correspondant au type de remaillage necessaire (centre,decentre ou modifie) + !------------------------------------------------------------------------------------------ + + blocg(1:npart)=1 + blocd(1:npart)=1 + + + ordonne: do j=1,dim2 + + !peut calculer la longeur -> gain si longeur eleve + + !parcours la grille, bloc par bloc:determine le type des bloc + !--------------------------------- + + blocg(0)=100 + blocd(0)=100 + Nbloc(0)=100 + + type_bloc:do i=1,dim1,long_bloc+1 + + + if ( (i+long_bloc)<(dim1-1) ) then + fin=i+long_bloc + call sub_typeb + else + !parcours le bloc plus premier point du bloc suivant + fin=dim1-1 + call sub_typeb + blocg(pg(dim1,j))=blocg(pg(dim1-1,j)) + blocd(pg(dim1,j))=blocd(pg(dim1-1,j)) + Nbloc(pg(dim1,j))=Nbloc(pg(dim1-1,j)) + end if + + end do type_bloc + + + !parcours la grille, bloc par bloc:determine si modif de remaillage necessaire a l'intersection des blocs + !--------------------------------- + type_remaill:do i=1,dim1,long_bloc+1 + + if (((i+long_bloc)<dim1).and.(i>1+long_bloc)) then + fin=i+long_bloc + call sub_remb + else + if (i<=1+long_bloc)then + !premier bloc + !------------- + fin=i+long_bloc + call sub_remb + + else + !dernier bloc + !------------- + fin=dim1 + call sub_remb + + end if + + end if + + end do type_remaill + end do ordonne + + contains + + subroutine sub_typeb + + integer :: ni,N + real(kind=8) :: li + logical :: pasfait + + + !parcours une premiere fois le bloc pour savoir si c'est un bloc en 0 ou 1/2 + !---------------------------------- + pasfait=.true. + zero=.true. + do_zero:do ib=i,fin+1 !eviter cas change de bloc quand maille vide + if (pg(ib,j)/=0) then + if (pasfait) then !le N doit etre le meme pour tout le bloc ! + li=dt/pas*vit(pg(ib,j)) + ni=floor(li+0.5) + pasfait=.false. + end if + li=dt/pas*vit(pg(ib,j)) + if ( ((li)<(ni-0.5)).or.((li)>(ni+0.5)) ) then + zero=.false. + exit do_zero + end if + end if + end do do_zero + + + !parcours a nouveau le bloc + !------------------------- + !affecte le type de bloc a toute les part du bloc + + pasfait=.true. + bloc2:do ib=i,fin + + if (pg(ib,j)/=0) then + + !calcul de N + !------------ + if (pasfait) then + if (zero) then + N=floor(dt/pas*vit(pg(ib,j))+0.5) + pasfait=.false. + else + N=floor(dt/pas*vit(pg(ib,j))) + pasfait=.false. + end if + end if + + if (zero) then + !bloc pour lambda2 centre + blocg(pg(ib,j))=0 + blocd(pg(ib,j))=0 + end if + + !affecte la constante N + Nbloc(pg(ib,j))=N + + end if + end do bloc2 + + end subroutine sub_typeb + + + subroutine sub_remb + implicit none + + integer,dimension(-2:2) :: iper + integer :: k + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection de ces blocs + + bloc3:do ib=i,fin,fin-i + + if (pg(ib,j)/=0) then + + !si fin de bloc en 0. : + !---------------------- + do k=-2,2 + iper(k)=pg(mod(ib+k+dim1-1,dim1)+1,j) + end do + + + if ((ib==fin).and.(blocd(pg(ib,j))==0).and.((blocg(iper(1))==1).or.(blocg(iper(2))==1)).and.((Nbloc(iper(1))==Nbloc(pg(ib,j))-1) .or.(Nbloc(iper(2))==Nbloc(pg(ib,j))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j))<=Nbloc(pg(ib,j)) ) then + blocg(iper(1))=2 + blocd(pg(ib,j))=3 + else + blocg(iper(1))=2 + blocd(pg(ib,j))=4 + blocg(pg(ib,j))=5 + end if + + else + blocg(iper(1))=2 + blocg(iper(2))=5 + + if ( dt/pas*vit(pg(ib,j))<=Nbloc(pg(ib,j)) ) then + blocd(pg(ib,j))=3 + else + blocd(pg(ib,j))=7 + blocg(pg(ib,j))=8 + end if + + if ( dt/pas*vit(iper(-1))<=Nbloc(pg(ib,j)) ) then + blocd(iper(-1))=6 + else + blocd(iper(-1))=5 + end if + end if + + end if + + + !si debut de bloc en 0 : detecte quelle correction il faudra apporter + !---------------------- + if ((ib==i) .and.(blocg(pg(ib,j))==0).and.((blocd(iper(-1))==1).or.(blocd(iper(-2))==1)).and.((Nbloc(iper(-1))==Nbloc(pg(ib,j))-1) .or. (Nbloc(iper(-2))==Nbloc(pg(ib,j))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j))>Nbloc(pg(ib,j)) ) then + blocd(iper(-1))=2 + blocg(pg(ib,j))=4 + else + blocd(iper(-1))=2 + blocg(pg(ib,j))=3 + end if + + else + + blocd(iper(-1))=2 + blocd(iper(-2))=4 + + if ( dt/pas*vit(pg(ib,j))>Nbloc(pg(ib,j)) ) then + blocg(pg(ib,j))=4 + else + blocg(pg(ib,j))=3 + end if + + if ( dt/pas*vit(iper(1))>Nbloc(pg(ib,j)) ) then + blocg(iper(1))=7 + else + blocg(iper(1))=6 + end if + + end if + end if + + + + end if + end do bloc3 + + end subroutine sub_remb + + function pg(a,b) + implicit none + integer,intent(in) :: a,b + integer :: pg + + select case (esp) + case(1) + pg=numpg(a,b) + case(2) + pg=numpg(b,a) + end select + + end function pg + + function vit(ind) + implicit none + integer,intent(in) :: ind + real(kind=8) :: vit + + select case (esp) + case(1) + vit=vx(ind) + case(2) + vit=vy(ind) + end select + + end function vit + + + end subroutine make_bloc + + + + subroutine make_bloc_v2(esp) + use donnees_mod + implicit none + integer,intent(in) :: esp + integer :: fin,ib,i,j,k,im,ip,dim1,dim2,n,np,part,partp,partm,partpp + logical :: zero + real(kind=8) :: pas + + select case(esp) + case(1) + dim1=nx + dim2=ny + pas=dx + case(2) + dim1=ny + dim2=nx + pas=dy + end select + + + !----------------------------------------------------------------------------------------- + !Determine la nature des blocs + !Donne un flag correspondant au type de remaillage necessaire (centre,decentre ou modifie) + !------------------------------------------------------------------------------------------ + + blocg(1:npart)=0 + blocd(1:npart)=0 + + blocg(0)=100 + blocd(0)=100 + Nbloc(0)=100 + + ordonne: do j=1,dim2 + + !peut calculer la longeur -> gain si longeur eleve + + !parcours la grille, bloc par bloc:determine le type des bloc + !--------------------------------- + + + + type_bloc:do i=1,dim1,long_bloc+1 + + + if ( (i+long_bloc).le.dim1 ) then + fin=i+long_bloc + call sub_typeb + else + !met les dernieres particules du meme type que bloc precedent + do k=i,dim1 + blocg(pg(k,j))=blocg(pg(i-1,j)) + blocd(pg(k,j))=blocd(pg(i-1,j)) + Nbloc(pg(k,j))=Nbloc(pg(i-1,j)) + end do + end if + + end do type_bloc + + + !parcours la grille, bloc par bloc:determine si modif de remaillage necessaire a l'intersection des blocs + !--------------------------------- + type_remaill:do i=1,dim1,long_bloc+1 + + if ((i+long_bloc)<dim1) then + fin=i+long_bloc + !call sub_remb + + k=fin + do while ((pg(k,j)==0).and.(k>i)) + k=k-1 + end do + n=Nbloc(pg(k,j)) ! s'il n'y a pas de part dans le bloc N=100 -> ne fera pas de correction + + k=fin+1 + do while ((pg(k,j)==0).and.(k<(fin+long_bloc+2)).and.(k<nx)) + k=k+1 + end do + np=Nbloc(pg(k,j)) + + part=pg(fin,j) + partp=pg(fin+1,j) + partm=pg(fin-1,j) + partpp=pg(fin+2,j) + + if (type_b==2) call sub_remb_2(n,np,part,partp) + if (type_b==4) call sub_remb_4(n,np,part,partp,partm,partpp) + + else + !dernier bloc + !------------- + fin=dim1 + !call sub_remb + + k=fin + do while ((pg(k,j)==0).and.(k>i)) + k=k-1 + end do + n=Nbloc(pg(k,j)) + + k=1 + do while ((pg(k,j)==0).and.(k<(1+long_bloc+1))) + k=k+1 + end do + np=Nbloc(pg(k,j)) + + part=pg(fin,j) + partp=pg(1,j) + partm=pg(fin-1,j) + partpp=pg(2,j) + + if (type_b==2) call sub_remb_2(n,np,part,partp) + if (type_b==4) call sub_remb_4(n,np,part,partp,partm,partpp) + + + end if + + end do type_remaill + + + + end do ordonne + + contains + + subroutine sub_typeb + + integer :: N,intl + real(kind=8) :: li,lmin + + + !calcul de lambda_min + !-------------------- + lmin=99999999999999999999999. + do_lmin:do ib=i,fin + if (pg(ib,j)/=0) then + li=dt/pas*vit(pg(ib,j)) + lmin=min(lmin,li) + end if + end do do_lmin + + !calcul du type de bloc et de N + !------------------------------- + intl=floor(lmin) + if ((lmin-intl).le.0.5) then + !type gauche + !----------- + N=intl + do_typeg:do ib=i,fin + if (pg(ib,j)/=0) then + blocg(pg(ib,j))=1 + blocd(pg(ib,j))=1 + Nbloc(pg(ib,j))=N + end if + end do do_typeg + else + !type centre + !----------- + N=intl+1 + do_typec:do ib=i,fin + if (pg(ib,j)/=0) then + blocg(pg(ib,j))=0 + blocd(pg(ib,j))=0 + Nbloc(pg(ib,j))=N + end if + end do do_typec + end if + + + end subroutine sub_typeb + + + + subroutine sub_remb_2(n,np,partf,partfp) + !attention les bords ne sont pas bien traités + implicit none + + integer,intent(in) ::n,np,partf,partfp + real(kind=8) :: li + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection des blocs + if ((np) == (n-1)) then + li=dt/pas*vit(partf) + if ( (li<n).and.(blocg(partf)==0) ) then !seconde condition=bloc centre + blocg(partf)=2 + else + blocg(partf)=3 + end if + blocg(partfp)=4 + end if + if ((np) == (n+1)) then + li=dt/pas*vit(partfp) + blocg(partf)=5 + if ((li<np).and.(blocg(partfp)==0)) then + blocg(partfp)=6 + else + blocg(partfp)=7 + end if + end if + + + + end subroutine sub_remb_2 + + + subroutine sub_remb_4(n,np,partf,partfp,partfm,partfpp) + !attention les bords ne sont pas bien traités + implicit none + + integer,intent(in) ::n,np,partf,partfp,partfm,partfpp + real(kind=8) :: li + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection des blocs + + !N_{m+1}=N_m -1 + !-------------- + if ((np) == (n-1)) then + !si bloc centre + if (blocd(partfm)==0) then + li=dt/pas*vit(partfm) + if ( (li<n) ) then + blocd(partfm)=2 + else + blocd(partfm)=3 + end if + else + blocd(partfm)=3 + end if + if (blocg(partf)==0) then + li=dt/pas*vit(partf) + if ( (li<n) ) then + blocg(partf)=2 + blocd(partf)=4 + else + blocg(partf)=3 + blocd(partf)=5 + end if + else + blocg(partf)=3 + blocd(partf)=5 + end if + blocg(partfp)=4 + blocd(partfp)=1 + li=dt/pas*vit(partfpp) + if ( (blocg(partfpp)==0).and.(li<np) ) then + blocg(partfpp)=5 + else + blocg(partfpp)=6 + end if + end if + !N_{m+1}=N_m +1 + !-------------- + if ((np) == (n+1)) then + li=dt/pas*vit(partfm) + if ( (blocd(partfm)==0).and.(li<n) ) then + blocd(partfm)=6 + else + blocd(partfm)=7 + end if + blocg(partf)=1 + blocd(partf)=8 + if (blocg(partfp)==0) then + li=dt/pas*vit(partfp) + if ( (li<np) ) then + blocg(partfp)=7 + blocd(partfp)=0 + else + blocg(partfp)=8 + blocd(partfp)=1 + end if + else + blocg(partfp)=8 + blocd(partfp)=1 + end if + if (blocg(partfpp)==0) then + li=dt/pas*vit(partfpp) + if ( (li<np) ) then + blocg(partfpp)=9 + else + blocg(partfpp)=10 + end if + else + blocg(partfpp)=10 + end if + + end if + + + + end subroutine sub_remb_4 + + + + function pg(a,b) + implicit none + integer,intent(in) :: a,b + integer :: pg + + select case (esp) + case(1) + pg=numpg(a,b) + case(2) + pg=numpg(b,a) + end select + + end function pg + + function vit(ind) + implicit none + integer,intent(in) :: ind + real(kind=8) :: vit + + select case (esp) + case(1) + vit=vx(ind) + case(2) + vit=vy(ind) + end select + + end function vit + + + end subroutine make_bloc_v2 + + + + + + + +end module utile_mod + + diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/Makefile b/CodesEnVrac/CodesAdrien/split_3d_rapide/Makefile new file mode 100644 index 000000000..17d0e77ef --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/Makefile @@ -0,0 +1,25 @@ +# +# Makefile +# +#Compilateur = ifort +Compilateur = ifort -pg +#Compilateur = ifort -O0 -debug +Programme = split_3d +FILES = donnees_mod.f90 tab_mod.f90 init_mod.f90 remaillage_mod.f90 interpolation_mod.f90 advection_mod.f90 resultats_mod.f90 utile_mod.f90 main.f90 +OBJS = $(patsubst %.f90, %.o, $(FILES)) + +$(Programme): $(OBJS) + @echo edition de liens + @$(Compilateur) $(OBJS) -o $@ + +%.o: %.f90 + @echo compilation de $? + @$(Compilateur) -c $? + +clean: + @rm -f *.o *~ *.mod + @echo nettoyage + +clean_all: + @rm -f *.o *~ *.mod *exe *.out + @echo nettoyage diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/advection_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/advection_mod.f90 new file mode 100644 index 000000000..94667e3ff --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/advection_mod.f90 @@ -0,0 +1,664 @@ +module advection_mod + use donnees_mod + use tab_mod + use remaillage_mod + use interpolation_mod +contains + + subroutine def_v_advec (vitx,vity,vitz,tps) + implicit none + + real(kind=8),intent(in) :: tps + real(kind=8),dimension(1:nx_gro,1:ny_gro,1:nz_gro),intent(out) :: vitx,vity,vitz + integer :: i,j,k + real(kind=8) :: x,y,z,r2,tmp,r,per,t3 + real,dimension(1:nx_gro,1:ny_gro,1:nz_gro) :: tvitx,tvity,tvitz + + + !------------------- + !deformation sphere: + !-------------------- +!!$ do k=1,nz_gro +!!$ z=zd+(k-1)*dz_gro +!!$ do j=1,ny_gro +!!$ y=yb+(j-1)*dy_gro +!!$ do i=1,nx_gro +!!$ x=xg+(i-1)*dx_gro +!!$ +!!$ !t3=0.3 +!!$ !t3=3. +!!$ !t3=1. +!!$ +!!$ if (tps<=1.) then +!!$ vitx(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) !*cos(pi*tps/t3) +!!$ vity(i,j,k)=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) !*cos(pi*tps/t3) +!!$ vitz(i,j,k)=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 !*cos(pi*tps/t3) +!!$ else +!!$ vitx(i,j,k)=-2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) +!!$ vity(i,j,k)=sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) +!!$ vitz(i,j,k)=sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 +!!$ end if +!!$ +!!$ end do +!!$ end do +!!$ end do + + + !---------------------------------- + !deformation sphere: test tps + !---------------------------------- + +!!$ do k=1,nz_gro +!!$ z=zd+(k-1)*dz_gro +!!$ do j=1,ny_gro +!!$ y=yb+(j-1)*dy_gro +!!$ do i=1,nx_gro +!!$ x=xg+(i-1)*dx_gro +!!$ +!!$ +!!$ vitx(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) *cos(2.*pi*tps) +!!$ vity(i,j,k)=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z)*cos(2.*pi*tps) +!!$ vitz(i,j,k)=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2*cos(2.*pi*tps) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ !---------------------------------- +!!$ !deformation sphere: calta +!!$ !---------------------------------- +!!$ +!!$ +!!$ do k=1,nz_gro +!!$ z=zd+(k-1)*dz_gro +!!$ do j=1,ny_gro +!!$ y=yb+(j-1)*dy_gro +!!$ do i=1,nx_gro +!!$ x=xg+(i-1)*dx_gro +!!$ +!!$ !calta: pas à div=0 +!!$ !-------------------- +!!$ !vitx(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)**2*sin(2.*pi*z)**2 *cos(pi*tps/3.) +!!$ !vity(i,j,k)=-sin(2.*pi*x)**2*sin(pi*y)**2*sin(2.*pi*z)**2 *cos(pi*tps/3.) +!!$ !vitz(i,j,k)=-2.*sin(2.*pi*x)**2*sin(2.*pi*y)**2*sin(pi*z)**2 *cos(pi*tps/3.) +!!$ +!!$ +!!$ !Petros + terme en temps +!!$ !------------------------ +!!$ vitx(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) *cos(pi*tps/3.) +!!$ vity(i,j,k)=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) *cos(pi*tps/3.) +!!$ vitz(i,j,k)=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 *cos(pi*tps/3.) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ + !---------------------------------- + !champ turbulent de gh + !---------------------------------- + + + open(20,file='datavelx',form='unformatted',convert='big_endian',status='unknown') + read(20) (((tvitx(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) + close(20) + + open(20,file='datavely',form='unformatted',convert='big_endian',status='unknown') + read(20) (((tvity(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) + close(20) + + open(20,file='datavelz',form='unformatted',convert='big_endian',status='unknown') + read(20) (((tvitz(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) + close(20) + + vitx=tvitx + vity=tvity + vitz=tvitz + + + + end subroutine def_v_advec + + + + + + + subroutine evalv (vitx,vity,vitz,tps,x,y,z) + implicit none + real(kind=8),intent(in) :: tps,x,y,z + real(kind=8),intent(out) :: vitx,vity,vitz + integer :: i,j,k + real(kind=8) :: t3 + + + t3=0.3 + + vitx=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) *cos(pi*tps/t3) + vity=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) *cos(pi*tps/t3) + vitz=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 *cos(pi*tps/t3) + + end subroutine evalv + + + + + + + + subroutine crea_part_x + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff!*maxval(abs(qg)) + npart=0 + numpg=0 + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + if (abs(qg(i,j,k))>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l5(vxg,x,y,z) + !vy(npart)=interpol_v_l5(vyg,x,y,z) + !vz(npart)=interpol_v_l5(vzg,x,y,z) + qp(npart)=qg(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_x + + subroutine crea_part_y + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff!*maxval(abs(qg)) + npart=0 + numpg=0 + do k=1,nz + z=ztab(k) + do i=1,nx + x=xtab(i) + do j=1,ny + y=ytab(j) + + if (abs(qg(i,j,k))>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l5(vxg,x,y,z) + !vy(npart)=interpol_v_l5(vyg,x,y,z) + !vz(npart)=interpol_v_l5(vzg,x,y,z) + qp(npart)=qg(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_y + + subroutine crea_part_z + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff!*maxval(abs(qg)) + npart=0 + numpg=0 + + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + do k=1,nz + z=ztab(k) + + if (abs(qg(i,j,k))>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l5(vxg,x,y,z) + !vy(npart)=interpol_v_l5(vyg,x,y,z) + !vz(npart)=interpol_v_l5(vzg,x,y,z) + qp(npart)=qg(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_z + + + !================== + !TENSORIEL + !================== + + subroutine ad_tenso_euler + implicit none + + integer :: i,j,k + real(kind=8) :: x,y,z + + do i=1,npart + xp(i)=xp(i)+dt*vx(i) + yp(i)=yp(i)+dt*vy(i) + zp(i)=zp(i)+dt*vz(i) + end do + + end subroutine ad_tenso_euler + + subroutine ad_tenso_rk2 + implicit none + integer :: ib + !allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + + !call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx) + !call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy) + !call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz) + + !call interpo_l3_3d(vxg,xp1,yp1,zp1,vx) + !call interpo_l3_3d(vyg,xp1,yp1,zp1,vy) + !call interpo_l3_3d(vzg,xp1,yp1,zp1,vz) + + call interpo_l2_3d(vxg,xp1,yp1,zp1,vx) + call interpo_l2_3d(vyg,xp1,yp1,zp1,vy) + call interpo_l2_3d(vzg,xp1,yp1,zp1,vz) + + do ib=1,npart + xp(ib)=xp(ib)+dt*vx(ib) + yp(ib)=yp(ib)+dt*vy(ib) + zp(ib)=zp(ib)+dt*vz(ib) + end do + + !deallocate(xp1,yp1,zp1) + end subroutine ad_tenso_rk2 + + + subroutine ad_tenso_rk3 + implicit none + integer :: ib + + + !allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp1(1:npart),zp2(1:npart)) + !allocate (vx1(1:npart),vx2(1:npart),vy1(1:npart),vy2(1:npart),vz1(1:npart),vz2(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + + call interpo_l3_3d(vxg,xp1,yp1,zp1,vx1) + call interpo_l3_3d(vyg,xp1,yp1,zp1,vy1) + call interpo_l3_3d(vzg,xp1,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)+2.*vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+2.*vy1(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)+2.*vz1(ib)) + end do + + call interpo_l3_3d(vxg,xp2,yp2,zp2,vx2) + call interpo_l3_3d(vyg,xp2,yp2,zp2,vy2) + call interpo_l3_3d(vzg,xp2,yp2,zp2,vz2) + + do ib=1,npart + xp(ib)=xp(ib)+dt*(vx(ib)/6.+2.*vx1(ib)/3.+vx2(ib)/6.) + yp(ib)=yp(ib)+dt*(vy(ib)/6.+2.*vy1(ib)/3.+vy2(ib)/6.) + zp(ib)=zp(ib)+dt*(vz(ib)/6.+2.*vz1(ib)/3.+vz2(ib)/6.) + end do + + ! deallocate (xp1,xp2,yp1,yp2,zp1,zp2) + ! deallocate (vx1,vx2,vy1,vy2,vz1,vz2) + + + end subroutine ad_tenso_rk3 + + subroutine ad_tenso_rk4 + implicit none + integer :: ib + + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + + call interpo_l4_3d(vxg,xp1,yp1,zp1,vx1) + call interpo_l4_3d(vyg,xp1,yp1,zp1,vy1) + call interpo_l4_3d(vzg,xp1,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+0.5*dt*vx1(ib) + yp2(ib)=yp(ib)+0.5*dt*vy1(ib) + zp2(ib)=zp(ib)+0.5*dt*vz1(ib) + end do + + call interpo_l4_3d(vxg,xp2,yp2,zp2,vx2) + call interpo_l4_3d(vyg,xp2,yp2,zp2,vy2) + call interpo_l4_3d(vzg,xp2,yp2,zp2,vz2) + + do ib=1,npart + xp3(ib)=xp(ib)+dt*vx2(ib) + yp3(ib)=yp(ib)+dt*vy2(ib) + zp3(ib)=zp(ib)+dt*vz2(ib) + end do + + call interpo_l4_3d(vxg,xp3,yp3,zp3,vx3) + call interpo_l4_3d(vyg,xp3,yp3,zp3,vy3) + call interpo_l4_3d(vzg,xp3,yp3,zp3,vz3) + + do ib=1,npart + xp(ib)=xp(ib)+dt*(vx(ib)+2.*vx1(ib)+2.*vx2(ib)+vx3(ib))/6. + yp(ib)=yp(ib)+dt*(vy(ib)+2.*vy1(ib)+2.*vy2(ib)+vy3(ib))/6. + zp(ib)=zp(ib)+dt*(vz(ib)+2.*vz1(ib)+2.*vz2(ib)+vz3(ib))/6. + end do + + + end subroutine ad_tenso_rk4 + + + + subroutine ad_euler_x + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + xp(i)=xp(i)+dt*vx(i) + end do + + end subroutine ad_euler_x + + subroutine ad_euler_y + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + yp(i)=yp(i)+dt*vy(i) + end do + + end subroutine ad_euler_y + + subroutine ad_euler_z + implicit none + + integer :: i + + do i=1,npart + zp(i)=zp(i)+dt*vz(i) + end do + + end subroutine ad_euler_z + + + !=============================== + !SPLITTING + !calcul de la vitesse pour une advection d'euler à l'ordre 2 ou 3 + !=============================== + + subroutine update_vx_2 + implicit none + integer :: ib + + !allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + !call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx) + !call interpo_l3_3d(vxg,xp1,yp1,zp1,vx) + call interpo_l2_3d(vxg,xp1,yp1,zp1,vx) + !deallocate(xp1,yp1,zp1) + end subroutine update_vx_2 + + subroutine update_vy_2 + implicit none + integer :: ib + + !allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)-0.5*dt*vx(ib) + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + !call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy) + !call interpo_l3_3d(vyg,xp1,yp1,zp1,vy) + call interpo_l2_3d(vyg,xp1,yp1,zp1,vy) + !deallocate(xp1,yp1,zp1) + end subroutine update_vy_2 + + subroutine update_vz_2 + implicit none + integer :: ib + + !allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)-0.5*dt*vx(ib) + yp1(ib)=yp(ib)-0.5*dt*vy(ib) + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + !call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz) + !call interpo_l3_3d(vzg,xp1,yp1,zp1,vz) + call interpo_l2_3d(vzg,xp1,yp1,zp1,vz) + !deallocate(xp1,yp1,zp1) + end subroutine update_vz_2 + + + + subroutine update_vx_3 + implicit none + integer :: ib + + + !allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp1(1:npart),zp2(1:npart)) + !allocate (vx1(1:npart),vx2(1:npart),vx3(1:npart),vx4(1:npart),vy1(1:npart),vz1(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+2.*dt*vx(ib)/3. + yp1(ib)=yp(ib)+2.*dt*vy(ib)/3. + zp1(ib)=zp(ib)+2.*dt*vz(ib)/3. + end do + + !call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx1) + !call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy1) + !call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz1) + + call interpo_l3_3d(vxg,xp1,yp1,zp1,vx1) + call interpo_l3_3d(vyg,xp1,yp1,zp1,vy1) + call interpo_l3_3d(vzg,xp1,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)+vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+vy1(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)+vz1(ib)) + end do + + call interpo_l3_3d(vxg,xp2,yp,zp,vx2) + call interpo_l3_3d(vxg,xp,yp2,zp,vx3) + call interpo_l3_3d(vxg,xp,yp,zp2,vx4) + + do ib=1,npart + vx(ib)=-0.5*vx(ib)+3.*vx1(ib)/4.+vx2(ib)/4.+vx3(ib)/4.+vx4(ib)/4. + end do + + !deallocate (xp1,xp2,yp1,yp2,zp1,zp2) + !deallocate (vx1,vx2,vx3,vx4,vy1,vz1) + + + end subroutine update_vx_3 + + subroutine update_vy_3 + implicit none + integer :: ib,i,j + + !allocate (xp0(1:npart),xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp1(1:npart),zp2(1:npart)) + !allocate (vx1(1:npart),vz1(1:npart),vy1(1:npart),vy2(1:npart),vy3(1:npart),vy4(1:npart),vy5(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)-dt*vx(ib)/3. + yp1(ib)=yp(ib)+2.*dt*vy(ib)/3. + zp1(ib)=zp(ib)+2.*dt*vz(ib)/3. + xp0(ib)=xp(ib)-4.*dt*vx(ib)/3. + end do + + !call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx1) + !call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy1) + !call interpo_l3_3d(vyg1,xp0,yp1,zp1,vy2) + !call interpo_l3_3d(vzg1,xp0,yp1,zp1,vz1) + + call interpo_l3_3d(vxg,xp1,yp1,zp1,vx1) + call interpo_l3_3d(vyg,xp1,yp1,zp1,vy1) + call interpo_l3_3d(vyg,xp0,yp1,zp1,vy2) + call interpo_l3_3d(vzg,xp0,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(vx(ib)-2.*vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+vy2(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)/4.+vz1(ib)/4.) + end do + + call interpo_l3_3d(vyg,xp2,yp,zp,vy3) + call interpo_l3_3d(vyg,xp,yp2,zp,vy4) + call interpo_l3_3d(vyg,xp,yp,zp2,vy5) + + do ib=1,npart + vy(ib)=-5.*vy(ib)/4.+3.*vy1(ib)/4.+vy3(ib)/4.+vy4(ib)/4.+vy5(ib) + end do + + + !deallocate (xp0,xp1,xp2,yp1,yp2,zp1,zp2) + !deallocate (vx1,vz1,vy1,vy2,vy3,vy4,vy5) + + end subroutine update_vy_3 + + subroutine update_vz_3 + implicit none + integer :: ib,i,j,k + + !allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp0(1:npart),zp1(1:npart),zp2(1:npart)) + !allocate (vx1(1:npart),vy1(1:npart),vz1(1:npart),vz2(1:npart),vz3(1:npart),vz4(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)-2.*dt*vx(ib)/3. + yp1(ib)=yp(ib)-2.*dt*vy(ib)/3. + zp1(ib)=zp(ib)+dt*vz(ib)/3. + zp0(ib)=zp(ib)+4.*dt*vz(ib)/3. + end do + + !call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz1) + !call interpo_l3_3d(vxg2,xp1,yp1,zp0,vx1) + !call interpo_l3_3d(vyg2,xp1,yp1,zp0,vy1) + + call interpo_l3_3d(vzg,xp1,yp1,zp1,vz1) + call interpo_l3_3d(vxg,xp1,yp1,zp0,vx1) + call interpo_l3_3d(vyg,xp1,yp1,zp0,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)+vx1(ib)) + yp2(ib)=yp(ib)+dt*(vy(ib)-vy1(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)+2.*vz1(ib)) + end do + + call interpo_l3_3d(vzg,xp2,yp,zp,vz2) + call interpo_l3_3d(vzg,xp,yp2,zp,vz3) + !call interpo_l3_3d(vzg3,xp,yp,zp2,vz4) + call interpo_l3_3d(vzg,xp,yp,zp2,vz4) + + do ib=1,npart + vz(ib)=3.*vz1(ib)/4.-vz2(ib)/4.+vz3(ib)/4.+vz4(ib)/4. + end do + + + !deallocate (xp1,xp2,yp1,yp2,zp0,zp1,zp2) + !deallocate (vx1,vy1,vz1,vz2,vz3,vz4) + + end subroutine update_vz_3 + + + + + + !================================== + !STRANG + !================================== + + subroutine update_vx_strang + implicit none + integer :: ib + + !allocate (xp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5*dt*vx(ib) + end do + !call interpo_l2_3d(vxg,xp1,yp,zp,vx) + call interpo_l2_1d_x(vxg,xp1,yp,zp,vx) + !deallocate(xp1) + end subroutine update_vx_strang + + subroutine update_vy_strang + implicit none + integer :: ib + + !allocate (yp1(1:npart)) + do ib=1,npart + yp1(ib)=yp(ib)+0.5*dt*vy(ib) + end do + !call interpo_l2_3d(vyg,xp,yp1,zp,vy) + call interpo_l2_1d_y(vyg,xp,yp1,zp,vy) + !deallocate(yp1) + end subroutine update_vy_strang + + subroutine update_vz_strang + implicit none + integer :: ib + + !allocate (zp1(1:npart)) + do ib=1,npart + zp1(ib)=zp(ib)+0.5*dt*vz(ib) + end do + !call interpo_l2_3d(vzg,xp,yp,zp1,vz) + call interpo_l2_1d_z(vzg,xp,yp,zp1,vz) + !deallocate(zp1) + end subroutine update_vz_strang + + + + + +end module advection_mod + + diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/donnees_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/donnees_mod.f90 new file mode 100644 index 000000000..9a4223ecf --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/donnees_mod.f90 @@ -0,0 +1,10 @@ +module donnees_mod + + integer :: nx,ny,nz,nx_gro,ny_gro,nz_gro,npg,npart,ideb,npart_init,npart_t1 + integer :: kx,ky,kz,type_b,long_bloc + real(kind=8) :: time,dx,dy,dz,dx_gro,dy_gro,dz_gro,xg,xd,yb,yh,zd,zf,dt,tfin,cfl,pi + real(kind=8) :: xdeb,cutoff,dt_sauv + character(len=90) :: nom_fich_vtk,name_err,dossier,nom_fich_tps_cpu + + +end module donnees_mod diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/init_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/init_mod.f90 new file mode 100644 index 000000000..7eb85c85d --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/init_mod.f90 @@ -0,0 +1,89 @@ +module init_mod + ! + !initialisation des valeurs sur la grille + ! +contains + subroutine init_grille + use donnees_mod + use tab_mod + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,r,t2 + + !------------ + !sphere + !------------ +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ y=ytab(j) +!!$ do i=1,nx +!!$ x=xtab(i) +!!$ +!!$ r=sqrt((x-0.35)**2+(y-0.35)**2+(z-0.35)**2) +!!$ qg(i,j,k)=0. +!!$ if (r<=0.15) qg(i,j,k)=1. +!!$ +!!$ end do +!!$ end do +!!$ end do + + +!!$ !---gaussienne sur [0,1]^3------------------------- +!!$ !---------------------------------------------------- +!!$ +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ y=ytab(j) +!!$ do i=1,nx +!!$ x=xtab(i) +!!$ +!!$ qg(i,j,k)=(1.-((x-0.5)**2+(y-0.5)**2+(z-0.5)**2))**6 +!!$ if (((x-0.5)**2+(y-0.5)**2+(z-0.5)**2)>1.) qg(i,j,k)=0. +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ + + +!!$ !------------ +!!$ !cos / sin +!!$ !------------ +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ y=ytab(j) +!!$ do i=1,nx +!!$ x=xtab(i) +!!$ +!!$ t2=0.2 +!!$ qg(i,j,k)=cos(pi*time/t2)*cos(2.*pi*x)*cos(2.*pi*y)*cos(2.*pi*z) +!!$ +!!$ end do +!!$ end do +!!$ end do + + + !------------ + !test + !------------ + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + qg(i,j,k)=1. + + end do + end do + end do + + end subroutine init_grille + + + +end module init_mod diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/interpolation_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/interpolation_mod.f90 new file mode 100644 index 000000000..7e24e74ed --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/interpolation_mod.f90 @@ -0,0 +1,883 @@ +module interpolation_mod + use donnees_mod + contains + + subroutine interpo_l4_3d(tab_grille,posx,posy,posz,tab_part) + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb + integer,dimension(0:5) :: ip,jp,kp + real(kind=8),dimension(0:5) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,y2,y3,y4,z2,z3,z4 + + tab_part(1:npart)=0. + + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + kp(2) = floor((posz(i)-zd)/dz) + kp(0) = kp(2) - 2 + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + kp(5) = kp(2) + 3 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + if (yy1<=0.5) then + poidy(0)=(2.*yy1-y2-2*y3+y4)/24. + poidy(1)=(-4.*yy1+4.*y2+y3-y4)/6. + poidy(2)=1.+(-5.*y2+y4)/4. + poidy(3)=(4.*yy1+4.*y2-y3-y4)/6. + poidy(4)=(-2.*yy1-y2+2*y3+y4)/24. + poidy(5)=0. + else + poidy(0)=0. + poidy(1)=(-6.*yy1+11.*y2-6.*y3+y4)/24. + poidy(2)=1.+(-5.*yy1-5.*y2+5.*y3-y4)/6. + poidy(3)=(6.*yy1+y2-4.*y3+y4)/4. + poidy(4)=(-3.*yy1+y2+3.*y3-y4)/6. + poidy(5)=(2.*yy1-y2-2.*y3+y4)/24. + end if + if (zz1<=0.5) then + poidz(0)=(2.*zz1-z2-2*z3+z4)/24. + poidz(1)=(-4.*zz1+4.*z2+z3-z4)/6. + poidz(2)=1.+(-5.*z2+z4)/4. + poidz(3)=(4.*zz1+4.*z2-z3-z4)/6. + poidz(4)=(-2.*zz1-z2+2*z3+z4)/24. + poidz(5)=0. + else + poidz(0)=0. + poidz(1)=(-6.*zz1+11.*z2-6.*z3+z4)/24. + poidz(2)=1.+(-5.*zz1-5.*z2+5.*z3-z4)/6. + poidz(3)=(6.*zz1+z2-4.*z3+z4)/4. + poidz(4)=(-3.*zz1+z2+3.*z3-z4)/6. + poidz(5)=(2.*zz1-z2-2.*z3+z4)/24. + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,5 + do d=0,5 + do c=0,5 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine interpo_l4_3d + + subroutine interpo_l3_3d(tab_grille,posx,posy,posz,tab_part) + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb + integer,dimension(0:3) :: ip,jp,kp + real(kind=8),dimension(0:3) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + kp(1) = floor((posz(i)-zd)/dz_gro) + kp(0) = kp(1) - 1 + kp(2) = kp(1) + 1 + kp(3) = kp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro + zz1 = (posz(i) - real(kp(1),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + + do c=0,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=0,3 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + poidy(0)=-1./6.*yy1*(yy1-1.)*(yy1-2.) + poidy(1)=0.5*(1.-yy1)*(1.+yy1)*(2.-yy1) + poidy(2)=-0.5*yy1*(yy1+1.)*(yy1-2.) + poidy(3)=1/6.*yy1*(1.+yy1)*(yy1-1.) + + poidz(0)=-1./6.*zz1*(zz1-1.)*(zz1-2.) + poidz(1)=0.5*(1.-zz1)*(1.+zz1)*(2.-zz1) + poidz(2)=-0.5*zz1*(zz1+1.)*(zz1-2.) + poidz(3)=1/6.*zz1*(1.+zz1)*(zz1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,3 + do d=0,3 + do c=0,3 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine interpo_l3_3d + + + subroutine interpo_l2_3d(tab_grille,posx,posy,posz,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb,kb,e + integer,dimension(0:2) :: ip,jp,kp + real(kind=8),dimension(0:2) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + + kp(1) = floor((posz(i)-zd)/dz_gro) + kp(0) = kp(1) - 1 + kp(2) = kp(1) + 1 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro !relatif + zz1 = (posz(i) - real(kp(1),kind=8)*dz_gro-zd)/dz_gro !relatif + + !conditions au bord + !------------------ + !periodique: + do c=0,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=0,2 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=0.5*xx1*(xx1-1.) + poidx(1)=1.-xx1**2 + poidx(2)=0.5*xx1*(1.+xx1) + + poidy(0)=0.5*yy1*(yy1-1.) + poidy(1)=1.-yy1**2 + poidy(2)=0.5*yy1*(1.+yy1) + + poidz(0)=0.5*zz1*(zz1-1.) + poidz(1)=1.-zz1**2 + poidz(2)=0.5*zz1*(1.+zz1) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,2 + do d=0,2 + do e=0,2 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine interpo_l2_3d + + subroutine interpo_l1_3d(tab_grille,posx,posy,posz,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,ib,jb,kb,e + integer,dimension(1:2) :: ip,jp,kp + real(kind=8),dimension(1:2) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1 + + tab_part=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(2) = ip(1) + 1 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(2) = jp(1) + 1 + + kp(1) = floor((posz(i)-zd)/dz_gro) + kp(2) = kp(1) + 1 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro !relatif + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro !relatif + zz1 = (posz(i) - real(kp(1),kind=8)*dz_gro-zd)/dz_gro !relatif + + !conditions au bord + !------------------ + !periodique: + do c=1,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=1,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=1,2 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(1)=1.-xx1 + poidx(2)=xx1 + + poidy(1)=1.-yy1 + poidy(2)=yy1 + + poidz(1)=1.-zz1 + poidz(2)=zz1 + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=1,2 + do d=1,2 + do e=1,2 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine interpo_l1_3d + + + + subroutine interpo_l2_1d_x(tab_grille,posx,posy,posz,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + tab_part(1:npart)=0. + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-1,2 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jvar,kvar)*poidx(c) + end do + + end do + + end subroutine interpo_l2_1d_x + + subroutine interpo_l2_1d_y(tab_grille,posx,posy,posz,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + tab_part(1:npart)=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-1,2 + tab_part(i)=tab_part(i)+tab_grille(ivar,ip(c)+1,kvar)*poidx(c) + end do + + end do + + end subroutine interpo_l2_1d_y + + subroutine interpo_l2_1d_z(tab_grille,posx,posy,posz,tab_part) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + tab_part(1:npart)=0. + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-1,2 + tab_part(i)=tab_part(i)+tab_grille(ivar,jvar,ip(c)+1)*poidx(c) + end do + + end do + + end subroutine interpo_l2_1d_z + + + + !=========================================================================== + !pour interpoler le champ de vitesse de la grille grossiere à la grille fine + !=========================================================================== + + + function interpol_v_l1(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(0:1) :: ip,jp,kp + real(kind=8),dimension(0:1) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(1) = ip(0)+1 + + jp(0) = floor((posy-yb)/dy_gro) + jp(1) = jp(0)+1 + + kp(0) = floor((posz-zd)/dz_gro) + kp(1) = kp(0)+1 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=0,1 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,1 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=0,1 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=1.-xx + poidx(1)=xx + + poidy(0)=1.-yy + poidy(1)=yy + + poidz(0)=1.-zz + poidz(1)=zz + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,1 + do c=0,1 + do d=0,1 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + + end function interpol_v_l1 + + function interpol_v_l3(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(-1:2) :: ip,jp,kp + real(kind=8),dimension(-1:2) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + + kp(0) = floor((posz-zd)/dz_gro) + kp(-1) = kp(0)-1 + kp(1) = kp(0)+1 + kp(2) = kp(0)+2 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-1,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=-1,2 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(-1)=-1./6.*xx*(xx-1.)*(xx-2.) + poidx(0)=0.5*(1.-xx)*(1.+xx)*(2.-xx) + poidx(1)=-0.5*xx*(xx+1.)*(xx-2.) + poidx(2)=1/6.*xx*(1.+xx)*(xx-1.) + + poidy(-1)=-1./6.*yy*(yy-1.)*(yy-2.) + poidy(0)=0.5*(1.-yy)*(1.+yy)*(2.-yy) + poidy(1)=-0.5*yy*(yy+1.)*(yy-2.) + poidy(2)=1/6.*yy*(1.+yy)*(yy-1.) + + poidz(-1)=-1./6.*zz*(zz-1.)*(zz-2.) + poidz(0)=0.5*(1.-zz)*(1.+zz)*(2.-zz) + poidz(1)=-0.5*zz*(zz+1.)*(zz-2.) + poidz(2)=1/6.*zz*(1.+zz)*(zz-1.) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-1,2 + do c=-1,2 + do d=-1,2 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidy(e) + end do + end do + end do + + end function interpol_v_l3 + + function interpol_v_l5(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(-2:3) :: ip,jp,kp + real(kind=8),dimension(-2:3) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + real(kind=8) :: x2,x3,x4,x5,y2,y3,y4,y5 + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-2) = ip(0)-2 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + ip(3) = ip(0)+3 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-2) = jp(0)-2 + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + jp(3) = jp(0)+3 + + kp(0) = floor((posz-zd)/dz_gro) + kp(-2) = kp(0)-2 + kp(-1) = kp(0)-1 + kp(1) = kp(0)+1 + kp(2) = kp(0)+2 + kp(3) = kp(0)+3 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=-2,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-2,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=-2,3 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + x2=xx**2 + x3=xx**3 + x4=xx**4 + x5=xx**5 + y2=yy**2 + y3=yy**3 + y4=yy**4 + y5=yy**5 + + poidx(-2)=xx/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(-1)=-xx/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(0)=1.-xx/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(1)=xx+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(2)=-xx/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(3)=xx/30.-x3/24.+x5/120. + + poidy(-2)=yy/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(-1)=-yy/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(0)=1.-yy/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(1)=yy+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(2)=-yy/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(3)=yy/30.-y3/24.+y5/120. + + poidz(-2)=zz/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidz(-1)=-zz/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidz(0)=1.-zz/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidz(1)=zz+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidz(2)=-zz/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidz(3)=zz/30.-y3/24.+y5/120. + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-2,3 + do c=-2,3 + do d=-2,3 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + + end function interpol_v_l5 + + + + + end module interpolation_mod diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/main.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/main.f90 new file mode 100644 index 000000000..87be5adbe --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/main.f90 @@ -0,0 +1,706 @@ +program split + !-------------------------------------------------------------------------- + !etude de l'ordre pour splitting 3D + ! + !-------------------------------------------------------------------------- + use donnees_mod ! donnees + use tab_mod ! donnees dans tableaux + use init_mod ! init_grille + use advection_mod ! crea_part,advection + use remaillage_mod ! remaill_4m_centre (formules de remaillage) + use interpolation_mod ! formules d'interpolation (pour range kutta) + use resultats_mod ! res_grille_tps,res_grille_freq + use utile_mod + + + real(kind=8) :: x,y + integer :: n + real(kind=8) :: time1,time2,time3,time4,dt_deb,maxv + + !pour test + integer :: c,i,j,cpt_ite,ib,jb,k,cpt,nx_boucle + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8,t9,tmp,dt_boucle,r,grad,div + + + !lecture données + !--------------- + open(unit=10,file="parameter",form="formatted") + read(10,*) xg,xd,yb,yh,zd,zf + read(10,*) tfin + read(10,*) cutoff + read(10,*) type_b + read(10,*) long_bloc + read(10,*) nom_fich_vtk + read(10,*) name_err + read(10,*) dossier + read(10,*) nom_fich_tps_cpu + close(10) + + + name_err=trim(name_err) + + call cpu_time(t1) + + erreur:do nx_boucle=129,129 + + open(unit=10,file="parameter",form="formatted") + read(10,*) xg,xd,yb,yh,zd,zf + close (10) + + nx=nx_boucle + ny=nx_boucle + nz=nx_boucle + + nx_gro=nx + ny_gro=nx_gro + nz_gro=nx_gro + + dx=(xd-xg)/(nx-1.) + dy=(yh-yb)/(ny-1.) + dz=(zf-zd)/(nz-1.) + + dx_gro=(xd-xg)/(nx_gro-1.) + dy_gro=(yh-yb)/(ny_gro-1.) + dz_gro=(zf-zd)/(nz_gro-1.) + + + maxv=2. + !maxv=3.3 + !maxv=1. + cfl=0.4 + !cfl=5. + !cfl=14. + !cfl=4. +! cfl=8. + + !cfl=2.*0.025252525252525/dx! cfl5 + !cfl=2.*0.02424242520573163/dx !cfl 4.8 + + + + !print*,"cfl=",cfl + + dt=cfl*dx/maxv +! dt=2./150. + + dt=0.049 + + print*,"dt",dt + + ! + !calcul init + !----------- + cpt_ite=0 + time=0. + + + npart=nx*ny*nz + + + xd=xd-1./nx !pour conditions periodiques + yh=yh-1./ny + zf=zf-1./nz + + nx=nx-1 + ny=ny-1 + nz=nz-1 + + nx_gro=nx_gro-1 + ny_gro=ny_gro-1 + nz_gro=nz_gro-1 + + + pi=4.*atan(1.) + + ! + !alloc tableaux + !-------------- + call alloc_sub + + open(unit=29,file=name_err,form="formatted") + call cpu_time(t2) + + ! + !initialisation + !-------------- + call make_grille + call init_grille() + + cutoff=cutoff*maxval(abs(qg)) + + + !============================= + !champ de vitesse + !============================= + call def_v_advec (vxg,vyg,vzg,time) + + + ! + !boucle temps + !------------ + temps: do while(time<tfin) + + !print*,"cflmax:",dt*max(maxval(vxg),maxval(vyg),maxval(vzg))/dx + + !if ((time+dt)>tfin) dt=tfin-time + + if (time<=2.*dt) dt_deb=dt + + + call crea_part_x() + + if (time<dt) npart_init=npart + if ((time<=1.).and.(time+dt>1.)) npart_t1=npart + + + !================================ + !si remaillage tenso en espace + !================================ + +!!$ !RK2 +!!$ !allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) +!!$ !call def_v_advec (vxg1,vyg1,vzg1,time+0.5*dt) +!!$ +!!$ !RK3 +!!$ !allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) +!!$ !allocate(vxg2(1:nx_gro,1:ny_gro,1:nz_gro),vyg2(1:nx_gro,1:ny_gro,1:nz_gro),vzg2(1:nx_gro,1:ny_gro,1:nz_gro)) +!!$ !call def_v_advec (vxg1,vyg1,vzg1,time+0.5*dt) +!!$ !call def_v_advec (vxg2,vyg2,vzg2,time+dt) +!!$ +!!$ +!!$ !t source:rk4 +!!$ !------------ +!!$ !call source_rk4 +!!$ +!!$ !advection +!!$ !--------- +!!$ !call ad_tenso_euler +!!$ call ad_tenso_rk2 +!!$ !call ad_tenso_rk3 +!!$ !call ad_tenso_rk4 +!!$ +!!$ !remaillage +!!$ !---------- +!!$ call remaill_l2(qp,xp,yp,zp,qg) +!!$ !call remaill_l3(qp,xp,yp,zp,qg) +!!$ !call remaill_l4(qp,xp,yp,zp,qg) +!!$ !call remaill_l6(qp,xp,yp,zp,qg) +!!$ !call remaill_l8(qp,xp,yp,zp,qg) +!!$ !call remaill_mp4(qp,xp,yp,zp,qg) +!!$ +!!$ !deallocate(vxg1,vyg1,vzg1) +!!$ !deallocate(vxg2,vyg2,vzg2) +!!$ + + !===================== + !splitting en espace + !===================== +!!$ + !RK2 + !allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) + !call def_v_advec (vxg1,vyg1,vzg1,time +0.5*dt) + !vxg1=vxg + !vyg1=vyg + !vzg1=vzg + + !RK3 + !allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) + !allocate(vxg2(1:nx_gro,1:ny_gro,1:nz_gro),vyg2(1:nx_gro,1:ny_gro,1:nz_gro),vzg2(1:nx_gro,1:ny_gro,1:nz_gro)) + !allocate(vxg3(1:nx_gro,1:ny_gro,1:nz_gro),vyg3(1:nx_gro,1:ny_gro,1:nz_gro),vzg3(1:nx_gro,1:ny_gro,1:nz_gro)) + !call def_v_advec (vxg1,vyg1,vzg1,time+2.*dt/3.) + + + !t source + !--------- + !call source_split_1 + + !test v + !------- + !print*,"vmax grille",max(maxval(abs(vxg)),maxval(abs(vyg)),maxval(abs(vzg))) + !print*,"vmax interpole",max(maxval(abs(vx)),maxval(abs(vy)),maxval(abs(vz))) + + + !update v + !-------- + !call update_vx_2 + !call update_vx_3 + + !print*,"vmax interpole rk2",max(maxval(abs(vx)),maxval(abs(vy)),maxval(abs(vz))) + !stop + + !test cfl + !======== + !print*,"test cfl en x " + !print*,"cfl,cflpart en x",dt/dx*maxval(abs(vxg)),dt/dx*maxval(abs(vx)) +! ainf=0. +! do k=1,nz +! do j=1,ny +! do i=1,nx-1 +! if ( (numpg(i+1,j,k)/=0).and.(numpg(i,j,k)/=0) ) ainf=max(ainf,abs(vx(numpg(i+1,j,k))-vx(numpg(i,j,k)))) +! end do +! end do +! end do +! if (dt>(0.5*dx/(ainf))) then +! print*,"" +! print*,"cfl l2 viole" ,dt,0.5*dx/(ainf),0.5*dx/(2.*ainf) +! print*,"" +! end if +! if (dt>(0.5*dx/(2.*ainf))) then +! print*,"" +! print*,"cfl l4 viole" ,dt,0.5*dx/(ainf),0.5*dx/(2.*ainf) +! print*,"" +! end if +! if (dt>(0.5*dx/(3.*ainf))) then +! print*,"" +! print*,"cfl l4 papier viole" ,dt,0.5*dx/(2.*ainf),0.5*dx/(3.*ainf) +! print*,"" +! end if + !fin test + !-------- + + + !bloc x + !------- + !call make_bloc(1) + call make_bloc_v2(1) + !blocg=0 + !blocd=0 + + !advection + !---------- + call ad_euler_x + + + !remaillage + !---------- + if (type_b==200) call remaill_l2_x(qp,xp,yp,zp,qg) + if (type_b==400) call remaill_l4_x(qp,xp,yp,zp,qg) + !call remaill_l5_x(qp,xp,yp,zp,qg) + if (type_b==600) call remaill_l6_x(qp,xp,yp,zp,qg) + !call remaill_l8_x(qp,xp,yp,zp,qg) + if (type_b==2) call remaill_l2_bloc_x_v2(qp,xp,yp,zp,qg) + if (type_b==4) call remaill_l4_bloc_x_v2(qp,xp,yp,zp,qg) + if (type_b==20) call limit_l2_bloc_x(qp,xp,yp,zp,qg) + + !contrainte cfl + !-------------- + ! grad=0. + ! do k=1,nz_gro + ! do j=1,ny_gro + ! do i=1,nx_gro-1 + ! if ((numpg(i+1,j,k)/=0).and.(numpg(i,j,k)/=0)) grad=max(grad,abs(vx(numpg(i+1,j,k))-vx(numpg(i,j,k)))/dx) + ! end do + ! end do + ! end do + + + + + !y + !-- + call crea_part_y() + !call crea_part_x() + + + !update v + !-------- + !call update_vy_2 + !call update_vy_3 + + !bloc y + !------- + !call make_bloc(2) + call make_bloc_v2(2) + !blocg=0 + !blocd=0 + + !advection + !---------- + call ad_euler_y + !remaillage + !---------- + if (type_b==200) call remaill_l2_y(qp,xp,yp,zp,qg) + if (type_b==400) call remaill_l4_y(qp,xp,yp,zp,qg) + !call remaill_l5_y(qp,xp,yp,zp,qg) + if (type_b==600) call remaill_l6_y(qp,xp,yp,zp,qg) + !call remaill_l8_y(qp,xp,yp,zp,qg) + if (type_b==2)call remaill_l2_bloc_y_v2(qp,xp,yp,zp,qg) + if (type_b==4)call remaill_l4_bloc_y_v2(qp,xp,yp,zp,qg) + if (type_b==20) call limit_l2_bloc_y(qp,xp,yp,zp,qg) + + !contrainte cfl + !-------------- + ! do k=1,nz_gro + ! do j=1,ny_gro-1 + ! do i=1,nx_gro + ! if ((numpg(i,j+1,k)/=0).and.(numpg(i,j,k)/=0)) grad=max(grad,abs(vy(numpg(i,j+1,k))-vy(numpg(i,j,k)))/dy) + ! end do + ! end do + ! end do + + + + !z + !-- + call crea_part_z() + !call crea_part_x() + + !update v + !-------- + !call update_vz_2 + !call update_vz_3 + + !call def_v_advec (vxg1,vyg1,vzg1,time+dt/3.) + !call def_v_advec (vxg2,vyg2,vzg2,time+4.*dt/3.) + !call def_v_advec (vxg3,vyg3,vzg3,time+dt) + !call update_vz_3 + + !bloc z + !------- + !call make_bloc(3) + call make_bloc_v2(3) + !blocg=0 + !blocd=0 + + !advection + !---------- + call ad_euler_z + + !remaillage + !---------- + if (type_b==200) call remaill_l2_z(qp,xp,yp,zp,qg) + if (type_b==400) call remaill_l4_z(qp,xp,yp,zp,qg) + !call remaill_l5_z(qp,xp,yp,zp,qg) + if (type_b==600) call remaill_l6_z(qp,xp,yp,zp,qg) + !call remaill_l8_z(qp,xp,yp,zp,qg) + if (type_b==2)call remaill_l2_bloc_z_v2(qp,xp,yp,zp,qg) + if (type_b==4)call remaill_l4_bloc_z_v2(qp,xp,yp,zp,qg) + if (type_b==20) call limit_l2_bloc_z(qp,xp,yp,zp,qg) + + !contrainte cfl + !-------------- + ! do k=1,nz_gro-1 + ! do j=1,ny_gro + ! do i=1,nx_gro + ! if ((numpg(i,j,k+1)/=0).and.(numpg(i,j,k)/=0)) grad=max(grad,abs(vz(numpg(i,j,k+1))-vz(numpg(i,j,k)))/dz) + ! end do + ! end do + ! end do + + ! print*,"t=0,dt,1/(4.*grad),1/(6.*grad)" + ! print*,"(vitesse sur part)" + ! print*,dt,1./(4.*grad),1./(6.*grad) + + + !t source + !--------- + !call source_split_2 + + + !deallocate(vxg1,vyg1,vzg1) + !deallocate(vxg2,vyg2,vzg2) + !deallocate(vxg3,vyg3,vzg3) + + + + + !================= + !splitting strang + !================= + +!!$ !allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) +!!$ !call def_v_advec (vxg1,vyg1,vzg1,time+0.5*dt) +!!$ +!!$ !t source +!!$ !-------- +!!$ !call source_split_1 +!!$ +!!$ dt_sauv=dt +!!$ dt=0.5*dt +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_strang +!!$ +!!$ +!!$ !bloc x +!!$ !------- +!!$ !call make_bloc_v2(1) +!!$ !blocg=0 +!!$ !blocd=0 +!!$ +!!$ +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !if (type_b==2)call remaill_l2_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ !call remaill_l2_x(qp,xp,yp,zp,qg) +!!$ call remaill_l4_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l5_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l6_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l8_x(qp,xp,yp,zp,qg) +!!$ +!!$ !y +!!$ !-- +!!$ call crea_part_y() +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_strang +!!$ +!!$ !bloc y +!!$ !------- +!!$ !call make_bloc_v2(2) +!!$ !blocg=0 +!!$ !blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !if (type_b==2)call remaill_l2_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ !call remaill_l2_y(qp,xp,yp,zp,qg) +!!$ call remaill_l4_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l5_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l6_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l8_y(qp,xp,yp,zp,qg) +!!$ +!!$ +!!$ !z +!!$ !-- +!!$ call crea_part_z() +!!$ +!!$ dt=dt_sauv +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vz_strang +!!$ +!!$ !bloc y +!!$ !------- +!!$ !call make_bloc_v2(3) +!!$ !blocg=0 +!!$ !blocd=0 +!!$ +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_z +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !if (type_b==2)call remaill_l2_bloc_z_v2(qp,xp,yp,zp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_z_v2(qp,xp,yp,zp,qg) +!!$ !call remaill_l2_z(qp,xp,yp,zp,qg) +!!$ call remaill_l4_z(qp,xp,yp,zp,qg) +!!$ !call remaill_l5_z(qp,xp,yp,zp,qg) +!!$ !call remaill_l6_z(qp,xp,yp,zp,qg) +!!$ !call remaill_l8_z(qp,xp,yp,zp,qg) +!!$ +!!$ +!!$ !y +!!$ !-- +!!$ call crea_part_y() +!!$ dt=0.5*dt +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_strang +!!$ +!!$ !bloc y +!!$ !------- +!!$ !call make_bloc_v2(2) +!!$ !blocg=0 +!!$ !blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !if (type_b==2)call remaill_l2_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ !call remaill_l2_y(qp,xp,yp,zp,qg) +!!$ call remaill_l4_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l5_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l6_y(qp,xp,yp,zp,qg) +!!$ !call remaill_l8_y(qp,xp,yp,zp,qg) +!!$ +!!$ +!!$ !x +!!$ !-- +!!$ call crea_part_x() +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_strang +!!$ +!!$ !bloc x +!!$ !------- +!!$ !call make_bloc_v2(1) +!!$ !blocg=0 +!!$ !blocd=0 +!!$ +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !if (type_b==2)call remaill_l2_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ !if (type_b==4)call remaill_l4_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ !call remaill_l2_x(qp,xp,yp,zp,qg) +!!$ call remaill_l4_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l5_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l6_x(qp,xp,yp,zp,qg) +!!$ !call remaill_l8_x(qp,xp,yp,zp,qg) +!!$ +!!$ +!!$ dt=dt_sauv +!!$ +!!$ !t source +!!$ !-------- +!!$ !call source_split_2 +!!$ +!!$ !deallocate(vxg1,vyg1,vzg1) + + + + + + + !========================== + !splitting additif ordre 1 + !=========================== +!!$ +!!$ !bloc x +!!$ !------- +!!$ call make_bloc_v2(1) +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_x(qp,xp,yp,zp,qg) +!!$ if (type_b==2)call remaill_l2_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ if (type_b==4)call remaill_l4_bloc_x_v2(qp,xp,yp,zp,qg) +!!$ +!!$ !y +!!$ !-- +!!$ call crea_part_y() +!!$ +!!$ !bloc y +!!$ !------- +!!$ call make_bloc_v2(2) +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_y(qp,xp,yp,zp,qg) +!!$ if (type_b==2)call remaill_l2_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ if (type_b==4)call remaill_l4_bloc_y_v2(qp,xp,yp,zp,qg) +!!$ +!!$ +!!$ !z +!!$ !-- +!!$ call crea_part_z() +!!$ +!!$ !bloc y +!!$ !------- +!!$ call make_bloc_v2(3) +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_z +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_z(qp,xp,yp,zp,qg) +!!$ if (type_b==2)call remaill_l2_bloc_z_v2(qp,xp,yp,zp,qg) +!!$ if (type_b==4)call remaill_l4_bloc_z_v2(qp,xp,yp,zp,qg) + + + + + + + ! write(29,'(3(e18.10,2x))') time,minval(qg),maxval(qg) + + + + time=time+dt + cpt_ite=cpt_ite+1 + + + + + + end do temps + + + + ! write(29,'(4(e18.10,2x))') dt_deb,dx,dx*dy*dz*sum(abs(exa-qg)),sqrt(dx*dy*dz*sum((exa-qg)**2)) + + + end do erreur + + call cpu_time(t3) + + !resultat final + !-------------- + print*,"tps final",time + print*,"nbre d'ite",cpt_ite + print*,"nart final",npart + print*,"dt,dt_fin,dx,dy,dz",dt_deb,dt,dx,dy,dz + print*,"temps cpu",nom_fich_vtk,t3-t1,t3-t2 + + + + call res_vtk_q(trim(dossier)//trim(nom_fich_vtk)) + !call res_vtk("RES/vtk/"//nom_fich_vtk) + + open(unit=10,file=trim(dossier)//"tps/"//trim(nom_fich_tps_cpu),form="formatted") + write(10,*) t3-t1,t3-t2 + write(10,*) npart_init,npart_t1,npart + + ! + !dealloc fermeture + !----------------- + close(50) + close(51) + close(52) + close(53) + close(66) + close(67) + close(10) + close(29) + + deallocate (xp,qp,vx,vy,yp,zp,vz) + deallocate (qg,vxg,vyg,vzg) + deallocate (xtab,ytab,ztab) + deallocate (xp1,yp1,zp1) + deallocate (xp2,yp2,zp2) + deallocate (xp3,yp3,zp3) + deallocate (numpg,blocg,blocd,Nbloc) + !deallocate (exa) + + +end program split + + + diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/parameter b/CodesEnVrac/CodesAdrien/split_3d_rapide/parameter new file mode 100644 index 000000000..07a0d9f7f --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/parameter @@ -0,0 +1,9 @@ +0. 1. 0. 1. 0. 1. ! xg xd yb yh zd zf +0.0001 ! TFin +0. 0.0001 0.0001 0.1 !cutoff +4 ! type bloc +3 !longeur bloc +"vtk/test_o1_long_b_3.vtk" ! sortie fin vtk +"RES/test.er" ! fichier erreur +"/users/these/magni/parmes/trunk/Remesh/split_3d_rapide/RES/" "/home/magni/split_3d_rapide/" "RES/vtk/" !dossier +"test.tps" ! fichier tps cpu \ No newline at end of file diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/remaillage_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/remaillage_mod.f90 new file mode 100644 index 000000000..41f2f0647 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/remaillage_mod.f90 @@ -0,0 +1,4938 @@ +module remaillage_mod + use donnees_mod + use tab_mod +contains + + subroutine remaill_l2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(1:4) :: ip,jp,kp + real(kind=8),dimension(1:4) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + + jp(2) = floor((posy(i)-yb)/dy) + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + + kp(2) = floor((posz(i)-zd)/dz) + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=1,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=1,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=1,4 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx1<=0.5) then + + poidx(1)=-0.5*xx1*(1.-xx1) + poidx(2)=1.-xx1**2 + poidx(3)=0.5*xx1*(1.+xx1) + poidx(4)=0. + + else + + poidx(1)=0. + poidx(2)=0.5*(xx1-1.)*(xx1-2.) + poidx(3)=xx1*(2.-xx1) + poidx(4)=0.5*xx1*(xx1-1.) + + end if + + if (yy1<=0.5) then + + poidy(1)=-0.5*yy1*(1.-yy1) + poidy(2)=1.-yy1**2 + poidy(3)=0.5*yy1*(1.+yy1) + poidy(4)=0. + + else + + poidy(1)=0. + poidy(2)=0.5*(yy1-1.)*(yy1-2.) + poidy(3)=yy1*(2.-yy1) + poidy(4)=0.5*yy1*(yy1-1.) + + end if + + if (zz1<=0.5) then + + poidz(1)=-0.5*zz1*(1.-zz1) + poidz(2)=1.-zz1**2 + poidz(3)=0.5*zz1*(1.+zz1) + poidz(4)=0. + + else + + poidz(1)=0. + poidz(2)=0.5*(zz1-1.)*(zz1-2.) + poidz(3)=zz1*(2.-zz1) + poidz(4)=0.5*zz1*(zz1-1.) + + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=1,4 + do d=1,4 + do c=1,4 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l2 + + subroutine remaill_l3 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:3) :: ip,jp,kp + real(kind=8),dimension(0:3) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + kp(1) = floor((posz(i)-zd)/dz) + kp(0) = kp(1) - 1 + kp(2) = kp(1) + 1 + kp(3) = kp(1) + 2 + + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(1),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,3 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + poidy(0)=-1./6.*yy1*(yy1-1.)*(yy1-2.) + poidy(1)=0.5*(1.-yy1)*(1.+yy1)*(2.-yy1) + poidy(2)=-0.5*yy1*(yy1+1.)*(yy1-2.) + poidy(3)=1/6.*yy1*(1.+yy1)*(yy1-1.) + + poidz(0)=-1./6.*zz1*(zz1-1.)*(zz1-2.) + poidz(1)=0.5*(1.-zz1)*(1.+zz1)*(2.-zz1) + poidz(2)=-0.5*zz1*(zz1+1.)*(zz1-2.) + poidz(3)=1/6.*zz1*(1.+zz1)*(zz1-1.) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,3 + do d=0,3 + do c=0,3 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l3 + + subroutine remaill_mp4 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:3) :: ip,jp,kp + real(kind=8),dimension(0:3) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + + kp(1) = floor((posz(i)-zd)/dz) + kp(0) = kp(1) - 1 + kp(2) = kp(1) + 1 + kp(3) = kp(1) + 2 + + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(1),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(1),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,3 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + poidx(0)=-0.5*xx1+x2-0.5*x3 + poidx(1)=1-5./2.*x2+3.*0.5*x3 + poidx(2)=0.5*xx1+2.*x2-3.*0.5*x3 + poidx(3)=-0.5*x2+0.5*x3 + + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + poidy(0)=-0.5*yy1+y2-0.5*y3 + poidy(1)=1-5./2.*y2+3.*0.5*y3 + poidy(2)=0.5*yy1+2.*y2-3.*0.5*y3 + poidy(3)=-0.5*y2+0.5*y3 + + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + z5=zz1**5 + poidz(0)=-0.5*zz1+z2-0.5*z3 + poidz(1)=1-5./2.*z2+3.*0.5*z3 + poidz(2)=0.5*zz1+2.*z2-3.*0.5*z3 + poidz(3)=-0.5*z2+0.5*z3 + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,3 + do d=0,3 + do c=0,3 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_mp4 + + subroutine remaill_l4 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:5) :: ip,jp,kp + real(kind=8),dimension(0:5) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + kp(2) = floor((posz(i)-zd)/dz) + kp(0) = kp(2) - 2 + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + kp(5) = kp(2) + 3 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + + if (xx1<=0.5) then + poidx(0)=(2.*xx1-x2-2*x3+x4)/24. + poidx(1)=(-4.*xx1+4.*x2+x3-x4)/6. + poidx(2)=1.+(-5.*x2+x4)/4. + poidx(3)=(4.*xx1+4.*x2-x3-x4)/6. + poidx(4)=(-2.*xx1-x2+2*x3+x4)/24. + poidx(5)=0. + else + poidx(0)=0. + poidx(1)=(-6.*xx1+11.*x2-6.*x3+x4)/24. + poidx(2)=1.+(-5.*xx1-5.*x2+5.*x3-x4)/6. + poidx(3)=(6.*xx1+x2-4.*x3+x4)/4. + poidx(4)=(-3.*xx1+x2+3.*x3-x4)/6. + poidx(5)=(2.*xx1-x2-2.*x3+x4)/24. + end if + + if (yy1<=0.5) then + poidy(0)=(2.*yy1-y2-2*y3+y4)/24. + poidy(1)=(-4.*yy1+4.*y2+y3-y4)/6. + poidy(2)=1.+(-5.*y2+y4)/4. + poidy(3)=(4.*yy1+4.*y2-y3-y4)/6. + poidy(4)=(-2.*yy1-y2+2*y3+y4)/24. + poidy(5)=0. + else + poidy(0)=0. + poidy(1)=(-6.*yy1+11.*y2-6.*y3+y4)/24. + poidy(2)=1.+(-5.*yy1-5.*y2+5.*y3-y4)/6. + poidy(3)=(6.*yy1+y2-4.*y3+y4)/4. + poidy(4)=(-3.*yy1+y2+3.*y3-y4)/6. + poidy(5)=(2.*yy1-y2-2.*y3+y4)/24. + end if + if (zz1<=0.5) then + poidz(0)=(2.*zz1-z2-2*z3+z4)/24. + poidz(1)=(-4.*zz1+4.*z2+z3-z4)/6. + poidz(2)=1.+(-5.*z2+z4)/4. + poidz(3)=(4.*zz1+4.*z2-z3-z4)/6. + poidz(4)=(-2.*zz1-z2+2*z3+z4)/24. + poidz(5)=0. + else + poidz(0)=0. + poidz(1)=(-6.*zz1+11.*z2-6.*z3+z4)/24. + poidz(2)=1.+(-5.*zz1-5.*z2+5.*z3-z4)/6. + poidz(3)=(6.*zz1+z2-4.*z3+z4)/4. + poidz(4)=(-3.*zz1+z2+3.*z3-z4)/6. + poidz(5)=(2.*zz1-z2-2.*z3+z4)/24. + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,5 + do d=0,5 + do c=0,5 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l4 + + subroutine remaill_l5 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:5) :: ip,jp,kp + real(kind=8),dimension(0:5) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + kp(2) = floor((posz(i)-zd)/dz) + kp(0) = kp(2) - 2 + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + kp(5) = kp(2) + 3 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + z5=zz1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + poidy(0)=yy1/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(1)=-yy1/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(2)=1.-yy1/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(3)=yy1+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(4)=-yy1/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(5)=yy1/30.-y3/24.+y5/120. + + poidz(0)=zz1/20.-z2/24.-z3/24.+z4/24.-z5/120. + poidz(1)=-zz1/2.+2.*z2/3.-z3/24.-z4/6.+z5/24. + poidz(2)=1.-zz1/3.-5*z2/4.+5.*z3/12.+z4/4.-z5/12. + poidz(3)=zz1+2.*z2/3.-7.*z3/12.-z4/6.+z5/12. + poidz(4)=-zz1/4.-z2/24.+7.*z3/24.+z4/24.-z5/24. + poidz(5)=zz1/30.-z3/24.+z5/120. + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,5 + do d=0,5 + do c=0,5 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l5 + + + subroutine remaill_l5_x(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ip(c)+1,j,kvar)=remaille(ip(c)+1,j,kvar)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_x + + + subroutine remaill_l5_y(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posy(i)-yb)/dy) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(2),kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_y + + + subroutine remaill_l5_z(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posz(i)-zd)/dz) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posz(i) - real(ip(2),kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nz,nz) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(1)=-xx1/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(2)=1.-xx1/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(3)=xx1+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(4)=-xx1/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(5)=xx1/30.-x3/24.+x5/120. + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_z + + + + + + + + subroutine remaill_l6 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(-3:4) :: ip,jp,kp + real(kind=8),dimension(-3:4) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + real(kind=8) :: t1,t2,t3,t4,t5,t6 + + remaille=0. + + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + jp(0) = floor((posy(i)-yb)/dy) + jp(-1) = jp(0) - 1 + jp(-2) = jp(0) - 2 + jp(-3) = jp(0) - 3 + jp(1) = jp(0) + 1 + jp(2) = jp(0) + 2 + jp(3) = jp(0) + 3 + jp(4) = jp(0) + 4 + + kp(0) = floor((posz(i)-zd)/dz) + kp(-1) = kp(0) - 1 + kp(-2) = kp(0) - 2 + kp(-3) = kp(0) - 3 + kp(1) = kp(0) + 1 + kp(2) = kp(0) + 2 + kp(3) = kp(0) + 3 + kp(4) = kp(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + yy = (posy(i) - real(jp(0),kind=8)*dy-yb)/dy !relatif + zz = (posz(i) - real(kp(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=-3,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=-3,4 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5) then + t3=(xx+1.)*(xx+2.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+3.) + t6=(xx-1.)*xx + + t1=t4*(xx-1.) + t2=t3*(xx+3.) + + poidx(-3)=t1*xx*t3/720. + poidx(-2)=-t1*t5*(xx+1.)/120. + poidx(-1)=t1*t5*(xx+2.)/48. + poidx(0)=-t1*t2/36. + poidx(1)=t4*xx*t2/48. + poidx(2)=-(xx-3.)*t6*t2/120. + poidx(3)=(xx-2.)*t6*t2/720. + poidx(4)=0. + else + + t3=xx*(xx+1.) + t4=(xx-3.)*(xx-2.) + + t1=(xx-4.)*t4*(xx-1.) + t2=(xx-1.)*t3*(xx+2.) + + poidx(-3)=0. + poidx(-2)=t1*t3/720. + poidx(-1)=-t1*xx*(xx+2.)/120. + poidx(0)=t1*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*t4*t3*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*t2/48. + poidx(3)=-(xx-4.)*(xx-2.)*t2/120. + poidx(4)=t4*t2/720. + end if + + if (yy<=0.5) then + t3=(yy+1.)*(yy+2.) + t4=(yy-3.)*(yy-2.) + t5=yy*(yy+3.) + t6=(yy-1.)*yy + + t1=t4*(yy-1.) + t2=t3*(yy+3.) + + poidy(-3)=t1*yy*t3/720. + poidy(-2)=-t1*t5*(yy+1.)/120. + poidy(-1)=t1*t5*(yy+2.)/48. + poidy(0)=-t1*t2/36. + poidy(1)=t4*yy*t2/48. + poidy(2)=-(yy-3.)*t6*t2/120. + poidy(3)=(yy-2.)*t6*t2/720. + poidy(4)=0. + else + + t3=yy*(yy+1.) + t4=(yy-3.)*(yy-2.) + + t1=(yy-4.)*t4*(yy-1.) + t2=(yy-1.)*t3*(yy+2.) + + poidy(-3)=0. + poidy(-2)=t1*t3/720. + poidy(-1)=-t1*yy*(yy+2.)/120. + poidy(0)=t1*(yy+1.)*(yy+2.)/48. + poidy(1)=-(yy-4.)*t4*t3*(yy+2.)/36. + poidy(2)=(yy-4.)*(yy-3.)*t2/48. + poidy(3)=-(yy-4.)*(yy-2.)*t2/120. + poidy(4)=t4*t2/720. + end if + + if (zz<=0.5) then + t3=(zz+1.)*(zz+2.) + t4=(zz-3.)*(zz-2.) + t5=zz*(zz+3.) + t6=(zz-1.)*zz + + t1=t4*(zz-1.) + t2=t3*(zz+3.) + + poidz(-3)=t1*zz*t3/720. + poidz(-2)=-t1*t5*(zz+1.)/120. + poidz(-1)=t1*t5*(zz+2.)/48. + poidz(0)=-t1*t2/36. + poidz(1)=t4*zz*t2/48. + poidz(2)=-(zz-3.)*t6*t2/120. + poidz(3)=(zz-2.)*t6*t2/720. + poidz(4)=0. + else + + t3=zz*(zz+1.) + t4=(zz-3.)*(zz-2.) + + t1=(zz-4.)*t4*(zz-1.) + t2=(zz-1.)*t3*(zz+2.) + + poidz(-3)=0. + poidz(-2)=t1*t3/720. + poidz(-1)=-t1*zz*(zz+2.)/120. + poidz(0)=t1*(zz+1.)*(zz+2.)/48. + poidz(1)=-(zz-4.)*t4*t3*(zz+2.)/36. + poidz(2)=(zz-4.)*(zz-3.)*t2/48. + poidz(3)=-(zz-4.)*(zz-2.)*t2/120. + poidz(4)=t4*t2/720. + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-3,4 + do d=-3,4 + do c=-3,4 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + + end subroutine remaill_l6 + + + + subroutine remaill_l8 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(-4:5) :: ip,jp,kp + real(kind=8),dimension(-4:5) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(-4) = ip(0) - 4 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + ip(5) = ip(0) + 5 + + jp(0) = floor((posy(i)-yb)/dy) + jp(-1) = jp(0) - 1 + jp(-2) = jp(0) - 2 + jp(-3) = jp(0) - 3 + jp(-4) = jp(0) - 4 + jp(1) = jp(0) + 1 + jp(2) = jp(0) + 2 + jp(3) = jp(0) + 3 + jp(4) = jp(0) + 4 + jp(5) = jp(0) + 5 + + kp(0) = floor((posz(i)-zd)/dz) + kp(-1) = kp(0) - 1 + kp(-2) = kp(0) - 2 + kp(-3) = kp(0) - 3 + kp(-4) = kp(0) - 4 + kp(1) = kp(0) + 1 + kp(2) = kp(0) + 2 + kp(3) = kp(0) + 3 + kp(4) = kp(0) + 4 + kp(5) = kp(0) + 5 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + yy = (posy(i) - real(jp(0),kind=8)*dy-yb)/dy !relatif + zz = (posz(i) - real(kp(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=-4,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=-4,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=-4,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx+3.)*(xx+4.) + t5=(xx-4.)*(xx-3.) + t6=(xx-2.)*(xx-1.)*xx + + t1=t5*t6 + t2=t3*t4 + + poidx(-4)=t1*t3*(xx+3.)/(40320.) + poidx(-3)=-t1*t3*(xx+4.)/(5040.) + poidx(-2)=t1*(xx+1.)*t4/(1440.) + poidx(-1)=-t1*(xx+2.)*t4/(720.) + poidx(0)=t5*(xx-2.)*(xx-1.)*t2/(576.) + poidx(1)=-t5*(xx-2.)*xx*t2/(720.) + poidx(2)=t5*(xx-1.)*xx*t2/(1440.) + poidx(3)=-(xx-4.)*t6*t2/(5040.) + poidx(4)=(xx-3.)*t6*t2/(40320.) + poidx(5)=0. + else + + t3=(xx-5.)*(xx-4.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+1.) + t6=(xx+2.)*(xx+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(xx-1.) + t8=(xx-1.)*t2 + + poidx(-4)=0. + poidx(-3)=t7*t5*(xx+2.)/(40320.) + poidx(-2)=-t7*t5*(xx+3.)/(5040.) + poidx(-1)=t7*xx*t6/(1440.) + poidx(0)=-t7*(xx+1.)*t6/(720.) + poidx(1)=t1*t2/(576.) + poidx(2)=-t3*(xx-3.)*t8/(720.) + poidx(3)=t3*(xx-2.)*t8/(1440.) + poidx(4)=-(xx-5.)*t4*t8/(5040.) + poidx(5)=(xx-4.)*t4*t8/(40320.) + end if + if (yy<=0.5) then + + t3=(yy+1.)*(yy+2.) + t4=(yy+3.)*(yy+4.) + t5=(yy-4.)*(yy-3.) + t6=(yy-2.)*(yy-1.)*yy + + t1=t5*t6 + t2=t3*t4 + + poidy(-4)=t1*t3*(yy+3.)/(40320.) + poidy(-3)=-t1*t3*(yy+4.)/(5040.) + poidy(-2)=t1*(yy+1.)*t4/(1440.) + poidy(-1)=-t1*(yy+2.)*t4/(720.) + poidy(0)=t5*(yy-2.)*(yy-1.)*t2/(576.) + poidy(1)=-t5*(yy-2.)*yy*t2/(720.) + poidy(2)=t5*(yy-1.)*yy*t2/(1440.) + poidy(3)=-(yy-4.)*t6*t2/(5040.) + poidy(4)=(yy-3.)*t6*t2/(40320.) + poidy(5)=0. + else + + t3=(yy-5.)*(yy-4.) + t4=(yy-3.)*(yy-2.) + t5=yy*(yy+1.) + t6=(yy+2.)*(yy+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(yy-1.) + t8=(yy-1.)*t2 + + poidy(-4)=0. + poidy(-3)=t7*t5*(yy+2.)/(40320.) + poidy(-2)=-t7*t5*(yy+3.)/(5040.) + poidy(-1)=t7*yy*t6/(1440.) + poidy(0)=-t7*(yy+1.)*t6/(720.) + poidy(1)=t1*t2/(576.) + poidy(2)=-t3*(yy-3.)*t8/(720.) + poidy(3)=t3*(yy-2.)*t8/(1440.) + poidy(4)=-(yy-5.)*t4*t8/(5040.) + poidy(5)=(yy-4.)*t4*t8/(40320.) + end if + if (zz<=0.5) then + + t3=(zz+1.)*(zz+2.) + t4=(zz+3.)*(zz+4.) + t5=(zz-4.)*(zz-3.) + t6=(zz-2.)*(zz-1.)*zz + + t1=t5*t6 + t2=t3*t4 + + poidz(-4)=t1*t3*(zz+3.)/(40320.) + poidz(-3)=-t1*t3*(zz+4.)/(5040.) + poidz(-2)=t1*(zz+1.)*t4/(1440.) + poidz(-1)=-t1*(zz+2.)*t4/(720.) + poidz(0)=t5*(zz-2.)*(zz-1.)*t2/(576.) + poidz(1)=-t5*(zz-2.)*zz*t2/(720.) + poidz(2)=t5*(zz-1.)*zz*t2/(1440.) + poidz(3)=-(zz-4.)*t6*t2/(5040.) + poidz(4)=(zz-3.)*t6*t2/(40320.) + poidz(5)=0. + else + + t3=(zz-5.)*(zz-4.) + t4=(zz-3.)*(zz-2.) + t5=zz*(zz+1.) + t6=(zz+2.)*(zz+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(zz-1.) + t8=(zz-1.)*t2 + + poidz(-4)=0. + poidz(-3)=t7*t5*(zz+2.)/(40320.) + poidz(-2)=-t7*t5*(zz+3.)/(5040.) + poidz(-1)=t7*zz*t6/(1440.) + poidz(0)=-t7*(zz+1.)*t6/(720.) + poidz(1)=t1*t2/(576.) + poidz(2)=-t3*(zz-3.)*t8/(720.) + poidz(3)=t3*(zz-2.)*t8/(1440.) + poidz(4)=-(zz-5.)*t4*t8/(5040.) + poidz(5)=(zz-4.)*t4*t8/(40320.) + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-4,5 + do d=-4,5 + do c=-4,5 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + + end subroutine remaill_l8 + + + subroutine remaill_l4_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-2:3) :: ip + real(kind=8),dimension(-2:3) :: poidx + real(kind=8) :: xx,x2,x3,x4 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-2,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- +!!$ x2=xx**2 +!!$ x3=xx**3 +!!$ x4=xx**4 +!!$ +!!$ if (xx<=0.5) then +!!$ poidx(-2)=(2.*xx-x2-2*x3+x4)/24. +!!$ poidx(-1)=(-4.*xx+4.*x2+x3-x4)/6. +!!$ poidx(0)=1.+(-5.*x2+x4)/4. +!!$ poidx(1)=(4.*xx+4.*x2-x3-x4)/6. +!!$ poidx(2)=(-2.*xx-x2+2*x3+x4)/24. +!!$ poidx(3)=0. +!!$ else +!!$ poidx(-2)=0. +!!$ poidx(-1)=(-6.*xx+11.*x2-6.*x3+x4)/24. +!!$ poidx(0)=1.+(-5.*xx-5.*x2+5.*x3-x4)/6. +!!$ poidx(1)=(6.*xx+x2-4.*x3+x4)/4. +!!$ poidx(2)=(-3.*xx+x2+3.*x3-x4)/6. +!!$ poidx(3)=(2.*xx-x2-2.*x3+x4)/24. +!!$ end if + + if (xx<=0.5) then + poidx(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poidx(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poidx(0)=(xx**2-4.)*(xx**2-1.)/4. !c + poidx(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poidx(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poidx(3)=0. + else + poidx(-2)=0. + poidx(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poidx(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poidx(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + poidx(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poidx(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,3 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l4_x + + + + subroutine remaill_l4_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ivar,jvar,kvar + integer,dimension(-2:3) :: ip + real(kind=8),dimension(-2:3) :: poidx + real(kind=8) :: xx,x2,x3,x4 + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + + + do c=-2,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + + !calcul des poids + !---------------- +!!$ x2=xx**2 +!!$ x3=xx**3 +!!$ x4=xx**4 +!!$ +!!$ if (xx<=0.5) then +!!$ poidx(-2)=(2.*xx-x2-2*x3+x4)/24. +!!$ poidx(-1)=(-4.*xx+4.*x2+x3-x4)/6. +!!$ poidx(0)=1.+(-5.*x2+x4)/4. +!!$ poidx(1)=(4.*xx+4.*x2-x3-x4)/6. +!!$ poidx(2)=(-2.*xx-x2+2*x3+x4)/24. +!!$ poidx(3)=0. +!!$ else +!!$ poidx(-2)=0. +!!$ poidx(-1)=(-6.*xx+11.*x2-6.*x3+x4)/24. +!!$ poidx(0)=1.+(-5.*xx-5.*x2+5.*x3-x4)/6. +!!$ poidx(1)=(6.*xx+x2-4.*x3+x4)/4. +!!$ poidx(2)=(-3.*xx+x2+3.*x3-x4)/6. +!!$ poidx(3)=(2.*xx-x2-2.*x3+x4)/24. +!!$ end if + + if (xx<=0.5) then + poidx(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poidx(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poidx(0)=(xx**2-4.)*(xx**2-1.)/4. !c + poidx(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poidx(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poidx(3)=0. + else + poidx(-2)=0. + poidx(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poidx(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poidx(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + poidx(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poidx(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-2,3 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l4_y + + subroutine remaill_l4_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-2:3) :: ip + real(kind=8),dimension(-2:3) :: poidx + real(kind=8) :: xx,x2,x3,x4 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + + do c=-2,3 + ip(c)=mod(ip(c)+nz,nz) + end do + + + !calcul des poids + !---------------- +!!$ x2=xx**2 +!!$ x3=xx**3 +!!$ x4=xx**4 +!!$ +!!$ if (xx<=0.5) then +!!$ poidx(-2)=(2.*xx-x2-2*x3+x4)/24. +!!$ poidx(-1)=(-4.*xx+4.*x2+x3-x4)/6. +!!$ poidx(0)=1.+(-5.*x2+x4)/4. +!!$ poidx(1)=(4.*xx+4.*x2-x3-x4)/6. +!!$ poidx(2)=(-2.*xx-x2+2*x3+x4)/24. +!!$ poidx(3)=0. +!!$ else +!!$ poidx(-2)=0. +!!$ poidx(-1)=(-6.*xx+11.*x2-6.*x3+x4)/24. +!!$ poidx(0)=1.+(-5.*xx-5.*x2+5.*x3-x4)/6. +!!$ poidx(1)=(6.*xx+x2-4.*x3+x4)/4. +!!$ poidx(2)=(-3.*xx+x2+3.*x3-x4)/6. +!!$ poidx(3)=(2.*xx-x2-2.*x3+x4)/24. +!!$ end if + + if (xx<=0.5) then + poidx(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poidx(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poidx(0)=(xx**2-4.)*(xx**2-1.)/4. !c + poidx(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poidx(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poidx(3)=0. + else + poidx(-2)=0. + poidx(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poidx(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poidx(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + poidx(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poidx(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-2,3 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l4_z + + subroutine remaill_l6_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+3.) + t6=(xx-1.)*xx + + t1=t4*(xx-1.) + t2=t3*(xx+3.) + + poidx(-3)=t1*xx*t3/720. + poidx(-2)=-t1*t5*(xx+1.)/120. + poidx(-1)=t1*t5*(xx+2.)/48. + poidx(0)=-t1*t2/36. + poidx(1)=t4*xx*t2/48. + poidx(2)=-(xx-3.)*t6*t2/120. + poidx(3)=(xx-2.)*t6*t2/720. + poidx(4)=0. + else + + t3=xx*(xx+1.) + t4=(xx-3.)*(xx-2.) + + t1=(xx-4.)*t4*(xx-1.) + t2=(xx-1.)*t3*(xx+2.) + + poidx(-3)=0. + poidx(-2)=t1*t3/720. + poidx(-1)=-t1*xx*(xx+2.)/120. + poidx(0)=t1*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*t4*t3*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*t2/48. + poidx(3)=-(xx-4.)*(xx-2.)*t2/120. + poidx(4)=t4*t2/720. + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_x + + + + subroutine remaill_l6_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + + + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+3.) + t6=(xx-1.)*xx + + t1=t4*(xx-1.) + t2=t3*(xx+3.) + + poidx(-3)=t1*xx*t3/720. + poidx(-2)=-t1*t5*(xx+1.)/120. + poidx(-1)=t1*t5*(xx+2.)/48. + poidx(0)=-t1*t2/36. + poidx(1)=t4*xx*t2/48. + poidx(2)=-(xx-3.)*t6*t2/120. + poidx(3)=(xx-2.)*t6*t2/720. + poidx(4)=0. + else + + t3=xx*(xx+1.) + t4=(xx-3.)*(xx-2.) + + t1=(xx-4.)*t4*(xx-1.) + t2=(xx-1.)*t3*(xx+2.) + + poidx(-3)=0. + poidx(-2)=t1*t3/720. + poidx(-1)=-t1*xx*(xx+2.)/120. + poidx(0)=t1*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*t4*t3*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*t2/48. + poidx(3)=-(xx-4.)*(xx-2.)*t2/120. + poidx(4)=t4*t2/720. + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-3,4 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_y + + subroutine remaill_l6_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + + do c=-3,4 + ip(c)=mod(ip(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+3.) + t6=(xx-1.)*xx + + t1=t4*(xx-1.) + t2=t3*(xx+3.) + + poidx(-3)=t1*xx*t3/720. + poidx(-2)=-t1*t5*(xx+1.)/120. + poidx(-1)=t1*t5*(xx+2.)/48. + poidx(0)=-t1*t2/36. + poidx(1)=t4*xx*t2/48. + poidx(2)=-(xx-3.)*t6*t2/120. + poidx(3)=(xx-2.)*t6*t2/720. + poidx(4)=0. + else + + t3=xx*(xx+1.) + t4=(xx-3.)*(xx-2.) + + t1=(xx-4.)*t4*(xx-1.) + t2=(xx-1.)*t3*(xx+2.) + + poidx(-3)=0. + poidx(-2)=t1*t3/720. + poidx(-1)=-t1*xx*(xx+2.)/120. + poidx(0)=t1*(xx+1.)*(xx+2.)/48. + poidx(1)=-(xx-4.)*t4*t3*(xx+2.)/36. + poidx(2)=(xx-4.)*(xx-3.)*t2/48. + poidx(3)=-(xx-4.)*(xx-2.)*t2/120. + poidx(4)=t4*t2/720. + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-3,4 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_z + + subroutine remaill_l8_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-4:5) :: ip + real(kind=8),dimension(-4:5) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(-4) = ip(0) - 4 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + ip(5) = ip(0) + 5 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-4,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx+3.)*(xx+4.) + t5=(xx-4.)*(xx-3.) + t6=(xx-2.)*(xx-1.)*xx + + t1=t5*t6 + t2=t3*t4 + + poidx(-4)=t1*t3*(xx+3.)/(40320.) + poidx(-3)=-t1*t3*(xx+4.)/(5040.) + poidx(-2)=t1*(xx+1.)*t4/(1440.) + poidx(-1)=-t1*(xx+2.)*t4/(720.) + poidx(0)=t5*(xx-2.)*(xx-1.)*t2/(576.) + poidx(1)=-t5*(xx-2.)*xx*t2/(720.) + poidx(2)=t5*(xx-1.)*xx*t2/(1440.) + poidx(3)=-(xx-4.)*t6*t2/(5040.) + poidx(4)=(xx-3.)*t6*t2/(40320.) + poidx(5)=0. + else + + t3=(xx-5.)*(xx-4.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+1.) + t6=(xx+2.)*(xx+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(xx-1.) + t8=(xx-1.)*t2 + + poidx(-4)=0. + poidx(-3)=t7*t5*(xx+2.)/(40320.) + poidx(-2)=-t7*t5*(xx+3.)/(5040.) + poidx(-1)=t7*xx*t6/(1440.) + poidx(0)=-t7*(xx+1.)*t6/(720.) + poidx(1)=t1*t2/(576.) + poidx(2)=-t3*(xx-3.)*t8/(720.) + poidx(3)=t3*(xx-2.)*t8/(1440.) + poidx(4)=-(xx-5.)*t4*t8/(5040.) + poidx(5)=(xx-4.)*t4*t8/(40320.) + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-4,5 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l8_x + +subroutine remaill_l8_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-4:5) :: ip + real(kind=8),dimension(-4:5) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(-4) = ip(0) - 4 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + ip(5) = ip(0) + 5 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-4,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx+3.)*(xx+4.) + t5=(xx-4.)*(xx-3.) + t6=(xx-2.)*(xx-1.)*xx + + t1=t5*t6 + t2=t3*t4 + + poidx(-4)=t1*t3*(xx+3.)/(40320.) + poidx(-3)=-t1*t3*(xx+4.)/(5040.) + poidx(-2)=t1*(xx+1.)*t4/(1440.) + poidx(-1)=-t1*(xx+2.)*t4/(720.) + poidx(0)=t5*(xx-2.)*(xx-1.)*t2/(576.) + poidx(1)=-t5*(xx-2.)*xx*t2/(720.) + poidx(2)=t5*(xx-1.)*xx*t2/(1440.) + poidx(3)=-(xx-4.)*t6*t2/(5040.) + poidx(4)=(xx-3.)*t6*t2/(40320.) + poidx(5)=0. + else + + t3=(xx-5.)*(xx-4.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+1.) + t6=(xx+2.)*(xx+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(xx-1.) + t8=(xx-1.)*t2 + + poidx(-4)=0. + poidx(-3)=t7*t5*(xx+2.)/(40320.) + poidx(-2)=-t7*t5*(xx+3.)/(5040.) + poidx(-1)=t7*xx*t6/(1440.) + poidx(0)=-t7*(xx+1.)*t6/(720.) + poidx(1)=t1*t2/(576.) + poidx(2)=-t3*(xx-3.)*t8/(720.) + poidx(3)=t3*(xx-2.)*t8/(1440.) + poidx(4)=-(xx-5.)*t4*t8/(5040.) + poidx(5)=(xx-4.)*t4*t8/(40320.) + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-4,5 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l8_y + +subroutine remaill_l8_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-4:5) :: ip + real(kind=8),dimension(-4:5) :: poidx + real(kind=8) :: xx + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8 + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(-4) = ip(0) - 4 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + ip(5) = ip(0) + 5 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-4,5 + ip(c)=mod(ip(c)+nz,nz) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + + t3=(xx+1.)*(xx+2.) + t4=(xx+3.)*(xx+4.) + t5=(xx-4.)*(xx-3.) + t6=(xx-2.)*(xx-1.)*xx + + t1=t5*t6 + t2=t3*t4 + + poidx(-4)=t1*t3*(xx+3.)/(40320.) + poidx(-3)=-t1*t3*(xx+4.)/(5040.) + poidx(-2)=t1*(xx+1.)*t4/(1440.) + poidx(-1)=-t1*(xx+2.)*t4/(720.) + poidx(0)=t5*(xx-2.)*(xx-1.)*t2/(576.) + poidx(1)=-t5*(xx-2.)*xx*t2/(720.) + poidx(2)=t5*(xx-1.)*xx*t2/(1440.) + poidx(3)=-(xx-4.)*t6*t2/(5040.) + poidx(4)=(xx-3.)*t6*t2/(40320.) + poidx(5)=0. + else + + t3=(xx-5.)*(xx-4.) + t4=(xx-3.)*(xx-2.) + t5=xx*(xx+1.) + t6=(xx+2.)*(xx+3.) + + t1=t3*t4 + t2=t5*t6 + + t7=t1*(xx-1.) + t8=(xx-1.)*t2 + + poidx(-4)=0. + poidx(-3)=t7*t5*(xx+2.)/(40320.) + poidx(-2)=-t7*t5*(xx+3.)/(5040.) + poidx(-1)=t7*xx*t6/(1440.) + poidx(0)=-t7*(xx+1.)*t6/(720.) + poidx(1)=t1*t2/(576.) + poidx(2)=-t3*(xx-3.)*t8/(720.) + poidx(3)=t3*(xx-2.)*t8/(1440.) + poidx(4)=-(xx-5.)*t4*t8/(5040.) + poidx(5)=(xx-4.)*t4*t8/(40320.) + end if + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-4,5 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l8_z + + + subroutine remaill_l2_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-1,2 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l2_x + + + + subroutine remaill_l2_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + + + do c=-1,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-1,2 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l2_y + + subroutine remaill_l2_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-1:2) :: ip + real(kind=8),dimension(-1:2) :: poidx + real(kind=8) :: xx + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + + do c=-1,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5) then + poidx(-1)=0.5*xx*(xx-1.) + poidx(0)=1.-xx**2 + poidx(1)=0.5*xx*(1.+xx) + poidx(2)=0. + else + poidx(-1)=0. + poidx(0)=0.5*(1.-xx)*(2.-xx) + poidx(1)=2.*xx-xx**2 + poidx(2)=0.5*(xx-1.)*xx + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-1,2 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l2_z + + + + + subroutine remaill_l2_bloc_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,k,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + else + poids(0)=0.5*(1.-xx)*(2.-xx) + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + case(2) + poids(0)=1.-0.5*xx*(1.+xx) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + case(4) + poids(-2)=0.5*xx*(1.+xx) + poids(-1)=-xx + poids(0)=1.-xx**2 + case(5) + poids(-1)=-0.5*xx+0.5*xx**2 + poids(0)=1.-poids(-1) + + end select + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + poids(1)=0.5*xx*(1.+xx) + else + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + end if + case(1) + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(1)=xx + poids(2)=0.5*xx*(xx-1) + case(3) + poids(1)=3.*0.5*xx-0.5*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_x + + + subroutine remaill_l2_bloc_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + else + poids(0)=0.5*(1.-xx)*(2.-xx) + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + case(2) + poids(0)=1.-0.5*xx*(1.+xx) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + case(4) + poids(-2)=0.5*xx*(1.+xx) + poids(-1)=-xx + poids(0)=1.-xx**2 + case(5) + poids(-1)=-0.5*xx+0.5*xx**2 + poids(0)=1.-poids(-1) + + end select + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + poids(1)=0.5*xx*(1.+xx) + else + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + end if + case(1) + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(1)=xx + poids(2)=0.5*xx*(xx-1) + case(3) + poids(1)=3.*0.5*xx-0.5*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_y + + subroutine remaill_l2_bloc_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + else + poids(0)=0.5*(1.-xx)*(2.-xx) + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + case(2) + poids(0)=1.-0.5*xx*(1.+xx) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + case(4) + poids(-2)=0.5*xx*(1.+xx) + poids(-1)=-xx + poids(0)=1.-xx**2 + case(5) + poids(-1)=-0.5*xx+0.5*xx**2 + poids(0)=1.-poids(-1) + + end select + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + poids(1)=0.5*xx*(1.+xx) + else + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + end if + case(1) + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(1)=xx + poids(2)=0.5*xx*(xx-1) + case(3) + poids(1)=3.*0.5*xx-0.5*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_z + + + + subroutine remaill_l2_bloc_x_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,k,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) !alpha + poids(0)=1.-xx**2 !beta + poids(1)=0.5*xx*(1.+xx) !gamma + else + poids(0)=0.5*(1.-xx)*(2.-xx) !alpha' + poids(1)=2.*xx-xx**2 !beta' + poids(2)=0.5*(xx-1.)*xx !gamma' + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(0)=0.5*(1.-xx)*(2.-xx) + poids(1)=1.-poids(0) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-poids(-1) + case(4) + poids(0)=-0.5*xx*(xx+1.)+1. + poids(1)=1.-poids(0) + case(5) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=xx + poids(2)=0.5*xx*(xx-1.) + case(6) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + case(7) + poids(-2)=0.5*xx*(xx+1) + poids(-1)=-xx + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_x_v2 + + + subroutine remaill_l2_bloc_y_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) !alpha + poids(0)=1.-xx**2 !beta + poids(1)=0.5*xx*(1.+xx) !gamma + else + poids(0)=0.5*(1.-xx)*(2.-xx) !alpha' + poids(1)=2.*xx-xx**2 !beta' + poids(2)=0.5*(xx-1.)*xx !gamma' + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(0)=0.5*(1.-xx)*(2.-xx) + poids(1)=1.-poids(0) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-poids(-1) + case(4) + poids(0)=-0.5*xx*(xx+1.)+1. + poids(1)=1.-poids(0) + case(5) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=xx + poids(2)=0.5*xx*(xx-1.) + case(6) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + case(7) + poids(-2)=0.5*xx*(xx+1) + poids(-1)=-xx + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_y_v2 + + subroutine remaill_l2_bloc_z_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0. + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + poids(-1)=0.5*xx*(xx-1.) !alpha + poids(0)=1.-xx**2 !beta + poids(1)=0.5*xx*(1.+xx) !gamma + else + poids(0)=0.5*(1.-xx)*(2.-xx) !alpha' + poids(1)=2.*xx-xx**2 !beta' + poids(2)=0.5*(xx-1.)*xx !gamma' + end if + case(1) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + case(2) + poids(0)=0.5*(1.-xx)*(2.-xx) + poids(1)=1.-poids(0) + case(3) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-poids(-1) + case(4) + poids(0)=-0.5*xx*(xx+1.)+1. + poids(1)=1.-poids(0) + case(5) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx**2 + poids(1)=xx + poids(2)=0.5*xx*(xx-1.) + case(6) + poids(-1)=0.5*xx*(xx-1.) + poids(0)=1.-xx + poids(1)=2.*xx-xx**2 + poids(2)=0.5*(xx-1.)*xx + case(7) + poids(-2)=0.5*xx*(xx+1) + poids(-1)=-xx + poids(0)=1.-xx**2 + poids(1)=0.5*xx*(1.+xx) + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_z_v2 + + + + + + + + + + + + + + + + subroutine remaill_l4_bloc_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,per,k + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + else + t1=(xx-1.)*(xx-2.)*(xx-3.) + poids(-1)=t1*xx/24. + poids(0)=-t1*(xx+1.)/6. + end if + case(1) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + + case(2) + t1=(xx-1.)*(xx-2.)/12. + poids(-1)=t1*xx*(xx-3)/2. + poids(0)=t1*(xx+6.)*(xx+1.) + case(3) + t1=0.5*(xx-1.)*(xx-2.) + poids(-2)=t1*xx/12.*(xx+1.) + poids(-1)=-t1*xx/3.*(xx+2.) + poids(0)=t1*(xx+1.) + case(4) + t2=(xx**2-1.) + t1=xx*(xx+2.)*0.5 + poids(-3)=t2*t1/12. + poids(-2)=-t2*xx/6.*(xx+3.) + poids(-1)=t1*(xx-1.) + poids(0)=t2*(xx**2-4.)/4. + case(5) + t1=(xx-2.)*(xx-1.)/4. + poids(-1)=-t1*xx/6.*(3*xx+7.) + poids(0)=t1*(xx+2.)*(xx+1.) + case(6) + t1= (xx-1.)*(xx-2.)/6. + t2=t1*(xx+1.) + poids(-2)=t2*xx/4. + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.) + case(7) + t1=(xx-1.)*(xx+2.) + t2=xx*(xx+1)/6. + poids(-3)=t1*t2/4. + poids(-2)=-t2*(xx-1.) + poids(-1)=-xx*t1/6.*(xx-2.) + poids(0)=t1*(xx-2.)/4.*(xx+1.) + case(8) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=(xx-6.)*(xx+2.)*(xx**2-1.)/12. + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + else + t1=xx*(xx+1.)*(xx-3.) + poids(1)=t1*(xx-2.)/4. + poids(2)=-t1*(xx-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + end if + case(1) + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + case(2) + t1=xx*(xx+1.)*0.5 + t2=t1*(xx-1.) + poids(1)=-t1*(xx-2.) + poids(2)=-t2/3.*(xx-3.) + poids(3)=t2*(xx-2.)/12. + case(3) + t1=xx*(xx+1.)/12. + poids(1)=t1*(xx-2.)*(xx-7.) + poids(2)=t1*(xx+2.)*(xx-1.)/2. + case(4) + t1=xx*(xx+1.) + t2=t1*(xx-1.)/6. + poids(1)=-t1*(xx+2.)*(xx-2.)/6. + poids(2)=t2 + poids(3)=t2*(xx-2.)/4. + case(5) + poids(1)=-xx/24.*(3.*xx-7.)*(xx+2.)*(xx+1.) + case(6) + t1=xx*(xx+1.)/4. + poids(1)=t1*(xx-3.)*(xx-2.) + poids(2)=-t1*(3.*xx-10.)*(xx-1.)/6. + case(7) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_x + + + subroutine remaill_l4_bloc_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + else + t1=(xx-1.)*(xx-2.)*(xx-3.) + poids(-1)=t1*xx/24. + poids(0)=-t1*(xx+1.)/6. + end if + case(1) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + + case(2) + t1=(xx-1.)*(xx-2.)/12. + poids(-1)=t1*xx*(xx-3)/2. + poids(0)=t1*(xx+6.)*(xx+1.) + case(3) + t1=0.5*(xx-1.)*(xx-2.) + poids(-2)=t1*xx/12.*(xx+1.) + poids(-1)=-t1*xx/3.*(xx+2.) + poids(0)=t1*(xx+1.) + case(4) + t2=(xx**2-1.) + t1=xx*(xx+2.)*0.5 + poids(-3)=t2*t1/12. + poids(-2)=-t2*xx/6.*(xx+3.) + poids(-1)=t1*(xx-1.) + poids(0)=t2*(xx**2-4.)/4. + case(5) + t1=(xx-2.)*(xx-1.)/4. + poids(-1)=-t1*xx/6.*(3*xx+7.) + poids(0)=t1*(xx+2.)*(xx+1.) + case(6) + t1= (xx-1.)*(xx-2.)/6. + t2=t1*(xx+1.) + poids(-2)=t2*xx/4. + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.) + case(7) + t1=(xx-1.)*(xx+2.) + t2=xx*(xx+1)/6. + poids(-3)=t1*t2/4. + poids(-2)=-t2*(xx-1.) + poids(-1)=-xx*t1/6.*(xx-2.) + poids(0)=t1*(xx-2.)/4.*(xx+1.) + case(8) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=(xx-6.)*(xx+2.)*(xx**2-1.)/12. + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + else + t1=xx*(xx+1.)*(xx-3.) + poids(1)=t1*(xx-2.)/4. + poids(2)=-t1*(xx-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + end if + case(1) + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + case(2) + t1=xx*(xx+1.)*0.5 + t2=t1*(xx-1.) + poids(1)=-t1*(xx-2.) + poids(2)=-t2/3.*(xx-3.) + poids(3)=t2*(xx-2.)/12. + case(3) + t1=xx*(xx+1.)/12. + poids(1)=t1*(xx-2.)*(xx-7.) + poids(2)=t1*(xx+2.)*(xx-1.)/2. + case(4) + t1=xx*(xx+1.) + t2=t1*(xx-1.)/6. + poids(1)=-t1*(xx+2.)*(xx-2.)/6. + poids(2)=t2 + poids(3)=t2*(xx-2.)/4. + case(5) + poids(1)=-xx/24.*(3.*xx-7.)*(xx+2.)*(xx+1.) + case(6) + t1=xx*(xx+1.)/4. + poids(1)=t1*(xx-3.)*(xx-2.) + poids(2)=-t1*(3.*xx-10.)*(xx-1.)/6. + case(7) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_y + + + subroutine remaill_l4_bloc_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poidss + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + else + t1=(xx-1.)*(xx-2.)*(xx-3.) + poids(-1)=t1*xx/24. + poids(0)=-t1*(xx+1.)/6. + end if + case(1) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=t2/4.*(xx**2-1.) + + case(2) + t1=(xx-1.)*(xx-2.)/12. + poids(-1)=t1*xx*(xx-3)/2. + poids(0)=t1*(xx+6.)*(xx+1.) + case(3) + t1=0.5*(xx-1.)*(xx-2.) + poids(-2)=t1*xx/12.*(xx+1.) + poids(-1)=-t1*xx/3.*(xx+2.) + poids(0)=t1*(xx+1.) + case(4) + t2=(xx**2-1.) + t1=xx*(xx+2.)*0.5 + poids(-3)=t2*t1/12. + poids(-2)=-t2*xx/6.*(xx+3.) + poids(-1)=t1*(xx-1.) + poids(0)=t2*(xx**2-4.)/4. + case(5) + t1=(xx-2.)*(xx-1.)/4. + poids(-1)=-t1*xx/6.*(3*xx+7.) + poids(0)=t1*(xx+2.)*(xx+1.) + case(6) + t1= (xx-1.)*(xx-2.)/6. + t2=t1*(xx+1.) + poids(-2)=t2*xx/4. + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.) + case(7) + t1=(xx-1.)*(xx+2.) + t2=xx*(xx+1)/6. + poids(-3)=t1*t2/4. + poids(-2)=-t2*(xx-1.) + poids(-1)=-xx*t1/6.*(xx-2.) + poids(0)=t1*(xx-2.)/4.*(xx+1.) + case(8) + t1=xx*(xx-1.) + t2=xx**2-4. + poids(-2)=t1/24.*(xx-2.)*(xx+1.) + poids(-1)=-t1/6.*t2 + poids(0)=(xx-6.)*(xx+2.)*(xx**2-1.)/12. + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5) then + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + else + t1=xx*(xx+1.)*(xx-3.) + poids(1)=t1*(xx-2.)/4. + poids(2)=-t1*(xx-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + end if + case(1) + t1=xx*(xx+1.)*(xx+2.) + poids(1)=-t1*(xx-2.)/6. + poids(2)=t1*(xx-1.)/24. + case(2) + t1=xx*(xx+1.)*0.5 + t2=t1*(xx-1.) + poids(1)=-t1*(xx-2.) + poids(2)=-t2/3.*(xx-3.) + poids(3)=t2*(xx-2.)/12. + case(3) + t1=xx*(xx+1.)/12. + poids(1)=t1*(xx-2.)*(xx-7.) + poids(2)=t1*(xx+2.)*(xx-1.)/2. + case(4) + t1=xx*(xx+1.) + t2=t1*(xx-1.)/6. + poids(1)=-t1*(xx+2.)*(xx-2.)/6. + poids(2)=t2 + poids(3)=t2*(xx-2.)/4. + case(5) + poids(1)=-xx/24.*(3.*xx-7.)*(xx+2.)*(xx+1.) + case(6) + t1=xx*(xx+1.)/4. + poids(1)=t1*(xx-3.)*(xx-2.) + poids(2)=-t1*(3.*xx-10.)*(xx-1.)/6. + case(7) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_z + + + subroutine remaill_l4_bloc_x_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,per,k + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + select case (blocg(i)) + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + end if + case(1) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx**4/12.-2.*xx**3/3.+5.*xx**2/12.+7.*xx/6. + case(3) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=1.+xx**4/12.-13.*xx**2/12.-xx**3/3.+xx/3. + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=xx*(xx-1.)*(xx-2.)*(xx-3.)/24. + poids(0)=xx**4/12.+xx**3/3.-13.*xx**2/12.-xx/3.+1. + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=1.-xx**4/8.+7.*xx**3/12.-3.*xx**2/8.-13.*xx/12. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=-xx**4/8.+xx**3/12.+5.*xx**2/8.-7.*xx/12. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(7) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=0.5*xx**3-xx**2-0.5*xx+1. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(8) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=-xx*(xx+3.)*(xx**2-1.)/6. + poids(-1)=0.5*xx**3+0.5*xx**2-xx + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(9) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx**3/6.+0.5*xx**2-xx/3. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(10) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=xx*(1.-xx**2)/6. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + else + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + poids(4)=0. + end if + case(1) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=-xx**4/8.+5.*xx**3/12.+xx**2/8.-5.*xx/12. + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=-xx**4/8.-xx**3/12.+5.*xx**2/8.+7.*xx/12. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=xx*(xx+2.)*(xx**2-1.)/24. + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. + poids(3)=xx**3/6.-0.5*xx*2+xx/3. + poids(4)=xx*(xx-1)*(xx-2.)*(xx-3.)/24. + case(7) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. + poids(2)=xx*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + case(8) + poids(1)=-0.5*xx**3+0.5*xx**2+xx + poids(2)=-xx*(xx-3)*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + end select + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_x_v2 + + + subroutine remaill_l4_bloc_y_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + select case (blocg(i)) + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + end if + case(1) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx**4/12.-2.*xx**3/3.+5.*xx**2/12.+7.*xx/6. + case(3) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=1.+xx**4/12.-13.*xx**2/12.-xx**3/3.+xx/3. + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=xx*(xx-1.)*(xx-2.)*(xx-3.)/24. + poids(0)=xx**4/12.+xx**3/3.-13.*xx**2/12.-xx/3.+1. + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=1.-xx**4/8.+7.*xx**3/12.-3.*xx**2/8.-13.*xx/12. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=-xx**4/8.+xx**3/12.+5.*xx**2/8.-7.*xx/12. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(7) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=0.5*xx**3-xx**2-0.5*xx+1. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(8) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=-xx*(xx+3.)*(xx**2-1.)/6. + poids(-1)=0.5*xx**3+0.5*xx**2-xx + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(9) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx**3/6.+0.5*xx**2-xx/3. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(10) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=xx*(1.-xx**2)/6. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + else + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + poids(4)=0. + end if + case(1) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=-xx**4/8.+5.*xx**3/12.+xx**2/8.-5.*xx/12. + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=-xx**4/8.-xx**3/12.+5.*xx**2/8.+7.*xx/12. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=xx*(xx+2.)*(xx**2-1.)/24. + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. + poids(3)=xx**3/6.-0.5*xx*2+xx/3. + poids(4)=xx*(xx-1)*(xx-2.)*(xx-3.)/24. + case(7) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. + poids(2)=xx*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + case(8) + poids(1)=-0.5*xx**3+0.5*xx**2+xx + poids(2)=-xx*(xx-3)*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_y_v2 + + + subroutine remaill_l4_bloc_z_v2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0. + + do i=1,npart + + poids=0. + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + do c=-3,4 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poidss + !---------------- + select case (blocg(i)) + case(0) + if (xx<=0.5) then + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + else + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. !a' + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. !b' + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. !c' + end if + case(1) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. !a + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. !b + poids(0)=(xx**2-4.)*(xx**2-1.)/4. !c + case(2) + poids(-3)=0. + poids(-2)=0. + poids(-1)=(xx-1.)*(xx-2.)*(xx-3.)*xx/24. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx**4/12.-2.*xx**3/3.+5.*xx**2/12.+7.*xx/6. + case(3) + poids(-3)=0. + poids(-2)=xx*(xx-1.)*(xx-2.)*(xx+1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=1.+xx**4/12.-13.*xx**2/12.-xx**3/3.+xx/3. + case(4) + poids(-3)=0. + poids(-2)=0. + poids(-1)=xx*(xx-1.)*(xx-2.)*(xx-3.)/24. + poids(0)=xx**4/12.+xx**3/3.-13.*xx**2/12.-xx/3.+1. + case(5) + poids(-3)=0. + poids(-2)=0. + poids(-1)=0. + poids(0)=1.-xx**4/8.+7.*xx**3/12.-3.*xx**2/8.-13.*xx/12. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(6) + poids(-3)=0. + poids(-2)=0. + poids(-1)=-xx**4/8.+xx**3/12.+5.*xx**2/8.-7.*xx/12. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(7) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=0.5*xx**3-xx**2-0.5*xx+1. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(8) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=-xx*(xx+3.)*(xx**2-1.)/6. + poids(-1)=0.5*xx**3+0.5*xx**2-xx + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + case(9) + poids(-3)=0. + poids(-2)=xx*(xx-2.)*(xx**2-1.)/24. + poids(-1)=-xx**3/6.+0.5*xx**2-xx/3. + poids(0)=-(xx-1.)*(xx-2.)*(xx-3.)*(xx+1.)/6. + poids(1)=xx*(xx+1.)*(xx-3.)*(xx-2.)/4. + case(10) + poids(-3)=(xx+2.)*xx*(xx**2-1.)/24. + poids(-2)=xx*(1.-xx**2)/6. + poids(-1)=-xx*(xx-1.)*(xx**2-4.)/6. + poids(0)=(xx**2-4.)*(xx**2-1.)/4. + end select + + select case (blocd(i)) + case(0) + if (xx<=0.5) then + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + else + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. !d' + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. !e' + poids(4)=0. + end if + case(1) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. !d + poids(2)=xx*(xx+1.)*(xx+2.)*(xx-1.)/24. !e + poids(3)=0. + poids(4)=0. + case(2) + poids(2)=-xx**4/8.+5.*xx**3/12.+xx**2/8.-5.*xx/12. + poids(3)=0. + poids(4)=0. + case(3) + poids(1)=-xx**4/8.-xx**3/12.+5.*xx**2/8.+7.*xx/12. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(4) + poids(2)=xx*(xx+2.)*(xx**2-1.)/24. + poids(3)=0. + poids(4)=0. + case(5) + poids(1)=xx*(xx+1.)*(xx+2.)*(xx+3.)/24. + poids(2)=0. + poids(3)=0. + poids(4)=0. + case(6) + poids(2)=-xx*(xx+1.)*(xx-3.)*(xx-1.)/6. + poids(3)=xx**3/6.-0.5*xx*2+xx/3. + poids(4)=xx*(xx-1)*(xx-2.)*(xx-3.)/24. + case(7) + poids(1)=-xx*(xx+1.)*(xx+2.)*(xx-2.)/6. + poids(2)=xx*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + case(8) + poids(1)=-0.5*xx**3+0.5*xx**2+xx + poids(2)=-xx*(xx-3)*(xx**2-1.)/6. + poids(3)=xx*(xx-2.)*(xx**2-1.)/24. + poids(4)=0. + end select + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_z_v2 + + + + subroutine limit_l2_bloc_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poidx + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2) :: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1) :: phi + + + remaille=0. + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + poidx=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + else + + poidx(0)=ca(xx-1.,1) + if (test (i,1) ) then + poidx(1)=cb(xx-1.,1,1) + poidx(2)=cc(xx-1.,1) + else + poidx(1)=cb(xx-1.,1,0) + poidx(2)=cc(xx-1.,0) + end if + + end if + + case(1) + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + + case(2) + poidx(0)=ca(xx-1.,1) + poidx(1)=cb(xx-1.,1,0)+cc(xx-1.,0) + case(3) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0)+cc(xx,0) + case(4) + poidx(0)=ca(xx,1)+cb(xx,1,0) + poidx(1)=cc(xx,0) + + + + case(5) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0)-cc(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + case(6) + poidx(-1)=ca(xx,0) + poidx(0)=ca(xx-1.,1)-ca(xx,0) + poidx(1)=cb(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + + case(7) + poidx(-2)=ca(xx+1.,0) + poidx(-1)=ca(xx,0)-ca(xx+1.,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0) + end select + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. ! +1./6. + case(0) + c=-x**2+1. -2./8. !-2./6. + case(1) + c=0.5*x*(1.+x) +1./8. ! +1./6. + end select + + end function coeff_tscg + + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posx(mod(ipart-1+vois+npart,npart)+1) - real( floor((posx(mod(ipart-1+vois+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posx(mod(i-1+ib+npart,npart)+1) - real( floor((posx(mod(i-1+ib+npart,npart)+1)-xg)/dx) ,kind=8)*dx-xg)/dx + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + + end subroutine limit_l2_bloc_x + + + + + subroutine limit_l2_bloc_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poidx + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2) :: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1) :: phi + + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + poidx=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + else + + poidx(0)=ca(xx-1.,1) + if (test (i,1) ) then + poidx(1)=cb(xx-1.,1,1) + poidx(2)=cc(xx-1.,1) + else + poidx(1)=cb(xx-1.,1,0) + poidx(2)=cc(xx-1.,0) + end if + + end if + + case(1) + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + + case(2) + poidx(0)=ca(xx-1.,1) + poidx(1)=cb(xx-1.,1,0)+cc(xx-1.,0) + case(3) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0)+cc(xx,0) + case(4) + poidx(0)=ca(xx,1)+cb(xx,1,0) + poidx(1)=cc(xx,0) + + + + case(5) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0)-cc(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + case(6) + poidx(-1)=ca(xx,0) + poidx(0)=ca(xx-1.,1)-ca(xx,0) + poidx(1)=cb(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + + case(7) + poidx(-2)=ca(xx+1.,0) + poidx(-1)=ca(xx,0)-ca(xx+1.,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0) + end select + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. + case(0) + c=-x**2+1. -2./8. + case(1) + c=0.5*x*(1.+x) +1./8. + end select + + end function coeff_tscg + + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posy(mod(ipart-1+vois+npart,npart)+1) - real( floor((posy(mod(ipart-1+vois+npart,npart)+1)-yb)/dy) ,kind=8)*dy-yb)/dy + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posy(mod(i-1+ib+npart,npart)+1) - real( floor((posy(mod(i-1+ib+npart,npart)+1)-yb)/dy) ,kind=8)*dy-yb)/dy + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + + end subroutine limit_l2_bloc_y + + + + + subroutine limit_l2_bloc_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar,j,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poidx + real(kind=8) :: xx,tmp_pos + real(kind=8),dimension(0:2) :: phi_mdemi,phi_pdemi + real(kind=8),dimension(0:1) :: phi + + + remaille=0. + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + jvar=nint((posy(i)-yb)/dy)+1 + + poidx=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul du limiteur pour cas de bloc centre avec xx>0.5 + !-------------------------------------------------------- + call calcul_phi_tvd(phi,1) + phi_mdemi(1)=phi(0) + phi_pdemi(1)=phi(1) + + !les autres cas ... + !--------------------- + call calcul_phi_tvd(phi,0) + phi_mdemi(0)=phi(0) + phi_pdemi(0)=phi(1) + + phi_mdemi(2)=0. + phi_pdemi(2)=0. + + select case (blocg(i)) + + case(0) + if (xx<=0.5) then + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + else + + poidx(0)=ca(xx-1.,1) + if (test (i,1) ) then + poidx(1)=cb(xx-1.,1,1) + poidx(2)=cc(xx-1.,1) + else + poidx(1)=cb(xx-1.,1,0) + poidx(2)=cc(xx-1.,0) + end if + + end if + + case(1) + + poidx(-1)=ca(xx,0) + if (test (i,1) ) then + poidx(0)=cb(xx,0,1) + poidx(1)=cc(xx,1) + else + poidx(0)=cb(xx,0,0) + poidx(1)=cc(xx,0) + end if + + + case(2) + poidx(0)=ca(xx-1.,1) + poidx(1)=cb(xx-1.,1,0)+cc(xx-1.,0) + case(3) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0)+cc(xx,0) + case(4) + poidx(0)=ca(xx,1)+cb(xx,1,0) + poidx(1)=cc(xx,0) + + + + case(5) + poidx(-1)=ca(xx,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0)-cc(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + case(6) + poidx(-1)=ca(xx,0) + poidx(0)=ca(xx-1.,1)-ca(xx,0) + poidx(1)=cb(xx-1.,1) + poidx(2)=cc(xx-1.,1) + + + case(7) + poidx(-2)=ca(xx+1.,0) + poidx(-1)=ca(xx,0)-ca(xx+1.,0) + poidx(0)=cb(xx,0) + poidx(1)=cc(xx,0) + end select + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + contains + + function coeff_l2g (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) + case(0) + c=1.-x**2 + case(1) + c=0.5*x*(1.+x) + end select + + end function coeff_l2g + + function coeff_tscg (num,x) result(c) + implicit none + integer,intent(in) :: num + real(kind=8),intent(in) :: x + real(kind=8) :: c + + select case(num) + case(-1) + c=0.5*x*(x-1.) +1./8. + case(0) + c=-x**2+1. -2./8. + case(1) + c=0.5*x*(1.+x) +1./8. + end select + + end function coeff_tscg + + function ca(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: ca + + ca=coeff_tscg(-1,x)+phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + + end function ca + + function cb(x,num,num2) + integer :: num + real(kind=8) :: x + integer,optional :: num2 + real(kind=8) :: cb + + if (present (num2)) then + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num2)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + else + cb=1.-(coeff_tscg(-1,x)+coeff_tscg(1,x))-phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x))-phi_mdemi(num)*(coeff_l2g(-1,x)-coeff_tscg(-1,x)) + end if + + end function cb + + function cc(x,num) + integer :: num + real(kind=8) :: x + real(kind=8) :: cc + + cc=coeff_tscg(1,x)+phi_pdemi(num)*(coeff_l2g(1,x)-coeff_tscg(1,x)) + + + end function cc + + function test (ipart,vois) + implicit none + integer :: ipart,vois + logical :: test + real(kind=8) :: x + + test=.false. + x=(posz(mod(ipart-1+vois+npart,npart)+1) - real( floor((posz(mod(ipart-1+vois+npart,npart)+1)-zd)/dz) ,kind=8)*dz-zd)/dz + if ( ((blocg(mod(ipart-1+vois+npart,npart)+1)==0).or.(blocg(mod(ipart-1+vois+npart,npart)+1)==2)).and.(x>0.5)) test=.true. + + end function test + + + + subroutine calcul_phi_tvd(phi_out,num) + implicit none + integer :: num + real(kind=8),dimension(0:1),intent(out):: phi_out + real(kind=8),dimension(-5:5) :: u + real(kind=8) :: rp,rm,diff1,diff2,diff3,diff0,rmm,y,r + integer :: ib,jb + real(kind=8),dimension(-5:5) :: xx_vois,x,tp1,tp2,tp3 + + !particules voisines + !------------------- + do ib=-2,2 + u(ib)=donne(mod(i-1+ib+npart,npart)+1) + end do + + do ib=-1,2 + x(ib)=(posz(mod(i-1+ib+npart,npart)+1) - real( floor((posz(mod(i-1+ib+npart,npart)+1)-zd)/dz) ,kind=8)*dz-zd)/dz + end do + + + !cas bloc centre xx>0.5 (psi) + !----------------------- + if (num==1) then + + do ib=0,1 + x(ib)=x(ib)-1. + tp1(ib)=6.-8.*x(ib)*x(ib) + tp3(ib)=4.*(x(ib)-0.5)**2 + end do + + do ib=0,1 + r=(u(ib+1)-u(ib))/(u(ib)-u(ib-1)) + + !anti diffusif + !phi_out(ib)=max(0.,min(tp3(ib),tp1(ib)*r)) + + !du type Minmod (attention non justifié pour y>=0.8) + phi_out(ib)=max(0.,min(1.,4.*r)) + + !bornes dépendent de la condition cfl + !phi_out(ib)=max(0.,min(1.,tp3(ib),tp1(ib)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + + + + else + !sinon (phi) + !----------------------- + + + do ib=-1,0 + tp1(ib)=6.-8.*x(ib)*x(ib) + tp2(ib)=4.*(x(ib)+0.5)**2 + end do + + + do ib=0,1 + r=(u(ib-1)-u(ib-2))/(u(ib)-u(ib-1)) + !phi_out(ib)=max(0.,min(tp2(ib-1),tp1(ib-1)*r)) + phi_out(ib)=max(0.,min(1.,4.*r)) + !phi_out(ib)=max(0.,min(1.,tp2(ib-1),tp1(ib-1)*r)) + + if(abs(u(ib)-u(ib-1))<0.0000001) phi_out(ib)=0. + end do + + end if + + + end subroutine calcul_phi_tvd + + + end subroutine limit_l2_bloc_z + + + + + + +end module remaillage_mod + + diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/resultats_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/resultats_mod.f90 new file mode 100644 index 000000000..00b0917ff --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/resultats_mod.f90 @@ -0,0 +1,90 @@ +module resultats_mod + use donnees_mod + use tab_mod +contains + + + subroutine res_vtk_q (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A15)') "SCALARS U FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + !ordre i,k,j pour plot vtk de la sphere "droit" + do i=1,nx + do k=1,nz + do j=1,ny + write(11,'(f20.9)') real(qg(i,j,k)) + end do + end do + end do + + + close (11) + + end subroutine res_vtk_q + + subroutine res_vtk (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A15)') "SCALARS U FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(f20.9)') real(qg(i,j,k)) + end do + end do + end do + + write(11,'(A21)') "" + write(11,'(A21)') "VECTORS VITESSE FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j,k)),real(vyg(i,j,k)),real(vzg(i,j,k)) + end do + end do + end do + + close (11) + + end subroutine res_vtk + + + + +end module resultats_mod + diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/tab_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/tab_mod.f90 new file mode 100644 index 000000000..02efd03f3 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/tab_mod.f90 @@ -0,0 +1,14 @@ +module tab_mod + + !grille + real(kind=8),dimension(:,:,:),pointer :: qg,vxg,vyg,vzg,vxg1,vyg1,vzg1,vxg2,vyg2,vzg2,vxg3,vyg3,vzg3,vxg4,vyg4,vzg4,exa + real(kind=8),dimension(:),pointer :: xtab,ytab,ztab + integer,dimension(:,:,:),pointer :: numpg + !particule + real(kind=8),dimension(:),pointer :: xp,yp,zp,qp,vx,vy,vz,xp0,xp1,xp2,xp3,yp0,yp1,yp2,yp3,zp0,zp1,zp2,zp3 + real(kind=8),dimension(:),pointer :: vx0,vx1,vx2,vx3,vx4,vx5,vy0,vy1,vy2,vy3,vy4,vy5,vz0,vz1,vz2,vz3,vz4,vz5 + integer,dimension(:),pointer :: blocg,blocd,Nbloc + + + +end module tab_mod diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/tps_Petros.txt b/CodesEnVrac/CodesAdrien/split_3d_rapide/tps_Petros.txt new file mode 100644 index 000000000..e4960323d --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/tps_Petros.txt @@ -0,0 +1,43 @@ + +CUTOFF 0.025 +------------ + +mp4_100_rk4_tenso_dtP_cutP_t1_karma.tps + 73.4125880000000 + 13718 30072 + +l2b_100_o2_sp_cfl4_cutP_t1_karma.tps + 83.8412390000000 + 13718 28648 + + + +CUTOFF 10-4 +----------- + +mp4_100_rk2_tenso_dtP_cutm4_t1_karma.tps + 22.1133810000000 + 13718 109841 + +mp4_100_rk4_tenso_dtP_cutm4_t1_karma.tps + 191.911994000000 + 13718 109808 + +l2b_100_o2_sp_cfl4_cutm4_t1_karma.tps + 86.5654090000000 86.5654090000000 + 13718 0 89526 + +l2_100_o2_sp_cfl4_cutm4_t1_karma.tps + 15.5729730000000 15.5729730000000 + 13718 0 85024 + +l2_100_rk2_tenso_cfl4_cutm4_t1_karma.tps + 11.9207440000000 11.9207440000000 + 13718 0 87452 + + + + + +cfl4 -> dt=0.02 +dtP=dt Petros=2/150=0.0133 diff --git a/CodesEnVrac/CodesAdrien/split_3d_rapide/utile_mod.f90 b/CodesEnVrac/CodesAdrien/split_3d_rapide/utile_mod.f90 new file mode 100644 index 000000000..0ad2996d2 --- /dev/null +++ b/CodesEnVrac/CodesAdrien/split_3d_rapide/utile_mod.f90 @@ -0,0 +1,800 @@ +module utile_mod + use donnees_mod + use tab_mod +contains + + subroutine alloc_sub + allocate (qg(1:nx,1:ny,1:nz),vxg(1:nx_gro,1:ny_gro,1:nz_gro),vyg(1:nx_gro,1:ny_gro,1:nz_gro),vzg(1:nx_gro,1:ny_gro,1:nz_gro)) + allocate (xp(1:npart),qp(1:npart),vx(1:npart),yp(1:npart),vy(1:npart),zp(1:npart),vz(1:npart)) + + allocate (xtab(1:nx),ytab(1:ny),ztab(1:nz)) + !allocate (exa(1:nx,1:ny,1:nz)) + + allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + + + !rk3 + allocate (xp2(1:npart),yp2(1:npart),zp2(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vx3(1:npart),vx4(1:npart),vy1(1:npart),vz1(1:npart)) + allocate (xp0(1:npart)) + allocate (vy2(1:npart),vy3(1:npart),vy4(1:npart),vy5(1:npart)) + allocate (zp0(1:npart)) + allocate (vz2(1:npart),vz3(1:npart),vz4(1:npart)) + + !rk4 + allocate (xp3(1:npart),yp3(1:npart),zp3(1:npart)) + + !pour la correction de consistance + allocate (numpg(1:nx,1:ny,1:nz)) + allocate (blocg(0:npart),blocd(0:npart),Nbloc(0:npart)) + end subroutine alloc_sub + + + + subroutine make_grille + implicit none + integer :: i,j,k + + do k=1,nz + ztab(k)=zd+(k-1)*dz + end do + do j=1,ny + ytab(j)=yb+(j-1)*dy + end do + do i=1,nx + xtab(i)=xg+(i-1)*dx + end do + + end subroutine make_grille + + + function tsource(t,x,y,z) + implicit none + real(kind=8),intent(in) :: t,x,y,z + real(kind=8) :: tsource,t1,t2,t3,c1,c2,c3 + + t2=0.2 + t3=0.3 + + !u=u(t,x,y,z) + !------------ + c1=cos(2.*pi*x)*cos(2.*pi*y)*cos(2.*pi*z) + c2=cos(pi*t/t2)*cos(pi*t/t3) + c3=sin(2.*pi*x)*sin(2.*pi*y)*sin(2.*pi*z) + + tsource=-pi*(sin(pi*t/t2)*c1)/t2 & + +2.*pi*c3*c2*c1& + -4.*pi*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z)*c2*sin(2.*pi*x)*cos(2.*pi*y)*cos(2.*pi*z)& + -pi*c3*c2*c1& + +2.*pi*sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z)*c2*cos(2.*pi*x)*sin(2.*pi*y)*cos(2.*pi*z)& + -pi*c3*c2*c1& + +2.*pi*sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2*c2*cos(2.*pi*x)*cos(2.*pi*y)*sin(2.*pi*z) +!!$ +!!$ tsource=0. + + end function tsource + + +subroutine source_rk4 + use advection_mod + implicit none + integer :: i + real(kind=8) :: rk1,rk2,rk3,rk4,t1,t2,t3 + real(kind=8) :: x1,x2,x3,y1,y2,y3,z1,z2,z3 + real(kind=8) :: v1x,v2x,v3x,v1y,v2y,v3y,v1z,v2z,v3z + + + + do i=1,npart + + !euler + !------ + !qp(i)=qp(i)+dt*tsource(time,xp(i),yp(i),zp(i)) + + !rk2 + !---- + !qp(i)=qp(i)+dt*tsource(time+0.5*dt,xp(i)+0.5*dt*vx(i),yp(i)+0.5*dt*vy(i),zp(i)+0.5*dt*vz(i)) + + + !rk4 + !--- + rk1=tsource(time,xp(i),yp(i),zp(i)) + x1=xp(i)+0.5*dt*vx(i) + y1=yp(i)+0.5*dt*vy(i) + z1=zp(i)+0.5*dt*vz(i) + rk2=tsource(time+0.5*dt,x1,y1,z1) + call evalv (v1x,v1y,v1z,time+0.5*dt,x1,y1,z1) + x2=xp(i)+0.5*dt*v1x + y2=yp(i)+0.5*dt*v1y + z2=zp(i)+0.5*dt*v1z + rk3=tsource(time+0.5*dt,x2,y2,z2) + call evalv (v2x,v2y,v2z,time+0.5*dt,x2,y2,z2) + x3=xp(i)+dt*v2x + y3=yp(i)+dt*v2y + z3=zp(i)+dt*v2z + rk4=tsource(time+dt,x3,y3,z3) + + qp(i)=qp(i)+dt*(rk1+2.*rk2+2.*rk3+rk4)/6. + + end do + + + end subroutine source_rk4 + + + subroutine source_split_1 + implicit none + integer :: i + + !ordre2 + !------ + do i=1,npart + qp(i)=qp(i)+0.5*dt*tsource(time,xp(i),yp(i),zp(i)) + end do + + + end subroutine source_split_1 + + subroutine source_split_2 + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z + + + !ordre2 + !------ + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + qg(i,j,k)=qg(i,j,k)+0.5*dt*tsource(time+dt,x,y,z) + !qg(i,j,k)=qg(i,j,k)+0.5*dt*tsource(time,x,y,z) + + end do + end do + end do + + end subroutine source_split_2 + + + + subroutine make_bloc(esp) + use donnees_mod + implicit none + integer,intent(in) :: esp + integer :: fin,ib,i,j,k,l,im,ip,dim1,dim2,dim3 + logical :: zero + real(kind=8) :: pas + + select case(esp) + case(1) + dim1=nx + dim2=ny + dim3=nz + pas=dx + case(2) + dim1=ny + dim2=nz + dim3=nx + pas=dy + case(3) + dim1=nz + dim2=nx + dim3=ny + pas=dz + end select + + + !----------------------------------------------------------------------------------------- + !Determine la nature des blocs + !Donne un flag correspondant au type de remaillage necessaire (centre,decentre ou modifie) + !------------------------------------------------------------------------------------------ + + blocg(1:npart)=1 + blocd(1:npart)=1 + + direction1: do l=1,dim3 + + direction2: do j=1,dim2 + + !peut calculer la longeur -> gain si longeur eleve + + !parcours la grille, bloc par bloc:determine le type des bloc + !--------------------------------- + + blocg(0)=100 + blocd(0)=100 + Nbloc(0)=100 + + type_bloc:do i=1,dim1,long_bloc+1 + + + if ( (i+long_bloc)<(dim1-1) ) then + fin=i+long_bloc + call sub_typeb + else + !parcours le bloc plus premier point du bloc suivant + fin=dim1-1 + call sub_typeb + blocg(pg(dim1,j,l))=blocg(pg(dim1-1,j,l)) + blocd(pg(dim1,j,l))=blocd(pg(dim1-1,j,l)) + Nbloc(pg(dim1,j,l))=Nbloc(pg(dim1-1,j,l)) + end if + + end do type_bloc + + !parcours la grille, bloc par bloc:determine si modif de remaillage necessaire a l'intersection des blocs + !--------------------------------- + type_remaill:do i=1,dim1,long_bloc+1 + + if (((i+long_bloc)<dim1).and.(i>1+long_bloc)) then + fin=i+long_bloc + call sub_remb + else + if (i<=1+long_bloc)then + !premier bloc + !------------- + fin=i+long_bloc + call sub_remb + + else + !dernier bloc + !------------- + fin=dim1 + call sub_remb + + end if + + end if + + end do type_remaill + end do direction2 + end do direction1 + + contains + + subroutine sub_typeb + + integer :: ni,N + real(kind=8) :: li + logical :: pasfait + + + !parcours une premiere fois le bloc pour savoir si c'est un bloc en 0 ou 1/2 + !---------------------------------- + pasfait=.true. + zero=.true. + do_zero:do ib=i,fin+1 !eviter cas change de bloc quand maille vide + if (pg(ib,j,l)/=0) then + if (pasfait) then !le N doit etre le meme pour tout le bloc ! + li=dt/pas*vit(pg(ib,j,l)) + ni=floor(li+0.5) + pasfait=.false. + end if + li=dt/pas*vit(pg(ib,j,l)) + if ( ((li)<(ni-0.5)).or.((li)>(ni+0.5)) ) then + zero=.false. + exit do_zero + end if + end if + end do do_zero + + + !parcours a nouveau le bloc + !------------------------- + !affecte le type de bloc a toute les part du bloc + + pasfait=.true. + bloc2:do ib=i,fin + + if (pg(ib,j,l)/=0) then + + !calcul de N + !------------ + if (pasfait) then + if (zero) then + N=floor(dt/pas*vit(pg(ib,j,l))+0.5) + pasfait=.false. + else + N=floor(dt/pas*vit(pg(ib,j,l))) + pasfait=.false. + end if + end if + + if (zero) then + !bloc pour lambda2 centre + blocg(pg(ib,j,l))=0 + blocd(pg(ib,j,l))=0 + end if + + !affecte la constante N + Nbloc(pg(ib,j,l))=N + + end if + end do bloc2 + + end subroutine sub_typeb + + + subroutine sub_remb + implicit none + + integer,dimension(-2:2) :: iper + integer :: k + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection de ces blocs + + if (i==fin) then + blocg(i)=blocg(i-1) + blocd(i)=blocd(i-1) + else + bloc3:do ib=i,fin,fin-i + + if (pg(ib,j,l)/=0) then + + !si fin de bloc en 0. : + !---------------------- + do k=-2,2 + iper(k)=pg(mod(ib+k+dim1-1,dim1)+1,j,l) + end do + + + if ((ib==fin).and.(blocd(pg(ib,j,l))==0).and.((blocg(iper(1))==1).or.(blocg(iper(2))==1)).and.((Nbloc(iper(1))==Nbloc(pg(ib,j,l))-1) .or.(Nbloc(iper(2))==Nbloc(pg(ib,j,l))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j,l))<=Nbloc(pg(ib,j,l)) ) then + blocg(iper(1))=2 + blocd(pg(ib,j,l))=3 + else + blocg(iper(1))=2 + blocd(pg(ib,j,l))=4 + blocg(pg(ib,j,l))=5 + end if + + else + blocg(iper(1))=2 + blocg(iper(2))=5 + + if ( dt/pas*vit(pg(ib,j,l))<=Nbloc(pg(ib,j,l)) ) then + blocd(pg(ib,j,l))=3 + else + blocd(pg(ib,j,l))=7 + blocg(pg(ib,j,l))=8 + end if + + if ( dt/pas*vit(iper(-1))<=Nbloc(pg(ib,j,l)) ) then + blocd(iper(-1))=6 + else + blocd(iper(-1))=5 + end if + end if + + end if + + + !si debut de bloc en 0 : detecte quelle correction il faudra apporter + !---------------------- + if ((ib==i) .and.(blocg(pg(ib,j,l))==0).and.((blocd(iper(-1))==1).or.(blocd(iper(-2))==1)).and.((Nbloc(iper(-1))==Nbloc(pg(ib,j,l))-1) .or. (Nbloc(iper(-2))==Nbloc(pg(ib,j,l))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j,l))>Nbloc(pg(ib,j,l)) ) then + blocd(iper(-1))=2 + blocg(pg(ib,j,l))=4 + else + blocd(iper(-1))=2 + blocg(pg(ib,j,l))=3 + end if + + else + + blocd(iper(-1))=2 + blocd(iper(-2))=4 + + if ( dt/pas*vit(pg(ib,j,l))>Nbloc(pg(ib,j,l)) ) then + blocg(pg(ib,j,l))=4 + else + blocg(pg(ib,j,l))=3 + end if + + if ( dt/pas*vit(iper(1))>Nbloc(pg(ib,j,l)) ) then + blocg(iper(1))=7 + else + blocg(iper(1))=6 + end if + + end if + end if + + + + end if + end do bloc3 + end if + + end subroutine sub_remb + + function pg(a,b,c) + implicit none + integer,intent(in) :: a,b,c + integer :: pg + + select case (esp) + case(1) + pg=numpg(a,b,c) + case(2) + pg=numpg(c,a,b) + case(3) + pg=numpg(b,c,a) + end select + + end function pg + + function vit(ind) + implicit none + integer,intent(in) :: ind + real(kind=8) :: vit + + select case (esp) + case(1) + vit=vx(ind) + case(2) + vit=vy(ind) + case(3) + vit=vz(ind) + end select + + end function vit + + + end subroutine make_bloc + + + +subroutine make_bloc_v2(esp) + use donnees_mod + implicit none + integer,intent(in) :: esp + integer :: fin,ib,i,j,k,l,im,ip,dim1,dim2,dim3 + integer :: n,np,part,partp,partm,partpp + real(kind=8) :: pas + + select case(esp) + case(1) + dim1=nx + dim2=ny + dim3=nz + pas=dx + case(2) + dim1=ny + dim2=nz + dim3=nx + pas=dy + case(3) + dim1=nz + dim2=nx + dim3=ny + pas=dz + end select + + !----------------------------------------------------------------------------------------- + !Determine la nature des blocs + !Donne un flag correspondant au type de remaillage necessaire (centre,decentre ou modifie) + !------------------------------------------------------------------------------------------ + + blocg(1:npart)=1 + blocd(1:npart)=1 + + blocg(0)=100 + blocd(0)=100 + Nbloc(0)=100 + + + + direction1: do l=1,dim3 + + direction2: do j=1,dim2 + + !peut calculer la longeur -> gain si longeur eleve + + !parcours la grille, bloc par bloc:determine le type des bloc + !--------------------------------- + + type_bloc:do i=1,dim1,long_bloc+1 + + + if ( (i+long_bloc)<(dim1-1) ) then + fin=i+long_bloc + call sub_typeb + else + !parcours le bloc plus premier point du bloc suivant + do k=i,dim1 + blocg(pg(k,j,l))=blocg(pg(i-1,j,l)) + blocd(pg(k,j,l))=blocd(pg(i-1,j,l)) + Nbloc(pg(k,j,l))=Nbloc(pg(i-1,j,l)) + end do + end if + + end do type_bloc + + !parcours la grille, bloc par bloc:determine si modif de remaillage necessaire a l'intersection des blocs + !--------------------------------- + type_remaill:do i=1,dim1,long_bloc+1 + + if ((i+long_bloc)<dim1) then + + fin=i+long_bloc + + k=fin + do while ((pg(k,j,l)==0).and.(k>i)) + k=k-1 + end do + n=Nbloc(pg(k,j,l)) ! s'il n'y a pas de part dans le bloc N=100 -> ne fera pas de correction + + k=fin+1 + do while ((pg(k,j,l)==0).and.(k<(fin+long_bloc+2)).and.(k<nx)) + k=k+1 + end do + np=Nbloc(pg(k,j,l)) + + part=pg(fin,j,l) + partp=pg(fin+1,j,l) + partm=pg(fin-1,j,l) + partpp=pg(fin+2,j,l) + + if (type_b==2) call sub_remb_2(n,np,part,partp) + if (type_b==4) call sub_remb_4(n,np,part,partp,partm,partpp) + + + else + + !dernier bloc + !------------- + fin=dim1 + + k=fin + do while ((pg(k,j,l)==0).and.(k>i)) + k=k-1 + end do + n=Nbloc(pg(k,j,l)) + + k=1 + do while ((pg(k,j,l)==0).and.(k<(1+long_bloc+1))) + k=k+1 + end do + np=Nbloc(pg(k,j,l)) + + part=pg(fin,j,l) + partp=pg(1,j,l) + partm=pg(fin-1,j,l) + partpp=pg(2,j,l) + + if (type_b==2) call sub_remb_2(n,np,part,partp) + if (type_b==4) call sub_remb_4(n,np,part,partp,partm,partpp) + + + end if + + end do type_remaill + end do direction2 + end do direction1 + + contains + + subroutine sub_typeb + + integer :: N,intl + real(kind=8) :: li,lmin + + + !parcours une premiere fois le bloc pour savoir si c'est un bloc en 0 ou 1/2 + !---------------------------------- + lmin=99999999999999999999999. + do_lmin:do ib=i,fin + if (pg(ib,j,l)/=0) then + li=dt/pas*vit(pg(ib,j,l)) + lmin=min(lmin,li) + end if + end do do_lmin + + !calcul du type de bloc et de N + !------------------------------- + intl=floor(lmin) + if ((lmin-intl).le.0.5) then + !type gauche + !----------- + N=intl + do_typeg:do ib=i,fin + if (pg(ib,j,l)/=0) then + blocg(pg(ib,j,l))=1 + blocd(pg(ib,j,l))=1 + Nbloc(pg(ib,j,l))=N + end if + end do do_typeg + else + !type centre + !----------- + N=intl+1 + do_typec:do ib=i,fin + if (pg(ib,j,l)/=0) then + blocg(pg(ib,j,l))=0 + blocd(pg(ib,j,l))=0 + Nbloc(pg(ib,j,l))=N + end if + end do do_typec + end if + + end subroutine sub_typeb + + subroutine sub_remb_2(n,np,partf,partfp) + !attention les bords ne sont pas bien traités + implicit none + + integer,intent(in) ::n,np,partf,partfp + real(kind=8) :: li + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection des blocs + if ((np) == (n-1)) then + li=dt/pas*vit(partf) + if ( (li<n).and.(blocg(partf)==0) ) then !seconde condition=bloc centre + blocg(partf)=2 + else + blocg(partf)=3 + end if + blocg(partfp)=4 + end if + if ((np) == (n+1)) then + li=dt/pas*vit(partfp) + blocg(partf)=5 + if ((li<np).and.(blocg(partfp)==0)) then + blocg(partfp)=6 + else + blocg(partfp)=7 + end if + end if + + + + end subroutine sub_remb_2 + + + subroutine sub_remb_4(n,np,partf,partfp,partfm,partfpp) + !attention les bords ne sont pas bien traités + implicit none + + integer,intent(in) ::n,np,partf,partfp,partfm,partfpp + real(kind=8) :: li + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection des blocs + + !N_{m+1}=N_m -1 + !-------------- + if ((np) == (n-1)) then + !si bloc centre + if (blocd(partfm)==0) then + li=dt/pas*vit(partfm) + if ( (li<n) ) then + blocd(partfm)=2 + else + blocd(partfm)=3 + end if + else + blocd(partfm)=3 + end if + if (blocg(partf)==0) then + li=dt/pas*vit(partf) + if ( (li<n) ) then + blocg(partf)=2 + blocd(partf)=4 + else + blocg(partf)=3 + blocd(partf)=5 + end if + else + blocg(partf)=3 + blocd(partf)=5 + end if + blocg(partfp)=4 + blocd(partfp)=1 + li=dt/pas*vit(partfpp) + if ( (blocg(partfpp)==0).and.(li<np) ) then + blocg(partfpp)=5 + else + blocg(partfpp)=6 + end if + end if + !N_{m+1}=N_m +1 + !-------------- + if ((np) == (n+1)) then + li=dt/pas*vit(partfm) + if ( (blocd(partfm)==0).and.(li<n) ) then + blocd(partfm)=6 + else + blocd(partfm)=7 + end if + blocg(partf)=1 + blocd(partf)=8 + if (blocg(partfp)==0) then + li=dt/pas*vit(partfp) + if ( (li<np) ) then + blocg(partfp)=7 + blocd(partfp)=0 + else + blocg(partfp)=8 + blocd(partfp)=1 + end if + else + blocg(partfp)=8 + blocd(partfp)=1 + end if + if (blocg(partfpp)==0) then + li=dt/pas*vit(partfpp) + if ( (li<np) ) then + blocg(partfpp)=9 + else + blocg(partfpp)=10 + end if + else + blocg(partfpp)=10 + end if + + end if + + + + end subroutine sub_remb_4 + + + function pg(a,b,c) + implicit none + integer,intent(in) :: a,b,c + integer :: pg + + select case (esp) + case(1) + pg=numpg(a,b,c) + case(2) + pg=numpg(c,a,b) + case(3) + pg=numpg(b,c,a) + end select + + end function pg + + function vit(ind) + implicit none + integer,intent(in) :: ind + real(kind=8) :: vit + + select case (esp) + case(1) + vit=vx(ind) + case(2) + vit=vy(ind) + case(3) + vit=vz(ind) + end select + + end function vit + + + end subroutine make_bloc_v2 + + + + end module utile_mod + + diff --git a/CodesEnVrac/LEGI/src/cart_topology.f90 b/CodesEnVrac/LEGI/src/cart_topology.f90 new file mode 100644 index 000000000..6985a4fa7 --- /dev/null +++ b/CodesEnVrac/LEGI/src/cart_topology.f90 @@ -0,0 +1,288 @@ +!------------------------------------------------------------------------------ +! +! MODULE: cart_topology +! +! +! DESCRIPTION: +!> This module provide a cartesien topology on the parrallel layout. +!! This virtual topology is created by the MPI procedures (and thus use +!! low-level optimisation based on the underlyinfg hardware). It +!! provides the different tools to create, to manipulate and to interface +!! it with the other topology and communicators. +!! The solver use some dimensionnal splitting and this module contains all the +!! method used to solve advection along the Y-axis. This is a parallel +!! implementation using MPI and the cartesien topology it provides. +!! +!! Nowaday, the domain is only splitted along Y and Z axis. Therefore, +!! we only use a 2D cartesian topology. +!! A "global" communicator is devoted to the (2D) cartesian structure. +!! Another communicator is added for each direction in order to deal +!! with all 1D communication (along Y or Z). +!! Be careful : the (Y,Z)-axis in the 3D mesh match to the (X,Y) axis on the 2D +!! mpi-topology. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module cart_topology + + use precision + + implicit none + + public + + ! ===== Public variables ===== + + ! ----- Communicators ----- + !> Communicator associated with the cartesian topology + integer :: cart_comm + !> Communicators devoted to 1-dimensionnal subgrids (along Y and Z) + integer :: X_comm, Y_comm, Z_comm + !> Table of the preivious communicators (ie comm devoted to 1D subgrids) + integer, dimension(3) :: D_comm + + ! ----- Information about mesh subdivision and on the global grid ----- + !> number of processes in each direction + integer, dimension(3) :: nb_proc_dim + !> information about min and max local indice on the current directory + integer, dimension(3) :: begin_proc, end_proc + !> space lengh of th domain + real(WP), dimension(3) :: length + !> space step for scalar discretisation + real(WP), dimension(3) :: d_sc + !> number of (sub)grid in each direction + integer, dimension(3) :: N!, N_proc + integer, dimension(3) :: N_proc + !> rank of current processus (in the cartesian communicator) + integer :: myrank + !> coordinate of the current processus + integer, dimension(3) :: coord + !> YZ coordinate of the current processus + integer, dimension(2) :: coordYZ + !> Periodic boundary conditions : logical array, equals true if periodic + logical, dimension(3) :: periods + !> Computation are done by group of line. Here we define their size + integer, dimension(3,2) :: group_size + !> To concatenate position in order to create unique mpi message tag + integer, dimension(3,2) :: tag_size + !> To concatenate rank in order to create unique mpi message tag + integer :: tag_rank + + + ! ==== Public procedures ==== + !> Creation of the cartesian topology + public :: cart_create + !> Initialise mesh information + public :: mesh_default + public :: mesh_init + !> Compute tag for mpi message + public :: compute_tag_gap + public :: compute_tag_NP + + interface compute_tag + module procedure compute_tag_gap, compute_tag_NP + end interface compute_tag + +contains + +!> Creation of the cartesian mesh and of all communicators +subroutine cart_create(dims, ierr) + + use mpi + use parallel + + !> @param[in] dims = array specifying the number of processes in each dimension + !> @param[out] ierr = error code + integer, dimension(2), intent(in) :: dims + integer, intent(out) :: ierr + + logical :: reorganisation ! to choose to reordered or not the processus rank. + logical, dimension(3) :: remains_dim ! use to create 1D-subdivision : remains_dims(i) equal + ! true if the i-th dimension is kept in the subgrid. + ! Creation of the cartesian topology + reorganisation = .true. + periods = .true. + nb_proc_dim = (/ 1, dims(1), dims(2) /) + + call mpi_cart_create(MPI_COMM_WORLD, 3, nb_proc_dim, periods, reorganisation, & + & cart_comm, ierr) + + + ! Subdivision in 1D-subgrids and creation of communicator devoted to + ! 1D-communication + ! Communication along X-axis + remains_dim = (/.true., .false., .false. /) + call mpi_cart_sub(cart_comm, remains_dim, X_comm, ierr) + D_comm(1) = X_comm + ! Communication along Y-axis (in the 3D mesh, ie the x-axis on the mpi-topology) + remains_dim = (/.false., .true., .false. /) + call mpi_cart_sub(cart_comm, remains_dim, Y_comm, ierr) + D_comm(2) = Y_comm + ! Communication along Z-axis + remains_dim = (/ .false., .false., .true. /) + call mpi_cart_sub(cart_comm, remains_dim, Z_comm, ierr) + D_comm(3) = Z_comm + + ! Initialise information about the current processus + call mpi_comm_rank(cart_comm, myrank, ierr) + call mpi_cart_coords(cart_comm, myrank, 3, coord, ierr) + coordYZ = (/ coord(2), coord(3) /) + + ! XXX ajouter un test du code d'erreur mpi +! if(ierr/=MPI_SUCCESS) then +! call parallel_error(ierr, 'cart_create') +! end if + +end subroutine cart_create + +!> Defaut mesh setup +subroutine mesh_default() + + ! A cubic geometry : unitary lengh and 100 mesh points in each direction. + N = 100 + length = 1. + length = 1 + N_proc = N / nb_proc_dim + begin_proc = 1 + end_proc = N_proc + + call mesh_init() + +end subroutine mesh_default + +!> To initialize last mesh parameters +subroutine mesh_init() + + integer :: direction ! direction (along X = 1, along Y = 2, along Z = 3) + integer :: group_dir ! direction "bis" + integer, dimension(3,2) :: N_group ! number of group on one processus along one direction + + d_sc = length/(N) + + ! XXX Pour le moment, on travaille par groupe d'une unique ligne + group_size = 1 + + ! Compute number of group + ! Group of line along X + N_group(1,1) = N_proc(2)/group_size(1,1) + N_group(1,2) = N_proc(3)/group_size(1,2) + ! Group of line along X + N_group(2,1) = N_proc(1)/group_size(2,1) + N_group(2,2) = N_proc(3)/group_size(2,2) + ! Group of line along X + N_group(3,1) = N_proc(1)/group_size(3,1) + N_group(3,2) = N_proc(2)/group_size(3,2) + + + ! tag_size = smallest power of ten to ensure tag_size > max ind_group + do direction = 1,3 + tag_size(direction,:) = 1 + do group_dir = 1,2 + do while (N_group(direction, group_dir)/(10**tag_size(direction, group_dir))>1) + tag_size(direction, group_dir) = tag_size(direction, group_dir)+1 + end do + end do + end do + + tag_rank = 1 + do while((nb_proc_dim(1)+nb_proc_dim(2)+nb_proc_dim(3))/(10**tag_rank)>=1) + tag_rank = tag_rank+1 + end do + if (tag_rank == 1) tag_rank = 2 + + +if(myrank==0) then + print*, ' ' + print*, ' -- initialisation: tag generation --' + do direction = 1,3 + print*, 'tag_size(',direction,',:) = ', tag_size(direction,:) + end do + print*, 'tag_rank = ', tag_rank + print*, ' ------------------------------------' + print*, ' ' +end if + +end subroutine mesh_init + +!> Compute unique tag for mpi message by concatenation of position (ie line coordinate), proc_gap and unique Id +!! @param[in] ind_group = indice of current group of line +!! @param[in] tag_param = couple of int unique for each message (used to create the tag) +!! @param[in] direction = current direction +!! @param[in] proc_gap = number of processus between the sender and the receiver +!! @return tag = unique tag: at each message send during an iteration have a different tag +!!@details +!! Use this procedure to compute tag in order to communicate with a distant processus or/and when +!! you will send more then two message. It produce longer tag compute_tag_NP because rather tyo use 0/1 it +!! put the gap between the sender and the receiver (ie the number of processus between them) in the tag. +!! Using these two procedure allow to obtain more unique tag for communication. +function compute_tag_gap(ind_group, tag_param, direction,proc_gap) result(tag) + + integer :: tag + integer, dimension(2), intent(in) :: ind_group + integer, dimension(2), intent(in) :: tag_param + integer, intent(in) :: direction + integer, intent(in) :: proc_gap + + integer :: abs_proc_gap ! absolute value of proc_gap + + abs_proc_gap = max(abs(proc_gap),1) + tag = (tag_param(1)*10+direction)*(10**(tag_rank+1)) + tag = tag + abs_proc_gap*10 + dim(proc_gap/abs_proc_gap,0) + tag = tag*(10**tag_size(direction,1))+(ind_group(1)-1) + tag = ((tag*(10**tag_size(direction,2)))+(ind_group(2)-1)) + tag = (tag*10)+tag_param(2) + +if ((tag<0) .and. (myrank==0)) then +print*, 'ind_group = ', ind_group, ' ; tag_param = ', tag_param +print*, 'direction = ', direction, ' gap = ', proc_gap ,' and tag = ', tag +end if + +end function compute_tag_gap + + +!> Compute unique tag for mpi message by concatenation of position(ie line coordinate), +1 or -1 and unique Id +!! @param[in] ind_group = indice of current group of line +!! @param[in] tag_param = couple of int unique for each message (used to create the tag) +!! @param[in] direction = current direction +!! @return tag_table = unique couple tag: use tag_table(1) for mesage to previous proc. (or first +!! message ) and tag_table(2) for the other message. +!!@details +!! Use this procedure to compute tag for communication with your neighbor or when only two message are send: +!! it produce smaller tag then compute_tag_gap because the gap between sender and receiver are replaced by 1, +!! for communicate with previous processus (or first of the two message), or 0, for communication with next +!! processus (or the second message). It allow to reuse some unique Id. +function compute_tag_NP(ind_group, tag_param, direction) result (tag_table) + + integer, dimension(2) :: tag_table + integer, dimension(2), intent(in) :: ind_group + integer, dimension(2), intent(in) :: tag_param + integer, intent(in) :: direction + + tag_table(2) = (tag_param(1)*10+direction)*10 + tag_table(1) = tag_table(2) + + tag_table(2) = tag_table(2) +1 + + tag_table(2) = (tag_table(2)*(10**tag_size(direction,1)))+(ind_group(1)-1) + tag_table(1) = (tag_table(1)*(10**tag_size(direction,1)))+(ind_group(1)-1) + + tag_table(2) = ((tag_table(2)*(10**tag_size(direction,2)))+(ind_group(2)-1)) + tag_table(1) = ((tag_table(1)*(10**tag_size(direction,2)))+(ind_group(2)-1)) + + tag_table(2) = (tag_table(2)*10)+tag_param(2) + tag_table(1) = (tag_table(1)*10)+tag_param(2) + +if ((minval(tag_table)<0) .and. (myrank==0)) then +print*, 'ind_group = ', ind_group, ' ; tag_param = ', tag_param +print*, 'direction = ', direction, ' and tag = ', tag_table +end if + +end function compute_tag_NP + + +end module cart_topology + + diff --git a/CodesEnVrac/LEGI/src/particles/advec.f90 b/CodesEnVrac/LEGI/src/particles/advec.f90 new file mode 100644 index 000000000..95c03ef06 --- /dev/null +++ b/CodesEnVrac/LEGI/src/particles/advec.f90 @@ -0,0 +1,141 @@ +module advec + + use string + implicit none + + ! ===== Variables ===== + !> numerical method use to advect the scalar + character(len=str_short), private :: type_part_solv + !> dimensionnal splitting (eg classical, Strang or particle) + character(len=str_short), private :: dim_splitting + + + ! ===== Public procedures ===== + + ! Scheme used to advec the scalar (order 2 or 4 ?) + public :: type_part_solver + + ! Advection methods + public :: advec_init ! initialize the scalar solver + public :: advec_step ! advec the scalar field during a time step. + +contains + +! ===== Public methods ===== + +!> Return the name of the particle method used for the advection +function type_part_solver() + character(len=str_short) :: type_part_solver + + type_part_solver = type_part_solv +end function + +!> Initialise the particle advection methods +!! @param order = to choose the remeshing method (and thus the order) +subroutine advec_init(order) + + use cart_topology + use advec_common + + character(len=*), optional, intent(in) :: order + + ! Remplissage de la valeur par defaut en l'absence de choix explicite de la méthode numérique + if(present(order)) then + type_solv = order + else + type_solv = 'p_O2' + end if + + ! Initialisation part adapted to each method + select case(type_solv) + case('p_O2') + bl_size = 2 + bl_bound_size = 1 + case('p_O4') + bl_size = 4 + bl_bound_size = 2 + case default + bl_size = 2 + bl_bound_size = 1 + end select + + ! Check if the subdomain contain a number of mesh wich could be divided by bl_size + if ((modulo(N_proc(1),bl_size)/=0).OR.(modulo(N_proc(2),bl_size)/=0).OR.(modulo(N_proc(3),bl_size)/=0)) then + if (myrank ==0) print*, 'Number of mesh by processus must be a muliple of ', bl_size + stop + end if + + ! Compute local number of block along each direction + bl_number = N_proc/bl_size + + ! Choosing the dimensionnal splitting to use + ! XXX parser le fichier input + dim_splitting = 'strang' + +end subroutine advec_init + + +!> advec_scheme +subroutine advec_step(dt, Vx, Vy, Vz, scal, dim_split) + + use cart_topology + use advec_common + use advecX + use advecY + !use advecZ + + ! @param[in] dt = time step + ! @param[in] Vx = velocity along x (could be discretised on a bigger mesh then the scalar) + ! @param[in] Vy = velocity along y + ! @param[in] Vz = velocity along z + ! @param[in,out] scal = scalar field to advect + ! @param[in] dim_split = dimensionnal splitting (eg classical, + !! Strang splitting or particle splitting) + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vx, Vy, Vz + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout):: scal + character(len=str_short), optional, intent(in) :: dim_split + + character(len=str_short) :: splitting ! to choose the splitting + + ! Default dimensionnal splitting if the user do not choose it + if(present(dim_split)) then + splitting = dim_split + else + splitting = dim_splitting + end if + + ! Scheme used for advection : particle method (order 2 or 4) or spectral one. + if (type_solv=='spectral') then + print*, 'Solveur non implémenté' + end if + + select case(splitting) + case('classical') + !call advecX_calc(dt, Vx, scal, type_part_solv) + call advecY_calc(dt, Vy, scal, type_part_solv) + !call advecZ_calc(dt, Vz, scal, type_part_solv) + case('Strang') + !call advecX_calc(dt/2.0, Vx, scal, type_part_solv) + call advecY_calc(dt/2.0, Vy, scal, type_part_solv) + !call advecZ_calc(dt/2.0, Vz, scal, type_part_solv) + !call advecZ_calc(dt/2.0, Vz, scal, type_part_solv) + call advecY_calc(dt/2.0, Vy, scal, type_part_solv) + !call advecX_calc(dt/2.0, Vz, scal, type_part_solv) + case default + !call advecX_calc(dt/2.0, Vx, scal, type_part_solv) + call advecY_calc(dt/2.0, Vy, scal, type_part_solv) + !call advecZ_calc(dt/2.0, Vz, scal, type_part_solv) + !call advecZ_calc(dt/2.0, Vz, scal, type_part_solv) + call advecY_calc(dt/2.0, Vy, scal, type_part_solv) + !call advecX_calc(dt/2.0, Vx, scal, type_part_solv) + end select + +end subroutine advec_step + + +!> ===== Private procedure ===== + + +end module advec + diff --git a/CodesEnVrac/LEGI/src/particles/advecX.f90 b/CodesEnVrac/LEGI/src/particles/advecX.f90 new file mode 100644 index 000000000..0fceffa1d --- /dev/null +++ b/CodesEnVrac/LEGI/src/particles/advecX.f90 @@ -0,0 +1,379 @@ +!------------------------------------------------------------------------------ +! +! MODULE: advecX +! +! +! DESCRIPTION: +!> This module is a part of the advection solver based on particles method. +!! The solver use some dimensionnal splitting and this module contains all the +!! method used to solve advection along the X-axis. This is a parallel +!! implementation using MPI and the cartesien topology it provides. +!! +!! This module can use the method and variables defined in the module +!! "advec_common" which gather information and tools shared for advection along +!! x, y and z-axis. +!! +!! The module "test_advec" can be used in order to validate the procedures +!! embedded in this module. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +!> @addtogroup part +!! @{ +module advecX + + use precision + + implicit none + + ! ===== Public procedures ===== + !> Generique procedure to advect the scalar with a particles solver + public :: advecX_calc + !----- (corrected) Remeshing method (these methods are set to public in validation purposes) ----- + public :: Xremesh_O2 ! order 2 + public :: Xremesh_O4 ! order 4 + + ! ===== Private porcedures ===== + !> particles solver with remeshing method at order 2 + private :: advecX_calc_O2 + private :: advecX_init ! initialize particle position, velocity and weight + + contains + +! ===== Public procedure ===== + +!> Scalar advection (this procedure call the right solver, depending on the simulation setup) +!! @param[in] dt = time step +!! @param[in] Vx = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] SC = scalar field to advect +!! @param[in] type_solver = scheme use for the advection (particle with order 2 or 4) +subroutine advecX_calc(dt, Vx, SC, type_solver) + + use string + use cart_topology + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vx + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: SC + character(len=*), intent(in) :: type_solver + + + + ! Call the right solver depending on the space order we want to. + select case(type_solver) + case('p_O2') + call advecX_calc_O2(dt, Vx, SC) + case default + call advecX_calc_O2(dt, Vx, SC) + end select + +end subroutine advecX_calc + +! ----- Remeshing procedures ----- + + +! ===== Private procedure ===== + +! ---- Order 2 solver, with correction for large time step ---- + +!> remeshing with an order 2 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in] bl_tag = contains information about bloc (is it tagged ?) +!! @param[in] j,k = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in,out] scal = scalar field to advect +subroutine Xremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,j,k,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: j, k + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + +integer :: direction=1 ! current direction + + real(WP), dimension(N_proc(1)) :: p_sc ! scalar advected by the particles + ! Variable used to remesh particles in a buffer + integer :: i ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + + + ! -- Initialise particle weigth + do i = 1, N_proc(direction) + p_sc(i) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-1 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-1 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+1 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+1 + end if + + ! XXX j_min and j_max could be optimized !! (use that sub-domains cut + ! particles block in two egals parts) + allocate(send_buffer(send_j_min:send_j_max)) + send_buffer = 0.0; + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do i = 1, N_proc(direction), bl_size + bl_ind = i/bl_size + 1 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_left(p_pos_adim(i+1),p_sc(i+1), send_buffer) + case (10) + ! no tag, the first particle belong to a left block and the last to centered block. + call AC_remesh_left(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_center(p_pos_adim(i+1),p_sc(i+1), send_buffer) + case (110) + ! no tag and only centered particle + call AC_remesh_center(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_center(p_pos_adim(i+1),p_sc(i+1), send_buffer) + case (100) + ! no tag, the first particle belong to a centered block and the last to left block. + call AC_remesh_center(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_left(p_pos_adim(i+1),p_sc(i+1), send_buffer) + ! XXX add the tagged cases + case (101) + ! tagged, the first particle belong to a centered block and the last to left block. + call AC_remesh_tag_CL(p_pos_adim(i), p_sc(i), p_pos_adim(i+1), p_sc(i+1), send_buffer) + case (11) + ! tagged, the first particle belong to a left block and the last to centered block. + call AC_remesh_tag_LC(p_pos_adim(i), p_sc(i), p_pos_adim(i+1), p_sc(i+1), send_buffer) + case default + print*, 'error on remeshing particles : bl_info equals to ', & + & bl_info, ' and must be 0, 10, 110, 100, 101 or 11. Mesh point = (',i, ', ', j,', ',k,')' + print*, 'paramètres du blocs : ind = ', bl_ind, ' , type(ind) = ', bl_type(bl_ind), & + & ' , type(ind+1) = ', bl_type(bl_ind+1), ' tag = ', bl_tag(bl_ind) + stop + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, X_comm, ind_group , send_j_min, send_j_max, send_buffer, scal(:,j,k)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Xremesh_O2 + + +!> remeshing with an order 4 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_tag = contains information about block (is it tagged ?) +!! @param[in] j,k = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in,out] scal = scalar field to advect +subroutine Xremesh_O4(ind_group, p_pos_adim, bl_type, bl_tag,j,k,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: j, k + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + + ! Variable used to remesh particles ... + ! ... and to communicate between subdomains. A variable prefixed by "send_"(resp "rece") + ! design something I send (resp. I receive). + real(WP), dimension(N_proc(1)) :: p_sc ! scalar advected by the particles + integer :: i ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + integer :: proc_gap ! gap between my Y-coordinate and the one of the processus + ! with wich I communicate. + integer :: proc_min, proc_max ! minimal and maximal gap between my Y-coordinate and the one of + ! sub-domains wherein the particle will be remeshed. + integer :: ierr ! mpi error code + integer :: comm_size ! number of element to send/receive + integer :: tag ! mpi message tag + integer :: direction = 1 ! current direction = along Z + + ! -- Initialise particle weigth + do i = 1, N_proc(direction) + p_sc(i) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-2 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-2 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+2 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+2 + end if + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do i = 1, N_proc(direction), bl_size + bl_ind = i/2 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_left(p_pos_adim(i+1),p_sc(i+1), send_buffer) + call AC_remesh_left(p_pos_adim(i+2),p_sc(i+2), send_buffer) + call AC_remesh_left(p_pos_adim(i+3),p_sc(i+3), send_buffer) + case (10) + ! no tag, the 2 first particles belong to a left block and the two last to centered block. + call AC_remesh_left(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_left(p_pos_adim(i+1),p_sc(i+1), send_buffer) + call AC_remesh_center(p_pos_adim(i+2),p_sc(i+2), send_buffer) + call AC_remesh_center(p_pos_adim(i+3),p_sc(i+3), send_buffer) + case (110) + ! no tag and only left particle + call AC_remesh_center(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_center(p_pos_adim(i+1),p_sc(i+1), send_buffer) + call AC_remesh_center(p_pos_adim(i+2),p_sc(i+2), send_buffer) + call AC_remesh_center(p_pos_adim(i+3),p_sc(i+3), send_buffer) + case (100) + ! no tag, the 2 first particles belong to a centered block and the two last to left block. + call AC_remesh_center(p_pos_adim(i),p_sc(i), send_buffer) + call AC_remesh_center(p_pos_adim(i+1),p_sc(i+1), send_buffer) + call AC_remesh_left(p_pos_adim(i+2),p_sc(i+2), send_buffer) + call AC_remesh_left(p_pos_adim(i+3),p_sc(i+3), send_buffer) + ! XXX add the tagged cases + case default + print*, 'error on remeshing particles' + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, X_comm, ind_group, send_j_min, send_j_max, send_buffer, scal(:,j,k)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Xremesh_O4 + + +!> Advection during a time step dt - order 2 +!! @param[in] dt = time step +!! @param[in] Vx = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] scal3D = scalar field to advect +subroutine advecX_calc_O2(dt,Vx,scal3D) + + use cart_topology + use advec_common +use mpi + + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vx + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal3D + + integer :: j,k ! indice of the currend mesh point + integer, dimension(2) :: ind_group ! indice of the currend group of line (=(i,k) by default) + integer :: direction=1 ! current direction = along Y + real(WP), dimension(N_proc(1)) :: p_pos_adim ! adimensionned particles position + real(WP), dimension(N_proc(1)) :: p_V ! particles velocity + integer, dimension(bl_number(1)+1) :: bl_type ! is the particle block a center block or a left one ? + integer, dimension(bl_number(1)) :: bl_tag ! indice of tagged particles +integer :: ierr + + ind_group = 0 + do k = 1, N_proc(3) + ind_group(2) = ind_group(2) + 1 + ind_group(1) = 0 + do j = 1, N_proc(2) + ind_group(1) = ind_group(1) + 1 + + ! ===== Init particles ===== + call advecX_init(Vx, j, k, p_pos_adim, p_V) + + ! ===== Advection ===== + ! -- Compute velocity (with a RK2 scheme) -- + call AC_particle_velocity(dt, direction, X_comm, ind_group, p_pos_adim, p_V) + ! -- Determine blocks type and tag particles -- + call AC_type_and_block(dt, direction, X_comm, ind_group, p_V, & + & bl_type, bl_tag) + ! -- Advec particles -- + p_pos_adim = p_pos_adim + dt*p_V/d_sc(direction) + + ! ===== Remeshing ===== + call Xremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,j,k,scal3D) + +call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + end do + +end subroutine advecX_calc_O2 + +!> Particle creation and initialisation +!! @param[in] Vx = 3D velocity field +!! @param[in] j = Y-indice of the current line +!! @param[in] k = Z-indice of the current line +!! @param[out] p_pos_adim = adimensioned particles postion +!! @param[out] p_V = particle velocity +subroutine advecX_init(Vx, j, k, p_pos_adim, p_V) + + use cart_topology + + integer, intent(in) :: j,k + real(WP), dimension(N_proc(2)), intent(out) :: p_pos_adim, p_V + real(WP), dimension(:,:,:), intent(in) :: Vx + + integer :: direction=1 ! current direction + integer :: ind ! indice + + do ind = 1, N_proc(direction) + p_pos_adim(ind) = ind + p_V(ind) = Vx(ind,j,k) + end do + +end subroutine advecX_init + +end module advecX +!! @} diff --git a/CodesEnVrac/LEGI/src/particles/advecY.f90 b/CodesEnVrac/LEGI/src/particles/advecY.f90 new file mode 100644 index 000000000..80f141369 --- /dev/null +++ b/CodesEnVrac/LEGI/src/particles/advecY.f90 @@ -0,0 +1,379 @@ +!------------------------------------------------------------------------------ +! +! MODULE: advecY +! +! +! DESCRIPTION: +!> This module is a part of the advection solver based on particles method. +!! The solver use some dimensionnal splitting and this module contains all the +!! method used to solve advection along the Y-axis. This is a parallel +!! implementation using MPI and the cartesien topology it provides. +!! +!! This module can use the method and variables defined in the module +!! "advec_common" which gather information and tools shared for advection along +!! x, y and z-axis. +!! +!! The module "test_advec" can be used in order to validate the procedures +!! embedded in this module. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +!> @addtogroup part +!! @{ +module advecY + + use precision + + implicit none + + ! ===== Public procedures ===== + !> Generique procedure to advect the scalar with a particles solver + public :: advecY_calc + !----- (corrected) Remeshing method (these methods are set to public in validation purposes) ----- + public :: Yremesh_O2 ! order 2 + public :: Yremesh_O4 ! order 4 + + ! ===== Private porcedures ===== + !> particles solver with remeshing method at order 2 + private :: advecY_calc_O2 + private :: advecY_init ! initialize particle position, velocity and weight + + contains + +! ===== Public procedure ===== + +!> Scalar advection (this procedure call the right solver, depending on the simulation setup) +!! @param[in] dt = time step +!! @param[in] Vy = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] SC = scalar field to advect +!! @param[in] type_solver = scheme use for the advection (particle with order 2 or 4) +subroutine advecY_calc(dt, Vy, SC, type_solver) + + use string + use cart_topology + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vy + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: SC + character(len=*), intent(in) :: type_solver + + + + ! Call the right solver depending on the space order we want to. + select case(type_solver) + case('p_O2') + call advecY_calc_O2(dt, Vy, SC) + case default + call advecY_calc_O2(dt, Vy, SC) + end select + +end subroutine advecY_calc + +! ----- Remeshing procedures ----- + + +! ===== Private procedure ===== + +! ---- Order 2 solver, with correction for large time step ---- + +!> remeshing with an order 2 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in] bl_tag = contains information about bloc (is it tagged ?) +!! @param[in] i,k = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in,out] scal = scalar field to advect +subroutine Yremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,i,k,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: i, k + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + +integer :: direction =2 ! current direction + + real(WP), dimension(N_proc(2)) :: p_sc ! scalar advected by the particles + ! Variable used to remesh particles in a buffer + integer :: j ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + + + ! -- Initialise particle weigth + do j = 1, N_proc(direction) + p_sc(j) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-1 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-1 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+1 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+1 + end if + + ! XXX j_min and j_max could be optimized !! (use that sub-domains cut + ! particles block in two egals parts) + allocate(send_buffer(send_j_min:send_j_max)) + send_buffer = 0.0; + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do j = 1, N_proc(direction), bl_size + bl_ind = j/bl_size + 1 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_left(p_pos_adim(j+1),p_sc(j+1), send_buffer) + case (10) + ! no tag, the first particle belong to a left block and the last to centered block. + call AC_remesh_left(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_center(p_pos_adim(j+1),p_sc(j+1), send_buffer) + case (110) + ! no tag and only centered particle + call AC_remesh_center(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_center(p_pos_adim(j+1),p_sc(j+1), send_buffer) + case (100) + ! no tag, the first particle belong to a centered block and the last to left block. + call AC_remesh_center(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_left(p_pos_adim(j+1),p_sc(j+1), send_buffer) + ! XXX add the tagged cases + case (101) + ! tagged, the first particle belong to a centered block and the last to left block. + call AC_remesh_tag_CL(p_pos_adim(j), p_sc(j), p_pos_adim(j+1), p_sc(j+1), send_buffer) + case (11) + ! tagged, the first particle belong to a left block and the last to centered block. + call AC_remesh_tag_LC(p_pos_adim(j), p_sc(j), p_pos_adim(j+1), p_sc(j+1), send_buffer) + case default + print*, 'error on remeshing particles : bl_info equals to ', & + & bl_info, ' and must be 0, 10, 110, 100, 101 or 11. Mesh point = (',i, ', ', j,', ',k,')' + print*, 'paramètres du blocs : ind = ', bl_ind, ' , type(ind) = ', bl_type(bl_ind), & + & ' , type(ind+1) = ', bl_type(bl_ind+1), ' tag = ', bl_tag(bl_ind) + stop + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, Y_comm, ind_group , send_j_min, send_j_max, send_buffer, scal(i,:,k)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Yremesh_O2 + + +!> remeshing with an order 4 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_tag = contains information about block (is it tagged ?) +!! @param[in] i,k = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in,out] scal = scalar field to advect +subroutine Yremesh_O4(ind_group, p_pos_adim, bl_type, bl_tag,i,k,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: i, k + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + + ! Variable used to remesh particles ... + ! ... and to communicate between subdomains. A variable prefixed by "send_"(resp "rece") + ! design something I send (resp. I receive). + real(WP), dimension(N_proc(2)) :: p_sc ! scalar advected by the particles + integer :: j ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + integer :: proc_gap ! gap between my Y-coordinate and the one of the processus + ! with wich I communicate. + integer :: proc_min, proc_max ! minimal and maximal gap between my Y-coordinate and the one of + ! sub-domains wherein the particle will be remeshed. + integer :: ierr ! mpi error code + integer :: comm_size ! number of element to send/receive + integer :: tag ! mpi message tag + integer :: direction = 2 ! current direction = along Z + + ! -- Initialise particle weigth + do j = 1, N_proc(direction) + p_sc(j) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-2 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-2 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+2 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+2 + end if + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do j = 1, N_proc(direction), bl_size + bl_ind = j/2 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_left(p_pos_adim(j+1),p_sc(j+1), send_buffer) + call AC_remesh_left(p_pos_adim(j+2),p_sc(j+2), send_buffer) + call AC_remesh_left(p_pos_adim(j+3),p_sc(j+3), send_buffer) + case (10) + ! no tag, the 2 first particles belong to a left block and the two last to centered block. + call AC_remesh_left(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_left(p_pos_adim(j+1),p_sc(j+1), send_buffer) + call AC_remesh_center(p_pos_adim(j+2),p_sc(j+2), send_buffer) + call AC_remesh_center(p_pos_adim(j+3),p_sc(j+3), send_buffer) + case (110) + ! no tag and only left particle + call AC_remesh_center(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_center(p_pos_adim(j+1),p_sc(j+1), send_buffer) + call AC_remesh_center(p_pos_adim(j+2),p_sc(j+2), send_buffer) + call AC_remesh_center(p_pos_adim(j+3),p_sc(j+3), send_buffer) + case (100) + ! no tag, the 2 first particles belong to a centered block and the two last to left block. + call AC_remesh_center(p_pos_adim(j),p_sc(j), send_buffer) + call AC_remesh_center(p_pos_adim(j+1),p_sc(j+1), send_buffer) + call AC_remesh_left(p_pos_adim(j+2),p_sc(j+2), send_buffer) + call AC_remesh_left(p_pos_adim(j+3),p_sc(j+3), send_buffer) + ! XXX add the tagged cases + case default + print*, 'error on remeshing particles' + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, Y_comm, ind_group, send_j_min, send_j_max, send_buffer, scal(i,:,k)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Yremesh_O4 + + +!> Advection during a time step dt - order 2 +!! @param[in] dt = time step +!! @param[in] Vy = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] scal3D = scalar field to advect +subroutine advecY_calc_O2(dt,Vy,scal3D) + + use cart_topology + use advec_common +use mpi + + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vy + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal3D + + integer :: i,k ! indice of the currend mesh point + integer, dimension(2) :: ind_group ! indice of the currend group of line (=(i,k) by default) + integer :: direction=2 ! current direction = along Y + real(WP), dimension(N_proc(2)) :: p_pos_adim ! adimensionned particles position + real(WP), dimension(N_proc(2)) :: p_V ! particles velocity + integer, dimension(bl_number(2)+1) :: bl_type ! is the particle block a center block or a left one ? + integer, dimension(bl_number(2)) :: bl_tag ! indice of tagged particles +integer :: ierr + + ind_group = 0 + do k = 1, N_proc(3) + ind_group(2) = ind_group(2) + 1 + ind_group(1) = 0 + do i = 1, N_proc(1) + ind_group(1) = ind_group(1) + 1 + + ! ===== Init particles ===== + call advecY_init(Vy, i, k, p_pos_adim, p_V) + + ! ===== Advection ===== + ! -- Compute velocity (with a RK2 scheme) -- + call AC_particle_velocity(dt, direction, Y_comm, ind_group, p_pos_adim, p_V) + ! -- Determine blocks type and tag particles -- + call AC_type_and_block(dt, direction, Y_comm, ind_group, p_V, & + & bl_type, bl_tag) + ! -- Advec particles -- + p_pos_adim = p_pos_adim + dt*p_V/d_sc(direction) + + ! ===== Remeshing ===== + call Yremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,i,k,scal3D) + +call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + end do + +end subroutine advecY_calc_O2 + +!> Particle creation and initialisation +!! @param[in] Vy = 3D velocity field +!! @param[in] i = X-indice of the current line +!! @param[in] k = Z-indice of the current line +!! @param[out] p_pos_adim = adimensioned particles postion +!! @param[out] p_V = particle velocity +subroutine advecY_init(Vy, i, k, p_pos_adim, p_V) + + use cart_topology + + integer, intent(in) :: i,k + real(WP), dimension(N_proc(2)), intent(out) :: p_pos_adim, p_V + real(WP), dimension(:,:,:), intent(in) :: Vy + + integer :: direction=2 ! current direction + integer :: ind ! indice + + do ind = 1, N_proc(direction) + p_pos_adim(ind) = ind + p_V(ind) = Vy(i,ind,k) + end do + +end subroutine advecY_init + +end module advecY +!! @} diff --git a/CodesEnVrac/LEGI/src/particles/advecZ.f90 b/CodesEnVrac/LEGI/src/particles/advecZ.f90 new file mode 100644 index 000000000..aa655077b --- /dev/null +++ b/CodesEnVrac/LEGI/src/particles/advecZ.f90 @@ -0,0 +1,386 @@ +!------------------------------------------------------------------------------ +! +! MODULE: advecZ +! +! +! DESCRIPTION: +!> This module is a part of the advection solver based on particles method. +!! The solver use some dimensionnal splitting and this module contains all the +!! method used to solve advection along the Z-axis. This is a parallel +!! implementation using MPI and the cartesien topology it provides. +!! +!! This module can use the method and variables defined in the module +!! "advec_common" which gather information and tools shared for advection along +!! x, y and z-axis. +!! +!! The module "test_advec" can be used in order to validate the procedures +!! embedded in this module. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +!> @addtogroup part +!! @{ +module advecZ + + use precision + + implicit none + + ! ===== Private variables ===== + ! Minimal and maximal indice of the buffer used in the different communication + !> minimal indice of the send buffer + !integer, public :: send_j_min + !> maximal indice of the send buffer + !integer, public :: send_j_max + + ! ===== Public procedures ===== + !> Generique procedure to advect the scalar with a particles solver + public :: advecZ_calc + !----- (corrected) Remeshing method (these methods are set to public in validation purposes) ----- + public :: Zremesh_O2 ! order 2 + public :: Zremesh_O4 ! order 4 + + ! ===== Private porcedures ===== + !> particles solver with remeshing method at order 2 + private :: advecZ_calc_O2 + private :: advecZ_init ! initialize particle position, velocity and weight + + contains + +! ===== Public procedure ===== + +!> Scalar advection (this procedure call the right solver, depending on the simulation setup) +!! @param[in] dt = time step +!! @param[in] Vz = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] SC = scalar field to advect +!! @param[in] type_solver = scheme use for the advection (particle with order 2 or 4) +subroutine advecZ_calc(dt, Vz, SC, type_solver) + + use string + use cart_topology + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vz + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: SC + character(len=*), intent(in) :: type_solver + + + + ! Call the right solver depending on the space order we want to. + select case(type_solver) + case('p_O2') + call advecZ_calc_O2(dt, Vz, SC) + case default + call advecZ_calc_O2(dt, Vz, SC) + end select + +end subroutine advecZ_calc + +! ----- Remeshing procedures ----- + + +! ===== Private procedure ===== + +! ---- Order 2 solver, with correction for large time step ---- + +!> remeshing with an order 2 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in] bl_tag = contains information about bloc (is it tagged ?) +!! @param[in] i,j = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in,out] scal = scalar field to advect +subroutine Zremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,i,j,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: i, j + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + +integer :: direction =3 ! current direction + + real(WP), dimension(N_proc(3)) :: p_sc ! scalar advected by the particles + ! Variable used to remesh particles in a buffer + integer :: k ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + + + ! -- Initialise particle weigth + do k = 1, N_proc(direction) + p_sc(k) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-1 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-1 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+1 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+1 + end if + + ! XXX j_min and j_max could be optimized !! (use that sub-domains cut + ! particles block in two egals parts) + allocate(send_buffer(send_j_min:send_j_max)) + send_buffer = 0.0; + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do k = 1, N_proc(direction), bl_size + bl_ind = k/bl_size + 1 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_left(p_pos_adim(k+1),p_sc(k+1), send_buffer) + case (10) + ! no tag, the first particle belong to a left block and the last to centered block. + call AC_remesh_left(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_center(p_pos_adim(k+1),p_sc(k+1), send_buffer) + case (110) + ! no tag and only centered particle + call AC_remesh_center(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_center(p_pos_adim(k+1),p_sc(k+1), send_buffer) + case (100) + ! no tag, the first particle belong to a centered block and the last to left block. + call AC_remesh_center(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_left(p_pos_adim(k+1),p_sc(k+1), send_buffer) + ! XXX add the tagged cases + case (101) + ! tagged, the first particle belong to a centered block and the last to left block. + call AC_remesh_tag_CL(p_pos_adim(k), p_sc(k), p_pos_adim(k+1), p_sc(k+1), send_buffer) + case (11) + ! tagged, the first particle belong to a left block and the last to centered block. + call AC_remesh_tag_LC(p_pos_adim(k), p_sc(k), p_pos_adim(k+1), p_sc(k+1), send_buffer) + case default + print*, 'error on remeshing particles : bl_info equals to ', & + & bl_info, ' and must be 0, 10, 110, 100, 101 or 11. Mesh point = (',i, ', ', j,', ',k,')' + print*, 'paramètres du blocs : ind = ', bl_ind, ' , type(ind) = ', bl_type(bl_ind), & + & ' , type(ind+1) = ', bl_type(bl_ind+1), ' tag = ', bl_tag(bl_ind) + stop + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, Z_comm, ind_group , send_j_min, send_j_max, send_buffer, scal(i,j,:)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Zremesh_O2 + + +!> remeshing with an order 4 method, corrected to allow large CFL number - untagged particles +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particles position +!! @param[in] bl_tag = contains information about block (is it tagged ?) +!! @param[in] i,j = indice of of the current line (x-coordinate and z-coordinate) +!! @param[in] bl_type = equal 0 (resp 1) if the block is left (resp centered) +!! @param[in,out] scal = scalar field to advect +subroutine Zremesh_O4(ind_group, p_pos_adim, bl_type, bl_tag,i,j,scal) + + use advec_common + use cart_topology + + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: i, j + integer, dimension(:), intent(in) :: bl_type + integer, dimension(:), intent(in) :: bl_tag + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal + + ! Variable used to remesh particles ... + ! ... and to communicate between subdomains. A variable prefixed by "send_"(resp "rece") + ! design something I send (resp. I receive). + real(WP), dimension(N_proc(3)) :: p_sc ! scalar advected by the particles + integer :: k ! indice of the current particle + integer :: bl_ind ! indice of the current "block end". + integer :: bl_info ! to know if particles are tagged and left/centered + ! (they depend on the block type) + real(WP),dimension(:),allocatable :: send_buffer ! buffer use to remesh the scalar before to send it to the right subdomain + integer :: proc_gap ! gap between my Y-coordinate and the one of the processus + ! with wich I communicate. + integer :: proc_min, proc_max ! minimal and maximal gap between my Y-coordinate and the one of + ! sub-domains wherein the particle will be remeshed. + integer :: ierr ! mpi error code + integer :: comm_size ! number of element to send/receive + integer :: tag ! mpi message tag + integer :: direction = 3 ! current direction = along Z + + ! -- Initialise particle weigth + do k = 1, N_proc(direction) + p_sc(k) = scal(i,j,k) + scal(i,j,k) = 0 + end do + + ! -- Allocate and initialize the buffer -- + if (bl_type(1)==0) then + ! First particle is a left one + send_j_min = floor(p_pos_adim(1))-2 + else + ! First particle is a centered one + send_j_min = nint(p_pos_adim(1))-2 + end if + if (bl_type(N_proc(direction)/bl_size +1)==0) then + ! Last particle is a left one + send_j_max = floor(p_pos_adim(N_proc(2)))+2 + else + ! Last particle is a centered one + send_j_max = nint(p_pos_adim(N_proc(2)))+2 + end if + + ! -- Remesh the particles in the buffer -- + ! The remeshing formula depends on the particle type : + ! 1 - Is the particle tagged ? + ! 2 - Does it belong to a centered or a left block ? + ! Observe that tagged particles go by group of two : if the particles of a + ! block end are tagged, the one first one of the following block are + ! tagged too. + ! The following algorithm is write for block of minimal size. + do k = 1, N_proc(direction), bl_size + bl_ind = k/2 + bl_info = 100*bl_type(bl_ind)+(10*bl_type(bl_ind+1))+bl_tag(bl_ind) + select case (bl_info) + case (0) + ! no tag and only left particle + call AC_remesh_left(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_left(p_pos_adim(k+1),p_sc(k+1), send_buffer) + call AC_remesh_left(p_pos_adim(k+2),p_sc(k+2), send_buffer) + call AC_remesh_left(p_pos_adim(k+3),p_sc(k+3), send_buffer) + case (10) + ! no tag, the 2 first particles belong to a left block and the two last to centered block. + call AC_remesh_left(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_left(p_pos_adim(k+1),p_sc(k+1), send_buffer) + call AC_remesh_center(p_pos_adim(k+2),p_sc(k+2), send_buffer) + call AC_remesh_center(p_pos_adim(k+3),p_sc(k+3), send_buffer) + case (110) + ! no tag and only left particle + call AC_remesh_center(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_center(p_pos_adim(k+1),p_sc(k+1), send_buffer) + call AC_remesh_center(p_pos_adim(k+2),p_sc(k+2), send_buffer) + call AC_remesh_center(p_pos_adim(k+3),p_sc(k+3), send_buffer) + case (100) + ! no tag, the 2 first particles belong to a centered block and the two last to left block. + call AC_remesh_center(p_pos_adim(k),p_sc(k), send_buffer) + call AC_remesh_center(p_pos_adim(k+1),p_sc(k+1), send_buffer) + call AC_remesh_left(p_pos_adim(k+2),p_sc(k+2), send_buffer) + call AC_remesh_left(p_pos_adim(k+3),p_sc(k+3), send_buffer) + ! XXX add the tagged cases + case default + print*, 'error on remeshing particles' + end select + end do + + ! -- Send the buffer to the matching processus and update the scalar field -- + call AC_bufferToScalar(direction, Z_comm, ind_group, send_j_min, send_j_max, send_buffer, scal(i,j,:)) + + ! Deallocate all field + deallocate(send_buffer) + +end subroutine Zremesh_O4 + + +!> Advection during a time step dt - order 2 +!! @param[in] dt = time step +!! @param[in] Vz = velocity along y (could be discretised on a bigger mesh then the scalar) +!! @param[in,out] scal3D = scalar field to advect +subroutine advecZ_calc_O2(dt,Vz,scal3D) + + use cart_topology + use advec_common +use mpi + + + real(WP), intent(in) :: dt + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(in) :: Vz + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(inout) :: scal3D + + integer :: i,j ! indice of the currend mesh point + integer, dimension(2) :: ind_group ! indice of the currend group of line (=(i,k) by default) + integer :: direction=3 ! current direction = along Y + real(WP), dimension(N_proc(3)) :: p_pos_adim ! adimensionned particles position + real(WP), dimension(N_proc(3)) :: p_V ! particles velocity + integer, dimension(bl_number(3)+1) :: bl_type ! is the particle block a center block or a left one ? + integer, dimension(bl_number(3)) :: bl_tag ! indice of tagged particles +integer :: ierr + + ind_group = 0 + do j = 1, N_proc(2) + ind_group(2) = ind_group(2) + 1 + ind_group(1) = 0 + do i = 1, N_proc(1) + ind_group(1) = ind_group(1) + 1 + + ! ===== Init particles ===== + call advecZ_init(Vz, i, j, p_pos_adim, p_V) + + ! ===== Advection ===== + ! -- Compute velocity (with a RK2 scheme) -- + call AC_particle_velocity(dt, direction, Z_comm, ind_group, p_pos_adim, p_V) + ! -- Determine blocks type and tag particles -- + call AC_type_and_block(dt, direction, Z_comm, ind_group, p_V, & + & bl_type, bl_tag) + ! -- Advec particles -- + p_pos_adim = p_pos_adim + dt*p_V/d_sc(direction) + + ! ===== Remeshing ===== + call Zremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag,i,j,scal3D) + +call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + end do + +end subroutine advecZ_calc_O2 + +!> Particle creation and initialisation +!! @param[in] Vz = 3D velocity field +!! @param[in] i = X-indice of the current line +!! @param[in] j = Y-indice of the current line +!! @param[out] p_pos_adim = adimensioned particles postion +!! @param[out] p_V = particle velocity +subroutine advecZ_init(Vz, i, j, p_pos_adim, p_V) + + use cart_topology + + integer, intent(in) :: i,j + real(WP), dimension(N_proc(3)), intent(out) :: p_pos_adim, p_V + real(WP), dimension(:,:,:), intent(in) :: Vz + + integer :: direction=3 ! current direction + integer :: ind ! indice + + do ind = 1, N_proc(direction) + p_pos_adim(ind) = ind + p_V(ind) = Vz(i,j,ind) + end do + +end subroutine advecZ_init + +end module advecZ +!! @} diff --git a/CodesEnVrac/LEGI/src/particles/advec_common.f90 b/CodesEnVrac/LEGI/src/particles/advec_common.f90 new file mode 100644 index 000000000..1b58e4e5d --- /dev/null +++ b/CodesEnVrac/LEGI/src/particles/advec_common.f90 @@ -0,0 +1,1043 @@ + +!> @addtogroup part +!! @{ +module advec_common + + use precision + use string + + implicit none + +! XXX Si passage au fortran 2003 : basculer toutes ces variables dans le module +! advec (fichier advec.F90) et mettre toutes les variables en protected. +! Seul la procédure "advec_init" doit pouvoir les modifier, mais de nombreuses +! procédures doivent pouvoir y accéder. + + + ! Information about the particles and their bloc + private + ! XXX Public variables have to be switched to "PROTECTED" when we will use fortran2003 norm + + ! ===== Private variables ===== + ! ----- Minimal and maximal indice of the buffer used in the different communication ----- + !> minimal indice of the send buffer + integer, public :: send_j_min + !> maximal indice of the send buffer + integer, public :: send_j_max + ! ------ Block infromation ----- + !> number of particles in a block + integer, public :: bl_size + !> number of particles in a block boundary wich used a specific remeshing formula + !! which is related to the stencil width. + integer, public :: bl_bound_size + !> Number of block on each processus along each direction + integer, dimension(3), public :: bl_number + + ! ------ To ensure unique mpi message tag ----- + ! Tag generate with a proc_gap + !> To create tag used in AC_particle_velocity to send range + integer, dimension(2) :: tag_velo_range = (/ 0,1 /) + !> To create tag used in AC_particle_velocity to send velocity field + integer, dimension(2) :: tag_velo_V = (/ 0,2 /) + !> To create tag used in bufferToScalar to send range of buffer which will be send + integer, dimension(2) :: tag_bufToScal_range = (/ 0,3 /) + !> To create tag used in bufferToScalar to send the buffer used to remesh particles + integer, dimension(2) :: tag_bufToScal_buffer = (/ 0,4 /) + + ! Tag generate with "compute_gap_NP" + !> To create tag used in AC_obtain_recevers to send ghost + integer, dimension(2) :: tag_obtrec_ghost_NP = (/ 0, 1/) + !> To create tag used in AC_type_and_bloc to exchange ghost with neighbors + integer, dimension(2) :: tag_part_tag_NP = (/ 0, 2/) + !> To create tag used in AC_obtain_recevers to send message about recevers of minimal and maximal rank + integer, dimension(2) :: tag_obtrec_NP = (/ 0, 3/) + !> To create tag used in AC_obtain_receivers to send message about senders of minimal and maximal rank + integer, dimension(2) :: tag_obtsend_NP = (/ 0, 4/) + + + + + + + ! ===== Public procedures ===== + character(len=str_short), public :: type_solv + !public :: tag_particles_O2 + !----- Determine block type and tag particles ----- + public :: AC_type_and_block + !----- To interpolate velocity ----- + public :: AC_obtain_receivers + public :: AC_particle_velocity + !----- To remesh particles ----- + public :: AC_obtain_senders + public :: AC_bufferToScalar + !----- Order 2 remeshing formula ----- + public :: AC_remesh_left ! left remeshing formula + public :: AC_remesh_center ! centered remeshing formula + public :: AC_remesh_tag_CL ! corrected formula for tagged particles : transition from C to L block. + public :: AC_remesh_tag_LC ! corrected formula for tagged particles : transition from L to C block + + + contains + +! ===== Public procedure ===== + +! XXX Subroutine à mettre à jour +! eps_bl=d_sc/10.0 +! cfl = dt/d_sc +! +! bl_nb_part = 0 +! bl_final_ind = 0 +! bl_lambdaMin = maxval(p_V)*cfl ! or any big value. We can perhaps used +! ! the cfl condition from the NS solver +! +! +! deallocate(bl_nb_part) +! deallocate(bl_final_ind) +! deallocate(bl_lambdaMin) +! deallocate(bl_ind) +! deallocate(bl_type) +! +!end subroutine tag_particles_O2 + +! ================================================================================== +! ==================== Compute particle velocity (RK2) ==================== +! ================================================================================== + +!> Interpolate the velocity field used in a RK2 scheme for particle advection. +!! @param[in] dt = time step +!! @param[in] direction = current direction (1 = along X, 2 = along Y and 3 = along Z) +!! @param[in] comm = mpi communicator associated to the current direction (Y_comm, Z_comm) +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_pos_adim = adimensionned particle postion +!! @param[in,out] p_V = particle velocity (along the current direction) +!! @details +!! A RK2 scheme is used to advect the particles : the midlle point scheme. An +!! intermediary position "p_pos_bis(i) = p_pos(i) + V(i)*dt/2" is computed and then +!! the numerical velocity of each particles is computed as the interpolation of V in +!! this point. This field is used to advect the particles at the seconde order in time : +!! p_pos(t+dt, i) = p_pos(i) + p_V(i). +!! The group line indice is used to ensure using unicity of each mpi message tag. +subroutine AC_particle_velocity(dt, direction, comm, ind_group, p_pos_adim, p_V) + + ! This code involve a recopy of p_V. It is possible to directly use the 3D velocity field but in a such code + ! a memory copy is still needed to send velocity field to other processus : mpi send contiguous memory values + + use mpi + use cart_topology + + ! --- In order to create an arry of pointer --- + type real_pter + real(WP), pointer :: pter + end type real_pter + ! --------------------------------------------- + + real(WP), intent(in) :: dt ! time step + integer, intent(in) :: direction + integer, intent(in) :: comm + integer, dimension(2), intent(in) :: ind_group + real(WP), dimension(:), intent(in) :: p_pos_adim + real(WP), dimension(:), intent(inout) :: p_V + + real(WP), dimension(N_proc(direction)) :: p_pos_bis ! adimensionned position of the middle point + real(WP), dimension(N_proc(direction)), target :: p_V_bis ! velocity of the middle point + real(WP), dimension(N_proc(direction)) :: weight ! interpolation weight + type(real_pter), dimension(N_proc(direction)) :: Vp, Vm ! Velocity on previous and next mesh point + real(WP), dimension(:), allocatable, target :: V_buffer ! Velocity buffer for postion outside of the local subdomain + integer :: size_buffer ! buffer size + integer :: temp ! use in some computations + integer :: rece_ind_min ! the minimal indice used in velocity interpolation + integer :: rece_ind_max ! the maximal indice used in velocity interpolation + integer :: ind, ind_com ! indices + integer :: pos, pos_old ! indices of the mesh point wich preceed the particle position + integer :: proc_gap, gap! distance between my (mpi) coordonate and coordinate of the + ! processus associated to a given position + integer, dimension(:), allocatable :: rece_rank ! rank of processus wich send me information + integer :: send_rank ! rank of processus to wich I send information + integer :: rankP ! rank of processus ("source rank" returned by mpi_cart_shift) + integer, dimension(2) :: rece_range ! range of the velocity fields I want to receive + integer, dimension(2) :: send_range ! range of the velocity fields I send + integer, dimension(2) :: rece_gap ! distance between me and processus wich send me information + integer, dimension(2) :: send_gap ! distance between me and processus to wich I send information + integer :: msg_size ! size of message send/receive + integer :: tag ! mpi message tag + integer :: ierr ! mpi error code + integer :: send_request ! mpi communication request (handle) of nonblocking send +! XXX debug - to delete XXX + integer, dimension(:), allocatable :: s_request ! mpi communication request (handle) of nonblocking send + integer, dimension(:), allocatable :: s_request_bis! mpi communication request (handle) of nonblocking send +! XXX end debug XXX + integer, dimension(:), allocatable :: rece_request ! mpi communication request (handle) of nonblocking receive + integer, dimension(MPI_STATUS_SIZE) :: rece_status ! mpi status (for mpi_wait) + + ! -- Initialisation -- + ind_com = 0 + do ind = 1, N_proc(direction) + nullify(Vp(ind)%pter) + nullify(Vm(ind)%pter) + end do + ! Compute the midlle point + p_pos_bis = p_pos_adim + (dt/2.0)*p_V/d_sc(direction) + p_V_bis = p_V + ! Compute range of the set of point where I need the velocity value + rece_ind_min = floor(p_pos_bis(1)) + rece_ind_max = floor(p_pos_bis(N_proc(direction))) + 1 + ! Allocate the buffer + ! If rece_ind_min and rece_ind_max are not in [N_proc(direction);1] then it will change the number of communication + ! size_buffer = max(temp - N_proc(direction), 0) - min(0, temp) + !size_buffer = - max(temp - N_proc(direction), 0) - min(0, temp) + ! It must work, but for first test we prefer compute size_buffer more simply + size_buffer = 0 + + ! -- Exchange non blocking message to do the computations during the + ! communication process + call AC_obtain_receivers(direction, comm, ind_group, rece_ind_min, rece_ind_max, send_gap, rece_gap) + allocate(rece_rank(rece_gap(1):rece_gap(2))) + ! Send messages about what I want +! XXX debug - to delete XXX + allocate(s_request_bis(rece_gap(1):rece_gap(2))) +! XXX end debug XXX + do proc_gap = rece_gap(1), rece_gap(2) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, rece_rank(proc_gap), ierr) + if (rece_rank(proc_gap) /= myrank) then + ! Range I want + gap = proc_gap*N_proc(direction) + rece_range(1) = max(rece_ind_min, gap+1) ! fortran => indice start from 0 + rece_range(2) = min(rece_ind_max, gap+N_proc(direction)) + ! Tag = concatenation of (rank+1), ind_group(1), ind_group(2), direction et unique Id. + tag = compute_tag(ind_group, tag_velo_range, direction, proc_gap) + ! Send message + size_buffer = size_buffer + (rece_range(2)-rece_range(1)) + 1 +! XXX debug - to delete XXX + call mpi_Isend(rece_range(1), 2, MPI_INTEGER, rece_rank(proc_gap), tag, comm, s_request_bis(proc_gap), ierr) +! XXX debug - uncomment the following line XXX +! call mpi_Isend(rece_range(1), 2, MPI_INTEGER, rece_rank(proc_gap), tag, comm, send_request, ierr) +! XXX end debug XXX + end if + end do + allocate(V_buffer(max(size_buffer,1))) + V_buffer = 0 + ! Send the velocity field to processus which need it +! XXX debug - to delete XXX + allocate(s_request(send_gap(1):send_gap(2))) +! XXX end debug XXX + do proc_gap = send_gap(1), send_gap(2) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank /= myrank) then + ! I - Receive messages about what I have to send + ! Ia - Compute reception tag = concatenation of (rank+1), ind_group(1), ind_group(2), direction et unique Id. + tag = compute_tag(ind_group, tag_velo_range, direction, -proc_gap) + ! Ib - Receive the message + call mpi_recv(send_range(1), 2, MPI_INTEGER, send_rank, tag, comm, rece_status, ierr) + send_range = send_range + proc_gap*N_proc(direction) + ! II - Send it + ! IIa - Compute send tag + tag = compute_tag(ind_group, tag_velo_V, direction, proc_gap) + ! IIb - Send message +! XXX debug - to delete XXX + call mpi_Isend(p_V(send_range(1)), send_range(2)-send_range(1)+1, MPI_DOUBLE_PRECISION, & + & send_rank, tag, comm, s_request(proc_gap), ierr) +! XXX debug - uncomment the two following line XXX +! call mpi_Isend(p_V(send_range(1)), send_range(2)-send_range(1)+1, MPI_DOUBLE_PRECISION, & +! & send_rank, tag, comm, send_request, ierr) +! XXX end debug XXX + end if + end do + + ! Non blocking reception of the velocity field + ind = 1 + allocate(rece_request(rece_gap(1):rece_gap(2))) + do proc_gap = rece_gap(1), rece_gap(2) + if (rece_rank(proc_gap) /= myrank) then + ! IIa - Compute reception tag + tag = compute_tag(ind_group, tag_velo_V, direction, -proc_gap) + ! IIb - Receive message + rece_range(1) = max(rece_ind_min, gap+1) ! fortran => indice start from 0 + rece_range(2) = min(rece_ind_max, gap+N_proc(direction)) + msg_size = rece_range(2)-rece_range(1)+1 + call mpi_Irecv(V_buffer(ind), msg_size, MPI_DOUBLE_PRECISION, rece_rank(proc_gap), tag, comm, & + & rece_request(proc_gap), ierr) + ind = ind + msg_size + end if + end do + + ! -- Compute the interpolated velocity + ! Compute the interpolation weight and update the pointers Vp and Vm + ! Initialisation of reccurence process + ind = 1 + pos = floor(p_pos_bis(ind)) + weight(ind) = p_pos_bis(ind)-pos + ! Vm = V(pos) + proc_gap = floor(real((pos-1)/N_proc(direction))) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank == myrank) then + Vm(ind)%pter => p_V_bis(pos-proc_gap*N_proc(direction)) + else + ind_com = ind_com + 1 + Vm(ind)%pter => V_buffer(ind_com) + end if + ! Vp = V(pos+1) + proc_gap = floor(real((pos+1-1)/N_proc(direction))) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank == myrank) then + Vp(ind)%pter => p_V_bis(pos+1-proc_gap*N_proc(direction)) + else + ind_com = ind_com + 1 + Vp(ind)%pter => V_buffer(ind_com) + end if + pos_old = pos + + ! Following indice : we use previous work (already done) + do ind = 2, N_proc(direction) + pos = floor(p_pos_bis(ind)) + weight(ind) = p_pos_bis(ind)-pos + select case(pos-pos_old) + case(0) + ! The particle belongs to the same segment than the previous one + Vm(ind)%pter => Vm(ind-1)%pter + Vp(ind)%pter => Vp(ind-1)%pter + case(1) + ! The particle follows the previous one + Vm(ind)%pter => Vp(ind-1)%pter + ! Vp = V(pos+1) + proc_gap = floor(real((pos+1-1)/N_proc(direction))) ! fortran -> indice starts from 1 + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank == myrank) then + Vp(ind)%pter => p_V_bis(pos+1-proc_gap*N_proc(direction)) + else + ind_com = ind_com + 1 + Vp(ind)%pter => V_buffer(ind_com) + end if + case(2) + ! pos = pos_old +2, wich correspond to "extention" + ! Vm = V(pos) + proc_gap = floor(real((pos-1)/N_proc(direction))) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank == myrank) then + Vm(ind)%pter => p_V_bis(pos-proc_gap*N_proc(direction)) + else + ind_com = ind_com + 1 + Vm(ind)%pter => V_buffer(ind_com) + end if + ! Vp = V(pos+1) + proc_gap = floor(real((pos+1-1)/N_proc(direction))) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank == myrank) then + Vp(ind)%pter => p_V_bis(pos+1-proc_gap*N_proc(direction)) + else + ind_com = ind_com + 1 + Vp(ind)%pter => V_buffer(ind_com) + end if + case default + print*, "unexpected case : pos = ", pos, " , pos_old = ", pos_old, " ind = ", ind + end select + pos_old = pos + end do + + ! -- Compute the interpolate velocity -- + ! Check if communication are done + do proc_gap = rece_gap(1), rece_gap(2) + if (rece_rank(proc_gap)/=myrank) then + call mpi_wait(rece_request(proc_gap), rece_status, ierr) + end if + end do + + + ! Then compute the field + do ind = 1, N_proc(direction) + p_V(ind) = weight(ind)*Vp(ind)%pter + (1-weight(ind))*Vm(ind)%pter + end do + +! XXX debug - to delete XXX + do ind = 1, N_proc(direction) + nullify(Vp(ind)%pter) + nullify(Vm(ind)%pter) + end do + + do proc_gap = send_gap(1), send_gap(2) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + if (send_rank /= myrank) then + call MPI_WAIT(s_request(proc_gap),rece_status,ierr) + end if + end do + deallocate(s_request) + do proc_gap = rece_gap(1), rece_gap(2) + if (rece_rank(proc_gap) /= myrank) then + call MPI_WAIT(s_request_bis(proc_gap),rece_status,ierr) + end if + end do + deallocate(s_request_bis) +! XXX end debug XXX + + ! Deallocation + deallocate(rece_rank) + deallocate(rece_request) + deallocate(V_buffer) + +end subroutine AC_particle_velocity + + +!> Determine the set of processes wich will send me information during the velocity interpolation. +!! @param[in] direction = current direction (1 = along X, 2 = along Y, 3 = along Z) +!! @param[in] comm = mpi communicator associated with the current direction +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] rece_ind_min = minimal indice of mesh involved in remeshing particles (of the my local subdomains) +!! @param[in] rece_ind_max = maximal indice of mesh involved in remeshing particles (of the my local subdomains) +!! @param[out] send_gap = gap between my coordinate and the processes of minimal coordinate which will send information to me +!! @param[out] rece_gap = gap between my coordinate and the processes of maximal coordinate which will receive information from me +!! @details +!! Obtain the list of processus wich need a part of my local velocity field +!! to interpolate the velocity used in the RK2 scheme to advect its particles. +subroutine AC_obtain_receivers(direction, comm, ind_group, rece_ind_min, rece_ind_max, send_gap, rece_gap) +! XXX Work only for periodic condition. + + use cart_topology + use mpi + + integer, intent(in) :: rece_ind_min, rece_ind_max + integer, intent(in) :: direction, comm + integer, dimension(2), intent(in) :: ind_group + integer, dimension(2), intent(out) :: rece_gap, send_gap + integer, dimension(MPI_STATUS_SIZE) :: statut + + integer :: proc_gap ! gap between a processus coordinate (along the current + ! direction) into the mpi-topology and my coordinate + integer :: rece_gapP ! gap between the coordinate of the previous processus (in the current direction) + ! and the processes of maximal coordinate which will receive information from it + integer :: rece_gapN ! same as above but for the next processus + integer :: rankP, rankN ! processus rank for shift (P= previous, N = next) + integer :: tag_min, tag_max ! mpi message tag (for communicate rece_proc(1) and rece_proc(2)) + integer :: send_request ! mpi status of nonblocking send + integer :: send_request_bis ! mpi status of nonblocking send + integer :: ierr ! mpi error code + integer :: tag ! mpi message tag + integer, dimension(2) :: tag_table ! some mpi message tag +! XXX debug - to delete XXX + integer :: pr + logical, dimension(:,:), allocatable:: test_request + integer, dimension(:,:), allocatable:: s_request +! XXX end debug XXX + + tag_min = 5 + tag_max = 6 + + send_gap = 3*N(direction) + + rece_gap(1) = floor(real(rece_ind_min-1)/N_proc(direction)) + rece_gap(2) = floor(real(rece_ind_max-1)/N_proc(direction)) + + ! Communicate with my neigbors + ! Compute their rank + call mpi_cart_shift(cart_comm, (direction-1), 1, rankP, rankN, ierr) + ! Inform that about processus from which I need information + tag_table = compute_tag(ind_group, tag_obtrec_ghost_NP, direction) + call mpi_Isend(rece_gap(1), 1, MPI_INTEGER, rankP, tag_table(1), comm, send_request, ierr) + call mpi_Isend(rece_gap(2), 1, MPI_INTEGER, rankN, tag_table(2), comm, send_request_bis, ierr) + ! Receive the same message form my neighbors + call mpi_recv(rece_gapN, 1, MPI_INTEGER, rankN, tag_table(1), comm, statut, ierr) + call mpi_recv(rece_gapP, 1, MPI_INTEGER, rankP, tag_table(2), comm, statut, ierr) + + + ! Send +! XXX debug - to delete XXX + allocate(s_request(rece_gap(1):rece_gap(2),2)) + allocate(test_request(rece_gap(1):rece_gap(2),2)) + test_request = .false. +! XXX end debug XXX + do proc_gap = rece_gap(1), rece_gap(2) + ! Compute the rank of the target processus + call mpi_cart_shift(cart_comm, (direction-1), proc_gap, rankP, rankN, ierr) + ! Determine if I am the the first or the last processes (considering the current directory) + ! to require information from this processus + if (proc_gap>rece_gapP-1) then + if(rankN /= myrank) then + tag_table = compute_tag(ind_group, tag_obtrec_NP, direction) +! XXX debug - to delete XXX + call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(1), comm, s_request(proc_gap,1), ierr) + test_request(proc_gap,1) = .true. +! XXX uncomment following line XXX +! call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(1), comm, send_request, ierr) +! XXX end debug XXX + else + send_gap(1) = -proc_gap + end if + end if + if (proc_gap<rece_gapN+1) then + if(rankN /= myrank) then +! XXX debug - to delete XXX + test_request(proc_gap,2) = .true. + call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(2), comm, s_request(proc_gap,2), ierr) +! XXX uncomment following line XXX +! call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(2), comm, send_request_bis, ierr) +! XXX end debug XXX + else + send_gap(2) = -proc_gap + end if + end if + end do + + + ! Receive + if (send_gap(1) == 3*N(direction)) then + call mpi_recv(send_gap(1), 1, MPI_INTEGER, MPI_ANY_SOURCE, tag_table(1), comm, statut, ierr) + end if + if (send_gap(2) == 3*N(direction)) then + call mpi_recv(send_gap(2), 1, MPI_INTEGER, MPI_ANY_SOURCE, tag_table(2), comm, statut, ierr) + end if + + +! XXX debug - to delete XXX + call MPI_WAIT(send_request,statut,ierr) + call MPI_WAIT(send_request_bis,statut,ierr) + do proc_gap = rece_gap(1), rece_gap(2) + if (test_request(proc_gap,1).eqv. .true.) call MPI_WAIT(s_request(proc_gap,1),statut,ierr) + if (test_request(proc_gap,2)) call MPI_WAIT(s_request(proc_gap,2),statut,ierr) + end do + deallocate(s_request) + deallocate(test_request) +! XXX end debug XXX + +end subroutine AC_obtain_receivers + + +! =================================================================================================== +! ==================== Others than velocity interpolation and remeshing ==================== +! =================================================================================================== + +!> Determine type (center or left) of each block and tag particle to know where +!! corrected remeshing formula are recquired. +!! @param[in] dt = time step +!! @param[in] direction = current direction (1 = along X, 2 = along Y and 3 = along Z) +!! @param[in] comm = mpi communicator associated to the current direction (Y_comm, Z_comm) +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] p_V = particle velocity (along the current direction) +!! @param[out] bl_type = table of blocks type (center of left) +!! @param[out] bl_tag = inform about tagged particles (bl_tag(ind_bl)=1 if the end of the bl_ind-th block +!! and the begining of the following one is tagged) +subroutine AC_type_and_block(dt, direction, comm, ind_group, p_V, & + & bl_type, bl_tag) + + use mpi + use cart_topology + use precision + + real(WP), intent(in) :: dt ! time step + integer, intent(in) :: direction + integer, intent(in) :: comm + integer, dimension(2), intent(in) :: ind_group + real(WP), dimension(:), intent(in) :: p_V + integer, dimension(bl_number(direction)+1), intent(out) :: bl_type ! is the particle block a center block or a left one ? + integer, dimension(bl_number(direction)), intent(out) :: bl_tag ! indice of tagged particles + + real(WP), dimension(bl_number(direction)+1) :: bl_lambdaMin ! for a particle, lamda = V*dt/dx ; bl_lambdaMin = min of + ! lambda on a block (take also into account first following particle) + real(WP) :: lambP, lambN ! buffer to exchange some lambda min with other processus + integer, dimension(bl_number(direction)+1) :: bl_ind ! block index : integer as lambda in (bl_ind,bl_ind+1) for a left block + ! and lambda in (bl_ind-1/2, bl_ind+1/2) for a right block + integer :: ind, ind2,i_p! some indices + real(WP) :: cfl ! = d_sc + integer :: rankP, rankN ! processus rank for shift (P= previous, N = next) + integer, dimension(2) :: send_request ! mpi status of nonblocking send + integer, dimension(2) :: rece_request ! mpi status of nonblocking receive + integer, dimension(MPI_STATUS_SIZE) :: rece_status ! mpi status (for mpi_wait) + integer :: tag ! tag for mpi message + integer, dimension(2) :: tag_table ! other tags for mpi message + integer :: ierr ! mpi error code + + ! ===== Initialisation ===== + cfl = dt/d_sc(direction) + + ! ===== Compute bl_lambdaMin ===== + ! -- Compute rank of my neighbor -- + call mpi_cart_shift(cart_comm, (direction-1), 1, rankP, rankN, ierr) + + ! -- For the first block (1/2) -- + ! The domain contains only its second half => exchange ghost with the previous processus + bl_lambdaMin(1) = p_V(1)*cfl + do i_p = 2, (bl_size/2)+1 + bl_lambdaMin(1) = min(bl_lambdaMin(1), p_V(i_p)*cfl) + end do + tag_table = compute_tag(ind_group, tag_part_tag_NP, direction) + ! Send message + call mpi_Isend(bl_lambdaMin(1), 1, MPI_DOUBLE_PRECISION, rankP, tag_table(1), comm, send_request(1), ierr) + ! Receive it + call mpi_Irecv(lambN, 1, MPI_DOUBLE_PRECISION, rankN, tag_table(1), comm, rece_request(1), ierr) + + ! -- For the last block (1/2) -- + ! The processus contains only its first half => exchange ghost with the next processus + ind = bl_number(direction) + 1 + bl_lambdaMin(ind) = p_V(N_proc(direction))*cfl + do i_p = N_proc(direction) - (bl_size/2)+2, N_proc(direction)-1 + bl_lambdaMin(ind) = min(bl_lambdaMin(ind), p_V(i_p)*cfl) + end do + ! Send message + call mpi_Isend(bl_lambdaMin(ind), 1, MPI_DOUBLE_PRECISION, rankN, tag_table(2), comm, send_request(2), ierr) + ! Receive it + call mpi_Irecv(lambP, 1, MPI_DOUBLE_PRECISION, rankP, tag_table(2), comm, rece_request(2), ierr) + + ! -- For the "middle" block -- + do ind = 2, bl_number(direction) + i_p = ((ind-1)*bl_size) + 1 - bl_size/2 + bl_lambdaMin(ind) = p_V(i_p)*cfl + do ind2 = 2, bl_size+1 + i_p = ((ind-1)*bl_size) + ind2 - bl_size/2 + bl_lambdaMin(ind) = min(bl_lambdaMin(ind), p_V(i_p)*cfl) + end do + end do + + ! -- For the first block (1/2) -- + ! The domain contains only its second half => use exchanged ghost + ! Check reception + call mpi_wait(rece_request(2), rece_status, ierr) + bl_lambdaMin(1) = min(bl_lambdaMin(1), lambP) + + ! -- For the last block (1/2) -- + ! The processus contains only its first half => use exchanged ghost + ! Check reception + call mpi_wait(rece_request(1), rece_status, ierr) + ind = bl_number(direction) + 1 + bl_lambdaMin(ind) = min(bl_lambdaMin(ind), lambN) + + ! ===== Compute block type and index ===== + do ind = 1, bl_number(direction) + 1 + bl_ind(ind) = nint(bl_lambdaMin(ind)) + if (bl_lambdaMin(ind)<bl_ind(ind)) then + ! => center type + bl_type(ind) = 1 + else + ! => left type + bl_type(ind) = 0 + end if + end do + + ! ===== Tag particles ===== + + do ind = 1, bl_number(direction) + if ((bl_ind(ind)/=bl_ind(ind+1)) .and. (bl_type(ind)/=bl_type(ind+1))) then + ! the end of ind-th block and the beginning of the following one are tagged + bl_tag(ind) = 1 + else + bl_tag(ind) = 0 + end if + end do + +end subroutine AC_type_and_block + + +! =================================================================== +! ==================== Remesh particles ==================== +! =================================================================== + +!> Determine the set of processes wich will send me information during the +!! scalar remeshing. +!! @param[in] send_j_min = minimal indice of mesh involved in remeshing particles (of the particles in my local subdomains) +!! @param[in] send_j_max = maximal indice of mesh involved in remeshing particles (of the particles in my local subdomains) +!! @param[in] direction = current direction (1 = along X, 2 = along Y, 3 = along Z) +!! @param[in] comm = mpi communicator associated with the current direction +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[out] proc_min = gap between my coordinate and the processes of minimal coordinate which will receive information from me +!! @param[out] proc_max = gap between my coordinate and the processes of maximal coordinate which will receive information from me +!! @param[out] rece_proc = coordinate range of processes which will send me information during the remeshing. +!! @details +!! Obtain the list of processus which contains some particles which belong to +!! my subdomains after their advection (and thus which will be remeshing into +!! my subdomain). This result is return as an interval [send_min; send_max]. +!! All the processus whose coordinate (into the current direction) belong to +!! this segment are involved into scalar remeshing into the current +!! subdomains. +subroutine AC_obtain_senders(send_j_min, send_j_max, direction, comm, ind_group, proc_min, proc_max, rece_proc) +! XXX Work only for periodic condition. For dirichlet conditions : it is +! possible to not receive either rece_proc(1), either rece_proc(2) or none of +! these two => detect it (track the first and the last particles) and deal with it. + + use cart_topology + use mpi + + integer, intent(in) :: send_j_min, send_j_max + integer, intent(in) :: direction, comm + integer, dimension(2), intent(in) :: ind_group + integer(kind=4), intent(out) :: proc_min, proc_max + integer, dimension(2), intent(out) :: rece_proc + integer, dimension(MPI_STATUS_SIZE) :: statut + + integer(kind=4) :: proc_gap ! gap between a processus coordinate (along the current + ! direction) into the mpi-topology and my coordinate + integer :: rankP, rankN ! processus rank for shift (P= previous, N = next) + integer, dimension(2) :: tag_table ! mpi message tag (for communicate rece_proc(1) and rece_proc(2)) + integer :: send_request ! mpi status of nonblocking send + integer :: ierr ! mpi error code + + tag_table = compute_tag(ind_group, tag_obtsend_NP, direction) + + rece_proc = 3*N(direction) + + proc_min = floor(real(send_j_min-1)/N_proc(direction)) + proc_max = floor(real(send_j_max-1)/N_proc(direction)) + + ! Send + do proc_gap = proc_min, proc_max + ! Compute the rank of the target processus + call mpi_cart_shift(cart_comm, (direction-1), proc_gap, rankP, rankN, ierr) + ! Determine if I am the the first or the last processes (considering my + ! coordinate along the current directory) to send information to + ! one of these processes. + ! Note that local indice go from 1 to N_proc (fortran). + ! I am the first ? + if ((send_j_min< +1-2*bl_bound_size + proc_gap*N_proc(direction)+1).AND. & + & (send_j_max>= proc_gap*N_proc(direction))) then + if(rankN /= myrank) then + call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(1), comm, send_request, ierr) + else + rece_proc(1) = -proc_gap + end if + end if + ! I am the last ? + if ((send_j_max > -1+2*bl_bound_size + (proc_gap+1)*N_proc(direction)) & + & .AND.(send_j_min<= (proc_gap+1)*N_proc(direction))) then + if(rankN /= myrank) then + call mpi_Isend(-proc_gap, 1, MPI_INTEGER, rankN, tag_table(2), comm, send_request, ierr) + else + rece_proc(2) = -proc_gap + end if + end if + end do + + + ! Receive + if (rece_proc(1) == 3*N(direction)) then + call mpi_recv(rece_proc(1), 1, MPI_INTEGER, MPI_ANY_SOURCE, tag_table(1), comm, statut, ierr) + end if + if (rece_proc(2) == 3*N(direction)) then + call mpi_recv(rece_proc(2), 1, MPI_INTEGER, MPI_ANY_SOURCE, tag_table(2), comm, statut, ierr) + end if + +end subroutine AC_obtain_senders + +!> Common procedure for remeshing wich perform all the communcation and provide +!! the update scalar field. +!! @param[in] direction = current direction (1 = along X, 2 = along Y and 3 = along Z) +!! @param[in] comm = mpi communicator associated to the current direction (Y_comm, Z_comm) +!! @param[in] ind_group = coordinate of the current group of lines +!! @param[in] send_i_min = minimal indice of the send buffer +!! @param[in] send_i_max = maximal indice of the send buffer +!! @param[in] send_buffer = buffer use to remesh the scalar before to send it to the right subdomain +!! @param[in,out] scal1D = mono-dimensionnal scalar field to advect +!! (XXX todo : decide if extraction from the 3D or pointeur) +!! @details +!! Remeshing are done in a local buffer. This subroutine distribute this buffer +!! to the right processes, receive the buffer send and update the scalar field. +subroutine AC_bufferToScalar(direction, comm, ind_group, send_i_min, send_i_max, send_buffer, scal1D) + + use cart_topology + use mpi + + integer, intent(in) :: direction + integer, intent(in) :: comm + integer, dimension(2), intent(in) :: ind_group + integer, intent(in) :: send_i_min + integer, intent(in) :: send_i_max + real(WP), dimension(send_i_min:send_i_max), intent(in) :: send_buffer + !XXX - ca ne devrait pas bugger sans les range + real(WP), dimension(N_proc(direction)), intent(inout) :: scal1D + +! XXX todo vrai scalaire = 3D -> choisir si on envoie un sous-tableau 1D du +! scalaire ou un tableau de pointeur 1D qui pointe vers les bonnes cases du +! champ scalaire + + ! Variables used to communicate between subdomains. A variable prefixed by "send_"(resp "rece") + ! design something I send (resp. I receive). + integer :: i ! table indice + integer :: proc_gap ! gap between my Y-coordinate and the one of the processus + integer, dimension(2) :: rece_proc ! minimal and maximal gap between my Y-coordinate and the one from which + ! I will receive data + integer :: proc_min ! smaller gap between me and the processes to where I send data + integer :: proc_max ! smaller gap between me and the processes to where I send data + real(WP), dimension(:), allocatable :: rece_buffer ! buffer use to stock received scalar field + integer :: send_gap ! number of mesh between my and another processus + integer,dimension(:,:), allocatable :: rece_range ! range of (local) indice where the received scalar field has to be save + integer, dimension(2) :: send_range ! range of (local) indice where the send scalar field has to be save + integer, dimension(:), allocatable :: rece_request ! mpi communication request (handle) of nonblocking receive + integer, dimension(:), allocatable :: rece_rank ! rank of processus from wich I receive data + integer :: send_rank ! rank of processus to which I send data + integer :: rankP ! rank used in mpi_cart_shift + integer, dimension(MPI_STATUS_SIZE) :: rece_status ! mpi status (for mpi_wait) + integer :: send_request ! mpi status of nonblocking send + integer :: rece_i_min ! the minimal indice from where belong the scalar field I receive + integer :: rece_i_max ! the maximal indice from where belong the scalar field I receive + integer :: ierr ! mpi error code + integer :: comm_size ! number of element to send/receive + integer :: tag ! mpi message tag + ! with wich I communicate. + + + ! Determine the communication needed : who will communicate whit who ? (ie compute sender and recer) + call AC_obtain_senders(send_i_min, send_i_max, direction, comm, ind_group, proc_min, proc_max, rece_proc) + ! Send the information + do proc_gap = proc_min, proc_max + ! Compute the rank of the target processus + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, send_rank, ierr) + send_gap = proc_gap*N_proc(direction) + send_range(1) = max(send_i_min, send_gap+1) ! fortran => indice start from 0 + send_range(2) = min(send_i_max, send_gap+N_proc(direction)) + if (send_rank/=myrank) then + ! Determine quantity of information to send + comm_size = send_range(2)-send_range(1)+1 + ! Send the range of the scalar field send + tag = compute_tag(ind_group, tag_bufToScal_range, direction, proc_gap) + call mpi_Isend(send_range(1), 2, MPI_INTEGER, send_rank, tag, comm, send_request, ierr) + ! And send the buffer + tag = compute_tag(ind_group, tag_bufToScal_buffer, direction, proc_gap) + call mpi_Isend(send_buffer(send_range(1)),comm_size, MPI_DOUBLE_PRECISION, send_rank, & + & tag, comm, send_request, ierr) + else + ! I have to distribute the buffer in myself + do i = send_range(1), send_range(2) + scal1D(i-send_gap) = scal1D(i-send_gap) + send_buffer(i) + end do + end if + end do + + ! Receive information + ! Allocate field + allocate(rece_rank(rece_proc(1):rece_proc(2))) + allocate(rece_range(2,rece_proc(1):rece_proc(2))) ! be careful that mpi use contiguous memory element + allocate(rece_request(rece_proc(1):rece_proc(2))) + ! Receive range + do proc_gap = rece_proc(1), rece_proc(2) + call mpi_cart_shift(cart_comm, direction-1, proc_gap, rankP, rece_rank(proc_gap), ierr) + if (rece_rank(proc_gap)/=myrank) then + tag = compute_tag(ind_group, tag_bufToScal_range, direction, -proc_gap) + call mpi_Irecv(rece_range(1,proc_gap), 2, MPI_INTEGER, rece_rank(proc_gap), tag, comm, & + & rece_request(proc_gap), ierr) ! we use tag = source rank + end if + end do + ! Check reception + do proc_gap = rece_proc(1), rece_proc(2) + if (rece_rank(proc_gap)/=myrank) then + call mpi_wait(rece_request(proc_gap), rece_status, ierr) + end if + end do + deallocate(rece_request) + ! Receive buffer and remesh it + ! XXX Possible optimisation : an optimal code will + ! 1 - have non-blocking reception of scalar buffers + ! 2 - check when a reception is done and then update the scalar + ! 3 - iterate step 2 until all message was rece and that the scalar + ! field was update with all the scalar buffers + do proc_gap = rece_proc(1), rece_proc(2) + if (rece_rank(proc_gap)/=myrank) then + rece_i_min = rece_range(1,proc_gap) + rece_i_max = rece_range(2,proc_gap) + ! Receive information + comm_size=(rece_i_max-rece_i_min+1) + allocate(rece_buffer(rece_i_min:rece_i_max)) ! XXX possible optimisation + ! by allocating one time to the max size, note that the range use in + ! this allocation instruction is include in (1, N_proc(2)) + tag = compute_tag(ind_group, tag_bufToScal_buffer, direction, -proc_gap) + call mpi_recv(rece_buffer(rece_i_min), comm_size, MPI_DOUBLE_PRECISION, & + & rece_rank(proc_gap), tag, Y_comm, rece_status, ierr) + ! Update the scalar field + send_gap = proc_gap*N_proc(direction) + scal1D(rece_i_min+send_gap:rece_i_max+send_gap) = scal1D(rece_i_min+send_gap:rece_i_max+send_gap) & + & + rece_buffer(rece_i_min:rece_i_max) + deallocate(rece_buffer) + end if + end do + + deallocate(rece_range) + deallocate(rece_rank) + +end subroutine AC_bufferToScalar + + +!> Left remeshing formula of order 2 +!! @param[in] pos_adim= adimensionned particle position +!! @param[in] sca = scalar advected by the particle +!! @param[in,out] buffer = temporaly remeshed scalar field +subroutine AC_remesh_left(pos_adim, sca, buffer) + + use cart_topology + + real(WP), intent(in) :: pos_adim, sca + real(WP), dimension(send_j_min:send_j_max), intent(inout) :: buffer + + integer :: j0 ! indice of the the nearest mesh points + real(WP) :: bM, b0, bP ! interpolation weight for the particles + real(WP) :: yM, y0, yP ! adimensionned distance to mesh points + ! Mesh point used in remeshing formula + j0 = floor(pos_adim) + !j0 = floor(pos/d_sc(2)) + + ! Distance to mesh points + y0 = (pos_adim - float(j0)) + !y0 = (pos - float(j0)*d_sc(2))/d_sc(2) + yM = y0-1 + yP = y0+1 + + ! Interpolation weights + bM=0.5*y0*yM + b0=1.-y0**2 + bP=0.5*y0*yP + + ! remeshing + buffer(j0-1) = buffer(j0-1) + bM*sca + buffer(j0) = buffer(j0) + b0*sca + buffer(j0+1) = buffer(j0+1) + bP*sca + +end subroutine AC_remesh_left + +!> Centered remeshing formula of order 2 +!! @param[in] pos_adim= adimensionned particle position +!! @param[in] sca = scalar advected by the particle +!! @param[in,out] buffer = temporaly remeshed scalar field +subroutine AC_remesh_center(pos_adim, sca, buffer) + + use cart_topology + + real(WP), intent(in) :: pos_adim, sca + real(WP), dimension(send_j_min:send_j_max), intent(inout) :: buffer + + integer :: j0 ! indice of the the nearest mesh points + real(WP) :: bM, b0, bP ! interpolation weight for the particles + real(WP) :: yM, y0, yP ! adimensionned distance to mesh points + + j0 = nint(pos_adim) + !j0 = nint(pos/d_sc(2)) + + ! Distance to mesh points + y0 = (pos_adim - float(j0)) + !y0 = (pos - float(j0)*d_sc(2))/d_sc(2) + yM = y0-1 + yP = y0+1 + + ! Interpolation weights + bM=0.5*y0*yM + b0=1.-y0**2 + bP=0.5*y0*yP + + ! remeshing + buffer(j0-1) = buffer(j0-1) + bM*sca + buffer(j0) = buffer(j0) + b0*sca + buffer(j0+1) = buffer(j0+1) + bP*sca + +end subroutine AC_remesh_center + + +!> Corrected remeshing formula for transition from Centered block to a Left block with a different indice (tagged particles) +!! @param[in] pos_adim= adimensionned particle position +!! @param[in] sca = scalar advected by this particle +!! @param[in] posP_ad = adimensionned position of the second particle +!! @param[in] scaP = scalar advected by this particle +!! @param[in,out] buffer = temporaly remeshed scalar field +!! @details +!! Remeshing formula devoted to tagged particles. +!! The particle group send into argument is composed of a block end and of the +!! begining of the next block. The first particles belong to a centered block +!! and the last to a left one. The block have difference indice (tagged +!! particles) and we have to use corrected formula. +subroutine AC_remesh_tag_CL(pos_adim, sca, posP_ad, scaP, buffer) + + use cart_topology + + real(WP), intent(in) :: pos_adim, sca, posP_ad, scaP + real(WP), dimension(send_j_min:send_j_max), intent(inout) :: buffer + + integer :: jM, j0, jP ! indice of the the nearest mesh points + ! (they depend on the block type) + integer :: j0_bis ! indice of the the nearest mesh point for the indP=ind+1 particle + real(WP) :: aM, a0, bP, b0 ! interpolation weight for the particles + real(WP) :: yM, y0, y0_bis, yP_bis ! adimensionned distance to mesh points + + j0 = nint(pos_adim) + !j0 = nint(pos/d_sc(2)) + j0_bis = floor(posP_ad) + !j0_bis = floor(posP/d_sc(2)) + jM=j0-1 + jP=j0+1 + + y0 = (pos_adim - float(j0)) + !y0 = (pos - float(j0)*d_sc(2))/d_sc(2) + y0_bis = (posP_ad - float(j0_bis)) + !y0_bis = (posP - float(j0_bis)*d_sc(2))/d_sc(2) + yM=y0-1. + yP_bis=y0_bis+1 + + aM=0.5*y0*yM + a0=1.-aM + bP=0.5*y0_bis*yP_bis + b0=1.-bP + + ! Remeshing + buffer(jM)=buffer(jM)+aM*sca + buffer(j0)=buffer(j0)+a0*sca+b0*scaP + buffer(jP)=buffer(jP)+bP*scaP + +end subroutine AC_remesh_tag_CL + + +!> Corrected remeshing formula for transition from Left block to a Centered block with a different indice (tagged particles) +!! @param[in] pos_adim= adimensionned particle position +!! @param[in] sca = scalar advected by this particle +!! @param[in] posP_ad = adimensionned position of the second particle +!! @param[in] scaP = scalar advected by this particle +!! @param[in,out] buffer = temporaly remeshed scalar field +!! @details +!! Remeshing formula devoted to tagged particles. +!! The particle group send into argument is composed of a block end and of the +!! begining of the next block. The first particles belong to a left block +!! and the last to a centered one. The block have difference indice (tagged +!! particles) and we have to use corrected formula. +subroutine AC_remesh_tag_LC(pos_adim, sca, posP_ad, scaP, buffer) + + use cart_topology + + real(WP), intent(in) :: pos_adim, sca, posP_ad, scaP + real(WP), dimension(send_j_min:send_j_max), intent(inout) :: buffer + + integer :: jM, j0, jP, jP2, jP3 ! indice of the the nearest mesh points + ! (they depend on the block type) + integer :: j0_bis ! indice of the the nearest mesh point for the indP=ind+1 particle + real(WP) :: aM, a0, aP,aP2, b0, bP, bP2, bP3 ! interpolation weight for the particles + real(WP) :: yM,y0,yP, yM_bis,y0_bis,yP_bis ! adimensionned distance to mesh points + + + ! Indice of mesh point used in order to remesh + j0 = floor(pos_adim) + !j0 = floor(pos/d_sc(2)) + j0_bis = nint(posP_ad) + !j0_bis = nint(posP/d_sc(2)) + jM=j0-1 + jP=j0+1 + jP2=j0+2 + jP3=j0+3 + + ! Distance to mesh point + y0 = (pos_adim - float(j0)) + !y0 = (pos - float(j0)*d_sc(2))/d_sc(2) + y0_bis = (posP_ad - float(j0_bis)) + !y0_bis = (posP - float(j0_bis)*d_sc(2))/d_sc(2) + yP=y0+1 + yM=y0-1 + yP_bis=y0_bis+1 + yM_bis=y0_bis-1 + + ! Interpolation weight + aM=y0*yM/2. + a0=1-y0**2 + aP=y0 + aP2=y0*yM/2. + b0=y0_bis*yP_bis/2. + bP=-y0_bis + bP2=1-y0_bis**2 + bP3=y0_bis*yP_bis/2. + + ! Remeshing + buffer(jM)= buffer(jM)+aM*sca + buffer(j0)= buffer(j0)+a0*sca+b0*scaP + buffer(jP)= buffer(jP)+aP*sca+bP*scaP + buffer(jP2)=buffer(jP2)+aP2*sca+bP2*scaP + buffer(jP3)=buffer(jP3)+bP3*scaP + +end subroutine AC_remesh_tag_LC + +end module advec_common +!! @} diff --git a/CodesEnVrac/LEGI/src/precision.F90 b/CodesEnVrac/LEGI/src/precision.F90 new file mode 100644 index 000000000..2a7cd1e02 --- /dev/null +++ b/CodesEnVrac/LEGI/src/precision.F90 @@ -0,0 +1,27 @@ +!------------------------------------------------------------------------------ +! +! MODULE: precision +! +!> @author +!> Guillaume Balarac, LEGI +! +! DESCRIPTION: +!> The aim of this module is set some parameters to fix the working data +!> representation in the code. It is set to double precision for REAL. +!------------------------------------------------------------------------------ + +MODULE precision + IMPLICIT NONE + INTEGER, PARAMETER :: SP = kind(1.0) + INTEGER, PARAMETER :: DP = kind(1.0d0) + INTEGER, PARAMETER :: WP = DP + REAL(WP), PRIVATE :: sample_real_at_WP + REAL(WP), PARAMETER :: MAX_REAL_WP = HUGE(sample_real_at_WP) + INTEGER, PRIVATE :: sample_int + INTEGER, PARAMETER :: MAX_INTEGER = HUGE(sample_int) + !> the MPI type for REAL exchanges in simple or double precision + INTEGER, PUBLIC :: MPI_REAL_WP + !> the MPI type for COMPLEX exchanges in simple or double precision + INTEGER, PUBLIC :: MPI_COMPLEX_WP + +END MODULE precision diff --git a/CodesEnVrac/LEGI/test/CMakeLists.txt b/CodesEnVrac/LEGI/test/CMakeLists.txt new file mode 100644 index 000000000..febd4f0ab --- /dev/null +++ b/CodesEnVrac/LEGI/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/CodesEnVrac/LEGI/test/src/CMakeLists.txt b/CodesEnVrac/LEGI/test/src/CMakeLists.txt new file mode 100644 index 000000000..77d584d85 --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/CMakeLists.txt @@ -0,0 +1,30 @@ +set(EXECUTABLE_OUTPUT_PATH "${TEST_EXE_DIR}") +include_directories(${CMAKE_Fortran_MODULE_DIRECTORY}) + +# ===== Test the parallel topology and how it interact with the "global" datalayout (used in the spectral code) ===== +set(TEST_NAME Test_topo) + file(GLOB ${TEST_NAME}_FILES ${TEST_NAME}/*.f90) + if(${TEST_NAME}_FILES) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_FILES}) + endif() + list(APPEND ${TEST_NAME}_SRC "test_common.f90") + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_topology.f90") +add_executable(${TEST_NAME} ${${TEST_NAME}_SRC}) +target_link_libraries(${TEST_NAME} ${LIBS}) + +# ===== Test the advection and the particular solver ===== +set(TEST_NAME Test_advec) + # Test file + file(GLOB ${TEST_NAME}_FILES ${TEST_NAME}/*.f90) + if(${TEST_NAME}_FILES) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_FILES}) + endif() + list(APPEND ${TEST_NAME}_SRC "test_common.f90") + # Tested solver + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_topology.f90") + file(GLOB ${TEST_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/particle/*.f90) + if(${TEST_NAME}_LIB) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_LIB}) + endif() +add_executable(${TEST_NAME} ${${TEST_NAME}_SRC}) +target_link_libraries(${TEST_NAME} ${LIBS}) diff --git a/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux.f90 b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux.f90 new file mode 100644 index 000000000..32393d6c3 --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux.f90 @@ -0,0 +1,368 @@ +!------------------------------------------------------------------------------ +! +! MODULE: test_advection +! +! DESCRIPTION: +!> Validation test for advection method. +!! +!! @details +!! This module provide different test to validate the transport solver. +!! All these test are unit test : they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular solver +!! The following test are included : +!! A - Validate the particular method, step by step +!! 1 -> Test the procedure "AC_obtain_senders" from advec_common +!! 2 -> Validate the redistribution the buffer during the remeshing (XXX todo) +!! 3 -> Validate the remeshing of untagged particles +!! 4 -> Validate the remeshing of tagged particles (XXX todo) +!! B - Validate an advection solver (XXX todo) +!! 1 -> advec a ball with a constant velocity +!! 2 -> advec a ball with a spheric velocity field (the ball turns) +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module advec_aux + + use string + use precision + implicit none + + real(WP), private :: epsilon_error = 1e-4 ! Error tolerance + + + ! Public procedures + + ! ===== Test for the particles solver ===== + ! Public function + public :: test_part_remesh_no_tag + public :: test_part_init + public :: test_part_advecO2 + public :: test_advecY + + + ! ===== Generic test for an advection solver ===== + + ! Private procedure + +contains + +!> Particle method: validation of particle creation +!! @param[in] direction = to select direction to test +!! @param[in] init_scal = optional parameter to select initialisation +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_init (direction, init_scal) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use advec_common + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(str_short), intent(in), optional :: init_scal + integer, intent(in) :: direction ! current direction + + character(str_short) :: initialisation ! to choose how to initialise the scalar field + real(WP), dimension(:, :, :), allocatable :: scalar ! the scalar field + real(WP), dimension(:), allocatable :: p_pos, p_V ! the particles position and the scalar they advect + real(WP) :: velocity ! constant velocity of the flux + + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'constant' + end if + success = .true. + call test_substatus('test of particle initialisation !', success, myrank) + +end function test_part_init + + + + + +!> Particles method: validation of the remeshing of untagged particles +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_remesh_no_tag (init_scal) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use advec_common + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + + character(len=17) :: initialisation ! to choose how to initialise the scalar field + character(len=str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scalar ! the scalar field + real(WP), dimension(:), allocatable :: p_pos_adim, p_SC ! the adimensionned particles position and the scalar they advect + integer, dimension(:), allocatable :: bl_type, bl_tag ! type and tag of each particle bloc + real(WP) :: velocity ! constant velocity of the flux + integer :: nb_proc ! number of processes + integer :: ierr ! mpi error code + integer :: i,j,k ! mesh indice + integer, dimension(2) :: ind_group ! indice of the current group of line + integer :: T_step ! time + integer :: T_end ! final time + real(WP), dimension(:,:,:), allocatable :: good_scal ! analytic solution + real(WP), dimension(3) :: translat ! to compute analytic solution + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + allocate(scalar(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(p_pos_adim(N_proc(2))) + allocate(p_SC(N_proc(2))) + allocate(bl_type(1+N_proc(2)/bl_size)) + allocate(bl_tag((N_proc(2)/bl_size))) + + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'constant' + end if + success = .true. + + !call cart_create((/ 1, nb_proc, 1 /), ierr) + !call mesh_default() + + ! Choose a velocity + velocity = N(2)/11*d_sc(2) + T_step = 1 + T_end = 1 + T_end = T_step + translat = 0 + translat(2) = - velocity*T_step + translat = translat/d_sc + + ! Initialise the scalar field + call scal_init(initialisation, scalar, good_scal, translat) + call test_substatus('initialisation', success, myrank) + + ! Choose to test remeshing for centered/left and tagged/untagged particles + bl_type = 1 + bl_tag = 0 + + ! Advec it with a particular method + do k = begin_proc(3), end_proc(3) + ind_group(2) = 0 + !k = begin_proc(3) + ind_group(1) = 0 + ind_group(2) = ind_group(2) + 1 + do i = begin_proc(1), end_proc(1) + !i = begin_proc(1) + ind_group(1) = ind_group(1) + 1 + ! Initialise the particles + p_SC = scalar(i,:,k) + !scalar(i,:,k)=0 + do j = begin_proc(2), end_proc(2) + p_pos_adim(j) = j + end do +! do T_step = 1, 11 + ! Advection + p_pos_adim = p_pos_adim + T_step*velocity/d_sc(2) + ! Remeshing + call Yremesh_O2(ind_group, p_pos_adim, bl_type, bl_tag, i, k, scalar) +! end do + end do + end do + + ! Check the final scalar field + call test_check_success(scalar, good_scal, success) + + deallocate(scalar) + deallocate(p_pos_adim) + deallocate(p_SC) + deallocate(bl_type) + deallocate(bl_tag) + + success = .not.success + +end function test_part_remesh_no_tag + + +!> Particles method: validation of the advection along one direction with the +!! order 2 particle method. +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @return error = test error (= false if the code pass the test) (= not success) +!! @detail +!! These tests are devoted to validate the advection solver based on particle +!! method. They can be used for other advection solvers too. Their specificity +!! is to test each configuration that could be encoutered in the order 2 solver +!! based on particle method. Therefore they provide complete test for this +!! order 2 solver but non necessary for a solver based on another method. +function test_part_advecO2(init_scal, shift) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + integer, intent(in), optional :: shift + + character(str_short) :: initialisation ! to choose how to initialise the fields + integer :: shift_bis ! shift effectly used in the test + character(str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: velo ! the flow + integer :: i,j,k ! mesh indice + integer :: T_step ! time + integer :: T_end ! final time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + integer :: direction = 2 ! current direction + + ! -- Allocation -- + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(velo(N_proc(1), N_proc(2), N_proc(3))) + + ! -- Initialisation -- + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'center' + end if + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + success = .true. + dt = 0.1 + + call test_substatus('shift', shift_bis, myrank) + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + ! Initialise the velocity, the scalar field and compute the theoritical solution + call scal_velo_init_part(init_scal, dt, shift_bis, scal3D, velo, direction, good_scal) + call test_substatus('initialisation', success, myrank) + + ! Advec it with a particular method + call advecY_calc(dt, velo, scal3D, 'p_O2') + call test_check_success(scal3D, good_scal, success) + call test_substatus('advection', success, myrank) + + + deallocate(scal3D) + deallocate(good_scal) + deallocate(velo) + + success = .not.success + +end function test_part_advecO2 + + +!> Test devoted to validate advection solver along one direction +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @return error = test error (= false if the code pass the test) (= not success) +function test_advecY(init_scal) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + + character(len=17) :: initialisation ! to choose how to initialise the scalar field + character(len=str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: Vy ! the flow + real(WP) :: velocity ! constant velocity of the flux + integer :: ierr ! mpi error code + integer :: i,j,k ! mesh indice + integer :: T_step ! time + integer :: T_end ! final time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + real(WP), dimension(3) :: translat ! to compute analytic solution + + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'constant' + end if + success = .true. + + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + + ! Initialise the velocity + velocity = N(2)/11*d_sc(2) + Vy = velocity + T_end = 1 + translat = 0 + translat(2) = - velocity*T_end + translat = translat/d_sc + + ! Initialise the scalar field + call scal_init(initialisation, scal3D, good_scal, translat) + call test_substatus('initialisation', success, myrank) + + ! Advec it with a particular method + dt = 1 + call advecY_calc(dt, Vy, scal3D, 'p_O2') + call test_check_success(scal3D, good_scal, success) + call test_substatus('advec along Y', success, myrank) + + + deallocate(scal3D) + deallocate(good_scal) + deallocate(Vy) + + success = .not.success + +end function test_advecY + + +end module advec_aux diff --git a/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_common.f90 b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_common.f90 new file mode 100644 index 000000000..298f84575 --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_common.f90 @@ -0,0 +1,905 @@ +!------------------------------------------------------------------------------ +! +! MODULE: test_part_common +! +! DESCRIPTION: +!> This module provides tests to validate the particular solver. It is +!! more precisly focused on testing the "common part" (advec_common) used for each +!! directions. +!! +!! @details +!! This module is devoted to validate all the procedure from "advec_common". All the +!! tests are unit tests: they return a logical value to check if the code version pass +!! it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular +!! solver +!! The following test are included : +!! A - Validate the particular method, step by step +!! 1 -> Test the procedure "AC_obtain_senders" from advec_common +!! 2a -> Validate the redistribution the buffer during the remeshing +!! 2b -> Validate the redistribution the buffer during the remeshing - +!! debug version : only one processus contains non-zero field. +!! 3 -> Validate the remeshing of untagged particles +!! 4 -> Validate the remeshing of tagged particles (XXX todo) +!! B - Validate an advection solver (in advec_aux) +!! 1 -> advec a ball with a constant velocity +!! 2 -> advec a ball with a spheric velocity field (the ball turns) +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module advec_aux_common + + use string + use precision + implicit none + + + + ! ===== Test for the particles solver ===== + ! Public function + public :: test_part_AC_obtain_senders + public :: test_part_AC_bufferToScalar + public :: test_part_AC_bufferToScalar_Deb + public :: test_part_AC_interpol_velocity + + + + +contains + + +!> Particles method: validation of the procedure "AC_obtain_senders" wich determine +!! who will comunicate with who during the remeshing +!! @return success = test success (= false if the code pass the test) +!! @param[in] shift = global translation of indices (optional) +function test_part_AC_obtain_senders(shift) result(success) + + ! Library + use mpi + ! Scale code + use advec + use advec_common + use cart_topology + ! Test procdure + use test_common + + integer, intent(in), optional :: shift + logical :: success + ! Be aware : during this function, success = true if everything is right, but we return not success = error + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + integer :: nb_proc ! number of processes + integer :: ierr ! mpi success code + integer :: j_min, j_max ! input argument of the tested procedure + integer :: proc_min,proc_max! input argument of the tested procedure + integer :: send_begin ! theoritical value of proc_min + integer :: send_end ! theoritical value of proc_max + integer, dimension(2) :: rece_proc ! output argument of the tested procedure + integer :: rece_begin ! theoritical value of rece_proc(1) + integer :: rece_end ! theoritical value of rece_proc(2) + integer, dimension(2) :: ind_group ! indice of current group of lines + integer :: direction ! current direction (alonG X, Y or Z) + + ! Some initialisation + success = .true. + ind_group = 1 + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, myrank) + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + call test_substatus('initialisation solveur', success, myrank) + call mpi_barrier(MPI_COMM_WORLD, ierr) + + do direction = 1, 3 + call test_substatus('direction', direction, myrank) + ! Test the procedure "AC_obtain_senders" + ! If I communicate just with my self + bl_bound_size = 0 + j_min = 1 + shift_bis*N_proc(direction) + j_max = N_proc(direction)*(shift_bis+1) + proc_min = -1 + proc_max = -1 + call AC_obtain_senders(j_min, j_max, direction, D_comm(direction), ind_group, proc_min, proc_max, rece_proc) + call mpi_barrier(MPI_COMM_WORLD, ierr) + if (rece_proc(1)/=-shift_bis) then + call test_substatus(' XXX error - just me', myrank) + call test_substatus('rece_proc(1)', rece_proc(1), myrank) + call test_substatus('and it must be', -shift_bis, myrank) + success = .false. + end if + if (rece_proc(2)/=-shift_bis) then + call test_substatus(' XXX error - just me', myrank) + call test_substatus('rece_proc(2)', rece_proc(2), myrank) + call test_substatus('and it must be', -shift_bis, myrank) + success = .false. + end if + if (proc_min/=shift_bis) then + call test_substatus(' XXX error - just me', myrank) + call test_substatus('send_proc_min', proc_min, myrank) + call test_substatus('and it must be', shift_bis, myrank) + success = .false. + end if + if (proc_max/=shift_bis) then + call test_substatus(' XXX error - just me', myrank) + call test_substatus('send_proc_max', proc_min, myrank) + call test_substatus('and it must be', shift_bis, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('just me', success, myrank) + + ! I communicate with my two neighbors + call advec_init(order) + j_min = shift_bis*N_proc(direction) + j_max = (1+shift_bis)*N_proc(direction) -1+2*bl_bound_size + proc_min = 0 + proc_max = 0 + call AC_obtain_senders(j_min, j_max, direction, D_comm(direction), ind_group, proc_min, proc_max, rece_proc) + call mpi_barrier(MPI_COMM_WORLD, ierr) + if (rece_proc(1)/=-1-shift_bis) then + call test_substatus(' XXX error - neighbors', myrank) + call test_substatus('rece_proc(1)', rece_proc(1), myrank) + call test_substatus('and it must be', -1-shift_bis, myrank) + success = .false. + end if + if (rece_proc(2)/=1-shift_bis) then + call test_substatus(' XXX error - neighbors', myrank) + call test_substatus('rece_proc(2)', rece_proc(2), myrank) + call test_substatus('and it must be', 1-shift_bis, myrank) + success = .false. + end if + if (proc_min/=-1+shift_bis) then + call test_substatus(' XXX error - neighbors', myrank) + call test_substatus('send_proc_min', proc_min, myrank) + call test_substatus('and it must be', -1+shift_bis, myrank) + success = .false. + end if + if (proc_max/=1+shift_bis) then + call test_substatus(' XXX error - neighbors', myrank) + call test_substatus('send_proc_max', proc_min, myrank) + call test_substatus('and it must be', 1+shift_bis, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('me and my neighbors', success, myrank) + + ! Contraction / extention + if (modulo(nb_proc_dim(direction),2)==0) then + if (modulo(myrank,2)== 0) then + ! Contraction + j_min = 1 + shift_bis*N_proc(2) + j_max = (1+shift_bis)*N_proc(2) + send_begin = 0 + send_end = 0 + else + ! Dilatation + j_min = +1 - 2*bl_bound_size + shift_bis*N_proc(direction) + j_max = (1+shift_bis)*N_proc(direction) + 2*bl_bound_size + send_begin = -1 + send_end = 1 + end if + if (modulo(myrank+shift_bis,2)== 0) then + rece_begin = -1 + rece_end = +1 + else + rece_begin = 0 + rece_end = 0 + end if + proc_min = send_begin + 1 + proc_max = send_end + 1 + call AC_obtain_senders(j_min, j_max, direction, D_comm(direction), ind_group, proc_min, proc_max, rece_proc) + call mpi_barrier(MPI_COMM_WORLD, ierr) + if (rece_proc(1)/=rece_begin-shift_bis) then + call test_substatus(' XXX error contract/dilat', myrank) + call test_substatus('rece_proc(1)', rece_proc(1), myrank) + call test_substatus('and it must be', rece_begin-shift_bis, myrank) + success = .false. + end if + if (rece_proc(2)/=rece_end-shift_bis) then + call test_substatus(' XXX error contract/dilat', myrank) + call test_substatus('rece_proc(2)', rece_proc(2), myrank) + call test_substatus('and it must be', rece_end-shift_bis, myrank) + success = .false. + end if + if (proc_min/=send_begin+shift_bis) then + call test_substatus(' XXX error contract/dilat', myrank) + call test_substatus('send_proc_min', proc_min, myrank) + call test_substatus('and it must be', send_begin+shift_bis, myrank) + success = .false. + end if + if (proc_max/=send_end+shift_bis) then + call test_substatus(' XXX error contract/dilat', myrank) + call test_substatus('send_proc_max', proc_min, myrank) + call test_substatus('and it must be', send_end+shift_bis, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('contraction/extension', success, myrank) + else + call test_substatus('nb of processus is even', myrank) + call test_substatus('no contraction/dilatation test', myrank) + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + + success = .not.success + +end function test_part_AC_obtain_senders + + + +!> Particles method: validation of the procedure "AC_bufferToScalar". +!! @return success = test success (= false if the code pass the test) +!! @param[in] shift = global translation of indices (optional) +!! @details +!! Test the procedure "AC_obtain_senders" wich send local buffer use for remeshing +!! to the right processes. This procedure belong to "advec_common". +function test_part_AC_bufferToScalar(shift) result(success) + + ! Library + use mpi + ! Scale code + use advec + use advec_common + use cart_topology + ! Test procdure + use test_common + + integer, intent(in), optional :: shift + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + integer :: nb_proc ! number of processes + integer :: ierr ! mpi success code + integer :: j_min, j_max ! input argument of the tested procedure + real(WP), dimension(:), allocatable :: send_buffer ! the buffer to redistribute + real(WP), dimension(:), allocatable :: scal1D ! the scalar field + integer :: direction ! direction (2 if along Y, 3=along Z) + integer :: success_inf ! norm L_inf of the success + real(WP) :: good_scal ! theoritical value of scal1D + integer, dimension(2) :: mycoord ! my coordonate in the mpi topology + integer, dimension(2) :: ind_group ! indice of current group of lines + + ! Some initialisation + success = .true. + ind_group = 1 + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, myrank) + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + do direction = 1, 3 + call test_substatus('direction', direction, myrank) + good_scal = modulo(coord(direction)-shift_bis, nb_proc_dim(direction)) + + ! Test 1 - unrealistic case with no communication + ! Initialize the buffer to remesh + bl_bound_size = 0 + j_min = 1 + shift_bis*N_proc(direction) + j_max = N_proc(direction)*(shift_bis+1) + allocate (send_buffer(j_min:j_max)) + allocate (scal1D(1:N_proc(direction))) + send_buffer = coord(direction) + scal1D = 0.0 + ! Let's go ! + call mpi_barrier(MPI_COMM_WORLD, ierr) + call AC_bufferToScalar(direction, D_comm(direction), ind_group, j_min, j_max, send_buffer, scal1D) + ! Check the success + call test_check_success_S(scal1D, good_scal, success) + deallocate (send_buffer) + deallocate (scal1D) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('just me', success, myrank) + + ! I communicate with my two neighbors + call advec_init(order) + j_min = shift_bis*N_proc(direction) + j_max = (1+shift_bis)*N_proc(direction) -1+2*bl_bound_size + allocate (send_buffer(j_min:j_max)) + allocate (scal1D(1:N_proc(direction))) + send_buffer = coord(direction) + send_buffer(j_min) = modulo(coord(direction)-1, nb_proc_dim(direction))/2.0 + send_buffer(j_min+1) = send_buffer(j_min+1)/2. + send_buffer(j_max) = modulo(coord(direction)+1, nb_proc_dim(direction))/2.0 + send_buffer(j_max-1) = send_buffer(j_max-1)/2. + scal1D = 0.0 + call AC_bufferToScalar(direction, D_comm(direction), ind_group, j_min, j_max, send_buffer, scal1D) + ! Check the success + call test_check_success_S(scal1D, good_scal, success) + deallocate (send_buffer) + deallocate (scal1D) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('me and my neighbors', success, myrank) + end do + + success = .not.success + +end function test_part_AC_bufferToScalar + + + +!> Particles method: validation of the procedure "AC_bufferToScalar" +!! @return success = test success (= false if the code pass the test) +!! @param[in] shift = global translation of indices (optional) +!! @param[in] rank = rank of the processus which will contains non-zero field. +!! @details +!! Debugging version : only one processus contains non zero field to remesh. +!! Each processus communicate with its two neibor. A shift could be add. +function test_part_AC_bufferToScalar_Deb(rank, shift) result(success) + + ! Library + use mpi + ! Scale code + use advec + use advec_common + use cart_topology + ! Test procdure + use test_common + + integer, intent(in) :: rank + integer, intent(in), optional :: shift + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + integer :: nb_proc ! number of processes + integer :: ierr ! mpi success code + integer :: j_min, j_max ! input argument of the tested procedure + real(WP), dimension(:), allocatable :: send_buffer ! the buffer to redistribute + real(WP), dimension(:), allocatable :: scal1D ! the scalar field + real(WP), dimension(:), allocatable :: good_scal ! theoritical value of scal1D + integer :: direction ! direction (2 if along Y, 3=along Z) + integer, dimension(3) :: mycoord ! my coordonates in the mpi topology + integer :: rank_shift ! rank of processus of rank = rank+shift + integer, dimension(2) :: ind_group ! indice of current group of lines + + ! Some initialisation + success = .true. + ind_group = 1 + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, myrank) + call test_substatus('rank tested', rank, myrank) + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + do direction = 1, 3 + call test_substatus('direction', direction, myrank) + ! Initialise the solver environnement and the field + call advec_init(order) + j_min = shift_bis*N_proc(direction) + j_max = (1+shift_bis)*N_proc(direction) -1+2*bl_bound_size + allocate (send_buffer(j_min:j_max)) + allocate (scal1D(1:N_proc(direction))) + send_buffer = 0 + if (myrank == rank) then + send_buffer = 2 + send_buffer(j_min) = 1 + send_buffer(j_max) = 3 + end if + scal1D = 0.0 + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! Compute the analytic solution + allocate (good_scal(1:N_proc(direction))) + good_scal = 0.0 + ! For the processus wich correcpond to me after the shift + call mpi_cart_coords(cart_comm, rank, 3, mycoord, ierr) + mycoord(direction) = mycoord(direction) + shift_bis + call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) + if (myrank==rank_shift) good_scal = 2 + ! For the next processus in the current direction + mycoord(direction) = mycoord(direction) + 1 + call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) + if (myrank==rank_shift) good_scal(1) = 3 + ! For the previous processus in the current direction + mycoord(direction) = mycoord(direction) -2 + call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) + if (myrank==rank_shift) good_scal(N_proc(direction)) = 1 + + ! Compute the numerical solution + call AC_bufferToScalar(direction, D_comm(direction), ind_group, j_min, j_max, send_buffer, scal1D) + ! Check the success + call test_check_success_F(scal1D, good_scal, success) + deallocate (send_buffer) + deallocate (scal1D) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('me and my neighbors', success, myrank) + end do + + success = .not.success + + +end function test_part_AC_bufferToScalar_Deb + + +!> Particles method: validation of the procedure "AC_obtain_senders" wich determine +!! who will comunicate with who during the remeshing +!! @return success = test success (= false if the code pass the test) +!! @param[in] shift = global translation of indices (optional) +function test_part_AC_obtain_recevers(shift) result(success) + + ! Library + use mpi + ! Scale code + use advec_common + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + integer, intent(in), optional :: shift + logical :: success + ! Be aware : during this function, success = true if everything is right, but we return not success = error + + integer :: shift_bis ! global translation of indices + integer :: direction ! current direction + integer :: comm ! associated mpi communicator + integer :: rece_ind_min ! the minimal indice used in velocity interpolation + integer :: rece_ind_max ! the maximal indice used in velocity interpolation + integer, dimension(2) :: rece_gap ! distance between me and processus wich send me information + integer, dimension(2) :: send_gap ! distance between me and processus to wich I send information + integer :: nn, clock ! to generate random number + integer, dimension(:), allocatable :: seed ! to generate random number + real(WP) :: p_pos_1,p_pos_end! location where the velocity is interpolated + integer :: ind, indbis ! indices + real(WP), dimension(2) :: r ! random numbers to initialise p_pos + integer :: ierr ! mpi error code + integer :: i, k, ite ! indices + + call test_substatus('test AC_obtain_recevers', myrank) + + ! Some initialisation + success = .true. + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, myrank) + direction = 2 + comm = Y_comm + ! Init the particles data + ! To generate random number + call RANDOM_SEED(size = nn) + allocate(seed(nn)) + call SYSTEM_CLOCK(COUNT=clock) + seed = clock + 37 * (/ (ind - 1, ind = 1, nn) /) + call RANDOM_SEED(PUT = seed) + deallocate(seed) + ! Position where the velocity will be interpolated + CALL RANDOM_NUMBER(r) + p_pos_1 = (1+shift_bis+r(1))*d_sc(direction) + p_pos_end = (N_proc(direction)+shift_bis+r(2))*d_sc(direction) + + ! Compute range of the set of point where I need the velocity value + rece_ind_min = floor(p_pos_1/d_sc(direction)) + rece_ind_max = floor(p_pos_end/d_sc(direction)) + 1 + ! Test the function + indbis=0 + do ite = 1, 10 + do i = 1, 100 + do k = 1, 100 + ind = ind + 1 + call AC_obtain_receivers(direction, comm, (/i, k/), rece_ind_min, rece_ind_max, send_gap, rece_gap) + if (ind>indbis*100000) then + call test_substatus('iteration/100000', ind/100000, myrank) + indbis = indbis+1 + end if + end do + end do + call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + + success = .not. success + +end function test_part_AC_obtain_recevers + + +!> Particles method: validation of the velocity interpolation +!! @return success = test success (= false if the code pass the test) +!! @param[in] direction = 1 for along X, 2 for along Y, 3 for along Z +!! @param[in] comm = mpi communcator associated to direction +!! @param[in] shift = global translation of indice +function test_part_AC_interpol_velocity(direction, comm, shift) result(success) + + ! External Library + use mpi + ! Scales code + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + integer, intent(in) :: direction, comm, shift + + integer :: ind ! indice + integer :: nn, clock ! to generate random number + integer, dimension(:), allocatable :: seed ! to generate random number + real(WP), dimension(N_proc(direction)) :: p_pos ! location where the velocity is interpolated + real(WP), dimension(N_proc(direction)) :: r ! random numbers to initialise p_pos + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)) :: velo ! velocity field + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)) :: good_velo ! analytic interpolation of velocity field in particles position + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)) :: num_velo ! numerical interpolation of velocity field in particles position + real(WP) :: dt ! time step + integer :: T ! for solver iteration + integer :: ierr ! mpi error code + + + call test_substatus('test velocity interpolation', myrank) + call test_substatus('shift', shift, myrank) + + ! Initialisation + success = .true. + ! To generate random number + call RANDOM_SEED(size = nn) + allocate(seed(nn)) + call SYSTEM_CLOCK(COUNT=clock) + seed = clock + 37 * (/ (ind - 1, ind = 1, nn) /) + call RANDOM_SEED(PUT = seed) + deallocate(seed) + ! Position where the velocity will be interpolated + CALL RANDOM_NUMBER(r) + do ind = 1, N_proc(direction) + p_pos(ind) = (ind+shift) + end do + + ! ===== Particles are on mesh point ===== + call test_substatus('particles are placed on a mesh point', myrank) + ! - Basic test : constant velocity - + call velo_init('constant', velo, direction, p_pos, good_velo) + dt = 0.0 +do T = 1, 10 + call aux_com_interpol(dt, direction, comm, p_pos, velo, num_velo) + ! Check result + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_check_success(num_velo, good_velo, success) +end do + call test_substatus('constant velocity', success, myrank) + call mpi_barrier(MPI_COMM_WORLD, ierr) + ! - Normal test - + call velo_init('translation_field', velo, direction, p_pos, good_velo) + call aux_com_interpol(dt, direction, comm, p_pos, velo, num_velo) + ! Check result + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_check_success(num_velo, good_velo, success) + call test_substatus('translation_field', success, myrank) + + + ! ===== Test with p_pos not on a mesh point ===== + call test_substatus('particles are not placed on a mesh point', myrank) + p_pos = p_pos + r*d_sc(direction) + ! - Basic test : constant velocity - + call velo_init('constant', velo, direction, p_pos, good_velo) + do T = 1, 10 + call aux_com_interpol(dt, direction, comm, p_pos, velo, num_velo) + call mpi_barrier(MPI_COMM_WORLD, ierr) + end do + ! Check result + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_check_success(num_velo, good_velo, success) + call test_substatus('constant velocity', success, myrank) + ! - Normal test - + call velo_init('translation_field', velo, direction, p_pos, good_velo) + call aux_com_interpol(dt, direction, comm, p_pos, velo, num_velo) + ! Check result + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_check_success(num_velo, good_velo, success) + call test_substatus('translation_field', success, myrank) + + + ! Return not success + success = .not. success + +end function test_part_AC_interpol_velocity + + +!> Particle method: validation of particle tag and block type determination +!! @return error = test error (= false if the code pass the test) (= not success) +!! @param[in] shift = global translation of indices (optional) +function test_part_AC_type_and_block_O2(shift) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advec_common + use cart_topology + ! Test procedures + use test_common + + integer, intent(in), optional :: shift + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + + integer, dimension(:), allocatable :: bl_type ! correct (analytic) type of block + integer, dimension(:), allocatable :: bl_tag ! correct (analytic) tag of block + integer, dimension(:), allocatable :: good_type ! correct (analytic) type of block + integer, dimension(:), allocatable :: good_tag ! correct (analytic) tag of block + integer :: ierr ! mpi success code + integer :: direction ! direction (2 if along Y, 3=along Z) + integer, dimension(2) :: ind_group ! indice of the current group of line + real(WP) :: dt, cfl ! time step and CFL number + real(WP), dimension(:), allocatable :: p_V ! particle velocity (used to tag particles) + real(WP) :: p_V_next ! velocity of the first particle of the next block + ! (used to determine block type and to tag particles) + integer, dimension(3) :: comm_table ! table of mpi communicator dedicaced to each direction + integer :: ind, ind2 ! indice of the current particle + integer :: ind_bl ! indice of the current block + real(WP) :: lambda_min ! minimum courant number on a block + integer :: ind_tag_bl ! indice of the first tagged block in the test + integer :: ind_tag_p ! indice of particle corresponding to the velocity + ! variation wich induce a tag of the block ind_tag_bl + integer :: ind_tag_bl2 ! indice of the second tagged block in the test + integer :: ind_tag_p2 ! indice of particle wich induce a tag of the block ind_tag_bl2 + + + ! Some initialisation + success = .true. + ind_group = 1 + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, myrank) + call advec_init('p_O2') + dt = 0.01 + comm_table(1) = X_comm + comm_table(2) = Y_comm + comm_table(3) = Z_comm + +direction = 2 +! do direction = 1, 3 + call test_substatus('direction', direction, myrank) + allocate(good_type(bl_number(direction)+1)) + allocate(good_tag(bl_number(direction))) + allocate(bl_type(bl_number(direction)+1)) + allocate(bl_tag(bl_number(direction))) + allocate(p_V(N_proc(direction))) + cfl = dt/d_sc(direction) + if (cfl == 0) cfl = 1 + + ! -- Test case 1 : only left block, no tag -- + p_V = 0.4/cfl + good_tag = 0 + good_type = 0 + call AC_type_and_block(dt, direction, comm_table(direction), (/1,1/), p_V, & + & bl_type, bl_tag) + call test_check_success(bl_tag, good_tag, success) + call test_substatus('test 1.a - no tag ', success, myrank) + call test_check_success(bl_type, good_type, success) + call test_substatus('test 1.a - left particle only', success, myrank) + call MPI_barrier(MPI_COMM_WORLD, ierr) + ! And for another velocity + p_V = -2.8/cfl + call AC_type_and_block(dt, direction, comm_table(direction), (/1,1/), p_V, & + & bl_type, bl_tag) + call test_check_success(bl_tag, good_tag, success) + call test_substatus('test 1.b - no tag ', success, myrank) + call test_check_success(bl_type, good_type, success) + call test_substatus('test 1.b - left block only', success, myrank) + + ! Test case 2 : only center block, no tag + p_V = -0.4/cfl + good_tag = 0 + good_type = 1 + call AC_type_and_block(dt, direction, comm_table(direction), (/1,1/), p_V, & + & bl_type, bl_tag) + call test_check_success(bl_tag, good_tag, success) + call test_substatus('test 2.a - no tag ', success, myrank) + call test_check_success(bl_type, good_type, success) + call test_substatus('test 2.a - center particle only', success, myrank) + call MPI_barrier(MPI_COMM_WORLD, ierr) + ! And for another velocity + p_V = 6.8/cfl + call AC_type_and_block(dt, direction, comm_table(direction), (/1,1/), p_V, & + & bl_type, bl_tag) + call test_check_success(bl_tag, good_tag, success) + call test_substatus('test 2.b - no tag ', success, myrank) + call test_check_success(bl_type, good_type, success) + call test_substatus('test 2.b - center particle only', success, myrank) + + ! Test case 3 = 2 tag + ! one for an extension: on the left part of the domain all block are left + ! one, on the right side they are center and there is a gap of 1 in the block index + ! one for a contraction: on the left part of the domain all block are center + ! one, on the right side they are left and there is a gap of -1 in the block index + ! => particles are tagged on the location of the switch + ! Update dt in order to create "chock" without broke the stability condition + dt = 0.8*d_sc(direction)/sqrt(2*1.2*bl_size) + cfl = dt/d_sc(direction) + good_type = 0 + good_tag = 0 + p_V = shift_bis/cfl + ind_tag_bl = (nb_proc_dim(direction)*bl_number(direction)/3) - (bl_number(direction)*coord(direction)) + ind_tag_p = (ind_tag_bl-1)*bl_size + bl_size/2 + 1 + ind_tag_p2 = floor((0.3/0.8)*(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p) + ind_tag_p) + ind_tag_p2 = ind_tag_p2 + 1 + ind_tag_bl2 = (ind_tag_p2 - 1 - bl_size/2)/bl_size + 1 + if (modulo(ind_tag_p2-1-bl_size/2, bl_size)==0) ind_tag_bl2 = ind_tag_bl2 -1 + if (ind_tag_bl <=bl_number(direction)) then + if (ind_tag_bl>=1) then + ! Tag the right block transition + good_tag(ind_tag_bl) = 1 + else + ! Change the velocity for the first half block + lambda_min = max(0,shift_bis) + 10 + do ind = 1, bl_size/2 + p_V(ind) = shift_bis/cfl + p_V(ind) = p_V(ind) + 0.8*(1.0-float(ind-ind_tag_p)/(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind+1<ind_tag_p2) good_type(1) = 1 + end if + ! Update velocity and block type + do ind_bl = max(2, ind_tag_bl+1), bl_number(direction) + lambda_min = max(0,shift_bis) + 10 + do ind = 1, bl_size + ind2 = ind+((ind_bl-2)*bl_size)+bl_size/2 ! the first block is only a half block + p_V(ind2) = shift_bis/cfl + p_V(ind2) = p_V(ind2)+0.8*(1.-float(ind2-ind_tag_p)/(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind2+1<ind_tag_p2) good_type(ind_bl) = 1 + end do + ! For the last half block + lambda_min = max(0,shift_bis) + 10 + ind_bl = bl_number(direction) + 1 + do ind = 1, bl_size/2 + ind2 = ind+((ind_bl-2)*bl_size)+bl_size/2 ! the first block is only a half block + p_V(ind2) = shift_bis/cfl + p_V(ind2) = p_V(ind2)+0.8*(1.-float(ind2-ind_tag_p)/(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind2+bl_size/2+1<ind_tag_p2) good_type(ind_bl) = 1 + end if + if ((ind_tag_bl2 <= bl_number(direction)).and.(ind_tag_bl2>0)) good_tag(ind_tag_bl2) = 1 + call AC_type_and_block(dt, direction, comm_table(direction), (/1,1/), p_V, & + & bl_type, bl_tag) + +! == Pour debugger sur 1 processus == +!print*, 'ind_tag_p2 = ', ind_tag_p2 +!print*, 'V(ind_tag_p2) = ', p_V(ind_tag_p2)*cfl +!print*, 'ind_tag_bl2 = ', ind_tag_bl2 +!do ind = 0, 9 +!print*, ' V de ', ind*10+1, ' a ', (ind+1)*10 +!print*, p_V(ind*10+1:(ind+1)*10)*cfl +!print*, 'tag associé :' +!print*, bl_tag(ind*5+1:(ind+1)*5) +!print*, 'tag prevu :' +!print*, good_tag(ind*5+1:(ind+1)*5) +!print*, 'type associé :' +!print*, bl_type(ind*5+1:(ind+1)*5+1) +!print*, 'type prevu :' +!print*, good_type(ind*5+1:(ind+1)*5+1) +!end do +! == Pour debugger en parallele == +if (maxval(abs(bl_type-good_type))>0) then +print*, 'myrank = ', myrank +print*, 'p_V = ', p_V*cfl +print*, 'type associé :' +print*, bl_type +print*, 'type prevu :' +print*, good_type +end if + + call test_check_success(bl_tag, good_tag, success) + call test_substatus('test 3 - one tag ', success, myrank) + call test_check_success(bl_type, good_type, success) + call test_substatus('test 3 - center at first, then left', success, myrank) + call MPI_barrier(MPI_COMM_WORLD, ierr) + + + deallocate(good_type) + deallocate(good_tag) + deallocate(bl_type) + deallocate(bl_tag) + deallocate(p_V) +! end do + + success = .not. success + +end function test_part_AC_type_and_block_O2 + + +! ===== Private procedure ===== + + +!> Particles method: interpolate the velocity on all the 3D domain +!! @param[in] dt = time step +!! @param[in] direction = 1 for along X, 2 for along Y, 3 for along Z +!! @param[in] comm = mpi communcator associated to direction +!! @param[in] p_pos = particle position +!! @param[in] velo = velocity field +!! @param[out] num_velo = numerical interpolation of the velocity field +!! @details +!! The function AC_particle_velocity interpolate the velocity on a 1D line +!! (along X, Y or Z-axis). In order to test it on all direction and on 3D +!! cases, this subroutine call this interpolation on each line of the domain. +subroutine aux_com_interpol(dt, direction, comm, p_pos, velo, num_velo) + + ! Scales code + use advec_common + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + real(WP), intent(in) :: dt ! time step + integer, intent(in) :: direction, comm + real(WP), dimension(N_proc(direction)), intent(in) :: p_pos ! location where the velocity is interpolated + real(WP), dimension(:,:,:), intent(in) :: velo ! velocity field + real(WP), dimension(N_proc(1), N_proc(2), N_proc(3)), intent(out) :: num_velo ! numerical interpolation of velocity field + + integer :: i,j,k,ind ! indice + real(WP), dimension(N_proc(direction)) :: p_V ! particles velocity (interpolation of velo in location p_pos) + + select case(direction) + case(1) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do ind = 1, N_proc(1) + p_V(ind) = velo(ind, j, k) + end do + call AC_particle_velocity(dt, direction, comm, (/j, k/), p_pos, p_V) + do ind = 1, N_proc(1) + num_velo(ind,j,k)= p_V(ind) + end do + end do + end do + case(2) + do k = 1, N_proc(3) + do i = 1, N_proc(1) + do ind = 1, N_proc(2) + p_V(ind) = velo(i, ind, k) + end do + call AC_particle_velocity(dt, direction, comm, (/i, k/), p_pos, p_V) + do ind = 1, N_proc(2) + num_velo(i, ind,k)= p_V(ind) + end do + end do + end do + case(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + do ind = 1, N_proc(2) + p_V(ind) = velo(i, j, ind) + end do + call AC_particle_velocity(dt, direction, comm, (/i, k/), p_pos, p_V) + do ind = 1, N_proc(2) + num_velo(i, j, ind)= p_V(ind) + end do + end do + end do + end select + +end subroutine aux_com_interpol + +end module advec_aux_common diff --git a/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_init.f90 b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_init.f90 new file mode 100644 index 000000000..77362d68f --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_advec/advec_aux_init.f90 @@ -0,0 +1,417 @@ +!------------------------------------------------------------------------------ +! +! MODULE: test_advection_init +! +! DESCRIPTION: +!> Initialisation procedure for advection test (and solver based on particle method). +!! +!! @details +!! This module provide different initialisation setup in order to test the transport solver. +!! +!! The following initialisation are included : +!! 1 -> Constant field for both scalar and velocity +!! 2 -> 2D-rotation of a sphere +!! 3 -> scalar(i,j,k) = i/Nx + 10* j/Ny + 100*k/Nz with periodic boundary condition +!! 4 -> velocity(i,j,k) = i/Nx + 10* j/Ny + 100*k/Nz with periodic boundary condition +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module advec_aux_init + + use string + use precision + implicit none + + ! ===== Initialisation for advection test ===== + ! Public function + public :: velo_init + public :: scal_init + public :: scal_velo_init_part + ! Private function + private :: compute_velo_tag + + ! ===== Setup parameter ===== + ! Public variables + !> Period for rotation cases + real(WP), public :: period = 1 + ! Private variable + !> Pi value + real(WP), private :: M_PI = ACOS(0.0) + + + + +contains + +!> Initialisation of the scalar field for the different tests. +!! @param[in] init = parameter to initialise the scalar fied to a constant one or to a sphere shape +!! @param[in] translat = optional argument, translat the field, in order to obtain analytic solution for non zero velocity in test case +!! "translation field" +!! @param[out] scalar = scalar field +!! @param[out] good_scal = analytic solution +subroutine scal_init(init, scalar, good_scal, translat) + + use test_common + use cart_topology + + character(len=*), intent(in) :: init + real(WP), dimension(:,:,:), intent(out) :: scalar + real(WP), dimension(:,:,:), intent(out) :: good_scal + real(WP), dimension(3), intent(in), optional :: translat + + real(WP) :: rr, rx, ry, rz, shift, rayon + real(WP) :: dist + integer :: i, j, k + integer :: ierr ! mpi error code + + + select case(init) + case('constant') + call test_substatus('constant scal', myrank) + scalar = 1. + good_scal = 1. + case('turning_sphere') + scalar = 0. + rayon = (minval(N*d_sc)/10.0)**2 + do k = 1, N_proc(3) + rz = (k + coordYZ(3-1)+1- 3.0*N(3)/5.0)**2 + do j = 1, N_proc(2) + ry = (j + coordYZ(2-1)+1- 3.0*N(2)/5.0)**2 + do i = 1, N_proc(1) + rx = (d_sc(1)*(i - 3.0*N(1)/5.0))**2 + rr = rx + ry + rz + if (rr> rayon) scalar(i,j,k) = 1 - rr/rayon + end do + end do + end do + good_scal = scalar + case('translation_field') +! XXX / Todo : la solution n'est pas périodique !! Pomper ce qui a été fait dans +! velo_init, car là c'est bien périodique. +! / XXX + call test_substatus('translation field', myrank) + if (present(translat)) then + call test_substatus('translation on X', translat(1), myrank) + call test_substatus('translation on Y', translat(2), myrank) + call test_substatus('translation on Z', translat(3), myrank) + else + call test_substatus('velocity = zero ', myrank) + end if + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + scalar(i,j,k) = (float(i-1+coord(1)*N_proc(1))/N(1)) + scalar(i,j,k) = scalar(i,j,k) + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) + scalar(i,j,k) = scalar(i,j,k) + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (present(translat)) then + ! Only periodic condition + dist = (i+translat(1)-1+coord(1)*N_proc(1))*d_sc(1) ! distance au bord x = 0 + dist = modulo(dist, length(1)) ! on utilise la periodicite + ! If dist belong to (length - dx, length) then with have to interpolate + ! the velocity between postion (length-dx) and 0 (due to periodicity boundary condition) + if (dist>length(1)-d_sc(1)) dist = (length(1)-dist)*(length(1)-d_sc(1))/d_sc(1) + ! In other case, as the velocity is a linear function of the position, the analytic velocity + ! is the same that the interpolate one + good_scal(i,j,k) = dist/length(1) + dist = (j+translat(2)-1+coord(2)*N_proc(2))*d_sc(2) + dist = modulo(dist, length(2)) + if (dist>length(2)-d_sc(2)) dist = (length(2)-dist)*(length(2)-d_sc(2))/d_sc(2) + good_scal(i,j,k) = good_scal(i,j,k) + 10*(dist)/length(2) + dist = (k+translat(3)-1+coord(3)*N_proc(3))*d_sc(3) + dist = modulo(dist, length(3)) + ! See direction 1 for explaination + if (dist>length(3)-d_sc(3)) dist = (length(3)-dist)*(length(3)-d_sc(3))/d_sc(3) + good_scal(i,j,k) = good_scal(i,j,k) + 100*(dist)/length(3) + else + good_scal(i,j,k) = scalar(i,j,k) + end if + end do + end do + end do + case default + scalar = 1. + good_scal = 1. + end select + +end subroutine scal_init + + + +!> Initialisation of the velocity field to test its interpolation +!! @param[in] init = parameter to initialise the scalar fied to a constant one or to a sphere shape +!! @param[out] velo = velocity field along one direction +!! @param[in] direction = current direction (along X,Y or Z-axis) +!! @param[in] p_pos_adim = adimensionned particles postion (location where the velocity will be interpolated) +!! @param[in,out] good_velo = analytic interpolation of the velocity field (on location p_pos) +subroutine velo_init(init, velo, direction, p_pos_adim, good_velo) + + use test_common + use cart_topology + + character(len=*), intent(in) :: init + real(WP), dimension(:,:,:), intent(inout) :: velo + real(WP), dimension(:), intent(in) :: p_pos_adim + integer, intent(in) :: direction + real(WP), dimension(:,:,:), intent(inout) :: good_velo + + integer :: i, j, k ! mesh indices + integer :: ierr ! mpi error code + real(WP) :: dist ! distance from boundary + + + select case(init) + case('constant') + velo = 1. + good_velo = 1. + case('2D_rot') + select case(direction) + case(1) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=(M_PI/period)*(N(2)/2.0-(j+coord(2)))*d_sc(2); + good_velo(i,j,k)=(M_PI/period)*(N(2)/2.0-j-0.5)*d_sc(2); + end do + end do + end do + case(2) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=(M_PI/period)*((i+coord(1)) - N(1)/2.0)*d_sc(1); + good_velo(i,j,k)=(M_PI/period)*((i+coord(1)) - N(1)/2.0)*d_sc(1); + end do + end do + end do + case(3) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=0 + good_velo(i,j,k)=0 + end do + end do + end do + case default + call test_substatus(' XXX error : wrong direction =', direction, myrank) + stop + end select + case('translation_field') + select case(direction) + case(1) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(1) .eqv. .true.) then + dist = (p_pos_adim(i)-1+coord(1)*N_proc(1))*d_sc(1) ! distance au bord x = 0 + dist = modulo(dist, length(1)) ! on utilise la periodicite + ! If dist belong to (length - dx, length) then with have to interpolate + ! the velocity between postion (length-dx) and 0 (due to periodicity boundary condition) + if (dist>length(1)-d_sc(1)) dist = (length(1)-dist)*(length(1)-d_sc(1))/d_sc(1) + ! In other case, as the velocity is a linear function of the position, the analytic velocity + ! is the same that the interpolate one + good_velo(i,j,k) = dist/length(1) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + else + call test_substatus(' boundary along X condition not implemented ', myrank) + end if + end do + end do + end do + case(2) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(2) .eqv. .true.) then + dist = (p_pos_adim(j)-1+coord(2)*N_proc(2))*d_sc(2) + dist = modulo(dist, length(2)) + ! See direction 1 for explaination + if (dist>length(2)-d_sc(2)) dist = (length(2)-dist)*(length(2)-d_sc(2))/d_sc(2) + good_velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(dist)/length(2) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + else + call test_substatus(' boundary along X condition not implemented ', myrank) + end if + end do + end do + end do + case(3) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(3) .eqv. .true.) then + dist = (p_pos_adim(k)-1+coord(3)*N_proc(3))*d_sc(3) + dist = modulo(dist, length(3)) + ! See direction 1 for explaination + if (dist>length(3)-d_sc(3)) dist = (length(3)-dist)*(length(3)-d_sc(3))/d_sc(3) + good_velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*dist/length(3) + else + call test_substatus(' boundary along X condition not implemented ', myrank) + end if + end do + end do + end do + case default + call test_substatus(' XXX error : wrong direction =', direction, myrank) + stop + end select + case default + velo = 1. + good_velo = 1. + end select + + +end subroutine velo_init + +!> Initialisation of the velocity field to test its interpolation +!! @param[in] init = parameter used to choose between the different setup +!! @param[in,out] dt = time step (used to compute solution) +!! @param[in] shift = global translation of indices (optional) +!! @param[out] scalar3D = scalar field +!! @param[out] velo = velocity field along one direction +!! @param[in] direction = current direction (along X,Y or Z-axis) +!! @param[out] good_scal = analytic solution of the advection problem +subroutine scal_velo_init_part(init, dt, shift, scal3D, velo, direction, good_scal) + + ! Scales code + use cart_topology + use advec_common + ! Test procedures + use test_common + + character(len=*), intent(in) :: init + real(WP), intent(inout) :: dt + integer, intent(in) :: shift + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: velo + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: scal3D + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: good_scal + integer, intent(in) :: direction + + integer :: i, j, k ! mesh indices + integer :: ierr ! mpi error code + real(WP) :: cfl ! ratio between time and space steps + real(WP) :: t ! some time indication + real(WP) :: dt_bis ! time step used to compute trajectories + ! with a numerical integration + real(WP) :: sX, sY, sZ ! some temp variable + real(WP), dimension(3) :: vect_dir ! some temp variable + + + cfl = dt/d_sc(direction) + + + ! -- Initialize velocity and compute some trajectories -- + select case(init) + case('left') + ! -- Test case 1 : only left block, no tag -- + velo = (shift+0.3)/cfl + velo = d_sc(direction)/dt + scal3D = -dt*velo + call test_substatus('particle- no tag, only left block', myrank) + + case('tag') + ! Update dt in order to create "chock" without broke the stability condition + dt = 0.8*d_sc(direction)/sqrt(2*1.2*bl_size) + cfl = dt/d_sc(direction) + ! Compute trajectories + scal3D = 0.0 + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = compute_velo_tag(dble(j), shift, cfl, direction) + dt_bis = min(0.01, dt/10) + t = 0 + do while(t <= dt-dt_bis) + scal3D(i,j,k) = scal3D(i,j,k) & + &- dt_bis*compute_velo_tag(j+scal3D(i,j,k), shift, cfl, direction)/d_sc(direction) + t = t + dt_bis + end do + dt_bis = dt - t + scal3D(i,j,k) = scal3D(i,j,k) & + &- dt_bis*compute_velo_tag(j+scal3D(i,j,k), shift, cfl, direction)/d_sc(direction) + end do + end do + end do + call test_substatus('particle- 2 tag, left and center', myrank) + + case default ! default = 'center' + ! Test case 2 : only center block, no tag + velo = (shift+0.8)/cfl + velo = d_sc(direction)/dt + scal3D = -dt*velo + call test_substatus('particle- no tag, only center block', myrank) + end select + + ! -- Compute solution of the advection problem + vect_dir = 0 + vect_dir(direction) = 1 + do k = 1, N_proc(3) + sZ = (k-1+(coord(3)*N_proc(3)))*d_sc(3) + do j = 1, N_proc(2) + sY = (j-1+(coord(2)*N_proc(2)))*d_sc(2) + do i = 1, N_proc(1) + sX = (i-1+(coord(1)*N_proc(1)))*d_sc(1) + good_scal(i,j,k) = cos(3*2*M_PI*(sZ+vect_dir(3)*scal3D(i,j,k))/length(3)) + good_scal(i,j,k) = good_scal(i,j,k)*cos(2*2*M_PI*(sY+vect_dir(2)*scal3D(i,j,k))/length(2)) + good_scal(i,j,k) = good_scal(i,j,k)*cos(2*M_PI*(sX+vect_dir(1)*scal3D(i,j,k))/length(1)) + scal3D(i,j,k) = cos(3*2*M_PI*sZ/length(3)) + scal3D(i,j,k) = scal3D(i,j,k)*cos(2*2*M_PI*sY/length(2)) + scal3D(i,j,k) = scal3D(i,j,k)*cos(2*M_PI*sX/length(1)) + end do + end do + end do + +end subroutine scal_velo_init_part + +!> Compute a velocity field wich produce 2 tagged block during an advection step +!! with the solver based on particle method +!! @param[in] pos = relative position along current direction +!! @param[in] shift = shift (in number of mesh) +!! @param[in] cfl = time step/space step +!! @param[in] direction = current direction +!! @return res = velocity field +function compute_velo_tag(pos, shift, cfl, direction) result(res) + + ! Topology + use cart_topology + ! Solver information + use advec_common + ! Test tools + use test_common + + real(WP), intent(in) :: pos, cfl + integer, intent(in) :: shift, direction + real(WP) :: res + real(WP) :: pos_abs ! absolute position (i,j,k are relative position in the current processus) + integer :: ind_tag_bl, ind_tag_p + + ind_tag_bl = (nb_proc_dim(direction)*(N(direction)/bl_size)/3)! - (bl_number(direction)*coord(direction)) + ind_tag_p = (ind_tag_bl-1)*bl_size + bl_size/2 + 1 + + pos_abs = pos + coord(direction)*N_proc(direction) + + res = shift/cfl + if ((pos_abs >= ind_tag_p).and.(pos_abs < N(direction))) then + res = res + 0.8*(1.0-(pos_abs-ind_tag_p)/(N(direction)-ind_tag_p))/cfl + end if + +end function compute_velo_tag + +end module advec_aux_init diff --git a/CodesEnVrac/LEGI/test/src/Test_advec/advec_main.f90 b/CodesEnVrac/LEGI/test/src/Test_advec/advec_main.f90 new file mode 100644 index 000000000..c7f69bf8d --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_advec/advec_main.f90 @@ -0,0 +1,146 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : advec_main +! +! DESCRIPTION: +!> This program use the function implemented in the module advec_aux to +!! test the advection solver. +!! +!! @details +!! All these test are unit test : they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular +!! solver +!! The following test are included : +!! 1 -> advec a ball with a constant velocity +!! 2 -> advec a ball with a spheric velocity field (the ball turns) +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program advec_main + + ! External Library + use mpi + ! Scales code + use cart_topology + ! Test procedures + use test_common + use advec_aux + use advec_aux_common + + implicit none + + logical :: error = .false. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc ! number of processus + integer :: i ! some boucle indice + + ! ===== Initialisation ===== + + ! Set the verbosity + verbose_test = .true. + verbose_more = .false. + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + if (mod(100, nb_proc)/=0) then + stop 'wrong number of processes : it have to divide 100' + end if + call cart_create((/ nb_proc, 1 /), ierr) + call mesh_default() + call mpi_barrier(MPI_COMM_WORLD, ierr) + + + ! ===== Test about procedures involved in remeshing process ===== + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('particle method - remeshing', rank_world) + + ! Does it well compute who communicate with who during remeshing ? + error = test_part_AC_obtain_senders() + call test_status(error, 'obtain_senders sans shift', rank_world) + error = test_part_AC_obtain_senders(1) + call test_status(error, 'obtain_senders avec shift', rank_world) + error = test_part_AC_obtain_senders(3*nb_proc_dim(2)+2) + call test_status(error, 'obtain_senders avec large shift', rank_world) + +verbose_more = .true. + if (nb_proc_dim(2)>1) then + ! The remeshing are done in a buffer. Is it well re-distribuate on processes ? + do i = 0, min(4, nb_proc-1) + error = test_part_AC_bufferToScalar_Deb(i) + call test_status(error, 'bufferToScalar deb, no shift, rank =', i, rank_world) + error = test_part_AC_bufferToScalar_Deb(i,1) + call test_status(error, 'bufferToScalar deb,shift; rank =', i, rank_world) + end do + error = test_part_AC_bufferToScalar() + call test_status(error, 'bufferToScalar sans shift', rank_world) + error = test_part_AC_bufferToScalar(1) + call test_status(error, 'bufferToScalar avec shift', rank_world) + error = test_part_AC_bufferToScalar(3*nb_proc_dim(2)+2) + call test_status(error, 'bufferToScalar avec large shift', rank_world) + + ! Test remeshing of untagged particles + error = test_part_remesh_no_tag() + call test_status(error, 'remeshing of cst field advected a cst v', rank_world) + + error = test_part_remesh_no_tag('translation_field') + call test_status(error, 'remeshing of uncst field advected a cst v', rank_world) + else + call test_status(error, 'only one proc along Y, no test on remesh', rank_world) + end if +verbose_more = .false. + + ! ===== Test about procedures involved in computation of particles advection ===== + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('particle method - particle advection', rank_world) + + ! Test auxiliary procedures + error = test_part_AC_obtain_recevers() + call test_status(error, 'AC_obtain_recevers', rank_world) + + + ! Test velocity interpolation + error = test_part_AC_interpol_velocity(2, Y_comm, 0) + call test_status(error, 'velocity interpolation along Y, no shift', rank_world) + error = test_part_AC_interpol_velocity(2, Y_comm, 1) + call test_status(error, 'velocity interpolation along Y, shift', rank_world) + + ! ===== Test others ===== + call test_title('particle method - tag and bloc type', rank_world) + call mpi_barrier(MPI_COMM_WORLD, ierr) + error = test_part_AC_type_and_block_O2() + call test_status(error, 'determine block type and tag particles', rank_world) + + ! ===== Test solvers ===== + + ! Test devoted to solver based on particles method + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('particle method - advection test', rank_world) + error = test_part_advecO2('left') + call test_status(error, 'advection - left block, no tag', rank_world) + error = test_part_advecO2() + call test_status(error, 'advection - center block, no tag', rank_world) + + ! Generic test + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('generic advection test - V=constant', rank_world) + error = test_advecY() + call test_status(error, 'advection of a constant field', rank_world) + error = test_advecY('translation_field') + call test_status(error, 'translation of a unconstant field', rank_world) + + call mpi_finalize(ierr) + +end program advec_main + diff --git a/CodesEnVrac/LEGI/test/src/Test_topo/topo_aux.f90 b/CodesEnVrac/LEGI/test/src/Test_topo/topo_aux.f90 new file mode 100644 index 000000000..02fe7ae93 --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_topo/topo_aux.f90 @@ -0,0 +1,277 @@ +!------------------------------------------------------------------------------ +! +! MODULE: topo_aux +! +! DESCRIPTION: +!> This module provides different tests to validate the topology and the +!! interface with the different data structures. +!! +!! @details +!! Different automatic test are developped in order to check the mesh creation +!! and the interface between the two data structures (the one used for the +!! particular method and the one from the spectral part). +!! All these test are unit test : they return a logical value to check if +!! the ierr version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! +!! The following test are included : +!! 1 -> Initialise the topology, check the number of processes and +!! the communicators. +!! 2 -> Check the periodicity. +!! 3 -> Check if the subgrid on each processus have the good size +!! n -> (XXX todo) Test the interface between the data structure in the advection +!! solver based on particular method and the one used in the rest of the +! ierr. +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module topo_aux + + use mpi + use cart_topology + use string + use precision + implicit none + + real(WP), private :: epsilon_success = 1e-4 ! Error tolerance + + + ! Public procedures + + ! ===== Test the topology ===== + ! Public function + public :: test_topo_init + public :: test_topo_perio + public :: test_topo_submesh + + + + +contains + +!> Test the topology initialisation +!! @return success = logical success (= false if the ierr pass the test) +!! @details +!! Test the cartesian topology : check the number of processes and the +!! communicators. +function test_topo_init() result(success) + + use test_common + + logical :: success ! success status + + integer :: ierr ! mpi success ierr + integer :: nb_proc ! total number of processus + integer :: nb_Y, nb_Z ! actual number of processus in each direction + integer, dimension(2) :: dims ! wanted number of processus in Y and Z direction + + success = .true. + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + dims = (/ nb_proc, 1 /) + call cart_create(dims, ierr) + + ! Check the number of process in each communicator + call mpi_comm_size(Y_comm, nb_Y, ierr) + if (nb_Y /= nb_proc) then + call test_substatus('number of processes in Y_comm', nb_Y, myrank) + call test_substatus('and it must be', nb_proc, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + + call mpi_comm_size(Z_comm, nb_Z, ierr) + if (nb_Z /= 1) then + call test_substatus('number of processes in Z_comm', nb_Z, myrank) + call test_substatus('and it must be', 1, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! Compare it with the one saved in cart_topo + if (nb_Y /= nb_proc_dim(2)) then + call test_substatus('number of processes in Y_comm', nb_Y, myrank) + call test_substatus('and the solver beleave it is', nb_proc_dim(2), myrank) + success = .false. + end if + if (nb_Z /= nb_proc_dim(3)) then + call test_substatus('number of processes in Y_comm', nb_Z, myrank) + call test_substatus('and the solver beleave it is', nb_proc_dim(3), myrank) + success = .false. + end if + + ! Return error = not succes + success = .not. success + +end function test_topo_init + +!> Check if it provide the right cartesian structure with a good periodicity +!! @return success = logical success (= false if the ierr pass the test) +function test_topo_perio() result(success) + + use test_common + + logical :: success ! success status + + integer :: ierr ! mpi success ierr + integer :: rankP, rankN ! rank of previous and next (for shift) + integer :: nb_Y, nb_Z ! number of processus in each direction + integer, dimension(2) :: dims ! number of processus in Y and Z direction + integer, dimension(3) :: coord_bis ! coordonate of another processus + integer :: new_coord ! theoritical coordinate + + success = .true. + + ! Get the size + call mpi_comm_size(Y_comm, nb_Y, ierr) + call mpi_comm_size(Z_comm, nb_Z, ierr) + + ! Shift along Y + ! Positive shift + call mpi_cart_shift(cart_comm, 2-1, 1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y-1 on rank', myrank, printer) + call test_substatus('theoritical Y-1', new_coord, printer) + call test_substatus('computed Y-1', coord_bis(2), printer) +call test_substatus('X', coord_bis(1), printer) +call test_substatus('Z', coord_bis(3), printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+1 on rank', myrank, printer) + success = .false. + end if + ! Negative shift + call mpi_cart_shift(cart_comm, 2-1, -1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y-(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('topo and periodicity along Y', success, myrank) + + ! Shift along Z + ! Positive shift + call mpi_cart_shift(cart_comm, 3-1, 1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(3)-1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z-1 on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(3)+1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z+1 on rank', myrank, printer) + success = .false. + end if + ! Negative shift + call mpi_cart_shift(cart_comm, 3-1, -1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(3)-1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z+(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(3)+1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z-(-1)) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('topo and periodicity along Z', success, myrank) + + ! Big shift + call mpi_cart_coords(cart_comm, myrank, 3, coord, ierr) + call mpi_cart_shift(cart_comm, 2-1, 1+2*Nb_Y, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y- on rank', myrank, printer) + call test_substatus('theoritical Y-', new_coord, printer) + call test_substatus('computed Y-', coord_bis(2), printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+ on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('huge shift along Y', success, myrank) + + ! Return error = not success + success = .not.success + +end function test_topo_perio + + +!> Test the construction of subdomain and the mesh size in each processus +!! @return success = logical success (= false if the ierr pass the test) +!! @details +!! Check if the subgrid on each processus have the good size +function test_topo_submesh() result(success) + + use test_common + + logical :: success + integer :: ierr ! mpi success code + + success = .true. + + call mesh_default() + + ! Check the number of mesh + if (N_proc(1)/= 100) then + call test_substatus('local number of mesh along X', N_proc(1), myrank) + success = .false. + end if + if (N_proc(2)/= 100/nb_proc_dim(2)) then + call test_substatus('local number of mesh along Y', N_proc(2), myrank) + success = .false. + end if + if (N_proc(3)/= 100/nb_proc_dim(3)) then + call test_substatus('local number of mesh along Z', N_proc(3), myrank) + success = .false. + end if + + ! Return error = not success + success = .not.success + + call mpi_barrier(MPI_COMM_WORLD, ierr) + +end function test_topo_submesh + + +end module topo_aux diff --git a/CodesEnVrac/LEGI/test/src/Test_topo/topo_main.f90 b/CodesEnVrac/LEGI/test/src/Test_topo/topo_main.f90 new file mode 100644 index 000000000..b7d2dd849 --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/Test_topo/topo_main.f90 @@ -0,0 +1,59 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : topo_main +! +! DESCRIPTION: +!> Test the cartesian topology and all the associated variable. +!! test the advection solver. +!! This program perform all the test include in "topo_aux". This module provide +!! unit test, ie logical function wich return a logical error. +!! There is a verbosity parameter to decide to print on screen the status of +!! result of each test (and sub-test) or not. +!! +!! See topo_aux for a list of available test. +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program topo_main + + use mpi + use topo_aux + use test_common + + implicit none + + logical :: error = .true. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc ! number of processus + + ! Set the verbosity + verbose_test = .true. + verbose_more = .true. + + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_test_substatus(ierr, error, 'mpi initialization', rank_world) + + ! Initialize the topology and test is + error=test_topo_init() + call test_status(error, '(mpi) topology initialisation', rank_world) + + ! Initialize the topology and test is + error=test_topo_perio() + call test_status(error, 'periodicity', rank_world) + + ! Initialize the topology and test is + error=test_topo_submesh() + call test_status(error, 'subdomain size', rank_world) + + call mpi_finalize(ierr) + +end program topo_main + diff --git a/CodesEnVrac/LEGI/test/src/test_common.f90 b/CodesEnVrac/LEGI/test/src/test_common.f90 new file mode 100644 index 000000000..fa159b5cc --- /dev/null +++ b/CodesEnVrac/LEGI/test/src/test_common.f90 @@ -0,0 +1,411 @@ +!------------------------------------------------------------------------------ +! +! MODULE: test_advection +! +! DESCRIPTION: +!> This module provide different tools useful to perform test. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module test_common + + use string + use precision + + implicit none + + ! ===== Public variables ===== + !> To print some status message during the test + logical :: verbose_test = .true. + !> More verbosity ! + logical :: verbose_more = .true. + !> To choose wich processes lead the screen output + integer :: printer = 0 + + ! ===== Public procedure ===== + ! - To print some information about the test (verbosity case) + public :: test_title + public :: test_status + public :: mpi_test_substatus + public :: test_substatus + + + ! ===== Private variables ===== + !> Error tolerance + real(WP), private :: epsilon_success = 1e-4 + + ! ===== Interface ===== + interface test_status + module procedure test_status_M, test_status_MI + end interface test_status + + interface test_substatus + module procedure test_substatus_M, test_substatus_MI, test_substatus_MR & + & , test_substatus_ML, test_substatus_M3I + end interface test_substatus + + interface test_check_success + module procedure test_check_success_S, test_check_success_F, & + & test_check_success_F2, test_check_success_F3, test_check_success_FI + end interface test_check_success + + + +contains + +!> Diffuse the error status and print the test status +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_title(message, rank) + + use cart_topology + + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + character(len=40) :: mess_bis ! message copy + + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(A1,1X,A40)')'#', mess_bis + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_title + + +!> Diffuse the error status and print the test status +!! @param[in, out] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_status_M(error, message, rank) + + use mpi + use cart_topology + + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + character(len=40) :: mess_bis ! message copy + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(error .eqv. .true.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) error=.true. + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(5X,A2,2X,A40,X,A2,L2)')'->', mess_bis, '=', .not.error + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_status_M + + +!> Diffuse the error status and print the test status +!! @param[in, out] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] message_int = integer added to the information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_status_MI(error, message, message_int , rank) + + use mpi + use cart_topology + + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank, message_int + + character(len=37) :: mess_bis ! message copy + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(error .eqv. .true.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) error=.true. + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(5X,A2,2X,A37,X,I2,X,A2,L2)')'->', mess_bis, message_int, '=', .not.error + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_status_MI + + +!> Use a mpi error code to update the test status and print it +!! @param[in] ierr = mpi error code +!! @param[in] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine mpi_test_substatus(ierr, error, message, rank) + + use mpi + + integer, intent(in) :: ierr + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + if (ierr /= MPI_SUCCESS) then + error = .false. + end if + + call test_substatus(message, error, rank) + error = .not. error + +end subroutine mpi_test_substatus + +!> Print a sub-status message +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_M(message, rank) + + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40)')'+', message + end if + +end subroutine test_substatus_M + + +!> Print a sub-status message and a integer +!! @param[in] message = information message +!! @param[in] i = integer to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_MI(message, i, rank) + + character(len =*), intent(in) :: message + integer, intent(in) :: i + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,I5)')'+', message, '=', i + end if + +end subroutine test_substatus_MI + + +!> Print a sub-status message and a integer +!! @param[in] message = information message +!! @param[in] i = integer table of dimension 3 to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_M3I(message, i, rank) + + character(len =*), intent(in) :: message + integer, dimension(3), intent(in) :: i + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,I3,X,A1,X,I3,X,A1,X,I3)')'+',message,'=',i(1),',',i(2),',',i(3) + end if + +end subroutine test_substatus_M3I + + +!> Print a sub-status message and a real +!! @param[in] message = information message +!! @param[in] r = real to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_MR(message, r, rank) + + use precision + + character(len=* ), intent(in) :: message + real(WP), intent(in) :: r + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,F8.4)')'+', message, '=', r + end if + +end subroutine test_substatus_MR + + +!> Print a sub-status message and a logical (after sending its value if false) +!! @param[in] message = information message +!! @param[in,out] l = logical to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_ML(message, l, rank) + + use precision + use mpi + use cart_topology + + character(len =*), intent(in) :: message + logical, intent(inout) :: l + integer, intent(in) :: rank + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(l .eqv. .false.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) l=.false. + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,L5)')'+', message, '=', l + end if + +end subroutine test_substatus_ML + + + +!> Check if the numerical success stay under a threshold - constant theoritical +!! solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +subroutine test_check_success_S(scal1D, good_scal, success) + + use precision + use cart_topology + + real(WP), intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + + integer :: success_inf ! norm L_inf of the success + + success_inf = maxval(scal1D - good_scal) + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', myrank) + call test_substatus('max scal0D', maxval(scal1D), myrank) + call test_substatus('min scal0D', minval(scal1D), myrank) + call test_substatus('and it must be', good_scal, myrank) + end if + +end subroutine test_check_success_S + + +!> Check if two integer 2-dimensionnal table are equal. +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +subroutine test_check_success_FI(scal1D, good_scal, success) + + use precision + use cart_topology + + integer, dimension(:),intent(in) :: good_scal ! theoritical value of scal1D + integer, dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + + integer :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal1D - good_scal)) + + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', myrank) + call test_substatus('max scal1D', maxval(scal1D), myrank) + call test_substatus('min scal1D', minval(scal1D), myrank) + call test_substatus('max solution', maxval(good_scal), myrank) + end if + +end subroutine test_check_success_FI + + +!> Check if the numerical success stay under a threshold - 1D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +subroutine test_check_success_F(scal1D, good_scal, success) + + use precision + use cart_topology + + real(WP), dimension(:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + + real(WP) :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal1D - good_scal)) + + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', myrank) + call test_substatus('max scal1D', maxval(scal1D), myrank) + call test_substatus('min scal1D', minval(scal1D), myrank) + call test_substatus('max solution', maxval(good_scal), myrank) + call test_substatus('min solution', minval(good_scal), myrank) + end if + +end subroutine test_check_success_F + + +!> Check if the numerical success stay under a threshold - 2D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal2D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +subroutine test_check_success_F2(scal2D, good_scal, success) + + use precision + use cart_topology + + real(WP), dimension(:,:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:,:),intent(in) :: scal2D ! the computed scalar field + logical, intent(inout) :: success + + real(WP) :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal2D - good_scal)) + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', myrank) + call test_substatus('max scal2D', maxval(scal2D), myrank) + call test_substatus('min scal2D', minval(scal2D), myrank) + call test_substatus('max solution', maxval(good_scal), myrank) + call test_substatus('min solution', minval(good_scal), myrank) + end if + +end subroutine test_check_success_F2 + + +!> Check if the numerical success stay under a threshold - 3D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal3D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +subroutine test_check_success_F3(scal3D, good_scal, success) + + use precision + use cart_topology + + real(WP), dimension(:,:,:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:,:,:),intent(in) :: scal3D ! the computed scalar field + logical, intent(inout) :: success + + real(WP) :: success_inf ! norm L_inf of the success + +integer, dimension(3) :: temp + + success_inf = maxval(abs(scal3D - good_scal)) + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', myrank) + temp = minloc(scal3D - good_scal) + call test_substatus('error min in', temp, myrank) + call test_substatus('scal3D', scal3D(temp(1), temp(2), temp(3)), myrank) + call test_substatus('sol', good_scal(temp(1), temp(2), temp(3)), myrank) + temp = maxloc(scal3D - good_scal) + call test_substatus('error max in', temp, myrank) + call test_substatus('scal3D', scal3D(temp(1), temp(2), temp(3)), myrank) + call test_substatus('sol', good_scal(temp(1), temp(2), temp(3)), myrank) + end if + +end subroutine test_check_success_F3 + + +end module test_common diff --git a/CodesEnVrac/NavierStokes3D-Penalization/CMake b/CodesEnVrac/NavierStokes3D-Penalization/CMake new file mode 120000 index 000000000..af160f912 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/CMake @@ -0,0 +1 @@ +../../CMake \ No newline at end of file diff --git a/CodesEnVrac/NavierStokes3D-Penalization/CMakeLists.txt b/CodesEnVrac/NavierStokes3D-Penalization/CMakeLists.txt new file mode 100644 index 000000000..29ae79e93 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/CMakeLists.txt @@ -0,0 +1,112 @@ +#======================================================= +# cmake utility to compile and install NavierStokes3D +# +# F. Pérignon, oct 2011 +# +#======================================================= + +# ============= Global cmake Settings ============= +# Set minimum version for cmake +cmake_minimum_required(VERSION 2.8) +# Set policy +cmake_policy(VERSION 2.8) +# Set cmake modules directory (i.e. the one which contains all user-defined FindXXX.cmake files among other things) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/CMake) +# Force out-of-source build +include(OutOfSourceBuild) +# Some usefull macros +include(MyTools) + +# ============= Specific settings ============= +# Here we set all variables +# required to compile and install the soft such as the name of +# the library to be created, the place where we can find the sources, +# the version number of the current package ... + +# User defined options +option(VERBOSE_MODE "enable verbose mode for cmake exec. Default = on" ON) + +# cmake project name +set(PROJECT_NAME NavierStokes3D) +# --- Name for the package --- +# This name will be used to install Parmes (library, headers, ...) and when another lib or soft will need to search for Parmes. +set(PACKAGE_NAME "NS3D") +# --- Set a version number for the package --- +set(${PACKAGE_NAME}_version 1.0.0) +# The list of all dirs containing sources to be compiled +# Any file in those dirs will be used to create our lib/exec +set(${PROJECT_NAME}_SRCDIRS + src + ) +# Matching expr for files to be compiled. +set(EXTS *.cxx *.f90 *.f95) +# Matching expr for headers +set(EXTS_HDRS *.hpp *.h) +# Note FP : we can also use cmake vars ${CMAKE_Fortran_SOURCE_FILE_EXTENSIONS} ${CMAKE_C_SOURCE_FILE_EXTENSIONS} ${CMAKE_CXX_SOURCE_FILE_EXTENSIONS} + +# ============= The project ============= +# Set project name and project languages +# => this automatically defines: +# - ${PROJECT_NAME}_BINARY_DIR : where you have run cmake, i.e. the place for compilation +# - ${PROJECT_NAME}_SOURCE_DIR : where sources (.f and .h and this CMakeLists.txt) are located +# Note that because of OutOfSourceBuild, binary_dir and source_dir must be different. +project(${PROJECT_NAME} Fortran) + +# ============= Prepare compilation ============= +# Force a default build type if not provided by user +# CMAKE_BUILD_TYPE = empty, Debug, Release, RelWithDebInfo or MinSizeRel. +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE RELEASE CACHE STRING "Choose the type of build, options are: None, Debug, Release, RelWithDebInfo or MinSizeRel." FORCE) +endif (NOT CMAKE_BUILD_TYPE) + +# If the project uses Fortran ... +# Set module files directory (i.e. where .mod will be created) +set(CMAKE_Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/Modules) +# To add compilation flags: +# append_Fortran_FLAGS("-Wall") + +# ============= Source and header files list ============= +# We scan all files with matching extension in directories +# containing sources. +# Source and header files list: +foreach(_DIR ${${PROJECT_NAME}_SRCDIRS}) + set(_DIR_FILES) + foreach(_EXT ${EXTS}) # Source files + file(GLOB _DIR_FILES_EXT ${_DIR}/${_EXT}) + if(_DIR_FILES_EXT) + list(APPEND ${PROJECT_NAME}_SRC ${_DIR_FILES_EXT}) + endif() + endforeach() +endforeach() + +# Add directories to those searched by compiler ... +# -I +include_directories(${${PROJECT_NAME}_SRCDIRS}) +include_directories(${CMAKE_Fortran_MODULE_DIRECTORY}) + +add_executable(${PROJECT_NAME} ${${PROJECT_NAME}_SRC}) +# Libs to link with PROJECT__NAME +target_link_libraries(${PROJECT_NAME} ${LIBS}) + +# ============= RPATH ============= +# Concerning rpath see for example http://www.itk.org/Wiki/CMake_RPATH_handling + +# -------------------------------------------- +# do not skip the full RPATH for the build tree +set(CMAKE_SKIP_BUILD_RPATH FALSE) +# when building, don't use the install RPATH already +# (but later on when installing) +set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +# the RPATH to be used when installing +set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +# ============= Summary ============= +if(VERBOSE_MODE) + message(STATUS "====================== Summary ======================") + message(STATUS " Compiler : ${CMAKE_Fortran_COMPILER}") + message(STATUS " Sources are in : ${CMAKE_SOURCE_DIR}") + message(STATUS "====================== ======= ======================") +endif() diff --git a/CodesEnVrac/NavierStokes3D-Penalization/examples/parameter b/CodesEnVrac/NavierStokes3D-Penalization/examples/parameter new file mode 100644 index 000000000..a43c24577 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/examples/parameter @@ -0,0 +1,12 @@ +-2.06441 2.06441 -3. 3. -2.06441 2.06441 ! xg xd yb yh zd zf +33 33 33 !33 65 129 257!nx ny nz +30. ! TFin +1.D-8 !cutoff +4 ! type bloc +2 !longeur bloc +"test.vtk" ! sortie fin vtk +1.D-16 1.D6 1.D2 !lambda_flu lambda_sol lambda_por +4.74833808D-03 (Re=210.6) 7.496251874D-03 (Re=133.4) !nu=1/Re +"RES/test/omg_" "RES/test/vg_" "RES/test/chi.vtk" "RES/test/lambda.vtk" 2000000 !vtk +"RES/test/test.res" "RES/test/test.drag" !coupe vitesse drag/lift +0 200000 "RES/test/sauv.vtk" !num_suite (0non 1 oui) num_ite name_relance diff --git a/CodesEnVrac/NavierStokes3D-Penalization/make_test_fft b/CodesEnVrac/NavierStokes3D-Penalization/make_test_fft new file mode 100644 index 000000000..41385dc1e --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/make_test_fft @@ -0,0 +1,23 @@ +# +# Makefile +# +Compilateur = ifort -O0 -debug extended +Programme = test_fft +FILES = nrtype.f90 nrutil.f90 nr.f90 four3.f90 fourrow_3d.f90 rlft3.f90 four2.f90 fourrow.f90 rlft2.f90 test_fft.f90 +OBJS = $(patsubst %.f90, %.o, $(FILES)) + +$(Programme): $(OBJS) + @echo edition de liens + @$(Compilateur) $(OBJS) -o $@ + +%.o: %.f90 + @echo compilation de $? + @$(Compilateur) -c $? + +clean: + @rm -f *.o *~ *.mod + @echo nettoyage + +clean_all: + @rm -f *.o *~ *.mod *exe *.out + @echo nettoyage diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/Unused/test_fft.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/Unused/test_fft.f90 new file mode 100644 index 000000000..20cd10f39 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/Unused/test_fft.f90 @@ -0,0 +1,1609 @@ +program test_fft + use nrtype + USE nrutil + USE nr + implicit none + + + + !============================== + !test aller/retour + !============================== + + +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:,:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz +!!$ real(SP),dimension(:,:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=4 +!!$ ny=4 +!!$ nz=4 + +!!$ allocate (donne_init(1:nx,1:ny,1:nz),donne_fin(1:nx,1:ny,1:nz), spec1(1:nx/2,1:ny,1:nz), spec2(1:ny,1:nz) ) +!!$ +!!$ donne_init=3. +!!$ fac=2./(nx*ny*nz) +!!$ +!!$ print*, "forward" +!!$ call rlft3(donne_init,spec1,spec2,1) +!!$ print*,"backward" +!!$ call rlft3(donne_fin,spec1,spec2,-1) +!!$ +!!$ print*,"donne(1,1,1)",fac*donne_fin(1,1,1) +!!$ +!!$ print*,"test" +!!$ do k=1,nz +!!$ do j=1,ny +!!$ do i=1,nx +!!$ if (abs((fac*donne_fin(i,j,k))-donne_init(i,j,k))>0.001) print*,i,j,k,fac*donne_fin(i,j,k),donne_init(i,j,k) +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ deallocate (donne_init,donne_fin,spec1,spec2) + + + + +!!$ +!!$ +!!$ !=============================================================== +!!$ !test laplacien 2D: discrétisation ordre2, utilisation de four2 +!!$ !================================================================ +!!$ integer(I4B) :: nx,ny +!!$ complex(SPC),dimension(:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,xg,xd,yb,yh,t1,t2,dx,dy,rn,rm +!!$ complex(SPC),dimension(:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=32 +!!$ ny=32 +!!$ +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ +!!$ +!!$ dx=t1/(nx) +!!$ dy=t2/(ny) +!!$ +!!$ +!!$ allocate (psi(1:nx,1:ny),exa(1:nx,1:ny),f(1:nx,1:ny)) +!!$ allocate (spec1(1:nx,1:ny),spec_exa1(1:nx,1:ny)) +!!$ +!!$ !nx+1 point mais le dernier = premier par sym +!!$ +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ f(i,j)=-(4.*pi**2*exa(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ +!!$ end do +!!$ end do +!!$ +!!$ spec1=f +!!$ spec_exa1=exa +!!$ +!!$ +!!$ !fft forward +!!$ call four2(spec1,1) +!!$ call four2(spec_exa1,1) +!!$ +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ +!!$ do n=1,ny +!!$ do m=1,nx +!!$ +!!$ spec1(m,n)=dx**2*spec1(m,n)/(2.*(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)-2.)) +!!$ ! le premier mode correspond à l'integrale de la masse: conservee pour un ecoulement periodique +!!$ if ((m==1).and.(n==1)) spec1(m,n)=0. +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ print*,"erreur spectre" +!!$ print*,maxval(abs(spec_exa1-spec1)),maxloc(abs(spec_exa1-spec1)) +!!$ +!!$ +!!$ !fft backward +!!$ fac=1./(nx*ny) +!!$ call four2(spec1,-1) +!!$ psi=fac*spec1 +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ print*,"dx**2",dx**2 +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1) + + + + +!!$ !=============================================================== +!!$ !test laplacien 2D: discretisation ordre2, utilisation de rlft2 +!!$ !================================================================ +!!$ integer(I4B) :: nx,ny +!!$ real(SP),dimension(:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,xg,xd,yb,yh,t1,t2,dx,dy +!!$ real(SP),dimension(:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=256 +!!$ ny=256 +!!$ +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ +!!$ +!!$ dx=t1/(nx) +!!$ dy=t2/(ny) +!!$ +!!$ +!!$ allocate (psi(1:nx,1:ny),exa(1:nx,1:ny),f(1:nx,1:ny)) +!!$ allocate (spec1(1:nx/2,1:ny), spec2(1:ny),spec_exa1(1:nx/2,1:ny), spec_exa2(1:ny) ) +!!$ +!!$ !nx+1 point mais le dernier = premier par sym +!!$ +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ f(i,j)=-(4.*pi**2*exa(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft forward +!!$ call rlft2(f,spec1,spec2,1) +!!$ call rlft2(exa,spec_exa1,spec_exa2,1) +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ !calcul de la solution dans l'espace des frequences (discretisation d'ordre2 du laplacien) +!!$ m=nx/2+1 +!!$ do n=1,ny +!!$ spec2(n)=0.5*dx**2*spec2(n)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)-2.) +!!$ end do +!!$ +!!$ do n=1,ny +!!$ do m=1,nx/2 +!!$ +!!$ spec1(m,n)=0.5*dx**2*spec1(m,n)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)-2.) +!!$ if ((n==1).and.(m==1)) spec1(m,n)=0. +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny) +!!$ call rlft2(psi,spec1,spec2,-1) +!!$ psi=fac*psi +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ print*,"dx**2",dx**2 +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1,spec2,spec_exa2) + + + + + +!!$ !=============================================================== +!!$ !test laplacien 3D: discretisation ordre2, utilisation de rlft3 +!!$ !================================================================ +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:,:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz +!!$ real(SP),dimension(:,:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=64 +!!$ ny=64 +!!$ nz=64 +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ zd=-1. +!!$ zf=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ t3=zf-zd +!!$ +!!$ +!!$ dx=t1/nx +!!$ dy=t2/ny +!!$ dz=t3/nz +!!$ +!!$ if ((dx/=dy).or.(dx/=dz)) then +!!$ print*,"attention dx=dy=dz" +!!$ stop +!!$ end if +!!$ +!!$ allocate (psi(1:nx,1:ny,1:nz),exa(1:nx,1:ny,1:nz),f(1:nx,1:ny,1:nz)) +!!$ allocate (spec1(1:nx/2,1:ny,1:nz), spec2(1:ny,1:nz),spec_exa1(1:nx/2,1:ny,1:nz), spec_exa2(1:ny,1:nz) ) +!!$ +!!$ do k=1,nz +!!$ z=zd+(k-1)*dz +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) +!!$ f(i,j,k)=-(4.*pi**2*exa(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft forward +!!$ call rlft3(f,spec1,spec2,1) +!!$ call rlft3(exa,spec_exa1,spec_exa2,1) +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ !calcul de la solution dans l'espace des frequences (discretisation d'ordre2 du laplacien) +!!$ m=nx/2+1 +!!$ do p=1,nz +!!$ do n=1,ny +!!$ spec2(n,p)=0.5*dx**2*spec2(n,p)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3.) +!!$ end do +!!$ end do +!!$ +!!$ do p=1,nz +!!$ do n=1,ny +!!$ do m=1,nx/2 +!!$ spec1(m,n,p)=0.5*dx**2*spec1(m,n,p)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3.) +!!$ if ((n==1).and.(m==1).and.(p==1)) spec1(m,n,p)=0. +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny*nz) +!!$ call rlft3(psi,spec1,spec2,-1) +!!$ psi=fac*psi +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ print*,"dx**2",dx**2 +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1,spec2,spec_exa2) +!!$ + + + + + + +!!$ !=============================================================== +!!$ !test laplacien 2D: utilisation de four2 +!!$ !================================================================ +!!$ integer(I4B) :: nx,ny +!!$ complex(SPC),dimension(:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,xg,xd,yb,yh,t1,t2,dx,dy,kx,ky +!!$ complex(SPC),dimension(:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=8 +!!$ ny=8 +!!$ +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ +!!$ +!!$ dx=t1/(nx) +!!$ dy=t2/(ny) +!!$ +!!$ +!!$ allocate (psi(1:nx,1:ny),exa(1:nx,1:ny),f(1:nx,1:ny)) +!!$ allocate (spec1(1:nx,1:ny),spec_exa1(1:nx,1:ny)) +!!$ +!!$ !nx+1 point mais le dernier = premier par sym +!!$ +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ f(i,j)=-(4.*pi**2*exa(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ +!!$ end do +!!$ end do +!!$ +!!$ spec1=f +!!$ spec_exa1=exa +!!$ +!!$ +!!$ !fft forward +!!$ call four2(spec1,1) +!!$ call four2(spec_exa1,1) +!!$ +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ do n=1,ny +!!$ do m=1,nx +!!$ +!!$ !attention au rangement des frequences: >0 puis 0 puis <0 +!!$ +!!$ if ( (m-1)<=(nx/2) ) then +!!$ kx=(m-1)/t1 +!!$ else +!!$ kx=(m-1-nx)/t1 +!!$ end if +!!$ +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ +!!$ spec1(m,n)=-spec1(m,n)/(4.*pi**2*(kx**2+ky**2)) +!!$ if ((kx==0).and.(ky==0)) spec1(m,n)=0. +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ +!!$ print*,"erreur spectre" +!!$ print*,maxval(abs(spec_exa1-spec1)),maxloc(abs(spec_exa1-spec1)) +!!$ +!!$ +!!$ !fft backward +!!$ fac=1./(nx*ny) +!!$ call four2(spec1,-1) +!!$ psi=fac*spec1 +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1) +!!$ + + + +!!$ +!!$ !=============================================================== +!!$ !test laplacien 2D: utilisation de rlft2 +!!$ !================================================================ +!!$ integer(I4B) :: nx,ny +!!$ complex(SPC),dimension(:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,xg,xd,yb,yh,t1,t2,dx,dy,kx,ky +!!$ real(SP),dimension(:,:),allocatable :: psi,f,exa +!!$ +!!$ nx=8 +!!$ ny=8 +!!$ +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ +!!$ +!!$ dx=t1/(nx) +!!$ dy=t2/(ny) +!!$ +!!$ +!!$ allocate (psi(1:nx,1:ny),exa(1:nx,1:ny),f(1:nx,1:ny)) +!!$ allocate (spec1(1:nx/2,1:ny), spec2(1:ny),spec_exa1(1:nx/2,1:ny), spec_exa2(1:ny) ) +!!$ +!!$ !nx+1 point mais le dernier = premier par sym +!!$ +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ f(i,j)=-(4.*pi**2*exa(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ +!!$ end do +!!$ end do +!!$ +!!$ !fft forward +!!$ call rlft2(f,spec1,spec2,1) +!!$ call rlft2(exa,spec_exa1,spec_exa2,1) +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ do n=1,ny +!!$ do m=1,nx/2 +!!$ +!!$ kx=(m-1)/t1 +!!$ +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ spec1(m,n)=-spec1(m,n)/(4.*pi**2*(kx**2+ky**2)) +!!$ if ((kx==0).and.(ky==0)) spec1(m,n)=0. +!!$ +!!$ end do +!!$ end do +!!$ +!!$ m=nx/2+1 +!!$ do n=1,ny +!!$ +!!$ kx=(m-1)/t1 +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ spec2(n)=-spec2(n)/(4.*pi**2*(kx**2+ky**2)) +!!$ if ((kx==0).and.(ky==0)) spec2(n)=0. +!!$ end do +!!$ +!!$ +!!$ print*,"spec_exa" +!!$ print*,spec_exa1 +!!$ print*,spec_exa2 +!!$ print*,"spec" +!!$ print*,spec1 +!!$ print*,spec2 +!!$ +!!$ +!!$ print*,"erreur spectre" +!!$ print*,maxval(abs(spec_exa1-spec1)),maxloc(abs(spec_exa1-spec1)) +!!$ print*,maxval(abs(spec_exa2-spec2)),maxloc(abs(spec_exa2-spec2)) +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny) +!!$ call rlft2(psi,spec1,spec2,-1) +!!$ psi=fac*psi +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1) +!!$ +!!$ + +!!$ !=============================================================== +!!$ !test laplacien 3D: utilisation de rlft3 +!!$ !================================================================ +!!$ +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec1,spec_exa1 +!!$ complex(SPC),dimension(:,:),allocatable :: spec2,spec_exa2 +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz,kx,ky,kz +!!$ real(SP),dimension(:,:,:),allocatable :: psi,f,exa +!!$ +!!$ +!!$ nx=8 +!!$ ny=64 +!!$ nz=32 +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ zd=-1. +!!$ zf=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ t3=zf-zd +!!$ +!!$ +!!$ dx=t1/nx +!!$ dy=t2/ny +!!$ dz=t3/nz +!!$ +!!$ +!!$ allocate (psi(1:nx,1:ny,1:nz),exa(1:nx,1:ny,1:nz),f(1:nx,1:ny,1:nz)) +!!$ allocate (spec1(1:nx/2,1:ny,1:nz), spec2(1:ny,1:nz),spec_exa1(1:nx/2,1:ny,1:nz), spec_exa2(1:ny,1:nz) ) +!!$ +!!$ do k=1,nz +!!$ z=zd+(k-1)*dz +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ exa(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) +!!$ f(i,j,k)=-(4.*pi**2*exa(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft forward +!!$ call rlft3(f,spec1,spec2,1) +!!$ call rlft3(exa,spec_exa1,spec_exa2,1) +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ !calcul de la solution dans l'espace des frequences (discretisation d'ordre2 du laplacien) +!!$ m=nx/2+1 +!!$ do p=1,nz +!!$ do n=1,ny +!!$ +!!$ kx=(m-1)/t1 +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ +!!$ spec2(n,p)=-spec2(n,p)/(4.*pi**2*(kx**2+ky**2+kz**2)) +!!$ if ((kx==0).and.(ky==0).and.(kz==0)) spec2(n,p)=0. +!!$ +!!$ +!!$ end do +!!$ end do +!!$ +!!$ do p=1,nz +!!$ do n=1,ny +!!$ do m=1,nx/2 +!!$ +!!$ +!!$ kx=(m-1)/t1 +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ +!!$ +!!$ spec1(m,n,p)=-spec1(m,n,p)/(4.*pi**2*(kx**2+ky**2+kz**2)) +!!$ if ((kx==0).and.(ky==0).and.(kz==0)) spec1(m,n,p)=0. +!!$ +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny*nz) +!!$ call rlft3(psi,spec1,spec2,-1) +!!$ psi=fac*psi +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psi-exa)),maxloc(abs(psi-exa)) +!!$ +!!$ +!!$ deallocate (psi,exa,f) +!!$ deallocate(spec1,spec_exa1,spec2,spec_exa2) + + + + + + !=============================================================== + !test laplacien 2D: utilisation de four2 calcul champ vitesse + !================================================================ +!!$ integer(I4B) :: nx,ny +!!$ complex(SPC),dimension(:,:),allocatable :: spec1x,spec1y,spec1z +!!$ complex(SPC),dimension(:,:),allocatable :: spec_exa1x,spec_exa1y,spec_exa1z +!!$ complex(SPC),dimension(:),allocatable :: spec2x,spec2y,spec2z +!!$ complex(SPC),dimension(:),allocatable :: spec_exa2x,spec_exa2y,spec_exa2z +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,xg,xd,yb,yh,t1,t2,dx,dy,kx,ky +!!$ complex(SPC),dimension(:,:),allocatable :: psix,fx,exax,psiy,fy,exay,psiz,fz,exaz +!!$ +!!$ nx=8 +!!$ ny=8 +!!$ +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ +!!$ +!!$ dx=t1/(nx) +!!$ dy=t2/(ny) +!!$ +!!$ +!!$ allocate (psix(1:nx,1:ny),exax(1:nx,1:ny),fx(1:nx,1:ny)) +!!$ allocate (psiy(1:nx,1:ny),exay(1:nx,1:ny),fy(1:nx,1:ny)) +!!$ allocate (spec1x(1:nx,1:ny),spec_exa1x(1:nx,1:ny)) +!!$ allocate (spec1y(1:nx,1:ny),spec_exa1y(1:nx,1:ny)) +!!$ +!!$ !nx+1 point mais le dernier = premier par sym +!!$ +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ psix(i,j)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2) +!!$ psiy(i,j)=sin(2.*pi*x/t1)*sin(2.*pi*y/t2) +!!$ +!!$ fx(i,j)=-(4.*pi**2*psix(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ fy(i,j)=-(4.*pi**2*psiy(i,j)*(t2**2+t1**2))/((t1*t2)**2) +!!$ +!!$ exax(i,j)=2.*pi*cos(2.*pi*x/t1)*sin(2.*pi*y/t2)*(t1+t2)/(t1*t2) +!!$ +!!$ end do +!!$ end do +!!$ +!!$ spec1x=fx +!!$ spec1y=fy +!!$ +!!$ !poisson +!!$ !spec_exa1x=psix +!!$ !spec_exa1y=psiy +!!$ +!!$ !vitesse +!!$ spec_exa1x=exax +!!$ spec_exa1y=exax +!!$ +!!$ +!!$ !fft forward +!!$ call four2(spec1x,1) +!!$ call four2(spec_exa1x,1) +!!$ call four2(spec1y,1) +!!$ call four2(spec_exa1y,1) +!!$ +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ do n=1,ny +!!$ do m=1,nx +!!$ +!!$ !attention au rangement des frequences: >0 puis 0 puis <0 +!!$ +!!$ if ( (m-1)<=(nx/2) ) then +!!$ kx=(m-1)/t1 +!!$ else +!!$ kx=(m-1-nx)/t1 +!!$ end if +!!$ +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ !poisson +!!$ !spec1x(m,n)=-spec1x(m,n)/(4.*pi**2*(kx**2+ky**2)) +!!$ !if ((kx==0).and.(ky==0)) spec1x(m,n)=0. +!!$ !spec1y(m,n)=-spec1y(m,n)/(4.*pi**2*(kx**2+ky**2)) +!!$ !if ((kx==0).and.(ky==0)) spec1y(m,n)=0. +!!$ +!!$ !poisson+vitesse +!!$ spec1x(m,n)=-2.*pi*cmplx(0.,1.)*(-kx*spec1y(m,n)/(4.*pi**2*(kx**2+ky**2)))& +!!$ -2.*pi*cmplx(0.,1.)*(ky*spec1x(m,n)/(4.*pi**2*(kx**2+ky**2))) +!!$ if ((kx==0).and.(ky==0)) spec1x(m,n)=0. +!!$ +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ +!!$ print*,"erreur spectre" +!!$ print*,maxval(abs(spec_exa1x-spec1x)),maxloc(abs(spec_exa1x-spec1x)) +!!$ !print*,maxval(abs(spec_exa1y-spec1y)),maxloc(abs(spec_exa1y-spec1y)) +!!$ +!!$ +!!$ !fft backward +!!$ fac=1./(nx*ny) +!!$ +!!$ !poisson +!!$ !call four2(spec1x,-1) +!!$ !exax=fac*spec1x +!!$ !call four2(spec1y,-1) +!!$ !exay=fac*spec1y +!!$ +!!$ !vitesse +!!$ call four2(spec1x,-1) +!!$ psix=fac*spec1x +!!$ +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psix-exax)),maxloc(abs(psix-exax)) +!!$ !print*,maxval(abs(psiy-exay)),maxloc(abs(psiy-exay)) +!!$ +!!$ +!!$ deallocate (psix,exax,fx) +!!$ deallocate(spec1x,spec_exa1x) +!!$ deallocate (psiy,exay,fy) +!!$ deallocate(spec1y,spec_exa1y) +!!$ +!!$ +!!$ +!!$ +!!$ + !=============================================================== + !test laplacien + champ de vitesse 3D: utilisation de four3 + !================================================================ + +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec1x, spec1y, spec1z +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec1xn, spec1yn, spec1zn +!!$ complex(SPC),dimension(:,:),allocatable :: spec2x, spec2y, spec2z +!!$ complex(SPC),dimension(:,:,:),allocatable :: spec_exa1x, spec_exa1y, spec_exa1z +!!$ complex(SPC),dimension(:,:),allocatable :: spec_exa2x, spec_exa2y, spec_exa2z +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz,kx,ky,kz,r2,coeff +!!$ real(SP),dimension(:,:,:),allocatable :: psix,psiy,psiz,fx,fy,fz,exax,exay,exaz +!!$ +!!$ +!!$ nx=4 +!!$ ny=4 +!!$ nz=4 +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ zd=-1. +!!$ zf=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ t3=zf-zd +!!$ +!!$ +!!$ dx=t1/nx +!!$ dy=t2/ny +!!$ dz=t3/nz +!!$ +!!$ +!!$ allocate (psix(1:nx,1:ny,1:nz),exax(1:nx,1:ny,1:nz),fx(1:nx,1:ny,1:nz)) +!!$ allocate (psiy(1:nx,1:ny,1:nz),exay(1:nx,1:ny,1:nz),fy(1:nx,1:ny,1:nz)) +!!$ allocate (psiz(1:nx,1:ny,1:nz),exaz(1:nx,1:ny,1:nz),fz(1:nx,1:ny,1:nz)) +!!$ allocate (spec1x(1:nx,1:ny,1:nz),spec1xn(1:nx,1:ny,1:nz) ) +!!$ allocate (spec1y(1:nx,1:ny,1:nz),spec1yn(1:nx,1:ny,1:nz) ) +!!$ allocate (spec1z(1:nx,1:ny,1:nz),spec1zn(1:nx,1:ny,1:nz) ) +!!$ allocate (spec_exa1x(1:nx,1:ny,1:nz) ) +!!$ allocate (spec_exa1y(1:nx,1:ny,1:nz) ) +!!$ allocate (spec_exa1z(1:nx,1:ny,1:nz) ) +!!$ +!!$ +!!$ do k=1,nz +!!$ z=zd+(k-1)*dz +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ !psi +!!$ psix(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) +!!$ psiy(i,j,k)=sin(2.*pi*x/t1)*sin(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ psiz(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ +!!$ !vitesse +!!$ exax(i,j,k)=-2.*pi*sin(2.*pi*y/t2)*(cos(2.*pi*x/t1)*sin(2.*pi*z/t3)*t3+sin(2.*pi*x/t1)*cos(2.*pi*z/t3)*t2)/(t2*t3) +!!$ exay(i,j,k)=-2.*pi*cos(2.*pi*y/t2)*sin(2.*pi*z/t3)*(cos(2.*pi*x/t1)*t1-sin(2.*pi*x/t1)*t3)/(t1*t3) +!!$ exaz(i,j,k)=2.*pi*sin(2.*pi*y/t2)*cos(2.*pi*x/t1)*(sin(2.*pi*z/t3)*t2+cos(2.*pi*z/t3)*t1)/(t2*t1) +!!$ +!!$ !-omega +!!$ fx(i,j,k)=-(4.*pi**2*psix(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fy(i,j,k)=-(4.*pi**2*psiy(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fz(i,j,k)=-(4.*pi**2*psiz(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ spec1x=fx +!!$ spec1y=fy +!!$ spec1z=fz +!!$ +!!$ spec_exa1x=exax +!!$ spec_exa1y=exay +!!$ spec_exa1z=exaz +!!$ +!!$ !fft forward +!!$ call four3(spec1x,1) +!!$ call four3(spec1y,1) +!!$ call four3(spec1z,1) +!!$ +!!$ call four3(spec_exa1x,1) +!!$ call four3(spec_exa1y,1) +!!$ call four3(spec_exa1z,1) +!!$ +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ +!!$ do p=1,nz +!!$ do n=1,ny +!!$ do m=1,nx +!!$ +!!$ if ( (m-1)<=(nx/2) ) then +!!$ kx=(m-1)/t1 +!!$ else +!!$ kx=(m-1-nx)/t1 +!!$ end if +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ +!!$ r2=kx**2+ky**2+kz**2 +!!$ +!!$ +!!$ !poisson+vitesse +!!$ spec1xn(m,n,p)=-2.*pi*cmplx(0.,1.)*(-ky*spec1z(m,n,p)/(4.*pi**2*r2))& +!!$ -2.*pi*cmplx(0.,1.)*(kz*spec1y(m,n,p)/(4.*pi**2*r2)) +!!$ if ((r2==0)) spec1xn(m,n,p)=0. +!!$ +!!$ spec1yn(m,n,p)=-2.*pi*cmplx(0.,1.)*(-kz*spec1x(m,n,p)/(4.*pi**2*r2))& +!!$ -2.*pi*cmplx(0.,1.)*(kx*spec1z(m,n,p)/(4.*pi**2*r2)) +!!$ if ((r2==0)) spec1yn(m,n,p)=0. +!!$ +!!$ +!!$ spec1zn(m,n,p)=-2.*pi*cmplx(0.,1.)*(-kx*spec1y(m,n,p)+ky*spec1x(m,n,p))/(4.*pi**2*r2) +!!$ if ((r2==0)) spec1zn(m,n,p)=0. +!!$ +!!$ +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ print*,"erreur spectre" +!!$ print*,maxval(abs(spec_exa1x-spec1xn)),maxloc(abs(spec_exa1x-spec1xn)) +!!$ print*,maxval(abs(spec_exa1y-spec1yn)),maxloc(abs(spec_exa1y-spec1yn)) +!!$ print*,maxval(abs(spec_exa1z-spec1zn)),maxloc(abs(spec_exa1z-spec1zn)) +!!$ +!!$ +!!$ !fft backward +!!$ fac=1./(nx*ny*nz) +!!$ +!!$ call four3(spec1xn,-1) +!!$ call four3(spec1yn,-1) +!!$ call four3(spec1zn,-1) +!!$ +!!$ psix=fac*spec1xn +!!$ psiy=fac*spec1yn +!!$ psiz=fac*spec1zn +!!$ +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psix-exax)),maxloc(abs(psix-exax)) +!!$ print*,maxval(abs(psiy-exay)),maxloc(abs(psiy-exay)) +!!$ print*,maxval(abs(psiz-exaz)),maxloc(abs(psiz-exaz)) +!!$ +!!$ +!!$ deallocate (psix,exax,fx) +!!$ deallocate (psiy,exay,fy) +!!$ deallocate (psiz,exaz,fz) +!!$ deallocate(spec1x,spec1xn) +!!$ deallocate(spec1y,spec1yn) +!!$ deallocate(spec1z,spec1zn) +!!$ deallocate(spec_exa1x) +!!$ deallocate(spec_exa1y) +!!$ deallocate(spec_exa1z) +!!$ + + !=============================================================== + !test laplacien + champ de vitesse 3D: utilisation de rlft3 + !================================================================ +!!$ +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: sf1x, sf1y, sf1z +!!$ complex(SPC),dimension(:,:,:),allocatable :: su1x, su1y, su1z +!!$ complex(SPC),dimension(:,:),allocatable :: sf2x, sf2y, sf2z +!!$ complex(SPC),dimension(:,:),allocatable :: su2x, su2y, su2z +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz,kx,ky,kz,r2,coeff +!!$ real(SP),dimension(:,:,:),allocatable :: psix,psiy,psiz,fx,fy,fz,exax,exay,exaz +!!$ +!!$ +!!$ nx=8 +!!$ ny=32 +!!$ nz=16 +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ zd=-1. +!!$ zf=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ t3=zf-zd +!!$ +!!$ +!!$ dx=t1/nx +!!$ dy=t2/ny +!!$ dz=t3/nz +!!$ +!!$ +!!$ allocate (psix(1:nx,1:ny,1:nz),exax(1:nx,1:ny,1:nz),fx(1:nx,1:ny,1:nz)) +!!$ allocate (psiy(1:nx,1:ny,1:nz),exay(1:nx,1:ny,1:nz),fy(1:nx,1:ny,1:nz)) +!!$ allocate (psiz(1:nx,1:ny,1:nz),exaz(1:nx,1:ny,1:nz),fz(1:nx,1:ny,1:nz)) +!!$ allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) +!!$ allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) +!!$ allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) +!!$ +!!$ +!!$ do k=1,nz +!!$ z=zd+(k-1)*dz +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ !psi +!!$ psix(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) +!!$ psiy(i,j,k)=sin(2.*pi*x/t1)*sin(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ psiz(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ +!!$ !vitesse +!!$ exax(i,j,k)=-2.*pi*sin(2.*pi*y/t2)*(cos(2.*pi*x/t1)*sin(2.*pi*z/t3)*t3+sin(2.*pi*x/t1)*cos(2.*pi*z/t3)*t2)/(t2*t3) +!!$ exay(i,j,k)=-2.*pi*cos(2.*pi*y/t2)*sin(2.*pi*z/t3)*(cos(2.*pi*x/t1)*t1-sin(2.*pi*x/t1)*t3)/(t1*t3) +!!$ exaz(i,j,k)=2.*pi*sin(2.*pi*y/t2)*cos(2.*pi*x/t1)*(sin(2.*pi*z/t3)*t2+cos(2.*pi*z/t3)*t1)/(t2*t1) +!!$ +!!$ !-omega +!!$ fx(i,j,k)=-(4.*pi**2*psix(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fy(i,j,k)=-(4.*pi**2*psiy(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fz(i,j,k)=-(4.*pi**2*psiz(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft forward +!!$ call rlft3(fx,sf1x,sf2x,1) +!!$ call rlft3(fy,sf1y,sf2y,1) +!!$ call rlft3(fz,sf1z,sf2z,1) +!!$ +!!$ +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ !calcul de la solution dans l'espace des frequences +!!$ +!!$ do p=1,nz +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ do n=1,ny +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ do m=1,nx/2 +!!$ +!!$ if ( (m-1)<=(nx/2) ) then +!!$ kx=(m-1)/t1 +!!$ else +!!$ kx=(m-1-nx)/t1 +!!$ end if +!!$ +!!$ +!!$ +!!$ r2=kx**2+ky**2+kz**2 +!!$ +!!$ +!!$ su1x(m,n,p)=cmplx(0.,1.)*(ky*sf1z(m,n,p)-kz*sf1y(m,n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su1x(m,n,p)=0. +!!$ +!!$ su1y(m,n,p)=cmplx(0.,1.)*(kz*sf1x(m,n,p)-kx*sf1z(m,n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su1y(m,n,p)=0. +!!$ +!!$ su1z(m,n,p)=cmplx(0.,1.)*(kx*sf1y(m,n,p)-ky*sf1x(m,n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su1z(m,n,p)=0. +!!$ +!!$ +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ m=nx/2+1 +!!$ kx=(m-1)/t1 +!!$ do p=1,nz +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ do n=1,ny +!!$ +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ +!!$ r2=kx**2+ky**2+kz**2 +!!$ +!!$ +!!$ !poisson+vitesse +!!$ su2x(n,p)=cmplx(0.,1.)*(ky*sf2z(n,p)-kz*sf2y(n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su2x(n,p)=0. +!!$ +!!$ su2y(n,p)=cmplx(0.,1.)*(kz*sf2x(n,p)-kx*sf2z(n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su2y(n,p)=0. +!!$ +!!$ +!!$ su2z(n,p)=cmplx(0.,1.)*(kx*sf2y(n,p)-ky*sf2x(n,p))/(2.*pi*r2) +!!$ if ((r2==0)) su2z(n,p)=0. +!!$ +!!$ !su2z(n,p)=-2.*pi*cmplx(0.,1.)*(-kx*sf2y(n,p)+ky*sf2x(n,p))/(4.*pi**2*r2) +!!$ !if ((r2==0)) su2z(n,p)=0. +!!$ +!!$ +!!$ +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny*nz) +!!$ +!!$ call rlft3(psix,su1x,su2x,-1) +!!$ call rlft3(psiy,su1y,su2y,-1) +!!$ call rlft3(psiz,su1z,su2z,-1) +!!$ +!!$ psix=fac*psix +!!$ psiy=fac*psiy +!!$ psiz=fac*psiz +!!$ +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psix-exax)),maxloc(abs(psix-exax)) +!!$ print*,maxval(abs(psiy-exay)),maxloc(abs(psiy-exay)) +!!$ print*,maxval(abs(psiz-exaz)),maxloc(abs(psiz-exaz)) +!!$ +!!$ +!!$ deallocate (psix,exax,fx) +!!$ deallocate (psiy,exay,fy) +!!$ deallocate (psiz,exaz,fz) +!!$ deallocate(sf1x,su1x) +!!$ deallocate(sf1y,su1y) +!!$ deallocate(sf1z,su1z) +!!$ deallocate(sf2x,su2x) +!!$ deallocate(sf2y,su2y) +!!$ deallocate(sf2z,su2z) + + !=============================================================== + !test laplacien + champ de vitesse 3D: utilisation de rlft3 + !================================================================ + + integer :: nx,ny,nz + real(kind=8),dimension(:,:,:),allocatable :: donne_init,donne_fin + complex(kind=8),dimension(:,:,:),allocatable :: sf1x, sf1y, sf1z + complex(kind=8),dimension(:,:,:),allocatable :: su1x, su1y, su1z + complex(kind=8),dimension(:,:),allocatable :: sf2x, sf2y, sf2z + complex(kind=8),dimension(:,:),allocatable :: su2x, su2y, su2z + + integer :: i,j,k,m,n,p + real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz,kx,ky,kz,r2,coeff,cpt + real(kind=8),dimension(:,:,:),allocatable :: psix,psiy,psiz,fx,fy,fz,exax,exay,exaz + + + nx=33 + ny=33 + nz=33 + + xg=-1. + xd=1. + yb=-1. + yh=1. + zd=-1. + zf=1. + + t1=xd-xg + t2=yh-yb + t3=zf-zd + + + dx=t1/(nx-1) + dy=t2/(ny-1) + dz=t3/(nz-1) + + nx=nx-1 + ny=ny-1 + nz=nz-1 + + + + allocate (psix(1:nx,1:ny,1:nz),exax(1:nx,1:ny,1:nz),fx(1:nx,1:ny,1:nz)) + allocate (psiy(1:nx,1:ny,1:nz),exay(1:nx,1:ny,1:nz),fy(1:nx,1:ny,1:nz)) + allocate (psiz(1:nx,1:ny,1:nz),exaz(1:nx,1:ny,1:nz),fz(1:nx,1:ny,1:nz)) + allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) + allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) + allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) + allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) + allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) + allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) + + + + do k=1,nz + z=zd+(k-1)*dz + do j=1,ny + y=yb+(j-1)*dy + do i=1,nx + x=xg+(i-1)*dx + + !psi + psix(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) + psiy(i,j,k)=sin(2.*pi*x/t1)*sin(2.*pi*y/t2)*sin(2.*pi*z/t3) + psiz(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*sin(2.*pi*z/t3) + + !vitesse + exax(i,j,k)=-2.*pi*sin(2.*pi*y/t2)*(cos(2.*pi*x/t1)*sin(2.*pi*z/t3)*t3+sin(2.*pi*x/t1)*cos(2.*pi*z/t3)*t2)/(t2*t3) + exay(i,j,k)=-2.*pi*cos(2.*pi*y/t2)*sin(2.*pi*z/t3)*(cos(2.*pi*x/t1)*t1-sin(2.*pi*x/t1)*t3)/(t1*t3) + exaz(i,j,k)=2.*pi*sin(2.*pi*y/t2)*cos(2.*pi*x/t1)*(sin(2.*pi*z/t3)*t2+cos(2.*pi*z/t3)*t1)/(t2*t1) + + !-omega + fx(i,j,k)=-(4.*pi**2*psix(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) + fy(i,j,k)=-(4.*pi**2*psiy(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) + fz(i,j,k)=-(4.*pi**2*psiz(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) + + end do + end do + end do + + + !fft forward + call rlft3(fx,sf1x,sf2x,1) + call rlft3(fy,sf1y,sf2y,1) + call rlft3(fz,sf1z,sf2z,1) + + + !frequence=0 : n=0 + !0<f<fc : 1<=n<=N/2-1 + !f=fc=-fc : n=N/2 + !-fc<f<0 : N/2+1<=n<=N-1 + + !calcul de la solution dans l'espace des frequences + + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/t3 + else + kz=(p-1-nz)/t3 + end if + do n=1,ny + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/t2 + else + ky=(n-1-ny)/t2 + end if + do m=1,nx/2 + + if ( (m-1)<=(nx/2) ) then + kx=(m-1)/t1 + else + kx=(m-1-nx)/t1 + end if + + + + r2=kx**2+ky**2+kz**2 + + + su1x(m,n,p)=cmplx(0.,1.)*(ky*sf1z(m,n,p)-kz*sf1y(m,n,p))/(2.*pi*r2) + if ((r2==0)) su1x(m,n,p)=0. + + su1y(m,n,p)=cmplx(0.,1.)*(kz*sf1x(m,n,p)-kx*sf1z(m,n,p))/(2.*pi*r2) + if ((r2==0)) su1y(m,n,p)=0. + + su1z(m,n,p)=cmplx(0.,1.)*(kx*sf1y(m,n,p)-ky*sf1x(m,n,p))/(2.*pi*r2) + if ((r2==0)) su1z(m,n,p)=0. + + + + end do + end do + end do + + m=nx/2+1 + kx=(m-1)/t1 + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/t3 + else + kz=(p-1-nz)/t3 + end if + do n=1,ny + + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/t2 + else + ky=(n-1-ny)/t2 + end if + + + r2=kx**2+ky**2+kz**2 + + + !poisson+vitesse + su2x(n,p)=cmplx(0.,1.)*(ky*sf2z(n,p)-kz*sf2y(n,p))/(2.*pi*r2) + if ((r2==0)) su2x(n,p)=0. + + su2y(n,p)=cmplx(0.,1.)*(kz*sf2x(n,p)-kx*sf2z(n,p))/(2.*pi*r2) + if ((r2==0)) su2y(n,p)=0. + + + su2z(n,p)=cmplx(0.,1.)*(kx*sf2y(n,p)-ky*sf2x(n,p))/(2.*pi*r2) + if ((r2==0)) su2z(n,p)=0. + + !su2z(n,p)=-2.*pi*cmplx(0.,1.)*(-kx*sf2y(n,p)+ky*sf2x(n,p))/(4.*pi**2*r2) + !if ((r2==0)) su2z(n,p)=0. + + + + end do + end do + + + !fft backward + fac=2./(nx*ny*nz) + + call rlft3(psix,su1x,su2x,-1) + call rlft3(psiy,su1y,su2y,-1) + call rlft3(psiz,su1z,su2z,-1) + + psix=fac*psix + psiy=fac*psiy + psiz=fac*psiz + + + !exa=f + !erreur + print*,"erreur" + print*,maxval(abs(psix-exax)),maxloc(abs(psix-exax)) + print*,maxval(abs(psiy-exay)),maxloc(abs(psiy-exay)) + print*,maxval(abs(psiz-exaz)),maxloc(abs(psiz-exaz)) + + + deallocate (psix,exax,fx) + deallocate (psiy,exay,fy) + deallocate (psiz,exaz,fz) + deallocate(sf1x,su1x) + deallocate(sf1y,su1y) + deallocate(sf1z,su1z) + deallocate(sf2x,su2x) + deallocate(sf2y,su2y) + deallocate(sf2z,su2z) + + + +!!$ !========================================================================== +!!$ !test laplacien 3D: poisson ordre2 + champ de vitesse utilisation de rlft3 +!!$ !=========================================================================== +!!$ +!!$ integer(I4B) :: nx,ny,nz +!!$ real(SP),dimension(:,:,:),allocatable :: donne_init,donne_fin +!!$ complex(SPC),dimension(:,:,:),allocatable :: sf1x, sf1y, sf1z ,deb1 +!!$ complex(SPC),dimension(:,:,:),allocatable :: su1x, su1y, su1z +!!$ complex(SPC),dimension(:,:),allocatable :: sf2x, sf2y, sf2z ,deb2 +!!$ complex(SPC),dimension(:,:),allocatable :: su2x, su2y, su2z +!!$ +!!$ integer :: i,j,k,m,n,p +!!$ real :: fac,x,y,z,xg,xd,yb,yh,zd,zf,t1,t2,t3,dx,dy,dz,kx,ky,kz,r2,coeff,ux,uy,uz +!!$ real(SP),dimension(:,:,:),allocatable :: psix,psiy,psiz,fx,fy,fz,exax,exay,exaz +!!$ +!!$ nx=8 +!!$ ny=8 +!!$ nz=8 +!!$ +!!$ xg=-1. +!!$ xd=1. +!!$ yb=-1. +!!$ yh=1. +!!$ zd=-1. +!!$ zf=1. +!!$ +!!$ t1=xd-xg +!!$ t2=yh-yb +!!$ t3=zf-zd +!!$ +!!$ +!!$ dx=t1/nx +!!$ dy=t2/ny +!!$ dz=t3/nz +!!$ +!!$ if ((dx/=dy).or.(dx/=dz)) then +!!$ print*,"attention dx=dy=dz" +!!$ stop +!!$ end if +!!$ +!!$ allocate (psix(1:nx,1:ny,1:nz),exax(1:nx,1:ny,1:nz),fx(1:nx,1:ny,1:nz)) +!!$ allocate (psiy(1:nx,1:ny,1:nz),exay(1:nx,1:ny,1:nz),fy(1:nx,1:ny,1:nz)) +!!$ allocate (psiz(1:nx,1:ny,1:nz),exaz(1:nx,1:ny,1:nz),fz(1:nx,1:ny,1:nz)) +!!$ allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) +!!$ allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) +!!$ allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) +!!$ allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) +!!$ +!!$ allocate (deb1(1:nx/2,1:ny,1:nz),deb2(1:ny,1:nz)) +!!$ +!!$ do k=1,nz +!!$ z=zd+(k-1)*dz +!!$ do j=1,ny +!!$ y=yb+(j-1)*dy +!!$ do i=1,nx +!!$ x=xg+(i-1)*dx +!!$ +!!$ !psi +!!$ psix(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*cos(2.*pi*z/t3) +!!$ psiy(i,j,k)=sin(2.*pi*x/t1)*sin(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ psiz(i,j,k)=cos(2.*pi*x/t1)*cos(2.*pi*y/t2)*sin(2.*pi*z/t3) +!!$ +!!$ !vitesse +!!$ exax(i,j,k)=-2.*pi*sin(2.*pi*y/t2)*(cos(2.*pi*x/t1)*sin(2.*pi*z/t3)*t3+sin(2.*pi*x/t1)*cos(2.*pi*z/t3)*t2)/(t2*t3) +!!$ exay(i,j,k)=-2.*pi*cos(2.*pi*y/t2)*sin(2.*pi*z/t3)*(cos(2.*pi*x/t1)*t1-sin(2.*pi*x/t1)*t3)/(t1*t3) +!!$ exaz(i,j,k)=2.*pi*sin(2.*pi*y/t2)*cos(2.*pi*x/t1)*(sin(2.*pi*z/t3)*t2+cos(2.*pi*z/t3)*t1)/(t2*t1) +!!$ +!!$ !-omega +!!$ fx(i,j,k)=-(4.*pi**2*psix(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fy(i,j,k)=-(4.*pi**2*psiy(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ fz(i,j,k)=-(4.*pi**2*psiz(i,j,k)*(t2**2*t3**2+t1**2*t3**2+t1**2*t2**2))/((t1*t2*t3)**2) +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ !fft forward +!!$ call rlft3(fx,sf1x,sf2x,1) +!!$ call rlft3(fy,sf1y,sf2y,1) +!!$ call rlft3(fz,sf1z,sf2z,1) +!!$ +!!$ call rlft3(exax,deb1,deb2,1) +!!$ +!!$ !frequence=0 : n=0 +!!$ !0<f<fc : 1<=n<=N/2-1 +!!$ !f=fc=-fc : n=N/2 +!!$ !-fc<f<0 : N/2+1<=n<=N-1 +!!$ +!!$ !calcul de la solution dans l'espace des frequences (discretisation d'ordre2 du laplacien) +!!$ m=nx/2+1 +!!$ kx=(m-1)/t1 +!!$ do p=1,nz +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ do n=1,ny +!!$ +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ +!!$ !su2x(n,p)=0.5*dx**2*sf2x(n,p)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3.) +!!$ +!!$ r2=cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3. +!!$ !r2=cos(2.*pi*kx*t1/nx)+cos(2.*pi*ky*t2/ny)+cos(2.*pi*kz*t3/nz)-3. +!!$ +!!$ ux=0.5*dx**2*sf2x(n,p)/r2 +!!$ uy=0.5*dx**2*sf2y(n,p)/r2 +!!$ uz=0.5*dx**2*sf2z(n,p)/r2 +!!$ +!!$ su2x(n,p)=-2.*pi*cmplx(0.,1.)*(ky*uz-kz*uy) +!!$ su2y(n,p)=-2.*pi*cmplx(0.,1.)*(kz*ux-kx*uz) +!!$ su2z(n,p)=-2.*pi*cmplx(0.,1.)*(kx*uy-ky*ux) +!!$ +!!$ +!!$ end do +!!$ end do +!!$ +!!$ do p=1,nz +!!$ if ( (p-1)<=(nz/2) ) then +!!$ kz=(p-1)/t3 +!!$ else +!!$ kz=(p-1-nz)/t3 +!!$ end if +!!$ do n=1,ny +!!$ if ( (n-1)<=(ny/2) ) then +!!$ ky=(n-1)/t2 +!!$ else +!!$ ky=(n-1-ny)/t2 +!!$ end if +!!$ do m=1,nx/2 +!!$ +!!$ if ( (m-1)<=(nx/2) ) then +!!$ kx=(m-1)/t1 +!!$ else +!!$ kx=(m-1-nx)/t1 +!!$ end if +!!$ !su1x(m,n,p)=0.5*dx**2*sf1x(m,n,p)/(cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3.) +!!$ !if ((n==1).and.(m==1).and.(p==1)) su1x(m,n,p)=0. +!!$ +!!$ r2=cos(2.*pi*(m-1)/nx)+cos(2.*pi*(n-1)/ny)+cos(2.*pi*(p-1)/nz)-3. +!!$ !r2=cos(2.*pi*kx*t1/nx)+cos(2.*pi*ky*t2/ny)+cos(2.*pi*kz*t3/nz)-3. +!!$ +!!$ ux=0.5*dx**2*sf1x(m,n,p)/r2 +!!$ uy=0.5*dx**2*sf1y(m,n,p)/r2 +!!$ uz=0.5*dx**2*sf1z(m,n,p)/r2 +!!$ +!!$ su1x(m,n,p)=-2.*pi*cmplx(0.,1.)*(ky*uz-kz*uy) +!!$ su1y(m,n,p)=-2.*pi*cmplx(0.,1.)*(kz*ux-kx*uz) +!!$ su1z(m,n,p)=-2.*pi*cmplx(0.,1.)*(kx*uy-ky*ux) +!!$ +!!$ if(r2==0.) then +!!$ su1x(m,n,p)=0. +!!$ su1y(m,n,p)=0. +!!$ su1z(m,n,p)=0. +!!$ end if +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ +!!$ +!!$ +!!$ !fft backward +!!$ fac=2./(nx*ny*nz) +!!$ +!!$ call rlft3(psix,su1x,su2x,-1) +!!$ call rlft3(psiy,su1y,su2y,-1) +!!$ call rlft3(psiz,su1z,su2z,-1) +!!$ +!!$ psix=fac*psix +!!$ psiy=fac*psiy +!!$ psiz=fac*psiz +!!$ +!!$ +!!$ !exa=f +!!$ !erreur +!!$ print*,"erreur" +!!$ print*,maxval(abs(psix-exax)),maxloc(abs(psix-exax)) +!!$ print*,maxval(abs(psiy-exay)),maxloc(abs(psiy-exay)) +!!$ print*,maxval(abs(psiz-exaz)),maxloc(abs(psiz-exaz)) +!!$ +!!$ print*,"dx**2",dx**2 +!!$ +!!$ +!!$ +!!$ deallocate (psix,exax,fx) +!!$ deallocate (psiy,exay,fy) +!!$ deallocate (psiz,exaz,fz) +!!$ deallocate(sf1x,su1x) +!!$ deallocate(sf1y,su1y) +!!$ deallocate(sf1z,su1z) +!!$ deallocate(sf2x,su2x) +!!$ deallocate(sf2y,su2y) +!!$ deallocate(sf2z,su2z) + + + + +end program test_fft diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/advection_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/advection_mod.f90 new file mode 100644 index 000000000..88c87c21f --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/advection_mod.f90 @@ -0,0 +1,711 @@ +module advection_mod + use donnees_mod + use tab_mod + use remaillage_mod + use interpolation_mod + use nrtype + USE nrutil + USE nr +contains + + subroutine def_v_advec (vitx,vity,vitz,tps) + implicit none + + real(kind=8),intent(in) :: tps + real(kind=8),dimension(1:nx_gro,1:ny_gro,1:nz_gro),intent(out) :: vitx,vity,vitz + integer :: i,j,k + real(kind=8) :: x,y,z + + + !------------------- + !deformation sphere: + !-------------------- + do k=1,nz_gro + z=zd+(k-1)*dz_gro + do j=1,ny_gro + y=yb+(j-1)*dy_gro + do i=1,nx_gro + x=xg+(i-1)*dx_gro + + vitx(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) + vity(i,j,k)=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) + vitz(i,j,k)=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 + + end do + end do + end do + + !---------------------------------- + !champ turbulent + !---------------------------------- + +!!$ allocate (vxgr(1:nx,1:ny,1:nz),vygr(1:nx,1:ny,1:nz),vzgr(1:nx,1:ny,1:nz)) +!!$ open(20,file='data_gh/datavelx',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((vxgr(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) +!!$ close(20) +!!$ +!!$ open(20,file='data_gh/datavely',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((vygr(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) +!!$ close(20) +!!$ +!!$ open(20,file='data_gh/datavelz',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((vzgr(i,j,k),i=1,nx_gro),j=1,nx_gro),k=1,nx_gro) +!!$ close(20) +!!$ +!!$ vitx=vxgr +!!$ vity=vygr +!!$ vitz=vzgr +!!$ deallocate (vxgr,vygr,vzgr) + + + end subroutine def_v_advec + + + subroutine vitesse_fft + implicit none + + complex(kind=8),dimension(:,:,:),pointer :: sf1x, sf1y, sf1z + complex(kind=8),dimension(:,:,:),pointer :: su1x, su1y, su1z + complex(kind=8),dimension(:,:),pointer :: sf2x, sf2y, sf2z + complex(kind=8),dimension(:,:),pointer :: su2x, su2y, su2z + + integer :: i,j,k,m,n,p + real(kind=8) :: fac,x,y,z,l1,l2,l3,kx,ky,kz,r2,coeff + complex(kind=8) :: coef + + + l1=(xd-xg) + l2=(yh-yb) + l3=(zf-zd) + + allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) + allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) + allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) + allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) + allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) + allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) + + + !fft forward + call rlft3(omgx,sf1x,sf2x,1) + call rlft3(omgy,sf1y,sf2y,1) + call rlft3(omgz,sf1z,sf2z,1) + + !frequence=0 : n=0 + !0<f<fc : 1<=n<=N/2-1 + !f=fc=-fc : n=N/2 + !-fc<f<0 : N/2+1<=n<=N-1 + + fac=2./(nx*ny*nz) ! pour normalisation de la fft inverse + + !calcul de la solution dans l'espace des frequences + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + do m=1,nx/2 + + if ( (m-1)<=(nx/2) ) then + kx=(m-1)/l1 + else + kx=(m-1-nx)/l1 + end if + + + + r2=kx**2+ky**2+kz**2 + coef=-fac*cmplx(0.,1.)/(2.*pi*r2) + + + su1x(m,n,p)=coef*(ky*sf1z(m,n,p)-kz*sf1y(m,n,p)) + if ((r2==0)) su1x(m,n,p)=0. + + su1y(m,n,p)=coef*(kz*sf1x(m,n,p)-kx*sf1z(m,n,p)) + if ((r2==0)) su1y(m,n,p)=0. + + su1z(m,n,p)=coef*(kx*sf1y(m,n,p)-ky*sf1x(m,n,p)) + if ((r2==0)) su1z(m,n,p)=0. + + + + end do + end do + end do + + m=nx/2+1 + kx=(m-1)/l1 + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + + + r2=kx**2+ky**2+kz**2 + coef=-fac*cmplx(0.,1.)/(2.*pi*r2) + + !poisson+vitess + su2x(n,p)=coef*(ky*sf2z(n,p)-kz*sf2y(n,p)) + su2y(n,p)=coef*(kz*sf2x(n,p)-kx*sf2z(n,p)) + su2z(n,p)=coef*(kx*sf2y(n,p)-ky*sf2x(n,p)) + + + !pour -omega et sans normalisation: + !--------------------------------- + !su2z(n,p)=-2.*pi*cmplx(0.,1.)*(-kx*sf2y(n,p)+ky*sf2x(n,p))/(4.*pi**2*r2) + !if ((r2==0)) su2z(n,p)=0. + + + + end do + end do + + !fft backward + + call rlft3(vxg,su1x,su2x,-1) + call rlft3(vyg,su1y,su2y,-1) + call rlft3(vzg,su1z,su2z,-1) + + deallocate(sf1x,su1x) + deallocate(sf1y,su1y) + deallocate(sf1z,su1z) + deallocate(sf2x,su2x) + deallocate(sf2y,su2y) + deallocate(sf2z,su2z) + + + end subroutine vitesse_fft + + + + + + + subroutine vitesse_fft_uinf + implicit none + + complex(kind=8),dimension(:,:,:),pointer :: sf1x, sf1y, sf1z + complex(kind=8),dimension(:,:,:),pointer :: su1x, su1y, su1z + complex(kind=8),dimension(:,:),pointer :: sf2x, sf2y, sf2z + complex(kind=8),dimension(:,:),pointer :: su2x, su2y, su2z + + integer :: i,j,k,m,n,p + real(kind=8) :: fac,x,y,z,l1,l2,l3,kx,ky,kz,r2,coeff,uinfx,uinfy + complex(kind=8) :: coef + + + l1=(xd-xg) + l2=(yh-yb) + l3=(zf-zd) + + allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) + allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) + allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) + allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) + allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) + allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) + + + !fft forward + call rlft3(omgx,sf1x,sf2x,1) + call rlft3(omgy,sf1y,sf2y,1) + call rlft3(omgz,sf1z,sf2z,1) + + !frequence=0 : n=0 + !0<f<fc : 1<=n<=N/2-1 + !f=fc=-fc : n=N/2 + !-fc<f<0 : N/2+1<=n<=N-1 + + fac=2./(nx*ny*nz) ! pour normalisation de la fft inverse + + !calcul de la solution dans l'espace des frequences + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + do m=1,nx/2 + + if ( (m-1)<=(nx/2) ) then + kx=(m-1)/l1 + else + kx=(m-1-nx)/l1 + end if + + + + r2=kx**2+ky**2+kz**2 + coef=-fac*cmplx(0.,1.)/(2.*pi*r2) + + + uinfx=(4.*(1./0.4844)**2)/((yh-yb)*(zf-zd))!debit*surface domaine physique/surface du domaine numérique + + !if ((time>=3.).and.(time<=4.)) then + ! uinfy=sin(pi*(time-3.)) + !else + uinfy=0. + !end if + + + su1x(m,n,p)=coef*(ky*sf1z(m,n,p)-kz*sf1y(m,n,p)) + if ((r2==0)) su1x(m,n,p)=2.*uinfx !atttention mettre 2*uinfx + + su1y(m,n,p)=coef*(kz*sf1x(m,n,p)-kx*sf1z(m,n,p)) + if ((r2==0)) su1y(m,n,p)=2.*uinfy + + su1z(m,n,p)=coef*(kx*sf1y(m,n,p)-ky*sf1x(m,n,p)) + if ((r2==0)) su1z(m,n,p)=0. + + + + end do + end do + end do + + m=nx/2+1 + kx=(m-1)/l1 + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + + + r2=kx**2+ky**2+kz**2 + coef=-fac*cmplx(0.,1.)/(2.*pi*r2) + + !poisson+vitess + su2x(n,p)=coef*(ky*sf2z(n,p)-kz*sf2y(n,p)) + su2y(n,p)=coef*(kz*sf2x(n,p)-kx*sf2z(n,p)) + su2z(n,p)=coef*(kx*sf2y(n,p)-ky*sf2x(n,p)) + + + !pour -omega et sans normalisation: + !--------------------------------- + !su2z(n,p)=-2.*pi*cmplx(0.,1.)*(-kx*sf2y(n,p)+ky*sf2x(n,p))/(4.*pi**2*r2) + !if ((r2==0)) su2z(n,p)=0. + + + + end do + end do + + !fft backward + + call rlft3(vxg,su1x,su2x,-1) + call rlft3(vyg,su1y,su2y,-1) + call rlft3(vzg,su1z,su2z,-1) + + deallocate(sf1x,su1x) + deallocate(sf1y,su1y) + deallocate(sf1z,su1z) + deallocate(sf2x,su2x) + deallocate(sf2y,su2y) + deallocate(sf2z,su2z) + + + end subroutine vitesse_fft_uinf + + + + + + + + + subroutine crea_part_x + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff*maxval(sqrt(omgx**2+omgy**2+omgz**2)) + npart=0 + numpg=0 + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + if (sqrt(omgx(i,j,k)**2+omgy(i,j,k)**2+omgz(i,j,k)**2)>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l3(vxg,x,y,z) + !vy(npart)=interpol_v_l3(vyg,x,y,z) + !vz(npart)=interpol_v_l3(vzg,x,y,z) + omx(npart)=omgx(i,j,k) + omy(npart)=omgy(i,j,k) + omz(npart)=omgz(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_x + + subroutine crea_part_y + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff*maxval(sqrt(omgx**2+omgy**2+omgz**2)) + npart=0 + numpg=0 + do k=1,nz + z=ztab(k) + do i=1,nx + x=xtab(i) + do j=1,ny + y=ytab(j) + + if (sqrt(omgx(i,j,k)**2+omgy(i,j,k)**2+omgz(i,j,k)**2)>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l3(vxg,x,y,z) + !vy(npart)=interpol_v_l3(vyg,x,y,z) + !vz(npart)=interpol_v_l3(vzg,x,y,z) + omx(npart)=omgx(i,j,k) + omy(npart)=omgy(i,j,k) + omz(npart)=omgz(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_y + + subroutine crea_part_z + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff*maxval(sqrt(omgx**2+omgy**2+omgz**2)) + npart=0 + numpg=0 + + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + do k=1,nz + z=ztab(k) + + if (sqrt(omgx(i,j,k)**2+omgy(i,j,k)**2+omgz(i,j,k)**2)>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + !vx(npart)=interpol_v_l3(vxg,x,y,z) + !vy(npart)=interpol_v_l3(vyg,x,y,z) + !vz(npart)=interpol_v_l3(vzg,x,y,z) + omx(npart)=omgx(i,j,k) + omy(npart)=omgy(i,j,k) + omz(npart)=omgz(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_z + + subroutine ad_euler_x + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + xp(i)=xp(i)+dt*vx(i) + end do + + end subroutine ad_euler_x + + subroutine ad_euler_y + implicit none + + integer :: i,j + real(kind=8) :: x,y + + do i=1,npart + yp(i)=yp(i)+dt*vy(i) + end do + + end subroutine ad_euler_y + + subroutine ad_euler_z + implicit none + + integer :: i + + do i=1,npart + zp(i)=zp(i)+dt*vz(i) + end do + + end subroutine ad_euler_z + + + + + + + !=============================== + !SPLITTING + !calcul de la vitesse pour une advection d'euler à l'ordre 2 ou 3 + !=============================== + + subroutine update_vx_2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5D0*dt*vx(ib) + yp1(ib)=yp(ib)+0.5D0*dt*vy(ib) + zp1(ib)=zp(ib)+0.5D0*dt*vz(ib) + end do + call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx) + deallocate(xp1,yp1,zp1) + end subroutine update_vx_2 + + subroutine update_vy_2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)-0.5D0*dt*vx(ib) + yp1(ib)=yp(ib)+0.5D0*dt*vy(ib) + zp1(ib)=zp(ib)+0.5D0*dt*vz(ib) + end do + call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy) + deallocate(xp1,yp1,zp1) + end subroutine update_vy_2 + + subroutine update_vz_2 + implicit none + integer :: ib + + allocate (xp1(1:npart),yp1(1:npart),zp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)-0.5D0*dt*vx(ib) + yp1(ib)=yp(ib)-0.5D0*dt*vy(ib) + zp1(ib)=zp(ib)+0.5D0*dt*vz(ib) + end do + call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz) + deallocate(xp1,yp1,zp1) + end subroutine update_vz_2 + + + + subroutine update_vx_3 + implicit none + integer :: ib + + + allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp1(1:npart),zp2(1:npart)) + allocate (vx1(1:npart),vx2(1:npart),vx3(1:npart),vx4(1:npart),vy1(1:npart),vz1(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)+2.D0*dt*vx(ib)/3.D0 + yp1(ib)=yp(ib)+2.D0*dt*vy(ib)/3.D0 + zp1(ib)=zp(ib)+2.D0*dt*vz(ib)/3.D0 + end do + + call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx1) + call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy1) + call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)+vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+vy1(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)+vz1(ib)) + end do + + call interpo_l3_3d(vxg,xp2,yp,zp,vx2) + call interpo_l3_3d(vxg,xp,yp2,zp,vx3) + call interpo_l3_3d(vxg,xp,yp,zp2,vx4) + + do ib=1,npart + vx(ib)=-0.5D0*vx(ib)+3.D0*vx1(ib)/4.D0+vx2(ib)/4.D0+vx3(ib)/4.D0+vx4(ib)/4.D0 + end do + + deallocate (xp1,xp2,yp1,yp2,zp1,zp2) + deallocate (vx1,vx2,vx3,vx4,vy1,vz1) + + + end subroutine update_vx_3 + + subroutine update_vy_3 + implicit none + integer :: ib,i,j + + allocate (xp0(1:npart),xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp1(1:npart),zp2(1:npart)) + allocate (vx1(1:npart),vz1(1:npart),vy1(1:npart),vy2(1:npart),vy3(1:npart),vy4(1:npart),vy5(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)-dt*vx(ib)/3.D0 + yp1(ib)=yp(ib)+2.D0*dt*vy(ib)/3.D0 + zp1(ib)=zp(ib)+2.D0*dt*vz(ib)/3.D0 + xp0(ib)=xp(ib)-4.D0*dt*vx(ib)/3.D0 + end do + + call interpo_l3_3d(vxg1,xp1,yp1,zp1,vx1) + call interpo_l3_3d(vyg1,xp1,yp1,zp1,vy1) + call interpo_l3_3d(vyg1,xp0,yp1,zp1,vy2) + call interpo_l3_3d(vzg1,xp0,yp1,zp1,vz1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(vx(ib)-2.D0*vx1(ib)) + yp2(ib)=yp(ib)+dt*(-vy(ib)+vy2(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)/4.D0+vz1(ib)/4.D0) + end do + + call interpo_l3_3d(vyg,xp2,yp,zp,vy3) + call interpo_l3_3d(vyg,xp,yp2,zp,vy4) + call interpo_l3_3d(vyg,xp,yp,zp2,vy5) + + do ib=1,npart + vy(ib)=-5.D0*vy(ib)/4.D0+3.D0*vy1(ib)/4.D0+vy3(ib)/4.D0+vy4(ib)/4.D0+vy5(ib) + end do + + + deallocate (xp0,xp1,xp2,yp1,yp2,zp1,zp2) + deallocate (vx1,vz1,vy1,vy2,vy3,vy4,vy5) + + end subroutine update_vy_3 + + subroutine update_vz_3 + implicit none + integer :: ib,i,j,k + + allocate (xp1(1:npart),xp2(1:npart),yp1(1:npart),yp2(1:npart),zp0(1:npart),zp1(1:npart),zp2(1:npart)) + allocate (vx1(1:npart),vy1(1:npart),vz1(1:npart),vz2(1:npart),vz3(1:npart),vz4(1:npart)) + + do ib=1,npart + xp1(ib)=xp(ib)-2.D0*dt*vx(ib)/3.D0 + yp1(ib)=yp(ib)-2.D0*dt*vy(ib)/3.D0 + zp1(ib)=zp(ib)+dt*vz(ib)/3.D0 + zp0(ib)=zp(ib)+4.D0*dt*vz(ib)/3.D0 + end do + + call interpo_l3_3d(vzg1,xp1,yp1,zp1,vz1) + call interpo_l3_3d(vxg2,xp1,yp1,zp0,vx1) + call interpo_l3_3d(vyg2,xp1,yp1,zp0,vy1) + + do ib=1,npart + xp2(ib)=xp(ib)+dt*(-vx(ib)+vx1(ib)) + yp2(ib)=yp(ib)+dt*(vy(ib)-vy1(ib)) + zp2(ib)=zp(ib)+dt*(-vz(ib)+2.D0*vz1(ib)) + end do + + call interpo_l3_3d(vzg,xp2,yp,zp,vz2) + call interpo_l3_3d(vzg,xp,yp2,zp,vz3) + call interpo_l3_3d(vzg3,xp,yp,zp2,vz4) + + do ib=1,npart + vz(ib)=3.D0*vz1(ib)/4.D0-vz2(ib)/4.D0+vz3(ib)/4.D0+vz4(ib)/4.D0 + end do + + + deallocate (xp1,xp2,yp1,yp2,zp0,zp1,zp2) + deallocate (vx1,vy1,vz1,vz2,vz3,vz4) + + end subroutine update_vz_3 + + + !================================== + !STRANG + !================================== + + subroutine update_vx_strang + implicit none + integer :: ib + + allocate (xp1(1:npart)) + do ib=1,npart + xp1(ib)=xp(ib)+0.5D0*dt*vx(ib) + end do + call interpo_l3_3d(vxg1,xp1,yp,zp,vx) + deallocate(xp1) + end subroutine update_vx_strang + + subroutine update_vy_strang + implicit none + integer :: ib + + allocate (yp1(1:npart)) + do ib=1,npart + yp1(ib)=yp(ib)+0.5D0*dt*vy(ib) + end do + call interpo_l3_3d(vyg1,xp,yp1,zp,vy) + deallocate(yp1) + end subroutine update_vy_strang + + subroutine update_vz_strang + implicit none + integer :: ib + + allocate (zp1(1:npart)) + do ib=1,npart + zp1(ib)=zp(ib)+0.5D0*dt*vz(ib) + end do + call interpo_l3_3d(vzg1,xp,yp,zp1,vz) + deallocate(zp1) + end subroutine update_vz_strang + + + + + + +end module advection_mod + + diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/donnees_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/donnees_mod.f90 new file mode 100644 index 000000000..00b50ba65 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/donnees_mod.f90 @@ -0,0 +1,12 @@ +module donnees_mod + + integer :: nx,ny,nz,nx_gro,ny_gro,nz_gro,npg,npart,ideb,ind_drag + integer :: kx,ky,kz,type_b,long_bloc,cpt_ite,nite_vtk,num_suite,sauv_cpt_ite + real(kind=8) :: time,dx,dy,dz,dx_gro,dy_gro,dz_gro,xg,xd,yb,yh,zd,zf,dt,tfin,cfl + real(kind=8) :: xdeb,cutoff,dt_sauv,lambda_flu,lambda_sol,lambda_por,pi,nu + real(kind=8) :: ix_2old,ix_old,ix_lift_2old,ix_lift_old + character(len=70) :: nom_fich_vtk,nom_fich_omg_nite,nom_fich_vit_nite,nom_fich_drag,nom_fich_coupev,name_relance + character(len=70) :: nom_fich_chi,nom_fich_lambda + + +end module donnees_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/drag_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/drag_mod.f90 new file mode 100644 index 000000000..60a00d4f9 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/drag_mod.f90 @@ -0,0 +1,279 @@ +module drag_mod + use donnees_mod + use tab_mod +contains + + function cd(f,u,d) + implicit none + real(kind=8),intent(in) :: f,u,d + real(kind=8) :: cd + !calcul du coeff de traine + !f=force scalaire x + !d=diametre (surface projette) + !u vitesse a l'infini + cd=2.*f/(u*u*d) + end function cd + + function cl(f,u,d) + implicit none + real(kind=8),intent(in) :: f,u,d + real(kind=8) :: cl + !calcul du coeff de portance + !f=force scalaire x + !d=diametre (surface projette) + !u vitesse a l'infini + cl=2.*f/(u*u*d) + end function cl + + + + + + + + + + + + + +!==================================== +!methode de l'impulsion +!===================================== + + function ix() + implicit none + real(kind=8) :: ix + integer :: i,j,k + real(kind=8) :: x,y,z,dvx,dvy,dvz + ix=0. + do i=1,nx + if ((i==1).or.(i==nx)) then + dvx=0.5*dx + else + dvx=dx + end if + do j=1,ny + if ((j==1).or.(j==ny)) then + dvy=0.5*dy + else + dvy=dy + end if + y=yb+(j-1)*dy + do k=1,nz + if ((k==1).or.(k==nz)) then + dvz=0.5*dz + else + dvz=dz + end if + z=zd+(k-1)*dz + + ix =ix-0.5*(y*omgz(i,j,k)-z*omgy(i,j,k))*dvx*dvy*dvz + end do + end do + end do + + end function ix + + function drag_tps() + implicit none + + real(kind=8) :: drag_tps + real(kind=8) :: f,ix_new + real(kind=8) :: rayon,uinf + + rayon=0.5 + uinf=1. + + !calcul du drag coeff pour t= time-dt + if(ind_drag==1)then + ix_2old=ix() + drag_tps=0. + else + if (ind_drag==2) then + ix_old=ix() + drag_tps=0. + else + ix_new=ix() + f=(ix_new-ix_2old)/(2.*dt) + ix_2old=ix_old + ix_old=ix_new + drag_tps=cd(f,uinf,2.*rayon) + + end if + end if + + end function drag_tps + + + function ix_lift()result(ix) + implicit none + real(kind=8) :: ix + integer :: i,j,k + real(kind=8) :: x,y,z,dvx,dvy,dvz + ix=0. + do i=1,nx + x=xg+(i-1)*dx + if ((i==1).or.(i==nx)) then + dvx=0.5*dx + else + dvx=dx + end if + do j=1,ny + if ((j==1).or.(j==ny)) then + dvy=0.5*dy + else + dvy=dy + end if + do k=1,nz + if ((k==1).or.(k==nz)) then + dvz=0.5*dz + else + dvz=dz + end if + z=zd+(k-1)*dz + + ix =ix-0.5*(z*omgx(i,j,k)-x*omgz(i,j,k))*dvx*dvy*dvz + end do + end do + end do + + end function ix_lift + + function lift_tps() + implicit none + + real(kind=8) :: lift_tps + real(kind=8) :: f,ix_lift_new + real(kind=8) :: rayon,uinf + + rayon=0.5 + uinf=1. + + !calcul du lift coeff pour t= time-dt + if(ind_drag==1)then + ix_lift_2old=ix_lift() + lift_tps=0. + else + if (ind_drag==2) then + ix_lift_old=ix_lift() + lift_tps=0. + else + ix_lift_new=ix_lift() + f=(ix_lift_new-ix_lift_2old)/(2.*dt) + ix_lift_2old=ix_lift_old + ix_lift_old=ix_lift_new + lift_tps=cl(f,uinf,2.*rayon) + + end if + end if + + end function lift_tps + + + + + + + + !======================================== + !methode de l'écoulement poreux + !=========================================== + + function drag_poreux() result(drag_po) + implicit none + real(kind=8) :: drag_po + integer :: i,j,k + real(kind=8) :: dvx,dvy,dvz + real(kind=8) :: rayon,uinf + + rayon=0.5 + uinf=1. + + + drag_po=0. + + + do i=1,nx + if ((i==1).or.(i==nx)) then + dvx=0.5*dx + else + dvx=dx + end if + do j=1,ny + if ((j==1).or.(j==ny)) then + dvy=0.5*dy + else + dvy=dy + end if + do k=1,nz + if ((k==1).or.(k==nz)) then + dvz=0.5*dz + else + dvz=dz + end if + drag_po =drag_po+lambda(i,j,k)*chi_sphere(i,j,k)*vxg(i,j,k)*dvx*dvy*dvz + end do + end do + end do + + + drag_po=cd(drag_po,uinf,2.*rayon) + + end function drag_poreux + + function lift_poreux() result(lift_po) + implicit none + real(kind=8) :: lift_po + integer :: i,j,k + real(kind=8) :: dvx,dvy,dvz + real(kind=8) :: rayon,uinf + + rayon=0.5 + uinf=1. + + + lift_po=0. + + + do i=1,nx + if ((i==1).or.(i==nx)) then + dvx=0.5*dx + else + dvx=dx + end if + do j=1,ny + if ((j==1).or.(j==ny)) then + dvy=0.5*dy + else + dvy=dy + end if + do k=1,nz + if ((k==1).or.(k==nz)) then + dvz=0.5*dz + else + dvz=dz + end if + lift_po =lift_po+lambda(i,j,k)*chi_sphere(i,j,k)*vyg(i,j,k)*dvx*dvy*dvz + end do + end do + end do + + + lift_po=cd(lift_po,uinf,2.*rayon) + + end function lift_poreux + + + + + + + + + + + +end module drag_mod + + diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/four2.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/four2.f90 new file mode 100644 index 000000000..a7a86c804 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/four2.f90 @@ -0,0 +1,12 @@ + SUBROUTINE four2(data,isign) + USE nrtype + USE nr, ONLY : fourrow + IMPLICIT NONE + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + COMPLEX(SPC), DIMENSION(size(data,2),size(data,1)) :: temp + call fourrow(data,isign) + temp=transpose(data) + call fourrow(temp,isign) + data=transpose(temp) + END SUBROUTINE four2 diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/four3.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/four3.f90 new file mode 100644 index 000000000..58197a672 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/four3.f90 @@ -0,0 +1,19 @@ +SUBROUTINE four3(data,isign) + USE nrtype + USE nr, ONLY : fourrow_3d + IMPLICIT NONE + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + COMPLEX(SPC), DIMENSION(:,:,:), ALLOCATABLE :: dat2,dat3 + + call fourrow_3d(data,isign) + allocate(dat2(size(data,2),size(data,3),size(data,1))) + dat2=reshape(data,shape=shape(dat2),order=(/3,1,2/)) + call fourrow_3d(dat2,isign) + allocate(dat3(size(data,3),size(data,1),size(data,2))) + dat3=reshape(dat2,shape=shape(dat3),order=(/3,1,2/)) + deallocate(dat2) + call fourrow_3d(dat3,isign) + data=reshape(dat3,shape=shape(data),order=(/3,1,2/)) + deallocate(dat3) +END SUBROUTINE four3 diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow.f90 new file mode 100644 index 000000000..d51895841 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow.f90 @@ -0,0 +1,89 @@ + SUBROUTINE fourrow_sp(data,isign) + USE nrtype; USE nrutil, ONLY : assert,swap + IMPLICIT NONE + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + INTEGER(I4B) :: n,i,istep,j,m,mmax,n2 + REAL(DP) :: theta + COMPLEX(SPC), DIMENSION(size(data,1)) :: temp + COMPLEX(DPC) :: w,wp + COMPLEX(SPC) :: ws + n=size(data,2) + call assert(iand(n,n-1)==0, 'n must be a power of 2 in fourrow_sp') + n2=n/2 + j=n2 + do i=1,n-2 + if (j > i) call swap(data(:,j+1),data(:,i+1)) + m=n2 + do + if (m < 2 .or. j < m) exit + j=j-m + m=m/2 + end do + j=j+m + end do + mmax=1 + do + if (n <= mmax) exit + istep=2*mmax + theta=PI_D/(isign*mmax) + wp=cmplx(-2.0_dp*sin(0.5_dp*theta)**2,sin(theta),kind=dpc) + w=cmplx(1.0_dp,0.0_dp,kind=dpc) + do m=1,mmax + ws=w + do i=m,n,istep + j=i+mmax + temp=ws*data(:,j) + data(:,j)=data(:,i)-temp + data(:,i)=data(:,i)+temp + end do + w=w*wp+w + end do + mmax=istep + end do + END SUBROUTINE fourrow_sp + + SUBROUTINE fourrow_dp(data,isign) + USE nrtype; USE nrutil, ONLY : assert,swap + IMPLICIT NONE + COMPLEX(DPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + INTEGER(I4B) :: n,i,istep,j,m,mmax,n2 + REAL(DP) :: theta + COMPLEX(DPC), DIMENSION(size(data,1)) :: temp + COMPLEX(DPC) :: w,wp + COMPLEX(DPC) :: ws + n=size(data,2) + call assert(iand(n,n-1)==0, 'n must be a power of 2 in fourrow_dp') + n2=n/2 + j=n2 + do i=1,n-2 + if (j > i) call swap(data(:,j+1),data(:,i+1)) + m=n2 + do + if (m < 2 .or. j < m) exit + j=j-m + m=m/2 + end do + j=j+m + end do + mmax=1 + do + if (n <= mmax) exit + istep=2*mmax + theta=PI_D/(isign*mmax) + wp=cmplx(-2.0_dp*sin(0.5_dp*theta)**2,sin(theta),kind=dpc) + w=cmplx(1.0_dp,0.0_dp,kind=dpc) + do m=1,mmax + ws=w + do i=m,n,istep + j=i+mmax + temp=ws*data(:,j) + data(:,j)=data(:,i)-temp + data(:,i)=data(:,i)+temp + end do + w=w*wp+w + end do + mmax=istep + end do + END SUBROUTINE fourrow_dp diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow_3d.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow_3d.f90 new file mode 100644 index 000000000..0dde413d4 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/fourrow_3d.f90 @@ -0,0 +1,44 @@ + SUBROUTINE fourrow_3d(data,isign) + USE nrtype; USE nrutil, ONLY : assert,swap + IMPLICIT NONE + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + INTEGER(I4B) :: n,i,istep,j,m,mmax,n2 + REAL(DP) :: theta + COMPLEX(SPC), DIMENSION(size(data,1),size(data,2)) :: temp + COMPLEX(DPC) :: w,wp + COMPLEX(SPC) :: ws + n=size(data,3) + call assert(iand(n,n-1)==0, 'n must be a power of 2 in fourrow_3d') + n2=n/2 + j=n2 + do i=1,n-2 + if (j > i) call swap(data(:,:,j+1),data(:,:,i+1)) + m=n2 + do + if (m < 2 .or. j < m) exit + j=j-m + m=m/2 + end do + j=j+m + end do + mmax=1 + do + if (n <= mmax) exit + istep=2*mmax + theta=PI_D/(isign*mmax) + wp=cmplx(-2.0_dp*sin(0.5_dp*theta)**2,sin(theta),kind=dpc) + w=cmplx(1.0_dp,0.0_dp,kind=dpc) + do m=1,mmax + ws=w + do i=m,n,istep + j=i+mmax + temp=ws*data(:,:,j) + data(:,:,j)=data(:,:,i)-temp + data(:,:,i)=data(:,:,i)+temp + end do + w=w*wp+w + end do + mmax=istep + end do + END SUBROUTINE fourrow_3d diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/init_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/init_mod.f90 new file mode 100644 index 000000000..f04a9dd77 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/init_mod.f90 @@ -0,0 +1,179 @@ +module init_mod + ! + !initialisation des valeurs sur la grille + ! +contains + subroutine init_grille + use donnees_mod + use tab_mod + implicit none + integer :: i,j,k,i_tmp + real(kind=8) :: x,y,z, ct,t2 + real :: romgx,romgy,romgz,r_tmp + character(len=70):: text_tmp + + + !--------------- + ! 0 + !--------------- +!!$ omgx=0. +!!$ omgy=0. +!!$ omgz=0. + !------------------------- + ! test poiseuille + !-------------------------- + +!!$ +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ do i=1,nx +!!$ omgx(i,j,k)=0. +!!$ omgy(i,j,k)=0. +!!$ if ( (z.ge.-1.).and.(z.le.1.)) then +!!$ omgy(i,j,k)=-3.*z/(4.*0.5*(yh-yb)) +!!$ else +!!$ omgy(i,j,k)=0. +!!$ end if +!!$ omgz(i,j,k)=0. +!!$ end do +!!$ end do +!!$ end do + + !--------------------------------- + ! test poiseuille/sphere + !-------------------------------- + + do k=1,nz + do j=1,ny + y=ytab(j) + do i=1,nx + omgx(i,j,k)=0. + omgy(i,j,k)=0. + omgz(i,j,k)=0. + if ( (y.ge.-(1./0.4844)).and.(y.le.(1./0.4844))) then + omgz(i,j,k)=3.*y/((1./0.4844)**2) + end if + end do + end do + end do + +!!$ +!!$ +!!$ !--------------- +!!$ ! 1 +!!$ !--------------- +!!$ omgx=1. +!!$ omgy=1. +!!$ omgz=1. + +!!$ !--------------- +!!$ !test analytique +!!$ !--------------- +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ y=ytab(j) +!!$ do i=1,nx +!!$ x=xtab(i) +!!$ +!!$ !ct=cos(pi*time) +!!$ ct=1.D0 +!!$ +!!$ omgx(i,j,k)=-2.*pi*sin(2.*pi*x)*cos(2.*pi*y)*sin(pi*z)**2*ct & +!!$ +2.*pi*sin(2.*pi*x)*sin(pi*y)**2*cos(2.*pi*z)*ct +!!$ omgy(i,j,k)=4.*pi*sin(pi*x)**2*sin(2.*pi*y)*cos(2.*pi*z)*ct & +!!$ +2.*pi*cos(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2*ct +!!$ omgz(i,j,k)=-2.*pi*cos(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z)*ct& +!!$ -4.*pi*sin(pi*x)**2*cos(2.*pi*y)*sin(2.*pi*z)*ct +!!$ +!!$ ! omgx(i,j,k)=1. +!!$ ! omgy(i,j,k)=0. +!!$ ! omgz(i,j,k)=0. +!!$ +!!$ end do +!!$ end do +!!$ end do + + +!!$ !---------------------------- +!!$ !vorticite turbulente de GH +!!$ !----------------------------- +!!$ +!!$ allocate (omgxr(1:nx,1:ny,1:nz),omgyr(1:nx,1:ny,1:nz),omgzr(1:nx,1:ny,1:nz)) +!!$ +!!$ open(20,file='data_gh/datax',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((omgxr(i,j,k),i=1,nx),j=1,ny),k=1,nz) +!!$ close(20) +!!$ +!!$ open(20,file='data_gh/datay',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((omgyr(i,j,k),i=1,nx),j=1,ny),k=1,nz) +!!$ close(20) +!!$ +!!$ open(20,file='data_gh/dataz',form='unformatted',convert='big_endian',status='unknown') +!!$ read(20) (((omgzr(i,j,k),i=1,nx),j=1,ny),k=1,nz) +!!$ close(20) +!!$ +!!$ omgx=omgxr +!!$ omgy=omgyr +!!$ omgz=omgzr +!!$ +!!$ deallocate (omgxr,omgyr,omgzr) + + + +!!$ if (num_suite==1) then +!!$ open(unit=25,file=trim(name_relance),form="formatted") +!!$ +!!$ read(25,'(A26)')text_tmp +!!$ read(25,'(A7)')text_tmp +!!$ read(25,'(A5)')text_tmp +!!$ read(25,'(A25)')text_tmp +!!$ read(25,'(A10,3(i4,1x))')text_tmp,i_tmp,i_tmp,i_tmp +!!$ read(25,'(a6,3(f10.5))')text_tmp,r_tmp,r_tmp,r_tmp +!!$ read(25,'(A7,3(f10.5))')text_tmp,r_tmp,r_tmp,r_tmp +!!$ +!!$ +!!$ read(25,'(A10,i10)') text_tmp,i_tmp +!!$ read(25,'(A21)') text_tmp +!!$ +!!$ do k=1,nz +!!$ do j=1,ny +!!$ do i=1,nx +!!$ read(25,'(3(f20.9))') romgx,romgy,romgz +!!$ omgx(i,j,k)=romgx +!!$ omgy(i,j,k)=romgy +!!$ omgz(i,j,k)=romgz +!!$ end do +!!$ end do +!!$ end do +!!$ close(25) +!!$ end if + + + + + + +!!$ +!!$ do k=1,nz +!!$ do j=1,ny +!!$ do i=1,nx +!!$ write(11,'(3(f20.9))') real(omgx(i,j,k)),real(omgy(i,j,k)),real(omgz(i,j,k)) +!!$ end do +!!$ end do +!!$ end do + + + + + + + + + + end subroutine init_grille + + + +end module init_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/interpolation_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/interpolation_mod.f90 new file mode 100644 index 000000000..e2f00c7ec --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/interpolation_mod.f90 @@ -0,0 +1,365 @@ +module interpolation_mod + use donnees_mod + contains + + subroutine interpo_l3_3d(tab_grille,posx,posy,posz,tab_part) + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_grille + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:npart),intent(out) :: tab_part + integer :: i,c,d,e,ib,jb + integer,dimension(0:3) :: ip,jp,kp + real(kind=8),dimension(0:3) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1 + + tab_part(1:npart)=0. + + !interpole en 2d la vorticite sur la grille en fonction de la position des particules et de leur vorticité + !--------------------------------------------------------------------------------------------------------- + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(1) = floor((posx(i)-xg)/dx_gro) + ip(0) = ip(1) - 1 + ip(2) = ip(1) + 1 + ip(3) = ip(1) + 2 + + jp(1) = floor((posy(i)-yb)/dy_gro) + jp(0) = jp(1) - 1 + jp(2) = jp(1) + 1 + jp(3) = jp(1) + 2 + + kp(1) = floor((posz(i)-zd)/dz_gro) + kp(0) = kp(1) - 1 + kp(2) = kp(1) + 1 + kp(3) = kp(1) + 2 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(1),kind=8)*dx_gro-xg)/dx_gro + yy1 = (posy(i) - real(jp(1),kind=8)*dy_gro-yb)/dy_gro + zz1 = (posz(i) - real(kp(1),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + + do c=0,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=0,3 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + + !calcul des poids + !---------------- + poidx(0)=-1./6.*xx1*(xx1-1.)*(xx1-2.) + poidx(1)=0.5*(1.-xx1)*(1.+xx1)*(2.-xx1) + poidx(2)=-0.5*xx1*(xx1+1.)*(xx1-2.) + poidx(3)=1/6.*xx1*(1.+xx1)*(xx1-1.) + + poidy(0)=-1./6.*yy1*(yy1-1.)*(yy1-2.) + poidy(1)=0.5*(1.-yy1)*(1.+yy1)*(2.-yy1) + poidy(2)=-0.5*yy1*(yy1+1.)*(yy1-2.) + poidy(3)=1/6.*yy1*(1.+yy1)*(yy1-1.) + + poidz(0)=-1./6.*zz1*(zz1-1.)*(zz1-2.) + poidz(1)=0.5*(1.-zz1)*(1.+zz1)*(2.-zz1) + poidz(2)=-0.5*zz1*(zz1+1.)*(zz1-2.) + poidz(3)=1/6.*zz1*(1.+zz1)*(zz1-1.) + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,3 + do d=0,3 + do c=0,3 + tab_part(i)=tab_part(i)+tab_grille(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine interpo_l3_3d + + + + + + + + !=========================================================================== + !pour interpoler le champ de vitesse de la grille grossiere à la grille fine + !=========================================================================== + + + function interpol_v_l1(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(0:1) :: ip,jp,kp + real(kind=8),dimension(0:1) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(1) = ip(0)+1 + + jp(0) = floor((posy-yb)/dy_gro) + jp(1) = jp(0)+1 + + kp(0) = floor((posz-zd)/dz_gro) + kp(1) = kp(0)+1 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=0,1 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=0,1 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=0,1 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(0)=1.-xx + poidx(1)=xx + + poidy(0)=1.-yy + poidy(1)=yy + + poidz(0)=1.-zz + poidz(1)=zz + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,1 + do c=0,1 + do d=0,1 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + + end function interpol_v_l1 + + function interpol_v_l3(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(-1:2) :: ip,jp,kp + real(kind=8),dimension(-1:2) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + + kp(0) = floor((posz-zd)/dz_gro) + kp(-1) = kp(0)-1 + kp(1) = kp(0)+1 + kp(2) = kp(0)+2 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=-1,2 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-1,2 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=-1,2 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + poidx(-1)=-1./6.*xx*(xx-1.)*(xx-2.) + poidx(0)=0.5*(1.-xx)*(1.+xx)*(2.-xx) + poidx(1)=-0.5*xx*(xx+1.)*(xx-2.) + poidx(2)=1/6.*xx*(1.+xx)*(xx-1.) + + poidy(-1)=-1./6.*yy*(yy-1.)*(yy-2.) + poidy(0)=0.5*(1.-yy)*(1.+yy)*(2.-yy) + poidy(1)=-0.5*yy*(yy+1.)*(yy-2.) + poidy(2)=1/6.*yy*(1.+yy)*(yy-1.) + + poidz(-1)=-1./6.*zz*(zz-1.)*(zz-2.) + poidz(0)=0.5*(1.-zz)*(1.+zz)*(2.-zz) + poidz(1)=-0.5*zz*(zz+1.)*(zz-2.) + poidz(2)=1/6.*zz*(1.+zz)*(zz-1.) + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-1,2 + do c=-1,2 + do d=-1,2 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidy(e) + end do + end do + end do + + end function interpol_v_l3 + + function interpol_v_l5(tab_gro,posx,posy,posz) result (v) + use tab_mod + implicit none + + real(kind=8),dimension(:,:,:),intent(in) :: tab_gro + real(kind=8),intent(in) :: posx,posy,posz + real(kind=8) :: v + integer,dimension(-2:3) :: ip,jp,kp + real(kind=8),dimension(-2:3) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + integer :: c,d,e + real(kind=8) :: x2,x3,x4,x5,y2,y3,y4,y5 + + v=0. + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx-xg)/dx_gro) !de 0 à nx_gro -1 + ip(-2) = ip(0)-2 + ip(-1) = ip(0)-1 + ip(1) = ip(0)+1 + ip(2) = ip(0)+2 + ip(3) = ip(0)+3 + + jp(0) = floor((posy-yb)/dy_gro) + jp(-2) = jp(0)-2 + jp(-1) = jp(0)-1 + jp(1) = jp(0)+1 + jp(2) = jp(0)+2 + jp(3) = jp(0)+3 + + kp(0) = floor((posz-zd)/dz_gro) + kp(-2) = kp(0)-2 + kp(-1) = kp(0)-1 + kp(1) = kp(0)+1 + kp(2) = kp(0)+2 + kp(3) = kp(0)+3 + + + !distance de la particule à remailler au premier point gauche + !----------------------------------------------------------- + xx = (posx - real(ip(0),kind=8)*dx_gro-xg)/dx_gro + yy = (posy - real(jp(0),kind=8)*dy_gro-yb)/dy_gro + zz = (posz - real(kp(0),kind=8)*dz_gro-zd)/dz_gro + + !conditions au bord + !------------------ + !periodique: + do c=-2,3 + ip(c)=mod(ip(c)+nx_gro,nx_gro) + end do + + do c=-2,3 + jp(c)=mod(jp(c)+ny_gro,ny_gro) + end do + + do c=-2,3 + kp(c)=mod(kp(c)+nz_gro,nz_gro) + end do + + !calcul des poids + !---------------- + x2=xx**2 + x3=xx**3 + x4=xx**4 + x5=xx**5 + y2=yy**2 + y3=yy**3 + y4=yy**4 + y5=yy**5 + + poidx(-2)=xx/20.-x2/24.-x3/24.+x4/24.-x5/120. + poidx(-1)=-xx/2.+2.*x2/3.-x3/24.-x4/6.+x5/24. + poidx(0)=1.-xx/3.-5*x2/4.+5.*x3/12.+x4/4.-x5/12. + poidx(1)=xx+2.*x2/3.-7.*x3/12.-x4/6.+x5/12. + poidx(2)=-xx/4.-x2/24.+7.*x3/24.+x4/24.-x5/24. + poidx(3)=xx/30.-x3/24.+x5/120. + + poidy(-2)=yy/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidy(-1)=-yy/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidy(0)=1.-yy/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidy(1)=yy+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidy(2)=-yy/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidy(3)=yy/30.-y3/24.+y5/120. + + poidz(-2)=zz/20.-y2/24.-y3/24.+y4/24.-y5/120. + poidz(-1)=-zz/2.+2.*y2/3.-y3/24.-y4/6.+y5/24. + poidz(0)=1.-zz/3.-5*y2/4.+5.*y3/12.+y4/4.-y5/12. + poidz(1)=zz+2.*y2/3.-7.*y3/12.-y4/6.+y5/12. + poidz(2)=-zz/4.-y2/24.+7.*y3/24.+y4/24.-y5/24. + poidz(3)=zz/30.-y3/24.+y5/120. + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-2,3 + do c=-2,3 + do d=-2,3 + v=v+tab_gro(ip(c)+1,jp(d)+1,kp(e)+1)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + + end function interpol_v_l5 + + + + + end module interpolation_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/main.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/main.f90 new file mode 100644 index 000000000..5506bf9d8 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/main.f90 @@ -0,0 +1,568 @@ +program NS + !-------------------------------------------------------------------------- + !resolution Navier Stokes + penalisation en periodoque + ! + !-------------------------------------------------------------------------- + use donnees_mod ! donnees + use tab_mod ! donnees dans tableaux + use init_mod ! init_grille + use advection_mod ! crea_part,advection + use remaillage_mod ! remaill_4m_centre (formules de remaillage) + use interpolation_mod ! formules d'interpolation (pour range kutta) + use resultats_mod ! res_grille_tps,res_grille_freq + use utile_mod + use penal_mod + use source_mod ! diffusion + strech (+ penal) + use drag_mod !calcul drag/lift + use old_mod ! ancien algo + + real(kind=8) :: x,y,z + integer :: n ,indi1,indi2,indj,indk + real(kind=8) :: time1,time2,time3,time4,maxv,dragi,dragp,lifti,liftp + + !pour test + integer :: c,i,j,ib,jb,k,cpt,nx_boucle + real(kind=8) :: t1,t2,t3,t4,t5,t6,t7,t8,t9,tmp,dt_boucle,r,grad,div,vexa,omexa + real(kind=8),dimension(1:3) :: pen + + !lecture données + !--------------- + open(unit=10,file="parameter",form="formatted") + read(10,*) xg,xd,yb,yh,zd,zf + read(10,*) nx,ny,nz + read(10,*) tfin + read(10,*) cutoff + read(10,*) type_b + read(10,*) long_bloc + read(10,*) nom_fich_vtk + read(10,*) lambda_flu,lambda_sol,lambda_por + read(10,*) nu + read(10,*) nom_fich_omg_nite,nom_fich_vit_nite,nom_fich_chi,nom_fich_lambda,nite_vtk + read(10,*) nom_fich_coupev,nom_fich_drag + read(10,*) num_suite,sauv_cpt_ite,name_relance + close(10) + + + nx_gro=nx + ny_gro=nx_gro + nz_gro=nx_gro + + dx=(xd-xg)/(nx-1.) + dy=(yh-yb)/(ny-1.) + dz=(zf-zd)/(nz-1.) + + dx_gro=(xd-xg)/(nx_gro-1.) + dy_gro=(yh-yb)/(ny_gro-1.) + dz_gro=(zf-zd)/(nz_gro-1.) + + + + !maxv=1.D0 + !maxv=2.D0 + !cfl=0.4D0 + + + !dt=cfl*dx/maxv + !dt=0.0125 + !dt=0.001 + !dt=min(cfl*dx/maxv,cfl pour diffusion) + dt=0.005 + !dt=0.01 + !dt=3./8.*dx**2/nu + + print*,"dt",dt + + ! + !calcul init + !----------- + cpt_ite=0 + time=0.D0 + ind_drag=0 + if (num_suite==1) then + cpt_ite=sauv_cpt_ite + time=cpt_ite*dt + end if + + npart=nx*ny*nz + + nx=nx-1 + ny=ny-1 + nz=nz-1 + + nx_gro=nx_gro-1 + ny_gro=ny_gro-1 + nz_gro=nz_gro-1 + + + PI=3.141592653589793238462643383279502884197D0 + + + ! + !alloc tableaux + !-------------- + allocate (vxg(1:nx_gro,1:ny_gro,1:nz_gro),vyg(1:nx_gro,1:ny_gro,1:nz_gro),vzg(1:nx_gro,1:ny_gro,1:nz_gro)) + allocate (omgx(1:nx,1:ny,1:nz),omgy(1:nx,1:ny,1:nz),omgz(1:nx,1:ny,1:nz)) + allocate (xp(1:npart),qp(1:npart),vx(1:npart),yp(1:npart),vy(1:npart),zp(1:npart),vz(1:npart)) + allocate (omx(1:npart),omy(1:npart),omz(1:npart)) + allocate (xtab(1:nx),ytab(1:ny),ztab(1:nz)) + allocate (chi(1:nx,1:ny,1:nz),chi_sphere(1:nx,1:ny,1:nz),lambda(1:nx,1:ny,1:nz)) + + !pour la correction de consistance + allocate (numpg(1:nx,1:ny,1:nz)) + allocate (blocg(0:npart),blocd(0:npart),Nbloc(0:npart)) + + + allocate (deb1(1:nx,1:ny,1:nz),deb2(1:nx,1:ny,1:nz),deb3(1:nx,1:ny,1:nz)) + + allocate(stxg(1:nx,1:ny,1:nz),styg(1:nx,1:ny,1:nz),stzg(1:nx,1:ny,1:nz)) + allocate(stx(1:npart),sty(1:npart),stz(1:npart)) + + open(unit=12,file=trim(nom_fich_drag),form="formatted") + open(unit=13,file=trim(nom_fich_coupev),form="formatted") + open(unit=14,file="RES/test/fich1.deb",form="formatted") + open(unit=15,file="RES/test/fich2.deb",form="formatted") + open(unit=16,file="RES/test/fich3.deb",form="formatted") + open(unit=17,file="RES/test/fich4.deb",form="formatted") + open(unit=18,file="RES/test/fich5.deb",form="formatted") + open(unit=19,file="RES/test/fich6.deb",form="formatted") + open(unit=20,file="RES/test/fich7.deb",form="formatted") + + + + + !================= + !initialisations + !================= + call make_grille + call make_chi + call init_grille() + + call res_vtk_chi(nom_fich_chi) + call res_vtk_lambda(nom_fich_lambda) + !============================================================ + !test: v->w retrouve par fft + ! + !si fonction en sin avec div=0 => erreur de 10-8 + ! si " " " " div/=0 => erreur elevée + ! doit regulariser et avoir u1diff(chi,x1)+ u2diff(chi,x2)+ u3diff(chi,x3)=0 + ! la vitesse apres penalisatin n'est pas à div nulle + ! mais celle calcule apres (a partir de la vorticite) est à div nulle + !============================================================= +!!$ do k=1,nz +!!$ z=ztab(k) +!!$ do j=1,ny +!!$ y=ytab(j) +!!$ do i=1,nx +!!$ x=xtab(i) +!!$ !vxg(i,j,k)=(1.-(x**2+y**2+z**2))**6 +!!$ !if ( (x**2+y**2+z**2)>1. ) vxg(i,j,k)=0. +!!$ !vxg(i,j,k)=cos(2.*Pi*x)!divu/=0 +!!$ vxg(i,j,k)=(1.-chi(i,j,k))*y +!!$ !if ( (x**2+y**2+z**2)<0.5 ) vxg(i,j,k)=0. +!!$ vyg(i,j,k)=(1.-chi(i,j,k))*(-x) +!!$ vzg(i,j,k)=0. +!!$ +!!$ +!!$ +!!$ !vxg(i,j,k)=2.*sin(pi*x)**2*sin(2.*pi*y)*sin(2.*pi*z) +!!$ !vyg(i,j,k)=-sin(2.*pi*x)*sin(pi*y)**2*sin(2.*pi*z) +!!$ !vzg(i,j,k)=-sin(2.*pi*x)*sin(2.*pi*y)*sin(pi*z)**2 +!!$ +!!$ end do +!!$ end do +!!$ end do +!!$ call res_vtk_omega(trim("RES/vtk/test_omg1.vtk")) +!!$ call res_vtk_vit(trim("RES/vtk/test_vg1.vtk")) +!!$ deb1=vxg +!!$ deb2=vyg +!!$ deb3=vzg +!!$ +!!$ call penal_fft ! calcul w=rot(v) par fft +!!$ +!!$ +!!$ +!!$ call res_vtk_omega(trim("RES/vtk/test_omg2.vtk")) +!!$ +!!$ call vitesse_fft_uinf +!!$ !call vitesse_fft_uavt +!!$ call res_vtk_vit(trim("RES/vtk/test_vg2.vtk")) +!!$ +!!$ print*,"erreur" +!!$ print*,maxval(abs(deb1-vxg)),maxval(abs(deb2-vyg)),maxval(abs(deb3-vzg)) +!!$ print*,"dx",dx +!!$ stop + + + + !=================== + !iterations en temps + !=================== + + temps: do while(time<tfin) + + if ((time+dt)>tfin) dt=tfin-time + + !======================= + !calcul champ de vitesse + !======================== + !call def_v_advec (vxg,vyg,vzg,time) + !call vitesse_fft + call cpu_time(t1) + call vitesse_fft_uinf + call cpu_time(t2) + + + !call imposer_debit(vxg,4.d0*2.06441*2.06441,nx,ny,nz,dx,dy,dz) + + !call imposer_debit(vxg,1.d0,nx,ny,nz,dx,dy,dz) + !vxg=vxg+1./(4.*1.*1.5) !debit=debit voulu +c*surface du domaine num, c etant la constante à ajouter au champ de vitesse. + + !test la valeur du débit + !----------------------- +!!$ t4=0. +!!$ do k=1,nz +!!$ do j=1,ny +!!$ t4=t4+vxg(1,j,k) +!!$ end do +!!$ end do +!!$ print*, "debit i=1 ",t4*dy*dz +!!$ print*,"bulk velocity",t4*dy*dz/(4.*(1./0.4854)**2) + + +!-------------------------test calcul vitesse avec omg exact------------------------------------------------------ +!!$ indi1=1 +!!$ indi2=nx/2 +!!$ indk1=1 +!!$ indk2=nz/2 +!!$ +!!$ do indj=1,ny +!!$ if ( ((yb+(indj-1)*dy).ge.-(1./0.4844)).and.((yb+(indj-1)*dy).le.(1./0.4844))) then +!!$ vexa=1.5*(1.-(yb+(indj-1)*dy)**2/(1./0.4844)**2) +!!$ omexa=3.*(yb+(indj-1)*dy)/((1./0.4844)**2) +!!$ else +!!$ vexa=0. +!!$ omexa=0. +!!$ end if +!!$ write(14,'(8(e25.15,2x))') time,yb+(indj-1)*dy,vxg(indi1,indj,indk1),omgz(indi1,indj,indk1),vexa,omexa,vxg(indi2,indj,indk2),omgz(indi2,indj,indk2) +!!$ end do +!!$!stop +!------------------------------------------------------------------------------------------------------ + + + + !penalisation: nouveau calcul de v + !--------------------------------- + do k=1,nz + do j=1,ny + do i=1,nx + + !tmp=exp(-lambda*dt*chi(i,j,k)) + tmp=1./(1.+lambda(i,j,k)*dt*chi(i,j,k)) + vxg(i,j,k)=vxg(i,j,k)*tmp + vyg(i,j,k)=vyg(i,j,k)*tmp + vzg(i,j,k)=vzg(i,j,k)*tmp + + end do + end do + end do + + call cpu_time(t3) + + !resultats + !--------- + + !-----------------(poiseuil en y)--------------------------------------- +!!$ call res_vtk_nite(nom_fich_omg_nite,nom_fich_vit_nite,nite_vtk,time) +!!$ indi1=-xg/dx+1 +!!$ indi2=(0.7-xg)/dx+1 +!!$ indj=-yb/dy+1 +!!$ if (mod(cpt_ite,5)==0) then +!!$ do indk=1,nz +!!$ if ( ((zd+(indk-1)*dz).ge.-1.).and.((zd+(indk-1)*dz).le.1.)) then +!!$ vexa=1.5*(1.-(zd+(indk-1)*dz)**2)/(4.*0.5*abs(yh-yb)) +!!$ omexa=-3.*(zd+(indk-1)*dz)/(4.*0.5*abs(yh-yb)) +!!$ else +!!$ vexa=0. +!!$ omexa=0. +!!$ end if +!!$ write(13,'(8(e25.15,2x))') time,zd+(indk-1)*dz,vxg(indi1,indj,indk),omgy(indi1,indj,indk),vexa,omexa,vxg(indi2,indj,indk),omgy(indi2,indj,indk) +!!$ end do +!!$ end if + !--------------------------------------------------------------------------- + + + !-----------------(poiseuil en z)--------------------------------------- +! call res_vtk_nite(nom_fich_omg_nite,nom_fich_vit_nite,nite_vtk,time) + indi1=1 + indi2=nx/2 + indk1=1 + indk2=nz/2 + if (mod(cpt_ite,20)==0) then + do indj=1,ny + if ( ((yb+(indj-1)*dy).ge.-(1./0.4844)).and.((yb+(indj-1)*dy).le.(1./0.4844))) then + vexa=1.5*(1.-(yb+(indj-1)*dy)**2/(1./0.4844)**2) + omexa=3.*(yb+(indj-1)*dy)/((1./0.4844)**2) + else + vexa=0. + omexa=0. + end if + write(13,'(8(e25.15,2x))') time,yb+(indj-1)*dy,vxg(indi1,indj,indk1), & + omgz(indi1,indj,indk1),vexa,omexa,vxg(indi2,indj,indk2),omgz(indi2,indj,indk2) + end do + end if + !--------------------------------------------------------------------------- + + + !================================================================================================ + !algo penalisation "marche": + ! + !penalisation: + !------------- + !si explicite: lambda<2/dt, mais drag poreux marche car vitesse dans obstacle de l'ordre de lambda + !si implicite: 1/peut pas mettre en terme source et 2/grandes vitesses dans l obstacle + ! (la formule developpe n'a pas l'air de marcher) + !================================================================================================== + + !call penal_exacte() + !call strech_old + !call diffusion_old() + + + !=================================================================== + !calcul du drag : !vitesse penalisee faible dans l'obstacle ! + !==================================================================== + dragi=drag_tps() + dragp=drag_poreux() + lifti=lift_tps() + liftp=lift_poreux() + if (time>dt) then + print*,"time",time + write(12,'(6(e25.15,2x))') time,time-dt,dragi,dragp,lifti,liftp + end if + if (ind_drag<5) ind_drag=ind_drag+1 + + !================================ + !algo sans splitting + !================================ + + !call penal_fft !calcul omg=rot(v) + call rotv_df4 + !call rotv_df2 + + call strech_diff_penal() ! penal commentee + + call crea_part_old() + + call advection_old() !RK2 + + call cpu_time(t4) + + call remaill_l4(omx,xp,yp,zp,omgx) + call remaill_l4(omy,xp,yp,zp,omgy) + call remaill_l4(omz,xp,yp,zp,omgz) + + call cpu_time(t5) + + +!!$ !====================================== +!!$ !splitting en espace : ordre2 en temps +!!$ !====================================== +!!$ call penal_exacte() +!!$ +!!$ +!!$ call crea_part_x() +!!$ +!!$ allocate(vxg1(1:nx_gro,1:ny_gro,1:nz_gro),vyg1(1:nx_gro,1:ny_gro,1:nz_gro),vzg1(1:nx_gro,1:ny_gro,1:nz_gro)) +!!$ !call def_v_advec (vxg1,vyg1,vzg1,time+0.5*dt) +!!$ vxg1=vxg +!!$ vyg1=vyg +!!$ vzg1=vzg +!!$ +!!$ !t source +!!$ !--------- +!!$ call source_split_1 +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vx_2 +!!$ +!!$ !test cfl +!!$ !-------- +!!$ !grad=0. +!!$ !do k=1,nz +!!$ ! do j=1,ny +!!$ ! do i=1,nx-1 +!!$ ! grad=max(grad,abs(vx(numpg(i+1,j,k))-vx(numpg(i,j,k)))) +!!$ ! !grad=max(grad,abs(vxg(i+1,j,k)-vxg(i,j,k))) +!!$ ! end do +!!$ ! end do +!!$ !end do +!!$ !print*,dt,dx/(4.*grad),dx/(6.*grad) +!!$ +!!$ +!!$ !bloc x +!!$ !------- +!!$ !call make_bloc(1) +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_x +!!$ +!!$ +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_x(omx,xp,yp,zp,omgx) +!!$ !call remaill_l6_x(omy,xp,yp,zp,omgy) +!!$ !call remaill_l6_x(omz,xp,yp,zp,omgz) +!!$ if (type_b==2) call remaill_l2_bloc_x(omx,xp,yp,zp,omgx) +!!$ if (type_b==2) call remaill_l2_bloc_x(omy,xp,yp,zp,omgy) +!!$ if (type_b==2) call remaill_l2_bloc_x(omz,xp,yp,zp,omgz) +!!$ if (type_b==4) call remaill_l4_bloc_x(omx,xp,yp,zp,omgx) +!!$ if (type_b==4) call remaill_l4_bloc_x(omy,xp,yp,zp,omgy) +!!$ if (type_b==4) call remaill_l4_bloc_x(omz,xp,yp,zp,omgz) +!!$ +!!$ +!!$ !y +!!$ !-- +!!$ call crea_part_y() +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vy_2 +!!$ +!!$ !bloc y +!!$ !------- +!!$ !call make_bloc(2) +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_y +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_y(omx,xp,yp,zp,omgx) +!!$ !call remaill_l6_y(omy,xp,yp,zp,omgy) +!!$ !call remaill_l6_y(omz,xp,yp,zp,omgz) +!!$ if (type_b==2)call remaill_l2_bloc_y(omx,xp,yp,zp,omgx) +!!$ if (type_b==2)call remaill_l2_bloc_y(omy,xp,yp,zp,omgy) +!!$ if (type_b==2)call remaill_l2_bloc_y(omz,xp,yp,zp,omgz) +!!$ if (type_b==4)call remaill_l4_bloc_y(omx,xp,yp,zp,omgx) +!!$ if (type_b==4)call remaill_l4_bloc_y(omy,xp,yp,zp,omgy) +!!$ if (type_b==4)call remaill_l4_bloc_y(omz,xp,yp,zp,omgz) +!!$ +!!$ +!!$ !z +!!$ !-- +!!$ call crea_part_z() +!!$ +!!$ !update v +!!$ !-------- +!!$ call update_vz_2 +!!$ +!!$ +!!$ !bloc z +!!$ !------- +!!$ !call make_bloc(3) +!!$ blocg=0 +!!$ blocd=0 +!!$ +!!$ !advection +!!$ !---------- +!!$ call ad_euler_z +!!$ +!!$ !remaillage +!!$ !---------- +!!$ !call remaill_l6_z(omx,xp,yp,zp,omgx) +!!$ !call remaill_l6_z(omy,xp,yp,zp,omgy) +!!$ !call remaill_l6_z(omz,xp,yp,zp,omgz) +!!$ if (type_b==2)call remaill_l2_bloc_z(omx,xp,yp,zp,omgx) +!!$ if (type_b==2)call remaill_l2_bloc_z(omy,xp,yp,zp,omgy) +!!$ if (type_b==2)call remaill_l2_bloc_z(omz,xp,yp,zp,omgz) +!!$ if (type_b==4)call remaill_l4_bloc_z(omx,xp,yp,zp,omgx) +!!$ if (type_b==4)call remaill_l4_bloc_z(omy,xp,yp,zp,omgy) +!!$ if (type_b==4)call remaill_l4_bloc_z(omz,xp,yp,zp,omgz) +!!$ +!!$ +!!$ +!!$ !t source +!!$ !--------- +!!$ call source_split_2 +!!$ +!!$ +!!$ deallocate(vxg1,vyg1,vzg1) + + + + + time=time+dt + cpt_ite=cpt_ite+1 + + !resultats + !----------- + + !call res_omg_nite(nom_fich_omg_nite,nom_fich_vit_nite,nite_vtk,time) + + + +!!$ print*,"tps" +!!$ print*,"" +!!$ print*,"u fourier",t2-t1 +!!$ print*,"penal",t3-t2 +!!$ print*,"remaillage",t5-t4 + + + end do temps + + + + + + + !resultat final + !-------------- + print*,"tps final",time + print*,"nbre d'ite",cpt_ite + print*,"nart final",npart + print*,"dt,dx,dy,dz",dt,dx,dy,dz + + + + !call res_vtk("RES/vtk/"//nom_fich_vtk) + !call res_vtk_omgx("RES/vtk/"//nom_fich_vtk) + + + + ! + !dealloc fermeture + !----------------- + + deallocate (xp,qp,vx,vy,yp,zp,vz) + deallocate (omgx,omgy,omgz) + deallocate (omx,omy,omz) + deallocate (vxg,vyg,vzg) + deallocate (xtab,ytab,ztab) + deallocate (chi,chi_sphere,lambda) + deallocate (deb1,deb2,deb3) + + deallocate(stxg,styg,stzg,stx,sty,stz) + + close(12) + close(13) + close(14) + close(15) + close(16) + close(17) + close(18) + close(19) + close(20) + +end program NS + + + + diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/nr.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/nr.f90 new file mode 100644 index 000000000..4d535a314 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/nr.f90 @@ -0,0 +1,2990 @@ +MODULE nr + INTERFACE + SUBROUTINE airy(x,ai,bi,aip,bip) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: ai,bi,aip,bip + END SUBROUTINE airy + END INTERFACE + INTERFACE + SUBROUTINE amebsa(p,y,pb,yb,ftol,func,iter,temptr) + USE nrtype + INTEGER(I4B), INTENT(INOUT) :: iter + REAL(SP), INTENT(INOUT) :: yb + REAL(SP), INTENT(IN) :: ftol,temptr + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y,pb + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: p + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE amebsa + END INTERFACE + INTERFACE + SUBROUTINE amoeba(p,y,ftol,func,iter) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: iter + REAL(SP), INTENT(IN) :: ftol + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: p + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE amoeba + END INTERFACE + INTERFACE + SUBROUTINE anneal(x,y,iorder) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(INOUT) :: iorder + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + END SUBROUTINE anneal + END INTERFACE + INTERFACE + SUBROUTINE avevar(data,ave,var) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data + REAL(SP), INTENT(OUT) :: ave,var + END SUBROUTINE avevar + END INTERFACE + INTERFACE + SUBROUTINE balanc(a) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + END SUBROUTINE balanc + END INTERFACE + INTERFACE + SUBROUTINE banbks(a,m1,m2,al,indx,b) + USE nrtype + INTEGER(I4B), INTENT(IN) :: m1,m2 + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indx + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a,al + REAL(SP), DIMENSION(:), INTENT(INOUT) :: b + END SUBROUTINE banbks + END INTERFACE + INTERFACE + SUBROUTINE bandec(a,m1,m2,al,indx,d) + USE nrtype + INTEGER(I4B), INTENT(IN) :: m1,m2 + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: indx + REAL(SP), INTENT(OUT) :: d + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: al + END SUBROUTINE bandec + END INTERFACE + INTERFACE + SUBROUTINE banmul(a,m1,m2,x,b) + USE nrtype + INTEGER(I4B), INTENT(IN) :: m1,m2 + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(OUT) :: b + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + END SUBROUTINE banmul + END INTERFACE + INTERFACE + SUBROUTINE bcucof(y,y1,y2,y12,d1,d2,c) + USE nrtype + REAL(SP), INTENT(IN) :: d1,d2 + REAL(SP), DIMENSION(4), INTENT(IN) :: y,y1,y2,y12 + REAL(SP), DIMENSION(4,4), INTENT(OUT) :: c + END SUBROUTINE bcucof + END INTERFACE + INTERFACE + SUBROUTINE bcuint(y,y1,y2,y12,x1l,x1u,x2l,x2u,x1,x2,ansy,& + ansy1,ansy2) + USE nrtype + REAL(SP), DIMENSION(4), INTENT(IN) :: y,y1,y2,y12 + REAL(SP), INTENT(IN) :: x1l,x1u,x2l,x2u,x1,x2 + REAL(SP), INTENT(OUT) :: ansy,ansy1,ansy2 + END SUBROUTINE bcuint + END INTERFACE + INTERFACE bessi + FUNCTION bessi_s(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessi_s + END FUNCTION bessi_s +!BL + FUNCTION bessi_v(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessi_v + END FUNCTION bessi_v + END INTERFACE + INTERFACE bessi0 + FUNCTION bessi0_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessi0_s + END FUNCTION bessi0_s +!BL + FUNCTION bessi0_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessi0_v + END FUNCTION bessi0_v + END INTERFACE + INTERFACE bessi1 + FUNCTION bessi1_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessi1_s + END FUNCTION bessi1_s +!BL + FUNCTION bessi1_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessi1_v + END FUNCTION bessi1_v + END INTERFACE + INTERFACE + SUBROUTINE bessik(x,xnu,ri,rk,rip,rkp) + USE nrtype + REAL(SP), INTENT(IN) :: x,xnu + REAL(SP), INTENT(OUT) :: ri,rk,rip,rkp + END SUBROUTINE bessik + END INTERFACE + INTERFACE bessj + FUNCTION bessj_s(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessj_s + END FUNCTION bessj_s +!BL + FUNCTION bessj_v(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessj_v + END FUNCTION bessj_v + END INTERFACE + INTERFACE bessj0 + FUNCTION bessj0_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessj0_s + END FUNCTION bessj0_s +!BL + FUNCTION bessj0_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessj0_v + END FUNCTION bessj0_v + END INTERFACE + INTERFACE bessj1 + FUNCTION bessj1_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessj1_s + END FUNCTION bessj1_s +!BL + FUNCTION bessj1_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessj1_v + END FUNCTION bessj1_v + END INTERFACE + INTERFACE bessjy + SUBROUTINE bessjy_s(x,xnu,rj,ry,rjp,ryp) + USE nrtype + REAL(SP), INTENT(IN) :: x,xnu + REAL(SP), INTENT(OUT) :: rj,ry,rjp,ryp + END SUBROUTINE bessjy_s +!BL + SUBROUTINE bessjy_v(x,xnu,rj,ry,rjp,ryp) + USE nrtype + REAL(SP), INTENT(IN) :: xnu + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(OUT) :: rj,rjp,ry,ryp + END SUBROUTINE bessjy_v + END INTERFACE + INTERFACE bessk + FUNCTION bessk_s(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessk_s + END FUNCTION bessk_s +!BL + FUNCTION bessk_v(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessk_v + END FUNCTION bessk_v + END INTERFACE + INTERFACE bessk0 + FUNCTION bessk0_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessk0_s + END FUNCTION bessk0_s +!BL + FUNCTION bessk0_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessk0_v + END FUNCTION bessk0_v + END INTERFACE + INTERFACE bessk1 + FUNCTION bessk1_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessk1_s + END FUNCTION bessk1_s +!BL + FUNCTION bessk1_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessk1_v + END FUNCTION bessk1_v + END INTERFACE + INTERFACE bessy + FUNCTION bessy_s(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessy_s + END FUNCTION bessy_s +!BL + FUNCTION bessy_v(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessy_v + END FUNCTION bessy_v + END INTERFACE + INTERFACE bessy0 + FUNCTION bessy0_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessy0_s + END FUNCTION bessy0_s +!BL + FUNCTION bessy0_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessy0_v + END FUNCTION bessy0_v + END INTERFACE + INTERFACE bessy1 + FUNCTION bessy1_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: bessy1_s + END FUNCTION bessy1_s +!BL + FUNCTION bessy1_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: bessy1_v + END FUNCTION bessy1_v + END INTERFACE + INTERFACE beta + FUNCTION beta_s(z,w) + USE nrtype + REAL(SP), INTENT(IN) :: z,w + REAL(SP) :: beta_s + END FUNCTION beta_s +!BL + FUNCTION beta_v(z,w) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: z,w + REAL(SP), DIMENSION(size(z)) :: beta_v + END FUNCTION beta_v + END INTERFACE + INTERFACE betacf + FUNCTION betacf_s(a,b,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,b,x + REAL(SP) :: betacf_s + END FUNCTION betacf_s +!BL + FUNCTION betacf_v(a,b,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b,x + REAL(SP), DIMENSION(size(x)) :: betacf_v + END FUNCTION betacf_v + END INTERFACE + INTERFACE betai + FUNCTION betai_s(a,b,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,b,x + REAL(SP) :: betai_s + END FUNCTION betai_s +!BL + FUNCTION betai_v(a,b,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b,x + REAL(SP), DIMENSION(size(a)) :: betai_v + END FUNCTION betai_v + END INTERFACE + INTERFACE bico + FUNCTION bico_s(n,k) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n,k + REAL(SP) :: bico_s + END FUNCTION bico_s +!BL + FUNCTION bico_v(n,k) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: n,k + REAL(SP), DIMENSION(size(n)) :: bico_v + END FUNCTION bico_v + END INTERFACE + INTERFACE + FUNCTION bnldev(pp,n) + USE nrtype + REAL(SP), INTENT(IN) :: pp + INTEGER(I4B), INTENT(IN) :: n + REAL(SP) :: bnldev + END FUNCTION bnldev + END INTERFACE + INTERFACE + FUNCTION brent(ax,bx,cx,func,tol,xmin) + USE nrtype + REAL(SP), INTENT(IN) :: ax,bx,cx,tol + REAL(SP), INTENT(OUT) :: xmin + REAL(SP) :: brent + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION brent + END INTERFACE + INTERFACE + SUBROUTINE broydn(x,check) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + LOGICAL(LGT), INTENT(OUT) :: check + END SUBROUTINE broydn + END INTERFACE + INTERFACE + SUBROUTINE bsstep(y,dydx,x,htry,eps,yscal,hdid,hnext,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:), INTENT(IN) :: dydx,yscal + REAL(SP), INTENT(INOUT) :: x + REAL(SP), INTENT(IN) :: htry,eps + REAL(SP), INTENT(OUT) :: hdid,hnext + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE bsstep + END INTERFACE + INTERFACE + SUBROUTINE caldat(julian,mm,id,iyyy) + USE nrtype + INTEGER(I4B), INTENT(IN) :: julian + INTEGER(I4B), INTENT(OUT) :: mm,id,iyyy + END SUBROUTINE caldat + END INTERFACE + INTERFACE + FUNCTION chder(a,b,c) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(IN) :: c + REAL(SP), DIMENSION(size(c)) :: chder + END FUNCTION chder + END INTERFACE + INTERFACE chebev + FUNCTION chebev_s(a,b,c,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,b,x + REAL(SP), DIMENSION(:), INTENT(IN) :: c + REAL(SP) :: chebev_s + END FUNCTION chebev_s +!BL + FUNCTION chebev_v(a,b,c,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(IN) :: c,x + REAL(SP), DIMENSION(size(x)) :: chebev_v + END FUNCTION chebev_v + END INTERFACE + INTERFACE + FUNCTION chebft(a,b,n,func) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: chebft + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END FUNCTION chebft + END INTERFACE + INTERFACE + FUNCTION chebpc(c) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: c + REAL(SP), DIMENSION(size(c)) :: chebpc + END FUNCTION chebpc + END INTERFACE + INTERFACE + FUNCTION chint(a,b,c) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(IN) :: c + REAL(SP), DIMENSION(size(c)) :: chint + END FUNCTION chint + END INTERFACE + INTERFACE + SUBROUTINE choldc(a,p) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:), INTENT(OUT) :: p + END SUBROUTINE choldc + END INTERFACE + INTERFACE + SUBROUTINE cholsl(a,p,b,x) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + REAL(SP), DIMENSION(:), INTENT(IN) :: p,b + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + END SUBROUTINE cholsl + END INTERFACE + INTERFACE + SUBROUTINE chsone(bins,ebins,knstrn,df,chsq,prob) + USE nrtype + INTEGER(I4B), INTENT(IN) :: knstrn + REAL(SP), INTENT(OUT) :: df,chsq,prob + REAL(SP), DIMENSION(:), INTENT(IN) :: bins,ebins + END SUBROUTINE chsone + END INTERFACE + INTERFACE + SUBROUTINE chstwo(bins1,bins2,knstrn,df,chsq,prob) + USE nrtype + INTEGER(I4B), INTENT(IN) :: knstrn + REAL(SP), INTENT(OUT) :: df,chsq,prob + REAL(SP), DIMENSION(:), INTENT(IN) :: bins1,bins2 + END SUBROUTINE chstwo + END INTERFACE + INTERFACE + SUBROUTINE cisi(x,ci,si) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: ci,si + END SUBROUTINE cisi + END INTERFACE + INTERFACE + SUBROUTINE cntab1(nn,chisq,df,prob,cramrv,ccc) + USE nrtype + INTEGER(I4B), DIMENSION(:,:), INTENT(IN) :: nn + REAL(SP), INTENT(OUT) :: chisq,df,prob,cramrv,ccc + END SUBROUTINE cntab1 + END INTERFACE + INTERFACE + SUBROUTINE cntab2(nn,h,hx,hy,hygx,hxgy,uygx,uxgy,uxy) + USE nrtype + INTEGER(I4B), DIMENSION(:,:), INTENT(IN) :: nn + REAL(SP), INTENT(OUT) :: h,hx,hy,hygx,hxgy,uygx,uxgy,uxy + END SUBROUTINE cntab2 + END INTERFACE + INTERFACE + FUNCTION convlv(data,respns,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data + REAL(SP), DIMENSION(:), INTENT(IN) :: respns + INTEGER(I4B), INTENT(IN) :: isign + REAL(SP), DIMENSION(size(data)) :: convlv + END FUNCTION convlv + END INTERFACE + INTERFACE + FUNCTION correl(data1,data2) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + REAL(SP), DIMENSION(size(data1)) :: correl + END FUNCTION correl + END INTERFACE + INTERFACE + SUBROUTINE cosft1(y) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + END SUBROUTINE cosft1 + END INTERFACE + INTERFACE + SUBROUTINE cosft2(y,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE cosft2 + END INTERFACE + INTERFACE + SUBROUTINE covsrt(covar,maska) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: covar + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: maska + END SUBROUTINE covsrt + END INTERFACE + INTERFACE + SUBROUTINE cyclic(a,b,c,alpha,beta,r,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN):: a,b,c,r + REAL(SP), INTENT(IN) :: alpha,beta + REAL(SP), DIMENSION(:), INTENT(OUT):: x + END SUBROUTINE cyclic + END INTERFACE + INTERFACE + SUBROUTINE daub4(a,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE daub4 + END INTERFACE + INTERFACE dawson + FUNCTION dawson_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: dawson_s + END FUNCTION dawson_s +!BL + FUNCTION dawson_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: dawson_v + END FUNCTION dawson_v + END INTERFACE + INTERFACE + FUNCTION dbrent(ax,bx,cx,func,dbrent_dfunc,tol,xmin) + USE nrtype + REAL(SP), INTENT(IN) :: ax,bx,cx,tol + REAL(SP), INTENT(OUT) :: xmin + REAL(SP) :: dbrent + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func +!BL + FUNCTION dbrent_dfunc(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: dbrent_dfunc + END FUNCTION dbrent_dfunc + END INTERFACE + END FUNCTION dbrent + END INTERFACE + INTERFACE + SUBROUTINE ddpoly(c,x,pd) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: c + REAL(SP), DIMENSION(:), INTENT(OUT) :: pd + END SUBROUTINE ddpoly + END INTERFACE + INTERFACE + FUNCTION decchk(string,ch) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(IN) :: string + CHARACTER(1), INTENT(OUT) :: ch + LOGICAL(LGT) :: decchk + END FUNCTION decchk + END INTERFACE + INTERFACE + SUBROUTINE dfpmin(p,gtol,iter,fret,func,dfunc) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: iter + REAL(SP), INTENT(IN) :: gtol + REAL(SP), INTENT(OUT) :: fret + REAL(SP), DIMENSION(:), INTENT(INOUT) :: p + INTERFACE + FUNCTION func(p) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: p + REAL(SP) :: func + END FUNCTION func +!BL + FUNCTION dfunc(p) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: p + REAL(SP), DIMENSION(size(p)) :: dfunc + END FUNCTION dfunc + END INTERFACE + END SUBROUTINE dfpmin + END INTERFACE + INTERFACE + FUNCTION dfridr(func,x,h,err) + USE nrtype + REAL(SP), INTENT(IN) :: x,h + REAL(SP), INTENT(OUT) :: err + REAL(SP) :: dfridr + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION dfridr + END INTERFACE + INTERFACE + SUBROUTINE dftcor(w,delta,a,b,endpts,corre,corim,corfac) + USE nrtype + REAL(SP), INTENT(IN) :: w,delta,a,b + REAL(SP), INTENT(OUT) :: corre,corim,corfac + REAL(SP), DIMENSION(:), INTENT(IN) :: endpts + END SUBROUTINE dftcor + END INTERFACE + INTERFACE + SUBROUTINE dftint(func,a,b,w,cosint,sinint) + USE nrtype + REAL(SP), INTENT(IN) :: a,b,w + REAL(SP), INTENT(OUT) :: cosint,sinint + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE dftint + END INTERFACE + INTERFACE + SUBROUTINE difeq(k,k1,k2,jsf,is1,isf,indexv,s,y) + USE nrtype + INTEGER(I4B), INTENT(IN) :: is1,isf,jsf,k,k1,k2 + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indexv + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: s + REAL(SP), DIMENSION(:,:), INTENT(IN) :: y + END SUBROUTINE difeq + END INTERFACE + INTERFACE + FUNCTION eclass(lista,listb,n) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: lista,listb + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B), DIMENSION(n) :: eclass + END FUNCTION eclass + END INTERFACE + INTERFACE + FUNCTION eclazz(equiv,n) + USE nrtype + INTERFACE + FUNCTION equiv(i,j) + USE nrtype + LOGICAL(LGT) :: equiv + INTEGER(I4B), INTENT(IN) :: i,j + END FUNCTION equiv + END INTERFACE + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B), DIMENSION(n) :: eclazz + END FUNCTION eclazz + END INTERFACE + INTERFACE + FUNCTION ei(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: ei + END FUNCTION ei + END INTERFACE + INTERFACE + SUBROUTINE eigsrt(d,v) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: d + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: v + END SUBROUTINE eigsrt + END INTERFACE + INTERFACE elle + FUNCTION elle_s(phi,ak) + USE nrtype + REAL(SP), INTENT(IN) :: phi,ak + REAL(SP) :: elle_s + END FUNCTION elle_s +!BL + FUNCTION elle_v(phi,ak) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: phi,ak + REAL(SP), DIMENSION(size(phi)) :: elle_v + END FUNCTION elle_v + END INTERFACE + INTERFACE ellf + FUNCTION ellf_s(phi,ak) + USE nrtype + REAL(SP), INTENT(IN) :: phi,ak + REAL(SP) :: ellf_s + END FUNCTION ellf_s +!BL + FUNCTION ellf_v(phi,ak) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: phi,ak + REAL(SP), DIMENSION(size(phi)) :: ellf_v + END FUNCTION ellf_v + END INTERFACE + INTERFACE ellpi + FUNCTION ellpi_s(phi,en,ak) + USE nrtype + REAL(SP), INTENT(IN) :: phi,en,ak + REAL(SP) :: ellpi_s + END FUNCTION ellpi_s +!BL + FUNCTION ellpi_v(phi,en,ak) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: phi,en,ak + REAL(SP), DIMENSION(size(phi)) :: ellpi_v + END FUNCTION ellpi_v + END INTERFACE + INTERFACE + SUBROUTINE elmhes(a) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + END SUBROUTINE elmhes + END INTERFACE + INTERFACE erf + FUNCTION erf_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: erf_s + END FUNCTION erf_s +!BL + FUNCTION erf_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: erf_v + END FUNCTION erf_v + END INTERFACE + INTERFACE erfc + FUNCTION erfc_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: erfc_s + END FUNCTION erfc_s +!BL + FUNCTION erfc_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: erfc_v + END FUNCTION erfc_v + END INTERFACE + INTERFACE erfcc + FUNCTION erfcc_s(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: erfcc_s + END FUNCTION erfcc_s +!BL + FUNCTION erfcc_v(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: erfcc_v + END FUNCTION erfcc_v + END INTERFACE + INTERFACE + SUBROUTINE eulsum(sum,term,jterm) + USE nrtype + REAL(SP), INTENT(INOUT) :: sum + REAL(SP), INTENT(IN) :: term + INTEGER(I4B), INTENT(IN) :: jterm + END SUBROUTINE eulsum + END INTERFACE + INTERFACE + FUNCTION evlmem(fdt,d,xms) + USE nrtype + REAL(SP), INTENT(IN) :: fdt,xms + REAL(SP), DIMENSION(:), INTENT(IN) :: d + REAL(SP) :: evlmem + END FUNCTION evlmem + END INTERFACE + INTERFACE expdev + SUBROUTINE expdev_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE expdev_s +!BL + SUBROUTINE expdev_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE expdev_v + END INTERFACE + INTERFACE + FUNCTION expint(n,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP) :: expint + END FUNCTION expint + END INTERFACE + INTERFACE factln + FUNCTION factln_s(n) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP) :: factln_s + END FUNCTION factln_s +!BL + FUNCTION factln_v(n) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: n + REAL(SP), DIMENSION(size(n)) :: factln_v + END FUNCTION factln_v + END INTERFACE + INTERFACE factrl + FUNCTION factrl_s(n) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP) :: factrl_s + END FUNCTION factrl_s +!BL + FUNCTION factrl_v(n) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: n + REAL(SP), DIMENSION(size(n)) :: factrl_v + END FUNCTION factrl_v + END INTERFACE + INTERFACE + SUBROUTINE fasper(x,y,ofac,hifac,px,py,jmax,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), INTENT(IN) :: ofac,hifac + INTEGER(I4B), INTENT(OUT) :: jmax + REAL(SP), INTENT(OUT) :: prob + REAL(SP), DIMENSION(:), POINTER :: px,py + END SUBROUTINE fasper + END INTERFACE + INTERFACE + SUBROUTINE fdjac(x,fvec,df) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: fvec + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: df + END SUBROUTINE fdjac + END INTERFACE + INTERFACE + SUBROUTINE fgauss(x,a,y,dyda) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,a + REAL(SP), DIMENSION(:), INTENT(OUT) :: y + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: dyda + END SUBROUTINE fgauss + END INTERFACE + INTERFACE + SUBROUTINE fit(x,y,a,b,siga,sigb,chi2,q,sig) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), INTENT(OUT) :: a,b,siga,sigb,chi2,q + REAL(SP), DIMENSION(:), OPTIONAL, INTENT(IN) :: sig + END SUBROUTINE fit + END INTERFACE + INTERFACE + SUBROUTINE fitexy(x,y,sigx,sigy,a,b,siga,sigb,chi2,q) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,sigx,sigy + REAL(SP), INTENT(OUT) :: a,b,siga,sigb,chi2,q + END SUBROUTINE fitexy + END INTERFACE + INTERFACE + SUBROUTINE fixrts(d) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: d + END SUBROUTINE fixrts + END INTERFACE + INTERFACE + FUNCTION fleg(x,n) + USE nrtype + REAL(SP), INTENT(IN) :: x + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: fleg + END FUNCTION fleg + END INTERFACE + INTERFACE + SUBROUTINE flmoon(n,nph,jd,frac) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n,nph + INTEGER(I4B), INTENT(OUT) :: jd + REAL(SP), INTENT(OUT) :: frac + END SUBROUTINE flmoon + END INTERFACE + INTERFACE four1 +!BL + SUBROUTINE four1_sp(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE four1_sp + END INTERFACE + INTERFACE + SUBROUTINE four1_alt(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE four1_alt + END INTERFACE + INTERFACE + SUBROUTINE four1_gather(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE four1_gather + END INTERFACE + INTERFACE + SUBROUTINE four2(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B),INTENT(IN) :: isign + END SUBROUTINE four2 + END INTERFACE + INTERFACE + SUBROUTINE four2_alt(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE four2_alt + END INTERFACE + INTERFACE + SUBROUTINE four3(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B),INTENT(IN) :: isign + END SUBROUTINE four3 + END INTERFACE + INTERFACE + SUBROUTINE four3_alt(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE four3_alt + END INTERFACE + INTERFACE + SUBROUTINE fourcol(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE fourcol + END INTERFACE + INTERFACE + SUBROUTINE fourcol_3d(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE fourcol_3d + END INTERFACE + INTERFACE + SUBROUTINE fourn_gather(data,nn,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: data + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: nn + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE fourn_gather + END INTERFACE + INTERFACE fourrow +!BL + SUBROUTINE fourrow_sp(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE fourrow_sp + END INTERFACE + INTERFACE + SUBROUTINE fourrow_3d(data,isign) + USE nrtype + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE fourrow_3d + END INTERFACE + INTERFACE + FUNCTION fpoly(x,n) + USE nrtype + REAL(SP), INTENT(IN) :: x + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: fpoly + END FUNCTION fpoly + END INTERFACE + INTERFACE + SUBROUTINE fred2(a,b,t,f,w,g,ak) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(OUT) :: t,f,w + INTERFACE + FUNCTION g(t) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: t + REAL(SP), DIMENSION(size(t)) :: g + END FUNCTION g +!BL + FUNCTION ak(t,s) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: t,s + REAL(SP), DIMENSION(size(t),size(s)) :: ak + END FUNCTION ak + END INTERFACE + END SUBROUTINE fred2 + END INTERFACE + INTERFACE + FUNCTION fredin(x,a,b,t,f,w,g,ak) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(IN) :: x,t,f,w + REAL(SP), DIMENSION(size(x)) :: fredin + INTERFACE + FUNCTION g(t) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: t + REAL(SP), DIMENSION(size(t)) :: g + END FUNCTION g +!BL + FUNCTION ak(t,s) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: t,s + REAL(SP), DIMENSION(size(t),size(s)) :: ak + END FUNCTION ak + END INTERFACE + END FUNCTION fredin + END INTERFACE + INTERFACE + SUBROUTINE frenel(x,s,c) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: s,c + END SUBROUTINE frenel + END INTERFACE + INTERFACE + SUBROUTINE frprmn(p,ftol,iter,fret) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: iter + REAL(SP), INTENT(IN) :: ftol + REAL(SP), INTENT(OUT) :: fret + REAL(SP), DIMENSION(:), INTENT(INOUT) :: p + END SUBROUTINE frprmn + END INTERFACE + INTERFACE + SUBROUTINE ftest(data1,data2,f,prob) + USE nrtype + REAL(SP), INTENT(OUT) :: f,prob + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + END SUBROUTINE ftest + END INTERFACE + INTERFACE + FUNCTION gamdev(ia) + USE nrtype + INTEGER(I4B), INTENT(IN) :: ia + REAL(SP) :: gamdev + END FUNCTION gamdev + END INTERFACE + INTERFACE gammln + FUNCTION gammln_s(xx) + USE nrtype + REAL(SP), INTENT(IN) :: xx + REAL(SP) :: gammln_s + END FUNCTION gammln_s +!BL + FUNCTION gammln_v(xx) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xx + REAL(SP), DIMENSION(size(xx)) :: gammln_v + END FUNCTION gammln_v + END INTERFACE + INTERFACE gammp + FUNCTION gammp_s(a,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,x + REAL(SP) :: gammp_s + END FUNCTION gammp_s +!BL + FUNCTION gammp_v(a,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,x + REAL(SP), DIMENSION(size(a)) :: gammp_v + END FUNCTION gammp_v + END INTERFACE + INTERFACE gammq + FUNCTION gammq_s(a,x) + USE nrtype + REAL(SP), INTENT(IN) :: a,x + REAL(SP) :: gammq_s + END FUNCTION gammq_s +!BL + FUNCTION gammq_v(a,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,x + REAL(SP), DIMENSION(size(a)) :: gammq_v + END FUNCTION gammq_v + END INTERFACE + INTERFACE gasdev + SUBROUTINE gasdev_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE gasdev_s +!BL + SUBROUTINE gasdev_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE gasdev_v + END INTERFACE + INTERFACE + SUBROUTINE gaucof(a,b,amu0,x,w) + USE nrtype + REAL(SP), INTENT(IN) :: amu0 + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a,b + REAL(SP), DIMENSION(:), INTENT(OUT) :: x,w + END SUBROUTINE gaucof + END INTERFACE + INTERFACE + SUBROUTINE gauher(x,w) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: x,w + END SUBROUTINE gauher + END INTERFACE + INTERFACE + SUBROUTINE gaujac(x,w,alf,bet) + USE nrtype + REAL(SP), INTENT(IN) :: alf,bet + REAL(SP), DIMENSION(:), INTENT(OUT) :: x,w + END SUBROUTINE gaujac + END INTERFACE + INTERFACE + SUBROUTINE gaulag(x,w,alf) + USE nrtype + REAL(SP), INTENT(IN) :: alf + REAL(SP), DIMENSION(:), INTENT(OUT) :: x,w + END SUBROUTINE gaulag + END INTERFACE + INTERFACE + SUBROUTINE gauleg(x1,x2,x,w) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2 + REAL(SP), DIMENSION(:), INTENT(OUT) :: x,w + END SUBROUTINE gauleg + END INTERFACE + INTERFACE + SUBROUTINE gaussj(a,b) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a,b + END SUBROUTINE gaussj + END INTERFACE + INTERFACE gcf + FUNCTION gcf_s(a,x,gln) + USE nrtype + REAL(SP), INTENT(IN) :: a,x + REAL(SP), OPTIONAL, INTENT(OUT) :: gln + REAL(SP) :: gcf_s + END FUNCTION gcf_s +!BL + FUNCTION gcf_v(a,x,gln) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,x + REAL(SP), DIMENSION(:), OPTIONAL, INTENT(OUT) :: gln + REAL(SP), DIMENSION(size(a)) :: gcf_v + END FUNCTION gcf_v + END INTERFACE + INTERFACE + FUNCTION golden(ax,bx,cx,func,tol,xmin) + USE nrtype + REAL(SP), INTENT(IN) :: ax,bx,cx,tol + REAL(SP), INTENT(OUT) :: xmin + REAL(SP) :: golden + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION golden + END INTERFACE + INTERFACE gser + FUNCTION gser_s(a,x,gln) + USE nrtype + REAL(SP), INTENT(IN) :: a,x + REAL(SP), OPTIONAL, INTENT(OUT) :: gln + REAL(SP) :: gser_s + END FUNCTION gser_s +!BL + FUNCTION gser_v(a,x,gln) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,x + REAL(SP), DIMENSION(:), OPTIONAL, INTENT(OUT) :: gln + REAL(SP), DIMENSION(size(a)) :: gser_v + END FUNCTION gser_v + END INTERFACE + INTERFACE + SUBROUTINE hqr(a,wr,wi) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: wr,wi + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + END SUBROUTINE hqr + END INTERFACE + INTERFACE + SUBROUTINE hunt(xx,x,jlo) + USE nrtype + INTEGER(I4B), INTENT(INOUT) :: jlo + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: xx + END SUBROUTINE hunt + END INTERFACE + INTERFACE + SUBROUTINE hypdrv(s,ry,rdyds) + USE nrtype + REAL(SP), INTENT(IN) :: s + REAL(SP), DIMENSION(:), INTENT(IN) :: ry + REAL(SP), DIMENSION(:), INTENT(OUT) :: rdyds + END SUBROUTINE hypdrv + END INTERFACE + INTERFACE + FUNCTION hypgeo(a,b,c,z) + USE nrtype + COMPLEX(SPC), INTENT(IN) :: a,b,c,z + COMPLEX(SPC) :: hypgeo + END FUNCTION hypgeo + END INTERFACE + INTERFACE + SUBROUTINE hypser(a,b,c,z,series,deriv) + USE nrtype + COMPLEX(SPC), INTENT(IN) :: a,b,c,z + COMPLEX(SPC), INTENT(OUT) :: series,deriv + END SUBROUTINE hypser + END INTERFACE + INTERFACE + FUNCTION icrc(crc,buf,jinit,jrev) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(IN) :: buf + INTEGER(I2B), INTENT(IN) :: crc,jinit + INTEGER(I4B), INTENT(IN) :: jrev + INTEGER(I2B) :: icrc + END FUNCTION icrc + END INTERFACE + INTERFACE + FUNCTION igray(n,is) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n,is + INTEGER(I4B) :: igray + END FUNCTION igray + END INTERFACE + INTERFACE + RECURSIVE SUBROUTINE index_bypack(arr,index,partial) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + INTEGER(I4B), DIMENSION(:), INTENT(INOUT) :: index + INTEGER, OPTIONAL, INTENT(IN) :: partial + END SUBROUTINE index_bypack + END INTERFACE + INTERFACE indexx + SUBROUTINE indexx_sp(arr,index) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: index + END SUBROUTINE indexx_sp + SUBROUTINE indexx_i4b(iarr,index) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: iarr + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: index + END SUBROUTINE indexx_i4b + END INTERFACE + INTERFACE + FUNCTION rank(indx) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indx + INTEGER(I4B), DIMENSION(size(indx)) :: rank + END FUNCTION rank + END INTERFACE + INTERFACE + FUNCTION irbit1(iseed) + USE nrtype + INTEGER(I4B), INTENT(INOUT) :: iseed + INTEGER(I4B) :: irbit1 + END FUNCTION irbit1 + END INTERFACE + INTERFACE + FUNCTION irbit2(iseed) + USE nrtype + INTEGER(I4B), INTENT(INOUT) :: iseed + INTEGER(I4B) :: irbit2 + END FUNCTION irbit2 + END INTERFACE + INTERFACE + SUBROUTINE jacobi(a,d,v,nrot) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: nrot + REAL(SP), DIMENSION(:), INTENT(OUT) :: d + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: v + END SUBROUTINE jacobi + END INTERFACE + INTERFACE + SUBROUTINE jacobn(x,y,dfdx,dfdy) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dfdx + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: dfdy + END SUBROUTINE jacobn + END INTERFACE + INTERFACE + FUNCTION julday(mm,id,iyyy) + USE nrtype + INTEGER(I4B), INTENT(IN) :: mm,id,iyyy + INTEGER(I4B) :: julday + END FUNCTION julday + END INTERFACE + INTERFACE + SUBROUTINE kendl1(data1,data2,tau,z,prob) + USE nrtype + REAL(SP), INTENT(OUT) :: tau,z,prob + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + END SUBROUTINE kendl1 + END INTERFACE + INTERFACE + SUBROUTINE kendl2(tab,tau,z,prob) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: tab + REAL(SP), INTENT(OUT) :: tau,z,prob + END SUBROUTINE kendl2 + END INTERFACE + INTERFACE + SUBROUTINE ks2d1s(x1,y1,quadvl,d1,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x1,y1 + REAL(SP), INTENT(OUT) :: d1,prob + INTERFACE + SUBROUTINE quadvl(x,y,fa,fb,fc,fd) + USE nrtype + REAL(SP), INTENT(IN) :: x,y + REAL(SP), INTENT(OUT) :: fa,fb,fc,fd + END SUBROUTINE quadvl + END INTERFACE + END SUBROUTINE ks2d1s + END INTERFACE + INTERFACE + SUBROUTINE ks2d2s(x1,y1,x2,y2,d,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x1,y1,x2,y2 + REAL(SP), INTENT(OUT) :: d,prob + END SUBROUTINE ks2d2s + END INTERFACE + INTERFACE + SUBROUTINE ksone(data,func,d,prob) + USE nrtype + REAL(SP), INTENT(OUT) :: d,prob + REAL(SP), DIMENSION(:), INTENT(INOUT) :: data + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE ksone + END INTERFACE + INTERFACE + SUBROUTINE kstwo(data1,data2,d,prob) + USE nrtype + REAL(SP), INTENT(OUT) :: d,prob + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + END SUBROUTINE kstwo + END INTERFACE + INTERFACE + SUBROUTINE laguer(a,x,its) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: its + COMPLEX(SPC), INTENT(INOUT) :: x + COMPLEX(SPC), DIMENSION(:), INTENT(IN) :: a + END SUBROUTINE laguer + END INTERFACE + INTERFACE + SUBROUTINE lfit(x,y,sig,a,maska,covar,chisq,funcs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,sig + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: maska + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: covar + REAL(SP), INTENT(OUT) :: chisq + INTERFACE + SUBROUTINE funcs(x,arr) + USE nrtype + REAL(SP),INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(OUT) :: arr + END SUBROUTINE funcs + END INTERFACE + END SUBROUTINE lfit + END INTERFACE + INTERFACE + SUBROUTINE linmin(p,xi,fret) + USE nrtype + REAL(SP), INTENT(OUT) :: fret + REAL(SP), DIMENSION(:), TARGET, INTENT(INOUT) :: p,xi + END SUBROUTINE linmin + END INTERFACE + INTERFACE + SUBROUTINE lnsrch(xold,fold,g,p,x,f,stpmax,check,func) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xold,g + REAL(SP), DIMENSION(:), INTENT(INOUT) :: p + REAL(SP), INTENT(IN) :: fold,stpmax + REAL(SP), DIMENSION(:), INTENT(OUT) :: x + REAL(SP), INTENT(OUT) :: f + LOGICAL(LGT), INTENT(OUT) :: check + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP) :: func + REAL(SP), DIMENSION(:), INTENT(IN) :: x + END FUNCTION func + END INTERFACE + END SUBROUTINE lnsrch + END INTERFACE + INTERFACE + FUNCTION locate(xx,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xx + REAL(SP), INTENT(IN) :: x + INTEGER(I4B) :: locate + END FUNCTION locate + END INTERFACE + INTERFACE + SUBROUTINE lubksb(a,indx,b) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indx + REAL(SP), DIMENSION(:), INTENT(INOUT) :: b + END SUBROUTINE lubksb + END INTERFACE + INTERFACE + SUBROUTINE ludcmp(a,indx,d) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: indx + REAL(SP), INTENT(OUT) :: d + END SUBROUTINE ludcmp + END INTERFACE + INTERFACE + SUBROUTINE machar(ibeta,it,irnd,ngrd,machep,negep,iexp,minexp,& + maxexp,eps,epsneg,xmin,xmax) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: ibeta,iexp,irnd,it,machep,maxexp,& + minexp,negep,ngrd + REAL(SP), INTENT(OUT) :: eps,epsneg,xmax,xmin + END SUBROUTINE machar + END INTERFACE + INTERFACE + SUBROUTINE medfit(x,y,a,b,abdev) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), INTENT(OUT) :: a,b,abdev + END SUBROUTINE medfit + END INTERFACE + INTERFACE + SUBROUTINE memcof(data,xms,d) + USE nrtype + REAL(SP), INTENT(OUT) :: xms + REAL(SP), DIMENSION(:), INTENT(IN) :: data + REAL(SP), DIMENSION(:), INTENT(OUT) :: d + END SUBROUTINE memcof + END INTERFACE + INTERFACE + SUBROUTINE midexp(funk,aa,bb,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: aa,bb + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION funk(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: funk + END FUNCTION funk + END INTERFACE + END SUBROUTINE midexp + END INTERFACE + INTERFACE + SUBROUTINE midinf(funk,aa,bb,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: aa,bb + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION funk(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: funk + END FUNCTION funk + END INTERFACE + END SUBROUTINE midinf + END INTERFACE + INTERFACE + SUBROUTINE midpnt(func,a,b,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE midpnt + END INTERFACE + INTERFACE + SUBROUTINE midsql(funk,aa,bb,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: aa,bb + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION funk(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: funk + END FUNCTION funk + END INTERFACE + END SUBROUTINE midsql + END INTERFACE + INTERFACE + SUBROUTINE midsqu(funk,aa,bb,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: aa,bb + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION funk(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: funk + END FUNCTION funk + END INTERFACE + END SUBROUTINE midsqu + END INTERFACE + INTERFACE + RECURSIVE SUBROUTINE miser(func,regn,ndim,npts,dith,ave,var) + USE nrtype + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP) :: func + REAL(SP), DIMENSION(:), INTENT(IN) :: x + END FUNCTION func + END INTERFACE + REAL(SP), DIMENSION(:), INTENT(IN) :: regn + INTEGER(I4B), INTENT(IN) :: ndim,npts + REAL(SP), INTENT(IN) :: dith + REAL(SP), INTENT(OUT) :: ave,var + END SUBROUTINE miser + END INTERFACE + INTERFACE + SUBROUTINE mmid(y,dydx,xs,htot,nstep,yout,derivs) + USE nrtype + INTEGER(I4B), INTENT(IN) :: nstep + REAL(SP), INTENT(IN) :: xs,htot + REAL(SP), DIMENSION(:), INTENT(IN) :: y,dydx + REAL(SP), DIMENSION(:), INTENT(OUT) :: yout + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE mmid + END INTERFACE + INTERFACE + SUBROUTINE mnbrak(ax,bx,cx,fa,fb,fc,func) + USE nrtype + REAL(SP), INTENT(INOUT) :: ax,bx + REAL(SP), INTENT(OUT) :: cx,fa,fb,fc + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE mnbrak + END INTERFACE + INTERFACE + SUBROUTINE mnewt(ntrial,x,tolx,tolf,usrfun) + USE nrtype + INTEGER(I4B), INTENT(IN) :: ntrial + REAL(SP), INTENT(IN) :: tolx,tolf + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + INTERFACE + SUBROUTINE usrfun(x,fvec,fjac) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(OUT) :: fvec + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: fjac + END SUBROUTINE usrfun + END INTERFACE + END SUBROUTINE mnewt + END INTERFACE + INTERFACE + SUBROUTINE moment(data,ave,adev,sdev,var,skew,curt) + USE nrtype + REAL(SP), INTENT(OUT) :: ave,adev,sdev,var,skew,curt + REAL(SP), DIMENSION(:), INTENT(IN) :: data + END SUBROUTINE moment + END INTERFACE + INTERFACE + SUBROUTINE mp2dfr(a,s,n,m) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B), INTENT(OUT) :: m + CHARACTER(1), DIMENSION(:), INTENT(INOUT) :: a + CHARACTER(1), DIMENSION(:), INTENT(OUT) :: s + END SUBROUTINE mp2dfr + END INTERFACE + INTERFACE + SUBROUTINE mpdiv(q,r,u,v,n,m) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(OUT) :: q,r + CHARACTER(1), DIMENSION(:), INTENT(IN) :: u,v + INTEGER(I4B), INTENT(IN) :: n,m + END SUBROUTINE mpdiv + END INTERFACE + INTERFACE + SUBROUTINE mpinv(u,v,n,m) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(OUT) :: u + CHARACTER(1), DIMENSION(:), INTENT(IN) :: v + INTEGER(I4B), INTENT(IN) :: n,m + END SUBROUTINE mpinv + END INTERFACE + INTERFACE + SUBROUTINE mpmul(w,u,v,n,m) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(IN) :: u,v + CHARACTER(1), DIMENSION(:), INTENT(OUT) :: w + INTEGER(I4B), INTENT(IN) :: n,m + END SUBROUTINE mpmul + END INTERFACE + INTERFACE + SUBROUTINE mppi(n) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + END SUBROUTINE mppi + END INTERFACE + INTERFACE + SUBROUTINE mprove(a,alud,indx,b,x) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a,alud + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indx + REAL(SP), DIMENSION(:), INTENT(IN) :: b + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + END SUBROUTINE mprove + END INTERFACE + INTERFACE + SUBROUTINE mpsqrt(w,u,v,n,m) + USE nrtype + CHARACTER(1), DIMENSION(:), INTENT(OUT) :: w,u + CHARACTER(1), DIMENSION(:), INTENT(IN) :: v + INTEGER(I4B), INTENT(IN) :: n,m + END SUBROUTINE mpsqrt + END INTERFACE + INTERFACE + SUBROUTINE mrqcof(x,y,sig,a,maska,alpha,beta,chisq,funcs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,a,sig + REAL(SP), DIMENSION(:), INTENT(OUT) :: beta + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: alpha + REAL(SP), INTENT(OUT) :: chisq + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: maska + INTERFACE + SUBROUTINE funcs(x,a,yfit,dyda) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,a + REAL(SP), DIMENSION(:), INTENT(OUT) :: yfit + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: dyda + END SUBROUTINE funcs + END INTERFACE + END SUBROUTINE mrqcof + END INTERFACE + INTERFACE + SUBROUTINE mrqmin(x,y,sig,a,maska,covar,alpha,chisq,funcs,alamda) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,sig + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: covar,alpha + REAL(SP), INTENT(OUT) :: chisq + REAL(SP), INTENT(INOUT) :: alamda + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: maska + INTERFACE + SUBROUTINE funcs(x,a,yfit,dyda) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,a + REAL(SP), DIMENSION(:), INTENT(OUT) :: yfit + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: dyda + END SUBROUTINE funcs + END INTERFACE + END SUBROUTINE mrqmin + END INTERFACE + INTERFACE + SUBROUTINE newt(x,check) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: x + LOGICAL(LGT), INTENT(OUT) :: check + END SUBROUTINE newt + END INTERFACE + INTERFACE + SUBROUTINE odeint(ystart,x1,x2,eps,h1,hmin,derivs,rkqs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: ystart + REAL(SP), INTENT(IN) :: x1,x2,eps,h1,hmin + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs +!BL + SUBROUTINE rkqs(y,dydx,x,htry,eps,yscal,hdid,hnext,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:), INTENT(IN) :: dydx,yscal + REAL(SP), INTENT(INOUT) :: x + REAL(SP), INTENT(IN) :: htry,eps + REAL(SP), INTENT(OUT) :: hdid,hnext + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE rkqs + END INTERFACE + END SUBROUTINE odeint + END INTERFACE + INTERFACE + SUBROUTINE orthog(anu,alpha,beta,a,b) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: anu,alpha,beta + REAL(SP), DIMENSION(:), INTENT(OUT) :: a,b + END SUBROUTINE orthog + END INTERFACE + INTERFACE + SUBROUTINE pade(cof,resid) + USE nrtype + REAL(DP), DIMENSION(:), INTENT(INOUT) :: cof + REAL(SP), INTENT(OUT) :: resid + END SUBROUTINE pade + END INTERFACE + INTERFACE + FUNCTION pccheb(d) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: d + REAL(SP), DIMENSION(size(d)) :: pccheb + END FUNCTION pccheb + END INTERFACE + INTERFACE + SUBROUTINE pcshft(a,b,d) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), DIMENSION(:), INTENT(INOUT) :: d + END SUBROUTINE pcshft + END INTERFACE + INTERFACE + SUBROUTINE pearsn(x,y,r,prob,z) + USE nrtype + REAL(SP), INTENT(OUT) :: r,prob,z + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + END SUBROUTINE pearsn + END INTERFACE + INTERFACE + SUBROUTINE period(x,y,ofac,hifac,px,py,jmax,prob) + USE nrtype + INTEGER(I4B), INTENT(OUT) :: jmax + REAL(SP), INTENT(IN) :: ofac,hifac + REAL(SP), INTENT(OUT) :: prob + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), DIMENSION(:), POINTER :: px,py + END SUBROUTINE period + END INTERFACE + INTERFACE plgndr + FUNCTION plgndr_s(l,m,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: l,m + REAL(SP), INTENT(IN) :: x + REAL(SP) :: plgndr_s + END FUNCTION plgndr_s +!BL + FUNCTION plgndr_v(l,m,x) + USE nrtype + INTEGER(I4B), INTENT(IN) :: l,m + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: plgndr_v + END FUNCTION plgndr_v + END INTERFACE + INTERFACE + FUNCTION poidev(xm) + USE nrtype + REAL(SP), INTENT(IN) :: xm + REAL(SP) :: poidev + END FUNCTION poidev + END INTERFACE + INTERFACE + FUNCTION polcoe(x,y) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), DIMENSION(size(x)) :: polcoe + END FUNCTION polcoe + END INTERFACE + INTERFACE + FUNCTION polcof(xa,ya) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xa,ya + REAL(SP), DIMENSION(size(xa)) :: polcof + END FUNCTION polcof + END INTERFACE + INTERFACE + SUBROUTINE poldiv(u,v,q,r) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: u,v + REAL(SP), DIMENSION(:), INTENT(OUT) :: q,r + END SUBROUTINE poldiv + END INTERFACE + INTERFACE + SUBROUTINE polin2(x1a,x2a,ya,x1,x2,y,dy) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x1a,x2a + REAL(SP), DIMENSION(:,:), INTENT(IN) :: ya + REAL(SP), INTENT(IN) :: x1,x2 + REAL(SP), INTENT(OUT) :: y,dy + END SUBROUTINE polin2 + END INTERFACE + INTERFACE + SUBROUTINE polint(xa,ya,x,y,dy) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xa,ya + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: y,dy + END SUBROUTINE polint + END INTERFACE + INTERFACE + SUBROUTINE powell(p,xi,ftol,iter,fret) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: p + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: xi + INTEGER(I4B), INTENT(OUT) :: iter + REAL(SP), INTENT(IN) :: ftol + REAL(SP), INTENT(OUT) :: fret + END SUBROUTINE powell + END INTERFACE + INTERFACE + FUNCTION predic(data,d,nfut) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data,d + INTEGER(I4B), INTENT(IN) :: nfut + REAL(SP), DIMENSION(nfut) :: predic + END FUNCTION predic + END INTERFACE + INTERFACE + FUNCTION probks(alam) + USE nrtype + REAL(SP), INTENT(IN) :: alam + REAL(SP) :: probks + END FUNCTION probks + END INTERFACE + INTERFACE psdes + SUBROUTINE psdes_s(lword,rword) + USE nrtype + INTEGER(I4B), INTENT(INOUT) :: lword,rword + END SUBROUTINE psdes_s +!BL + SUBROUTINE psdes_v(lword,rword) + USE nrtype + INTEGER(I4B), DIMENSION(:), INTENT(INOUT) :: lword,rword + END SUBROUTINE psdes_v + END INTERFACE + INTERFACE + SUBROUTINE pwt(a,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE pwt + END INTERFACE + INTERFACE + SUBROUTINE pwtset(n) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + END SUBROUTINE pwtset + END INTERFACE + INTERFACE pythag +!BL + FUNCTION pythag_sp(a,b) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP) :: pythag_sp + END FUNCTION pythag_sp + END INTERFACE + INTERFACE + SUBROUTINE pzextr(iest,xest,yest,yz,dy) + USE nrtype + INTEGER(I4B), INTENT(IN) :: iest + REAL(SP), INTENT(IN) :: xest + REAL(SP), DIMENSION(:), INTENT(IN) :: yest + REAL(SP), DIMENSION(:), INTENT(OUT) :: yz,dy + END SUBROUTINE pzextr + END INTERFACE + INTERFACE + SUBROUTINE qrdcmp(a,c,d,sing) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:), INTENT(OUT) :: c,d + LOGICAL(LGT), INTENT(OUT) :: sing + END SUBROUTINE qrdcmp + END INTERFACE + INTERFACE + FUNCTION qromb(func,a,b) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP) :: qromb + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END FUNCTION qromb + END INTERFACE + INTERFACE + FUNCTION qromo(func,a,b,choose) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP) :: qromo + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + INTERFACE + SUBROUTINE choose(funk,aa,bb,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: aa,bb + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION funk(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: funk + END FUNCTION funk + END INTERFACE + END SUBROUTINE choose + END INTERFACE + END FUNCTION qromo + END INTERFACE + INTERFACE + SUBROUTINE qroot(p,b,c,eps) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: p + REAL(SP), INTENT(INOUT) :: b,c + REAL(SP), INTENT(IN) :: eps + END SUBROUTINE qroot + END INTERFACE + INTERFACE + SUBROUTINE qrsolv(a,c,d,b) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + REAL(SP), DIMENSION(:), INTENT(IN) :: c,d + REAL(SP), DIMENSION(:), INTENT(INOUT) :: b + END SUBROUTINE qrsolv + END INTERFACE + INTERFACE + SUBROUTINE qrupdt(r,qt,u,v) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: r,qt + REAL(SP), DIMENSION(:), INTENT(INOUT) :: u + REAL(SP), DIMENSION(:), INTENT(IN) :: v + END SUBROUTINE qrupdt + END INTERFACE + INTERFACE + FUNCTION qsimp(func,a,b) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP) :: qsimp + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END FUNCTION qsimp + END INTERFACE + INTERFACE + FUNCTION qtrap(func,a,b) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP) :: qtrap + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END FUNCTION qtrap + END INTERFACE + INTERFACE + SUBROUTINE quadct(x,y,xx,yy,fa,fb,fc,fd) + USE nrtype + REAL(SP), INTENT(IN) :: x,y + REAL(SP), DIMENSION(:), INTENT(IN) :: xx,yy + REAL(SP), INTENT(OUT) :: fa,fb,fc,fd + END SUBROUTINE quadct + END INTERFACE + INTERFACE + SUBROUTINE quadmx(a) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: a + END SUBROUTINE quadmx + END INTERFACE + INTERFACE + SUBROUTINE quadvl(x,y,fa,fb,fc,fd) + USE nrtype + REAL(SP), INTENT(IN) :: x,y + REAL(SP), INTENT(OUT) :: fa,fb,fc,fd + END SUBROUTINE quadvl + END INTERFACE + INTERFACE + FUNCTION ran(idum) + INTEGER(selected_int_kind(9)), INTENT(INOUT) :: idum + REAL :: ran + END FUNCTION ran + END INTERFACE + INTERFACE ran0 + SUBROUTINE ran0_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE ran0_s +!BL + SUBROUTINE ran0_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE ran0_v + END INTERFACE + INTERFACE ran1 + SUBROUTINE ran1_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE ran1_s +!BL + SUBROUTINE ran1_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE ran1_v + END INTERFACE + INTERFACE ran2 + SUBROUTINE ran2_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE ran2_s +!BL + SUBROUTINE ran2_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE ran2_v + END INTERFACE + INTERFACE ran3 + SUBROUTINE ran3_s(harvest) + USE nrtype + REAL(SP), INTENT(OUT) :: harvest + END SUBROUTINE ran3_s +!BL + SUBROUTINE ran3_v(harvest) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: harvest + END SUBROUTINE ran3_v + END INTERFACE + INTERFACE + SUBROUTINE ratint(xa,ya,x,y,dy) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xa,ya + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: y,dy + END SUBROUTINE ratint + END INTERFACE + INTERFACE rc + FUNCTION rc_s(x,y) + USE nrtype + REAL(SP), INTENT(IN) :: x,y + REAL(SP) :: rc_s + END FUNCTION rc_s +!BL + FUNCTION rc_v(x,y) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), DIMENSION(size(x)) :: rc_v + END FUNCTION rc_v + END INTERFACE + INTERFACE rd + FUNCTION rd_s(x,y,z) + USE nrtype + REAL(SP), INTENT(IN) :: x,y,z + REAL(SP) :: rd_s + END FUNCTION rd_s +!BL + FUNCTION rd_v(x,y,z) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,z + REAL(SP), DIMENSION(size(x)) :: rd_v + END FUNCTION rd_v + END INTERFACE + INTERFACE realft +!BL + SUBROUTINE realft_sp(data,isign,zdata) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: data + INTEGER(I4B), INTENT(IN) :: isign + COMPLEX(SPC), DIMENSION(:), OPTIONAL, TARGET :: zdata + END SUBROUTINE realft_sp + END INTERFACE + INTERFACE + RECURSIVE FUNCTION recur1(a,b) RESULT(u) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b + REAL(SP), DIMENSION(size(a)) :: u + END FUNCTION recur1 + END INTERFACE + INTERFACE + FUNCTION recur2(a,b,c) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b,c + REAL(SP), DIMENSION(size(a)) :: recur2 + END FUNCTION recur2 + END INTERFACE + INTERFACE rf + FUNCTION rf_s(x,y,z) + USE nrtype + REAL(SP), INTENT(IN) :: x,y,z + REAL(SP) :: rf_s + END FUNCTION rf_s +!BL + FUNCTION rf_v(x,y,z) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,z + REAL(SP), DIMENSION(size(x)) :: rf_v + END FUNCTION rf_v + END INTERFACE + INTERFACE rj + FUNCTION rj_s(x,y,z,p) + USE nrtype + REAL(SP), INTENT(IN) :: x,y,z,p + REAL(SP) :: rj_s + END FUNCTION rj_s +!BL + FUNCTION rj_v(x,y,z,p) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,z,p + REAL(SP), DIMENSION(size(x)) :: rj_v + END FUNCTION rj_v + END INTERFACE + INTERFACE + SUBROUTINE rk4(y,dydx,x,h,yout,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: y,dydx + REAL(SP), INTENT(IN) :: x,h + REAL(SP), DIMENSION(:), INTENT(OUT) :: yout + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE rk4 + END INTERFACE + INTERFACE + SUBROUTINE rkck(y,dydx,x,h,yout,yerr,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: y,dydx + REAL(SP), INTENT(IN) :: x,h + REAL(SP), DIMENSION(:), INTENT(OUT) :: yout,yerr + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE rkck + END INTERFACE + INTERFACE + SUBROUTINE rkdumb(vstart,x1,x2,nstep,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: vstart + REAL(SP), INTENT(IN) :: x1,x2 + INTEGER(I4B), INTENT(IN) :: nstep + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE rkdumb + END INTERFACE + INTERFACE + SUBROUTINE rkqs(y,dydx,x,htry,eps,yscal,hdid,hnext,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:), INTENT(IN) :: dydx,yscal + REAL(SP), INTENT(INOUT) :: x + REAL(SP), INTENT(IN) :: htry,eps + REAL(SP), INTENT(OUT) :: hdid,hnext + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE rkqs + END INTERFACE + INTERFACE + SUBROUTINE rlft2(data,spec,speq,isign) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: data + COMPLEX(SPC), DIMENSION(:,:), INTENT(OUT) :: spec + COMPLEX(SPC), DIMENSION(:), INTENT(OUT) :: speq + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE rlft2 + END INTERFACE + INTERFACE + SUBROUTINE rlft3(data,spec,speq,isign) + USE nrtype + REAL(SP), DIMENSION(:,:,:), INTENT(INOUT) :: data + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(OUT) :: spec + COMPLEX(SPC), DIMENSION(:,:), INTENT(OUT) :: speq + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE rlft3 + END INTERFACE + INTERFACE + SUBROUTINE rotate(r,qt,i,a,b) + USE nrtype + REAL(SP), DIMENSION(:,:), TARGET, INTENT(INOUT) :: r,qt + INTEGER(I4B), INTENT(IN) :: i + REAL(SP), INTENT(IN) :: a,b + END SUBROUTINE rotate + END INTERFACE + INTERFACE + SUBROUTINE rsolv(a,d,b) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + REAL(SP), DIMENSION(:), INTENT(IN) :: d + REAL(SP), DIMENSION(:), INTENT(INOUT) :: b + END SUBROUTINE rsolv + END INTERFACE + INTERFACE + FUNCTION rtbis(func,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: rtbis + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION rtbis + END INTERFACE + INTERFACE + FUNCTION rtflsp(func,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: rtflsp + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION rtflsp + END INTERFACE + INTERFACE + FUNCTION rtnewt(funcd,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: rtnewt + INTERFACE + SUBROUTINE funcd(x,fval,fderiv) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: fval,fderiv + END SUBROUTINE funcd + END INTERFACE + END FUNCTION rtnewt + END INTERFACE + INTERFACE + FUNCTION rtsafe(funcd,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: rtsafe + INTERFACE + SUBROUTINE funcd(x,fval,fderiv) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: fval,fderiv + END SUBROUTINE funcd + END INTERFACE + END FUNCTION rtsafe + END INTERFACE + INTERFACE + FUNCTION rtsec(func,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: rtsec + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION rtsec + END INTERFACE + INTERFACE + SUBROUTINE rzextr(iest,xest,yest,yz,dy) + USE nrtype + INTEGER(I4B), INTENT(IN) :: iest + REAL(SP), INTENT(IN) :: xest + REAL(SP), DIMENSION(:), INTENT(IN) :: yest + REAL(SP), DIMENSION(:), INTENT(OUT) :: yz,dy + END SUBROUTINE rzextr + END INTERFACE + INTERFACE + FUNCTION savgol(nl,nrr,ld,m) + USE nrtype + INTEGER(I4B), INTENT(IN) :: nl,nrr,ld,m + REAL(SP), DIMENSION(nl+nrr+1) :: savgol + END FUNCTION savgol + END INTERFACE + INTERFACE + SUBROUTINE scrsho(func) + USE nrtype + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE scrsho + END INTERFACE + INTERFACE + FUNCTION select(k,arr) + USE nrtype + INTEGER(I4B), INTENT(IN) :: k + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + REAL(SP) :: select + END FUNCTION select + END INTERFACE + INTERFACE + FUNCTION select_bypack(k,arr) + USE nrtype + INTEGER(I4B), INTENT(IN) :: k + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + REAL(SP) :: select_bypack + END FUNCTION select_bypack + END INTERFACE + INTERFACE + SUBROUTINE select_heap(arr,heap) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + REAL(SP), DIMENSION(:), INTENT(OUT) :: heap + END SUBROUTINE select_heap + END INTERFACE + INTERFACE + FUNCTION select_inplace(k,arr) + USE nrtype + INTEGER(I4B), INTENT(IN) :: k + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + REAL(SP) :: select_inplace + END FUNCTION select_inplace + END INTERFACE + INTERFACE + SUBROUTINE simplx(a,m1,m2,m3,icase,izrov,iposv) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: m1,m2,m3 + INTEGER(I4B), INTENT(OUT) :: icase + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: izrov,iposv + END SUBROUTINE simplx + END INTERFACE + INTERFACE + SUBROUTINE simpr(y,dydx,dfdx,dfdy,xs,htot,nstep,yout,derivs) + USE nrtype + REAL(SP), INTENT(IN) :: xs,htot + REAL(SP), DIMENSION(:), INTENT(IN) :: y,dydx,dfdx + REAL(SP), DIMENSION(:,:), INTENT(IN) :: dfdy + INTEGER(I4B), INTENT(IN) :: nstep + REAL(SP), DIMENSION(:), INTENT(OUT) :: yout + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE simpr + END INTERFACE + INTERFACE + SUBROUTINE sinft(y) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + END SUBROUTINE sinft + END INTERFACE + INTERFACE + SUBROUTINE sncndn(uu,emmc,sn,cn,dn) + USE nrtype + REAL(SP), INTENT(IN) :: uu,emmc + REAL(SP), INTENT(OUT) :: sn,cn,dn + END SUBROUTINE sncndn + END INTERFACE + INTERFACE + SUBROUTINE sobseq(x,init) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: x + INTEGER(I4B), OPTIONAL, INTENT(IN) :: init + END SUBROUTINE sobseq + END INTERFACE + INTERFACE + SUBROUTINE solvde(itmax,conv,slowc,scalv,indexv,nb,y) + USE nrtype + INTEGER(I4B), INTENT(IN) :: itmax,nb + REAL(SP), INTENT(IN) :: conv,slowc + REAL(SP), DIMENSION(:), INTENT(IN) :: scalv + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: indexv + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: y + END SUBROUTINE solvde + END INTERFACE + INTERFACE + SUBROUTINE sort(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort + END INTERFACE + INTERFACE + SUBROUTINE sort2(arr,slave) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr,slave + END SUBROUTINE sort2 + END INTERFACE + INTERFACE + SUBROUTINE sort3(arr,slave1,slave2) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr,slave1,slave2 + END SUBROUTINE sort3 + END INTERFACE + INTERFACE + SUBROUTINE sort_bypack(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_bypack + END INTERFACE + INTERFACE + SUBROUTINE sort_byreshape(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_byreshape + END INTERFACE + INTERFACE + SUBROUTINE sort_heap(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_heap + END INTERFACE + INTERFACE + SUBROUTINE sort_pick(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_pick + END INTERFACE + INTERFACE + SUBROUTINE sort_radix(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_radix + END INTERFACE + INTERFACE + SUBROUTINE sort_shell(arr) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: arr + END SUBROUTINE sort_shell + END INTERFACE + INTERFACE + SUBROUTINE spctrm(p,k,ovrlap,unit,n_window) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(OUT) :: p + INTEGER(I4B), INTENT(IN) :: k + LOGICAL(LGT), INTENT(IN) :: ovrlap + INTEGER(I4B), OPTIONAL, INTENT(IN) :: n_window,unit + END SUBROUTINE spctrm + END INTERFACE + INTERFACE + SUBROUTINE spear(data1,data2,d,zd,probd,rs,probrs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + REAL(SP), INTENT(OUT) :: d,zd,probd,rs,probrs + END SUBROUTINE spear + END INTERFACE + INTERFACE sphbes + SUBROUTINE sphbes_s(n,x,sj,sy,sjp,syp) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: x + REAL(SP), INTENT(OUT) :: sj,sy,sjp,syp + END SUBROUTINE sphbes_s +!BL + SUBROUTINE sphbes_v(n,x,sj,sy,sjp,syp) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(OUT) :: sj,sy,sjp,syp + END SUBROUTINE sphbes_v + END INTERFACE + INTERFACE + SUBROUTINE splie2(x1a,x2a,ya,y2a) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x1a,x2a + REAL(SP), DIMENSION(:,:), INTENT(IN) :: ya + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: y2a + END SUBROUTINE splie2 + END INTERFACE + INTERFACE + FUNCTION splin2(x1a,x2a,ya,y2a,x1,x2) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x1a,x2a + REAL(SP), DIMENSION(:,:), INTENT(IN) :: ya,y2a + REAL(SP), INTENT(IN) :: x1,x2 + REAL(SP) :: splin2 + END FUNCTION splin2 + END INTERFACE + INTERFACE + SUBROUTINE spline(x,y,yp1,ypn,y2) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y + REAL(SP), INTENT(IN) :: yp1,ypn + REAL(SP), DIMENSION(:), INTENT(OUT) :: y2 + END SUBROUTINE spline + END INTERFACE + INTERFACE + FUNCTION splint(xa,ya,y2a,x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: xa,ya,y2a + REAL(SP), INTENT(IN) :: x + REAL(SP) :: splint + END FUNCTION splint + END INTERFACE + INTERFACE sprsax + SUBROUTINE sprsax_dp(sa,x,b) + USE nrtype + TYPE(sprs2_dp), INTENT(IN) :: sa + REAL(DP), DIMENSION (:), INTENT(IN) :: x + REAL(DP), DIMENSION (:), INTENT(OUT) :: b + END SUBROUTINE sprsax_dp +!BL + SUBROUTINE sprsax_sp(sa,x,b) + USE nrtype + TYPE(sprs2_sp), INTENT(IN) :: sa + REAL(SP), DIMENSION (:), INTENT(IN) :: x + REAL(SP), DIMENSION (:), INTENT(OUT) :: b + END SUBROUTINE sprsax_sp + END INTERFACE + INTERFACE sprsdiag + SUBROUTINE sprsdiag_dp(sa,b) + USE nrtype + TYPE(sprs2_dp), INTENT(IN) :: sa + REAL(DP), DIMENSION(:), INTENT(OUT) :: b + END SUBROUTINE sprsdiag_dp +!BL + SUBROUTINE sprsdiag_sp(sa,b) + USE nrtype + TYPE(sprs2_sp), INTENT(IN) :: sa + REAL(SP), DIMENSION(:), INTENT(OUT) :: b + END SUBROUTINE sprsdiag_sp + END INTERFACE + INTERFACE sprsin + SUBROUTINE sprsin_sp(a,thresh,sa) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: a + REAL(SP), INTENT(IN) :: thresh + TYPE(sprs2_sp), INTENT(OUT) :: sa + END SUBROUTINE sprsin_sp +!BL + SUBROUTINE sprsin_dp(a,thresh,sa) + USE nrtype + REAL(DP), DIMENSION(:,:), INTENT(IN) :: a + REAL(DP), INTENT(IN) :: thresh + TYPE(sprs2_dp), INTENT(OUT) :: sa + END SUBROUTINE sprsin_dp + END INTERFACE + INTERFACE + SUBROUTINE sprstp(sa) + USE nrtype + TYPE(sprs2_sp), INTENT(INOUT) :: sa + END SUBROUTINE sprstp + END INTERFACE + INTERFACE sprstx + SUBROUTINE sprstx_dp(sa,x,b) + USE nrtype + TYPE(sprs2_dp), INTENT(IN) :: sa + REAL(DP), DIMENSION (:), INTENT(IN) :: x + REAL(DP), DIMENSION (:), INTENT(OUT) :: b + END SUBROUTINE sprstx_dp +!BL + SUBROUTINE sprstx_sp(sa,x,b) + USE nrtype + TYPE(sprs2_sp), INTENT(IN) :: sa + REAL(SP), DIMENSION (:), INTENT(IN) :: x + REAL(SP), DIMENSION (:), INTENT(OUT) :: b + END SUBROUTINE sprstx_sp + END INTERFACE + INTERFACE + SUBROUTINE stifbs(y,dydx,x,htry,eps,yscal,hdid,hnext,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:), INTENT(IN) :: dydx,yscal + REAL(SP), INTENT(IN) :: htry,eps + REAL(SP), INTENT(INOUT) :: x + REAL(SP), INTENT(OUT) :: hdid,hnext + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE stifbs + END INTERFACE + INTERFACE + SUBROUTINE stiff(y,dydx,x,htry,eps,yscal,hdid,hnext,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: y + REAL(SP), DIMENSION(:), INTENT(IN) :: dydx,yscal + REAL(SP), INTENT(INOUT) :: x + REAL(SP), INTENT(IN) :: htry,eps + REAL(SP), INTENT(OUT) :: hdid,hnext + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE stiff + END INTERFACE + INTERFACE + SUBROUTINE stoerm(y,d2y,xs,htot,nstep,yout,derivs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: y,d2y + REAL(SP), INTENT(IN) :: xs,htot + INTEGER(I4B), INTENT(IN) :: nstep + REAL(SP), DIMENSION(:), INTENT(OUT) :: yout + INTERFACE + SUBROUTINE derivs(x,y,dydx) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: y + REAL(SP), DIMENSION(:), INTENT(OUT) :: dydx + END SUBROUTINE derivs + END INTERFACE + END SUBROUTINE stoerm + END INTERFACE + INTERFACE svbksb +!BL + SUBROUTINE svbksb_sp(u,w,v,b,x) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: u,v + REAL(SP), DIMENSION(:), INTENT(IN) :: w,b + REAL(SP), DIMENSION(:), INTENT(OUT) :: x + END SUBROUTINE svbksb_sp + END INTERFACE + INTERFACE svdcmp +!BL + SUBROUTINE svdcmp_sp(a,w,v) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:), INTENT(OUT) :: w + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: v + END SUBROUTINE svdcmp_sp + END INTERFACE + INTERFACE + SUBROUTINE svdfit(x,y,sig,a,v,w,chisq,funcs) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x,y,sig + REAL(SP), DIMENSION(:), INTENT(OUT) :: a,w + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: v + REAL(SP), INTENT(OUT) :: chisq + INTERFACE + FUNCTION funcs(x,n) + USE nrtype + REAL(SP), INTENT(IN) :: x + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: funcs + END FUNCTION funcs + END INTERFACE + END SUBROUTINE svdfit + END INTERFACE + INTERFACE + SUBROUTINE svdvar(v,w,cvm) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(IN) :: v + REAL(SP), DIMENSION(:), INTENT(IN) :: w + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: cvm + END SUBROUTINE svdvar + END INTERFACE + INTERFACE + FUNCTION toeplz(r,y) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: r,y + REAL(SP), DIMENSION(size(y)) :: toeplz + END FUNCTION toeplz + END INTERFACE + INTERFACE + SUBROUTINE tptest(data1,data2,t,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + REAL(SP), INTENT(OUT) :: t,prob + END SUBROUTINE tptest + END INTERFACE + INTERFACE + SUBROUTINE tqli(d,e,z) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: d,e + REAL(SP), DIMENSION(:,:), OPTIONAL, INTENT(INOUT) :: z + END SUBROUTINE tqli + END INTERFACE + INTERFACE + SUBROUTINE trapzd(func,a,b,s,n) + USE nrtype + REAL(SP), INTENT(IN) :: a,b + REAL(SP), INTENT(INOUT) :: s + INTEGER(I4B), INTENT(IN) :: n + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: x + REAL(SP), DIMENSION(size(x)) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE trapzd + END INTERFACE + INTERFACE + SUBROUTINE tred2(a,d,e,novectors) + USE nrtype + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a + REAL(SP), DIMENSION(:), INTENT(OUT) :: d,e + LOGICAL(LGT), OPTIONAL, INTENT(IN) :: novectors + END SUBROUTINE tred2 + END INTERFACE +! On a purely serial machine, for greater efficiency, remove +! the generic name tridag from the following interface, +! and put it on the next one after that. + INTERFACE tridag + RECURSIVE SUBROUTINE tridag_par(a,b,c,r,u) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b,c,r + REAL(SP), DIMENSION(:), INTENT(OUT) :: u + END SUBROUTINE tridag_par + END INTERFACE + INTERFACE + SUBROUTINE tridag_ser(a,b,c,r,u) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b,c,r + REAL(SP), DIMENSION(:), INTENT(OUT) :: u + END SUBROUTINE tridag_ser + END INTERFACE + INTERFACE + SUBROUTINE ttest(data1,data2,t,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + REAL(SP), INTENT(OUT) :: t,prob + END SUBROUTINE ttest + END INTERFACE + INTERFACE + SUBROUTINE tutest(data1,data2,t,prob) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + REAL(SP), INTENT(OUT) :: t,prob + END SUBROUTINE tutest + END INTERFACE + INTERFACE + SUBROUTINE twofft(data1,data2,fft1,fft2) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: data1,data2 + COMPLEX(SPC), DIMENSION(:), INTENT(OUT) :: fft1,fft2 + END SUBROUTINE twofft + END INTERFACE + INTERFACE + SUBROUTINE vegas(region,func,init,ncall,itmx,nprn,tgral,sd,chi2a) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: region + INTEGER(I4B), INTENT(IN) :: init,ncall,itmx,nprn + REAL(SP), INTENT(OUT) :: tgral,sd,chi2a + INTERFACE + FUNCTION func(pt,wgt) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: pt + REAL(SP), INTENT(IN) :: wgt + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE vegas + END INTERFACE + INTERFACE + SUBROUTINE voltra(t0,h,t,f,g,ak) + USE nrtype + REAL(SP), INTENT(IN) :: t0,h + REAL(SP), DIMENSION(:), INTENT(OUT) :: t + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: f + INTERFACE + FUNCTION g(t) + USE nrtype + REAL(SP), INTENT(IN) :: t + REAL(SP), DIMENSION(:), POINTER :: g + END FUNCTION g +!BL + FUNCTION ak(t,s) + USE nrtype + REAL(SP), INTENT(IN) :: t,s + REAL(SP), DIMENSION(:,:), POINTER :: ak + END FUNCTION ak + END INTERFACE + END SUBROUTINE voltra + END INTERFACE + INTERFACE + SUBROUTINE wt1(a,isign,wtstep) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: isign + INTERFACE + SUBROUTINE wtstep(a,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE wtstep + END INTERFACE + END SUBROUTINE wt1 + END INTERFACE + INTERFACE + SUBROUTINE wtn(a,nn,isign,wtstep) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: nn + INTEGER(I4B), INTENT(IN) :: isign + INTERFACE + SUBROUTINE wtstep(a,isign) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a + INTEGER(I4B), INTENT(IN) :: isign + END SUBROUTINE wtstep + END INTERFACE + END SUBROUTINE wtn + END INTERFACE + INTERFACE + FUNCTION wwghts(n,h,kermom) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), INTENT(IN) :: h + REAL(SP), DIMENSION(n) :: wwghts + END FUNCTION wwghts + END INTERFACE + INTERFACE + SUBROUTINE zbrac(func,x1,x2,succes) + USE nrtype + REAL(SP), INTENT(INOUT) :: x1,x2 + LOGICAL(LGT), INTENT(OUT) :: succes + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE zbrac + END INTERFACE + INTERFACE + SUBROUTINE zbrak(func,x1,x2,n,xb1,xb2,nb) + USE nrtype + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B), INTENT(OUT) :: nb + REAL(SP), INTENT(IN) :: x1,x2 + REAL(SP), DIMENSION(:), POINTER :: xb1,xb2 + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END SUBROUTINE zbrak + END INTERFACE + INTERFACE + FUNCTION zbrent(func,x1,x2,tol) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,tol + REAL(SP) :: zbrent + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION zbrent + END INTERFACE + INTERFACE + SUBROUTINE zrhqr(a,rtr,rti) + USE nrtype + REAL(SP), DIMENSION(:), INTENT(IN) :: a + REAL(SP), DIMENSION(:), INTENT(OUT) :: rtr,rti + END SUBROUTINE zrhqr + END INTERFACE + INTERFACE + FUNCTION zriddr(func,x1,x2,xacc) + USE nrtype + REAL(SP), INTENT(IN) :: x1,x2,xacc + REAL(SP) :: zriddr + INTERFACE + FUNCTION func(x) + USE nrtype + REAL(SP), INTENT(IN) :: x + REAL(SP) :: func + END FUNCTION func + END INTERFACE + END FUNCTION zriddr + END INTERFACE + INTERFACE + SUBROUTINE zroots(a,roots,polish) + USE nrtype + COMPLEX(SPC), DIMENSION(:), INTENT(IN) :: a + COMPLEX(SPC), DIMENSION(:), INTENT(OUT) :: roots + LOGICAL(LGT), INTENT(IN) :: polish + END SUBROUTINE zroots + END INTERFACE +END MODULE nr diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/nrtype.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/nrtype.f90 new file mode 100644 index 000000000..083ed64d1 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/nrtype.f90 @@ -0,0 +1,114 @@ +MODULE nrtype + INTEGER, PARAMETER :: I4B = SELECTED_INT_KIND(9) + INTEGER, PARAMETER :: I2B = SELECTED_INT_KIND(4) + INTEGER, PARAMETER :: I1B = SELECTED_INT_KIND(2) + INTEGER, PARAMETER :: SP = KIND(1.0D0) + INTEGER, PARAMETER :: DP = KIND(1.0D0) + INTEGER, PARAMETER :: SPC = KIND((1.0D0,1.0D0)) + INTEGER, PARAMETER :: DPC = KIND((1.0D0,1.0D0)) + INTEGER, PARAMETER :: LGT = KIND(.true.) +! REAL(SP), PARAMETER :: PI=3.141592653589793238462643383279502884197_sp + REAL(SP), PARAMETER :: PIO2=1.57079632679489661923132169163975144209858_sp + REAL(SP), PARAMETER :: TWOPI=6.283185307179586476925286766559005768394_sp + REAL(SP), PARAMETER :: SQRT2=1.41421356237309504880168872420969807856967_sp + REAL(SP), PARAMETER :: EULER=0.5772156649015328606065120900824024310422_sp + REAL(DP), PARAMETER :: PI_D=3.141592653589793238462643383279502884197_dp + REAL(DP), PARAMETER :: PIO2_D=1.57079632679489661923132169163975144209858_dp + REAL(DP), PARAMETER :: TWOPI_D=6.283185307179586476925286766559005768394_dp + TYPE sprs2_sp + INTEGER(I4B) :: n,len + REAL(SP), DIMENSION(:), POINTER :: val + INTEGER(I4B), DIMENSION(:), POINTER :: irow + INTEGER(I4B), DIMENSION(:), POINTER :: jcol + END TYPE sprs2_sp + TYPE sprs2_dp + INTEGER(I4B) :: n,len + REAL(DP), DIMENSION(:), POINTER :: val + INTEGER(I4B), DIMENSION(:), POINTER :: irow + INTEGER(I4B), DIMENSION(:), POINTER :: jcol + END TYPE sprs2_dp +END MODULE nrtype + +!About Converting to Higher Precision +!===================================== + +!!$You might hope that changing all the Numerical Recipes routines from single +!!$precision to double precision would be as simple as redefining the values of SP and +!!$DP in nrtype. Well . . . not quite. +!!$Converting algorithms to a higher precision is not a purely mechanical task +!!$because of the distinction between âroundoff errorâ and âtruncation error.â (Please +!!$see Volume 1, §1.2, if you are not familiar with these concepts.) While increasing the +!!$precision implied by the kind values SP and DP will indeed reduce a routineâs roundoff +!!$error, it will not reduce any truncation error that may be intrinsic to the algorithm. +!!$Sometimes, a routine contains âaccuracy parametersâ that can be adjusted to reduce +!!$the truncation error to the new, desired level. In other cases, however, the truncation +!!$error cannot be so easily reduced; then, a whole new algorithm is needed. Clearly +!!$such new algorithms are beyond the scope of a simple mechanical âconversion.â +!!$If, despite these cautionary words, you want to proceed with converting some +!!$routines to a higher precision, here are some hints: +!!$If your machine has a kind type that is distinct from, and has equal or greater +!!$precision than, the kind type that we use for DP, then, in nrtype, you can simply +!!$redefine DP to this new highest precision and redefine SP to what was previously +!!$DP. For example, DEC machines usually have a âquadruple precisionâ real type +!!$available, which can be used in this way. You should not need to make any further +!!$edits of nrtype or nrutil. +!!$If, on the other hand, the kind type that we already use for DP is the highest +!!$precision available, then you must leave DP defined as it is, and redefine SP in nrtype +!!$to be this same kind type. Now, however, you will also have to edit nrutil, because +!!$some overloaded routines that were previously distinguishable (by the different kind +!!$types) will now be seen by the compiler as indistinguishable â and it will object +!!$strenuously. Simply delete all the â dpâ function names from the list of overloaded +!!$procedures (i.e., from the MODULE PROCEDURE statements). Note that it is not +!!$necessary to delete the routines from the MODULE itself. Similarly, in the interface +!!$file nr.f90 you must delete the â dpâ interfaces, except for the sprs... routines. +!!$(Since they have TYPE(sprs2 dp) or TYPE(sprs2 sp), they are treated as distinct +!!$even though they have functionally equivalent kind types.) +!!$Finally, the following table gives some suggestions for changing the accuracy +!!$parameters, or constants, in some of the routines. Please note that this table is not +!!$necessarily complete, and that higher-precision performance is not guaranteed for all +!!$the routines, even if you make all the changes indicated. The above edits, and these +!!$suggestions, do, however, work in the majority of cases. +!!$ +!!$ +!!$ +!!$ +!!$ +!!$In routine... change... to... +!!$beschb NUSE1=5,NUSE2=5 NUSE1=7,NUSE2=8 +!!$bessi IACC=40 IACC=200 +!!$bessik EPS=1.0e-10 dp EPS=epsilon(x) +!!$bessj IACC=40 IACC=160 +!!$bessjy EPS=1.0e-10 dp EPS=epsilon(x) +!!$broydn TOLF=1.0e-4 sp TOLF=1.0e-8 sp +!!$TOLMIN=1.0e-6 sp TOLMIN=1.0e-12 sp +!!$fdjac EPS=1.0e-4 sp EPS=1.0e-8 sp +!!$frprmn EPS=1.0e-10 sp EPS=1.0e-18 sp +!!$gauher EPS=3.0e-13 dp EPS=1.0e-14 dp +!!$gaujac EPS=3.0e-14 dp EPS=1.0e-14 dp +!!$gaulag EPS=3.0e-13 dp EPS=1.0e-14 dp +!!$gauleg EPS=3.0e-14 dp EPS=1.0e-14 dp +!!$hypgeo EPS=1.0e-6 sp EPS=1.0e-14 sp +!!$linmin TOL=1.0e-4 sp TOL=1.0e-8 sp +!!$newt TOLF=1.0e-4 sp TOLF=1.0e-8 sp +!!$TOLMIN=1.0e-6 sp TOLMIN=1.0e-12 sp +!!$probks EPS1=0.001 sp EPS1=1.0e-6 sp +!!$EPS2=1.0e-8 sp EPS2=1.0e-16 sp +!!$qromb EPS=1.0e-6 sp EPS=1.0e-10 sp +!!$qromo EPS=1.0e-6 sp EPS=1.0e-10 sp +!!$qroot TINY=1.0e-6 sp TINY=1.0e-14 sp +!!$qsimp EPS=1.0e-6 sp EPS=1.0e-10 sp +!!$qtrap EPS=1.0e-6 sp EPS=1.0e-10 sp +!!$rc ERRTOL=0.04 sp ERRTOL=0.0012 sp +!!$rd ERRTOL=0.05 sp ERRTOL=0.0015 sp +!!$rf ERRTOL=0.08 sp ERRTOL=0.0025 sp +!!$rj ERRTOL=0.05 sp ERRTOL=0.0015 sp +!!$sfroid conv=5.0e-6 sp conv=1.0e-14 sp +!!$shoot EPS=1.0e-6 sp EPS=1.0e-14 sp +!!$shootf EPS=1.0e-6 sp EPS=1.0e-14 sp +!!$simplx EPS=1.0e-6 sp EPS=1.0e-14 sp +!!$sncndn CA=0.0003 sp CA=1.0e-8 sp +!!$sor EPS=1.0e-5 dp EPS=1.0e-13 dp +!!$sphfpt DXX=1.0e-4 sp DXX=1.0e-8 sp +!!$sphoot dx=1.0e-4 sp dx=1.0e-8 sp +!!$svdfit TOL=1.0e-5 sp TOL=1.0e-13 sp +!!$zroots EPS=1.0e-6 sp EPS=1.0e-14 sp diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/nrutil.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/nrutil.f90 new file mode 100644 index 000000000..f5b6a296f --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/nrutil.f90 @@ -0,0 +1,1154 @@ +MODULE nrutil + USE nrtype + IMPLICIT NONE + INTEGER(I4B), PARAMETER :: NPAR_ARTH=16,NPAR2_ARTH=8 + INTEGER(I4B), PARAMETER :: NPAR_GEOP=4,NPAR2_GEOP=2 + INTEGER(I4B), PARAMETER :: NPAR_CUMSUM=16 + INTEGER(I4B), PARAMETER :: NPAR_CUMPROD=8 + INTEGER(I4B), PARAMETER :: NPAR_POLY=8 + INTEGER(I4B), PARAMETER :: NPAR_POLYTERM=8 + INTERFACE array_copy + MODULE PROCEDURE array_copy_r,array_copy_i + END INTERFACE + INTERFACE swap + MODULE PROCEDURE swap_i,swap_r,swap_rv,swap_c, & + swap_cv,swap_cm, & + masked_swap_rs,masked_swap_rv,masked_swap_rm + END INTERFACE + INTERFACE reallocate + MODULE PROCEDURE reallocate_rv,reallocate_rm,& + reallocate_iv,reallocate_im,reallocate_hv + END INTERFACE + INTERFACE imaxloc + MODULE PROCEDURE imaxloc_r,imaxloc_i + END INTERFACE + INTERFACE assert + MODULE PROCEDURE assert1,assert2,assert3,assert4,assert_v + END INTERFACE + INTERFACE assert_eq + MODULE PROCEDURE assert_eq2,assert_eq3,assert_eq4,assert_eqn + END INTERFACE + INTERFACE arth + MODULE PROCEDURE arth_r, arth_i + END INTERFACE + INTERFACE geop + MODULE PROCEDURE geop_r, geop_i, geop_c + END INTERFACE + INTERFACE cumsum + MODULE PROCEDURE cumsum_r,cumsum_i + END INTERFACE + INTERFACE poly + MODULE PROCEDURE poly_rr,poly_rrv,& + poly_rc,poly_cc,poly_msk_rrv + END INTERFACE + INTERFACE poly_term + MODULE PROCEDURE poly_term_rr,poly_term_cc + END INTERFACE + INTERFACE outerprod + MODULE PROCEDURE outerprod_r + END INTERFACE + INTERFACE outerdiff + MODULE PROCEDURE outerdiff_r,outerdiff_i + END INTERFACE + INTERFACE scatter_add + MODULE PROCEDURE scatter_add_r + END INTERFACE + INTERFACE scatter_max + MODULE PROCEDURE scatter_max_r + END INTERFACE + INTERFACE diagadd + MODULE PROCEDURE diagadd_rv,diagadd_r + END INTERFACE + INTERFACE diagmult + MODULE PROCEDURE diagmult_rv,diagmult_r + END INTERFACE + INTERFACE get_diag + MODULE PROCEDURE get_diag_rv + END INTERFACE + INTERFACE put_diag + MODULE PROCEDURE put_diag_rv, put_diag_r + END INTERFACE +CONTAINS +!BL + SUBROUTINE array_copy_r(src,dest,n_copied,n_not_copied) + REAL(SP), DIMENSION(:), INTENT(IN) :: src + REAL(SP), DIMENSION(:), INTENT(OUT) :: dest + INTEGER(I4B), INTENT(OUT) :: n_copied, n_not_copied + n_copied=min(size(src),size(dest)) + n_not_copied=size(src)-n_copied + dest(1:n_copied)=src(1:n_copied) + END SUBROUTINE array_copy_r +!BL + SUBROUTINE array_copy_d(src,dest,n_copied,n_not_copied) + REAL(DP), DIMENSION(:), INTENT(IN) :: src + REAL(DP), DIMENSION(:), INTENT(OUT) :: dest + INTEGER(I4B), INTENT(OUT) :: n_copied, n_not_copied + n_copied=min(size(src),size(dest)) + n_not_copied=size(src)-n_copied + dest(1:n_copied)=src(1:n_copied) + END SUBROUTINE array_copy_d +!BL + SUBROUTINE array_copy_i(src,dest,n_copied,n_not_copied) + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: src + INTEGER(I4B), DIMENSION(:), INTENT(OUT) :: dest + INTEGER(I4B), INTENT(OUT) :: n_copied, n_not_copied + n_copied=min(size(src),size(dest)) + n_not_copied=size(src)-n_copied + dest(1:n_copied)=src(1:n_copied) + END SUBROUTINE array_copy_i +!BL +!BL + SUBROUTINE swap_i(a,b) + INTEGER(I4B), INTENT(INOUT) :: a,b + INTEGER(I4B) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_i +!BL + SUBROUTINE swap_r(a,b) + REAL(SP), INTENT(INOUT) :: a,b + REAL(SP) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_r +!BL + SUBROUTINE swap_rv(a,b) + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a,b + REAL(SP), DIMENSION(SIZE(a)) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_rv +!BL + SUBROUTINE swap_c(a,b) + COMPLEX(SPC), INTENT(INOUT) :: a,b + COMPLEX(SPC) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_c +!BL + SUBROUTINE swap_cv(a,b) + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: a,b + COMPLEX(SPC), DIMENSION(SIZE(a)) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_cv +!BL + SUBROUTINE swap_cm(a,b) + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: a,b + COMPLEX(SPC), DIMENSION(size(a,1),size(a,2)) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_cm +!BL + SUBROUTINE swap_z(a,b) + COMPLEX(DPC), INTENT(INOUT) :: a,b + COMPLEX(DPC) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_z +!BL + SUBROUTINE swap_zv(a,b) + COMPLEX(DPC), DIMENSION(:), INTENT(INOUT) :: a,b + COMPLEX(DPC), DIMENSION(SIZE(a)) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_zv +!BL + SUBROUTINE swap_zm(a,b) + COMPLEX(DPC), DIMENSION(:,:), INTENT(INOUT) :: a,b + COMPLEX(DPC), DIMENSION(size(a,1),size(a,2)) :: dum + dum=a + a=b + b=dum + END SUBROUTINE swap_zm +!BL + SUBROUTINE masked_swap_rs(a,b,mask) + REAL(SP), INTENT(INOUT) :: a,b + LOGICAL(LGT), INTENT(IN) :: mask + REAL(SP) :: swp + if (mask) then + swp=a + a=b + b=swp + end if + END SUBROUTINE masked_swap_rs +!BL + SUBROUTINE masked_swap_rv(a,b,mask) + REAL(SP), DIMENSION(:), INTENT(INOUT) :: a,b + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: mask + REAL(SP), DIMENSION(size(a)) :: swp + where (mask) + swp=a + a=b + b=swp + end where + END SUBROUTINE masked_swap_rv +!BL + SUBROUTINE masked_swap_rm(a,b,mask) + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: a,b + LOGICAL(LGT), DIMENSION(:,:), INTENT(IN) :: mask + REAL(SP), DIMENSION(size(a,1),size(a,2)) :: swp + where (mask) + swp=a + a=b + b=swp + end where + END SUBROUTINE masked_swap_rm +!BL +!BL + FUNCTION reallocate_rv(p,n) + REAL(SP), DIMENSION(:), POINTER :: p, reallocate_rv + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B) :: nold,ierr + allocate(reallocate_rv(n),stat=ierr) + if (ierr /= 0) call & + nrerror('reallocate_rv: problem in attempt to allocate memory') + if (.not. associated(p)) RETURN + nold=size(p) + reallocate_rv(1:min(nold,n))=p(1:min(nold,n)) + deallocate(p) + END FUNCTION reallocate_rv +!BL + FUNCTION reallocate_iv(p,n) + INTEGER(I4B), DIMENSION(:), POINTER :: p, reallocate_iv + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B) :: nold,ierr + allocate(reallocate_iv(n),stat=ierr) + if (ierr /= 0) call & + nrerror('reallocate_iv: problem in attempt to allocate memory') + if (.not. associated(p)) RETURN + nold=size(p) + reallocate_iv(1:min(nold,n))=p(1:min(nold,n)) + deallocate(p) + END FUNCTION reallocate_iv +!BL + FUNCTION reallocate_hv(p,n) + CHARACTER(1), DIMENSION(:), POINTER :: p, reallocate_hv + INTEGER(I4B), INTENT(IN) :: n + INTEGER(I4B) :: nold,ierr + allocate(reallocate_hv(n),stat=ierr) + if (ierr /= 0) call & + nrerror('reallocate_hv: problem in attempt to allocate memory') + if (.not. associated(p)) RETURN + nold=size(p) + reallocate_hv(1:min(nold,n))=p(1:min(nold,n)) + deallocate(p) + END FUNCTION reallocate_hv +!BL + FUNCTION reallocate_rm(p,n,m) + REAL(SP), DIMENSION(:,:), POINTER :: p, reallocate_rm + INTEGER(I4B), INTENT(IN) :: n,m + INTEGER(I4B) :: nold,mold,ierr + allocate(reallocate_rm(n,m),stat=ierr) + if (ierr /= 0) call & + nrerror('reallocate_rm: problem in attempt to allocate memory') + if (.not. associated(p)) RETURN + nold=size(p,1) + mold=size(p,2) + reallocate_rm(1:min(nold,n),1:min(mold,m))=& + p(1:min(nold,n),1:min(mold,m)) + deallocate(p) + END FUNCTION reallocate_rm +!BL + FUNCTION reallocate_im(p,n,m) + INTEGER(I4B), DIMENSION(:,:), POINTER :: p, reallocate_im + INTEGER(I4B), INTENT(IN) :: n,m + INTEGER(I4B) :: nold,mold,ierr + allocate(reallocate_im(n,m),stat=ierr) + if (ierr /= 0) call & + nrerror('reallocate_im: problem in attempt to allocate memory') + if (.not. associated(p)) RETURN + nold=size(p,1) + mold=size(p,2) + reallocate_im(1:min(nold,n),1:min(mold,m))=& + p(1:min(nold,n),1:min(mold,m)) + deallocate(p) + END FUNCTION reallocate_im +!BL + FUNCTION ifirstloc(mask) + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: mask + INTEGER(I4B) :: ifirstloc + INTEGER(I4B), DIMENSION(1) :: loc + loc=maxloc(merge(1,0,mask)) + ifirstloc=loc(1) + if (.not. mask(ifirstloc)) ifirstloc=size(mask)+1 + END FUNCTION ifirstloc +!BL + FUNCTION imaxloc_r(arr) + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + INTEGER(I4B) :: imaxloc_r + INTEGER(I4B), DIMENSION(1) :: imax + imax=maxloc(arr(:)) + imaxloc_r=imax(1) + END FUNCTION imaxloc_r +!BL + FUNCTION imaxloc_i(iarr) + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: iarr + INTEGER(I4B), DIMENSION(1) :: imax + INTEGER(I4B) :: imaxloc_i + imax=maxloc(iarr(:)) + imaxloc_i=imax(1) + END FUNCTION imaxloc_i +!BL + FUNCTION iminloc(arr) + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + INTEGER(I4B), DIMENSION(1) :: imin + INTEGER(I4B) :: iminloc + imin=minloc(arr(:)) + iminloc=imin(1) + END FUNCTION iminloc +!BL + SUBROUTINE assert1(n1,string) + CHARACTER(LEN=*), INTENT(IN) :: string + LOGICAL, INTENT(IN) :: n1 + if (.not. n1) then + write (*,*) 'nrerror: an assertion failed with this tag:', & + string + STOP 'program terminated by assert1' + end if + END SUBROUTINE assert1 +!BL + SUBROUTINE assert2(n1,n2,string) + CHARACTER(LEN=*), INTENT(IN) :: string + LOGICAL, INTENT(IN) :: n1,n2 + if (.not. (n1 .and. n2)) then + write (*,*) 'nrerror: an assertion failed with this tag:', & + string + STOP 'program terminated by assert2' + end if + END SUBROUTINE assert2 +!BL + SUBROUTINE assert3(n1,n2,n3,string) + CHARACTER(LEN=*), INTENT(IN) :: string + LOGICAL, INTENT(IN) :: n1,n2,n3 + if (.not. (n1 .and. n2 .and. n3)) then + write (*,*) 'nrerror: an assertion failed with this tag:', & + string + STOP 'program terminated by assert3' + end if + END SUBROUTINE assert3 +!BL + SUBROUTINE assert4(n1,n2,n3,n4,string) + CHARACTER(LEN=*), INTENT(IN) :: string + LOGICAL, INTENT(IN) :: n1,n2,n3,n4 + if (.not. (n1 .and. n2 .and. n3 .and. n4)) then + write (*,*) 'nrerror: an assertion failed with this tag:', & + string + STOP 'program terminated by assert4' + end if + END SUBROUTINE assert4 +!BL + SUBROUTINE assert_v(n,string) + CHARACTER(LEN=*), INTENT(IN) :: string + LOGICAL, DIMENSION(:), INTENT(IN) :: n + if (.not. all(n)) then + write (*,*) 'nrerror: an assertion failed with this tag:', & + string + STOP 'program terminated by assert_v' + end if + END SUBROUTINE assert_v +!BL + FUNCTION assert_eq2(n1,n2,string) + CHARACTER(LEN=*), INTENT(IN) :: string + INTEGER, INTENT(IN) :: n1,n2 + INTEGER :: assert_eq2 + if (n1 == n2) then + assert_eq2=n1 + else + write (*,*) 'nrerror: an assert_eq failed with this tag:', & + string + STOP 'program terminated by assert_eq2' + end if + END FUNCTION assert_eq2 +!BL + FUNCTION assert_eq3(n1,n2,n3,string) + CHARACTER(LEN=*), INTENT(IN) :: string + INTEGER, INTENT(IN) :: n1,n2,n3 + INTEGER :: assert_eq3 + if (n1 == n2 .and. n2 == n3) then + assert_eq3=n1 + else + write (*,*) 'nrerror: an assert_eq failed with this tag:', & + string + STOP 'program terminated by assert_eq3' + end if + END FUNCTION assert_eq3 +!BL + FUNCTION assert_eq4(n1,n2,n3,n4,string) + CHARACTER(LEN=*), INTENT(IN) :: string + INTEGER, INTENT(IN) :: n1,n2,n3,n4 + INTEGER :: assert_eq4 + if (n1 == n2 .and. n2 == n3 .and. n3 == n4) then + assert_eq4=n1 + else + write (*,*) 'nrerror: an assert_eq failed with this tag:', & + string + STOP 'program terminated by assert_eq4' + end if + END FUNCTION assert_eq4 +!BL + FUNCTION assert_eqn(nn,string) + CHARACTER(LEN=*), INTENT(IN) :: string + INTEGER, DIMENSION(:), INTENT(IN) :: nn + INTEGER :: assert_eqn + if (all(nn(2:) == nn(1))) then + assert_eqn=nn(1) + else + write (*,*) 'nrerror: an assert_eq failed with this tag:', & + string + STOP 'program terminated by assert_eqn' + end if + END FUNCTION assert_eqn +!BL + SUBROUTINE nrerror(string) + CHARACTER(LEN=*), INTENT(IN) :: string + write (*,*) 'nrerror: ',string + STOP 'program terminated by nrerror' + END SUBROUTINE nrerror +!BL + FUNCTION arth_r(first,increment,n) + REAL(SP), INTENT(IN) :: first,increment + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: arth_r + INTEGER(I4B) :: k,k2 + REAL(SP) :: temp + if (n > 0) arth_r(1)=first + if (n <= NPAR_ARTH) then + do k=2,n + arth_r(k)=arth_r(k-1)+increment + end do + else + do k=2,NPAR2_ARTH + arth_r(k)=arth_r(k-1)+increment + end do + temp=increment*NPAR2_ARTH + k=NPAR2_ARTH + do + if (k >= n) exit + k2=k+k + arth_r(k+1:min(k2,n))=temp+arth_r(1:min(k,n-k)) + temp=temp+temp + k=k2 + end do + end if + END FUNCTION arth_r +!BL + FUNCTION arth_d(first,increment,n) + REAL(DP), INTENT(IN) :: first,increment + INTEGER(I4B), INTENT(IN) :: n + REAL(DP), DIMENSION(n) :: arth_d + INTEGER(I4B) :: k,k2 + REAL(DP) :: temp + if (n > 0) arth_d(1)=first + if (n <= NPAR_ARTH) then + do k=2,n + arth_d(k)=arth_d(k-1)+increment + end do + else + do k=2,NPAR2_ARTH + arth_d(k)=arth_d(k-1)+increment + end do + temp=increment*NPAR2_ARTH + k=NPAR2_ARTH + do + if (k >= n) exit + k2=k+k + arth_d(k+1:min(k2,n))=temp+arth_d(1:min(k,n-k)) + temp=temp+temp + k=k2 + end do + end if + END FUNCTION arth_d +!BL + FUNCTION arth_i(first,increment,n) + INTEGER(I4B), INTENT(IN) :: first,increment,n + INTEGER(I4B), DIMENSION(n) :: arth_i + INTEGER(I4B) :: k,k2,temp + if (n > 0) arth_i(1)=first + if (n <= NPAR_ARTH) then + do k=2,n + arth_i(k)=arth_i(k-1)+increment + end do + else + do k=2,NPAR2_ARTH + arth_i(k)=arth_i(k-1)+increment + end do + temp=increment*NPAR2_ARTH + k=NPAR2_ARTH + do + if (k >= n) exit + k2=k+k + arth_i(k+1:min(k2,n))=temp+arth_i(1:min(k,n-k)) + temp=temp+temp + k=k2 + end do + end if + END FUNCTION arth_i +!BL +!BL + FUNCTION geop_r(first,factor,n) + REAL(SP), INTENT(IN) :: first,factor + INTEGER(I4B), INTENT(IN) :: n + REAL(SP), DIMENSION(n) :: geop_r + INTEGER(I4B) :: k,k2 + REAL(SP) :: temp + if (n > 0) geop_r(1)=first + if (n <= NPAR_GEOP) then + do k=2,n + geop_r(k)=geop_r(k-1)*factor + end do + else + do k=2,NPAR2_GEOP + geop_r(k)=geop_r(k-1)*factor + end do + temp=factor**NPAR2_GEOP + k=NPAR2_GEOP + do + if (k >= n) exit + k2=k+k + geop_r(k+1:min(k2,n))=temp*geop_r(1:min(k,n-k)) + temp=temp*temp + k=k2 + end do + end if + END FUNCTION geop_r +!BL + FUNCTION geop_d(first,factor,n) + REAL(DP), INTENT(IN) :: first,factor + INTEGER(I4B), INTENT(IN) :: n + REAL(DP), DIMENSION(n) :: geop_d + INTEGER(I4B) :: k,k2 + REAL(DP) :: temp + if (n > 0) geop_d(1)=first + if (n <= NPAR_GEOP) then + do k=2,n + geop_d(k)=geop_d(k-1)*factor + end do + else + do k=2,NPAR2_GEOP + geop_d(k)=geop_d(k-1)*factor + end do + temp=factor**NPAR2_GEOP + k=NPAR2_GEOP + do + if (k >= n) exit + k2=k+k + geop_d(k+1:min(k2,n))=temp*geop_d(1:min(k,n-k)) + temp=temp*temp + k=k2 + end do + end if + END FUNCTION geop_d +!BL + FUNCTION geop_i(first,factor,n) + INTEGER(I4B), INTENT(IN) :: first,factor,n + INTEGER(I4B), DIMENSION(n) :: geop_i + INTEGER(I4B) :: k,k2,temp + if (n > 0) geop_i(1)=first + if (n <= NPAR_GEOP) then + do k=2,n + geop_i(k)=geop_i(k-1)*factor + end do + else + do k=2,NPAR2_GEOP + geop_i(k)=geop_i(k-1)*factor + end do + temp=factor**NPAR2_GEOP + k=NPAR2_GEOP + do + if (k >= n) exit + k2=k+k + geop_i(k+1:min(k2,n))=temp*geop_i(1:min(k,n-k)) + temp=temp*temp + k=k2 + end do + end if + END FUNCTION geop_i +!BL + FUNCTION geop_c(first,factor,n) + COMPLEX(SP), INTENT(IN) :: first,factor + INTEGER(I4B), INTENT(IN) :: n + COMPLEX(SP), DIMENSION(n) :: geop_c + INTEGER(I4B) :: k,k2 + COMPLEX(SP) :: temp + if (n > 0) geop_c(1)=first + if (n <= NPAR_GEOP) then + do k=2,n + geop_c(k)=geop_c(k-1)*factor + end do + else + do k=2,NPAR2_GEOP + geop_c(k)=geop_c(k-1)*factor + end do + temp=factor**NPAR2_GEOP + k=NPAR2_GEOP + do + if (k >= n) exit + k2=k+k + geop_c(k+1:min(k2,n))=temp*geop_c(1:min(k,n-k)) + temp=temp*temp + k=k2 + end do + end if + END FUNCTION geop_c +!BL + FUNCTION geop_dv(first,factor,n) + REAL(DP), DIMENSION(:), INTENT(IN) :: first,factor + INTEGER(I4B), INTENT(IN) :: n + REAL(DP), DIMENSION(size(first),n) :: geop_dv + INTEGER(I4B) :: k,k2 + REAL(DP), DIMENSION(size(first)) :: temp + if (n > 0) geop_dv(:,1)=first(:) + if (n <= NPAR_GEOP) then + do k=2,n + geop_dv(:,k)=geop_dv(:,k-1)*factor(:) + end do + else + do k=2,NPAR2_GEOP + geop_dv(:,k)=geop_dv(:,k-1)*factor(:) + end do + temp=factor**NPAR2_GEOP + k=NPAR2_GEOP + do + if (k >= n) exit + k2=k+k + geop_dv(:,k+1:min(k2,n))=geop_dv(:,1:min(k,n-k))*& + spread(temp,2,size(geop_dv(:,1:min(k,n-k)),2)) + temp=temp*temp + k=k2 + end do + end if + END FUNCTION geop_dv +!BL +!BL + RECURSIVE FUNCTION cumsum_r(arr,seed) RESULT(ans) + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + REAL(SP), OPTIONAL, INTENT(IN) :: seed + REAL(SP), DIMENSION(size(arr)) :: ans + INTEGER(I4B) :: n,j + REAL(SP) :: sd + n=size(arr) + if (n == 0_i4b) RETURN + sd=0.0_sp + if (present(seed)) sd=seed + ans(1)=arr(1)+sd + if (n < NPAR_CUMSUM) then + do j=2,n + ans(j)=ans(j-1)+arr(j) + end do + else + ans(2:n:2)=cumsum_r(arr(2:n:2)+arr(1:n-1:2),sd) + ans(3:n:2)=ans(2:n-1:2)+arr(3:n:2) + end if + END FUNCTION cumsum_r +!BL + RECURSIVE FUNCTION cumsum_i(arr,seed) RESULT(ans) + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: arr + INTEGER(I4B), OPTIONAL, INTENT(IN) :: seed + INTEGER(I4B), DIMENSION(size(arr)) :: ans + INTEGER(I4B) :: n,j,sd + n=size(arr) + if (n == 0_i4b) RETURN + sd=0_i4b + if (present(seed)) sd=seed + ans(1)=arr(1)+sd + if (n < NPAR_CUMSUM) then + do j=2,n + ans(j)=ans(j-1)+arr(j) + end do + else + ans(2:n:2)=cumsum_i(arr(2:n:2)+arr(1:n-1:2),sd) + ans(3:n:2)=ans(2:n-1:2)+arr(3:n:2) + end if + END FUNCTION cumsum_i +!BL +!BL + RECURSIVE FUNCTION cumprod(arr,seed) RESULT(ans) + REAL(SP), DIMENSION(:), INTENT(IN) :: arr + REAL(SP), OPTIONAL, INTENT(IN) :: seed + REAL(SP), DIMENSION(size(arr)) :: ans + INTEGER(I4B) :: n,j + REAL(SP) :: sd + n=size(arr) + if (n == 0_i4b) RETURN + sd=1.0_sp + if (present(seed)) sd=seed + ans(1)=arr(1)*sd + if (n < NPAR_CUMPROD) then + do j=2,n + ans(j)=ans(j-1)*arr(j) + end do + else + ans(2:n:2)=cumprod(arr(2:n:2)*arr(1:n-1:2),sd) + ans(3:n:2)=ans(2:n-1:2)*arr(3:n:2) + end if + END FUNCTION cumprod +!BL +!BL + FUNCTION poly_rr(x,coeffs) + REAL(SP), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: coeffs + REAL(SP) :: poly_rr + REAL(SP) :: pow + REAL(SP), DIMENSION(:), ALLOCATABLE :: vec + INTEGER(I4B) :: i,n,nn + n=size(coeffs) + if (n <= 0) then + poly_rr=0.0_sp + else if (n < NPAR_POLY) then + poly_rr=coeffs(n) + do i=n-1,1,-1 + poly_rr=x*poly_rr+coeffs(i) + end do + else + allocate(vec(n+1)) + pow=x + vec(1:n)=coeffs + do + vec(n+1)=0.0_sp + nn=ishft(n+1,-1) + vec(1:nn)=vec(1:n:2)+pow*vec(2:n+1:2) + if (nn == 1) exit + pow=pow*pow + n=nn + end do + poly_rr=vec(1) + deallocate(vec) + end if + END FUNCTION poly_rr +!BL + FUNCTION poly_dd(x,coeffs) + REAL(DP), INTENT(IN) :: x + REAL(DP), DIMENSION(:), INTENT(IN) :: coeffs + REAL(DP) :: poly_dd + REAL(DP) :: pow + REAL(DP), DIMENSION(:), ALLOCATABLE :: vec + INTEGER(I4B) :: i,n,nn + n=size(coeffs) + if (n <= 0) then + poly_dd=0.0_dp + else if (n < NPAR_POLY) then + poly_dd=coeffs(n) + do i=n-1,1,-1 + poly_dd=x*poly_dd+coeffs(i) + end do + else + allocate(vec(n+1)) + pow=x + vec(1:n)=coeffs + do + vec(n+1)=0.0_dp + nn=ishft(n+1,-1) + vec(1:nn)=vec(1:n:2)+pow*vec(2:n+1:2) + if (nn == 1) exit + pow=pow*pow + n=nn + end do + poly_dd=vec(1) + deallocate(vec) + end if + END FUNCTION poly_dd +!BL + FUNCTION poly_rc(x,coeffs) + COMPLEX(SPC), INTENT(IN) :: x + REAL(SP), DIMENSION(:), INTENT(IN) :: coeffs + COMPLEX(SPC) :: poly_rc + COMPLEX(SPC) :: pow + COMPLEX(SPC), DIMENSION(:), ALLOCATABLE :: vec + INTEGER(I4B) :: i,n,nn + n=size(coeffs) + if (n <= 0) then + poly_rc=0.0_sp + else if (n < NPAR_POLY) then + poly_rc=coeffs(n) + do i=n-1,1,-1 + poly_rc=x*poly_rc+coeffs(i) + end do + else + allocate(vec(n+1)) + pow=x + vec(1:n)=coeffs + do + vec(n+1)=0.0_sp + nn=ishft(n+1,-1) + vec(1:nn)=vec(1:n:2)+pow*vec(2:n+1:2) + if (nn == 1) exit + pow=pow*pow + n=nn + end do + poly_rc=vec(1) + deallocate(vec) + end if + END FUNCTION poly_rc +!BL + FUNCTION poly_cc(x,coeffs) + COMPLEX(SPC), INTENT(IN) :: x + COMPLEX(SPC), DIMENSION(:), INTENT(IN) :: coeffs + COMPLEX(SPC) :: poly_cc + COMPLEX(SPC) :: pow + COMPLEX(SPC), DIMENSION(:), ALLOCATABLE :: vec + INTEGER(I4B) :: i,n,nn + n=size(coeffs) + if (n <= 0) then + poly_cc=0.0_sp + else if (n < NPAR_POLY) then + poly_cc=coeffs(n) + do i=n-1,1,-1 + poly_cc=x*poly_cc+coeffs(i) + end do + else + allocate(vec(n+1)) + pow=x + vec(1:n)=coeffs + do + vec(n+1)=0.0_sp + nn=ishft(n+1,-1) + vec(1:nn)=vec(1:n:2)+pow*vec(2:n+1:2) + if (nn == 1) exit + pow=pow*pow + n=nn + end do + poly_cc=vec(1) + deallocate(vec) + end if + END FUNCTION poly_cc +!BL + FUNCTION poly_rrv(x,coeffs) + REAL(SP), DIMENSION(:), INTENT(IN) :: coeffs,x + REAL(SP), DIMENSION(size(x)) :: poly_rrv + INTEGER(I4B) :: i,n,m + m=size(coeffs) + n=size(x) + if (m <= 0) then + poly_rrv=0.0_sp + else if (m < n .or. m < NPAR_POLY) then + poly_rrv=coeffs(m) + do i=m-1,1,-1 + poly_rrv=x*poly_rrv+coeffs(i) + end do + else + do i=1,n + poly_rrv(i)=poly_rr(x(i),coeffs) + end do + end if + END FUNCTION poly_rrv +!BL + FUNCTION poly_ddv(x,coeffs) + REAL(DP), DIMENSION(:), INTENT(IN) :: coeffs,x + REAL(DP), DIMENSION(size(x)) :: poly_ddv + INTEGER(I4B) :: i,n,m + m=size(coeffs) + n=size(x) + if (m <= 0) then + poly_ddv=0.0_dp + else if (m < n .or. m < NPAR_POLY) then + poly_ddv=coeffs(m) + do i=m-1,1,-1 + poly_ddv=x*poly_ddv+coeffs(i) + end do + else + do i=1,n + poly_ddv(i)=poly_dd(x(i),coeffs) + end do + end if + END FUNCTION poly_ddv +!BL + FUNCTION poly_msk_rrv(x,coeffs,mask) + REAL(SP), DIMENSION(:), INTENT(IN) :: coeffs,x + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: mask + REAL(SP), DIMENSION(size(x)) :: poly_msk_rrv + poly_msk_rrv=unpack(poly_rrv(pack(x,mask),coeffs),mask,0.0_sp) + END FUNCTION poly_msk_rrv +!BL + FUNCTION poly_msk_ddv(x,coeffs,mask) + REAL(DP), DIMENSION(:), INTENT(IN) :: coeffs,x + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: mask + REAL(DP), DIMENSION(size(x)) :: poly_msk_ddv + poly_msk_ddv=unpack(poly_ddv(pack(x,mask),coeffs),mask,0.0_dp) + END FUNCTION poly_msk_ddv +!BL +!BL + RECURSIVE FUNCTION poly_term_rr(a,b) RESULT(u) + REAL(SP), DIMENSION(:), INTENT(IN) :: a + REAL(SP), INTENT(IN) :: b + REAL(SP), DIMENSION(size(a)) :: u + INTEGER(I4B) :: n,j + n=size(a) + if (n <= 0) RETURN + u(1)=a(1) + if (n < NPAR_POLYTERM) then + do j=2,n + u(j)=a(j)+b*u(j-1) + end do + else + u(2:n:2)=poly_term_rr(a(2:n:2)+a(1:n-1:2)*b,b*b) + u(3:n:2)=a(3:n:2)+b*u(2:n-1:2) + end if + END FUNCTION poly_term_rr +!BL + RECURSIVE FUNCTION poly_term_cc(a,b) RESULT(u) + COMPLEX(SPC), DIMENSION(:), INTENT(IN) :: a + COMPLEX(SPC), INTENT(IN) :: b + COMPLEX(SPC), DIMENSION(size(a)) :: u + INTEGER(I4B) :: n,j + n=size(a) + if (n <= 0) RETURN + u(1)=a(1) + if (n < NPAR_POLYTERM) then + do j=2,n + u(j)=a(j)+b*u(j-1) + end do + else + u(2:n:2)=poly_term_cc(a(2:n:2)+a(1:n-1:2)*b,b*b) + u(3:n:2)=a(3:n:2)+b*u(2:n-1:2) + end if + END FUNCTION poly_term_cc +!BL +!BL + FUNCTION zroots_unity(n,nn) + INTEGER(I4B), INTENT(IN) :: n,nn + COMPLEX(SPC), DIMENSION(nn) :: zroots_unity + INTEGER(I4B) :: k + REAL(SP) :: theta + zroots_unity(1)=1.0 + theta=TWOPI/n + k=1 + do + if (k >= nn) exit + zroots_unity(k+1)=cmplx(cos(k*theta),sin(k*theta),SPC) + zroots_unity(k+2:min(2*k,nn))=zroots_unity(k+1)*& + zroots_unity(2:min(k,nn-k)) + k=2*k + end do + END FUNCTION zroots_unity +!BL + FUNCTION outerprod_r(a,b) + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b + REAL(SP), DIMENSION(size(a),size(b)) :: outerprod_r + outerprod_r = spread(a,dim=2,ncopies=size(b)) * & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerprod_r +!BL + FUNCTION outerprod_d(a,b) + REAL(DP), DIMENSION(:), INTENT(IN) :: a,b + REAL(DP), DIMENSION(size(a),size(b)) :: outerprod_d + outerprod_d = spread(a,dim=2,ncopies=size(b)) * & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerprod_d +!BL + FUNCTION outerdiv(a,b) + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b + REAL(SP), DIMENSION(size(a),size(b)) :: outerdiv + outerdiv = spread(a,dim=2,ncopies=size(b)) / & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerdiv +!BL + FUNCTION outersum(a,b) + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b + REAL(SP), DIMENSION(size(a),size(b)) :: outersum + outersum = spread(a,dim=2,ncopies=size(b)) + & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outersum +!BL + FUNCTION outerdiff_r(a,b) + REAL(SP), DIMENSION(:), INTENT(IN) :: a,b + REAL(SP), DIMENSION(size(a),size(b)) :: outerdiff_r + outerdiff_r = spread(a,dim=2,ncopies=size(b)) - & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerdiff_r +!BL + FUNCTION outerdiff_d(a,b) + REAL(DP), DIMENSION(:), INTENT(IN) :: a,b + REAL(DP), DIMENSION(size(a),size(b)) :: outerdiff_d + outerdiff_d = spread(a,dim=2,ncopies=size(b)) - & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerdiff_d +!BL + FUNCTION outerdiff_i(a,b) + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: a,b + INTEGER(I4B), DIMENSION(size(a),size(b)) :: outerdiff_i + outerdiff_i = spread(a,dim=2,ncopies=size(b)) - & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerdiff_i +!BL + FUNCTION outerand(a,b) + LOGICAL(LGT), DIMENSION(:), INTENT(IN) :: a,b + LOGICAL(LGT), DIMENSION(size(a),size(b)) :: outerand + outerand = spread(a,dim=2,ncopies=size(b)) .and. & + spread(b,dim=1,ncopies=size(a)) + END FUNCTION outerand +!BL + SUBROUTINE scatter_add_r(dest,source,dest_index) + REAL(SP), DIMENSION(:), INTENT(OUT) :: dest + REAL(SP), DIMENSION(:), INTENT(IN) :: source + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: dest_index + INTEGER(I4B) :: m,n,j,i + n=assert_eq2(size(source),size(dest_index),'scatter_add_r') + m=size(dest) + do j=1,n + i=dest_index(j) + if (i > 0 .and. i <= m) dest(i)=dest(i)+source(j) + end do + END SUBROUTINE scatter_add_r + SUBROUTINE scatter_add_d(dest,source,dest_index) + REAL(DP), DIMENSION(:), INTENT(OUT) :: dest + REAL(DP), DIMENSION(:), INTENT(IN) :: source + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: dest_index + INTEGER(I4B) :: m,n,j,i + n=assert_eq2(size(source),size(dest_index),'scatter_add_d') + m=size(dest) + do j=1,n + i=dest_index(j) + if (i > 0 .and. i <= m) dest(i)=dest(i)+source(j) + end do + END SUBROUTINE scatter_add_d + SUBROUTINE scatter_max_r(dest,source,dest_index) + REAL(SP), DIMENSION(:), INTENT(OUT) :: dest + REAL(SP), DIMENSION(:), INTENT(IN) :: source + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: dest_index + INTEGER(I4B) :: m,n,j,i + n=assert_eq2(size(source),size(dest_index),'scatter_max_r') + m=size(dest) + do j=1,n + i=dest_index(j) + if (i > 0 .and. i <= m) dest(i)=max(dest(i),source(j)) + end do + END SUBROUTINE scatter_max_r + SUBROUTINE scatter_max_d(dest,source,dest_index) + REAL(DP), DIMENSION(:), INTENT(OUT) :: dest + REAL(DP), DIMENSION(:), INTENT(IN) :: source + INTEGER(I4B), DIMENSION(:), INTENT(IN) :: dest_index + INTEGER(I4B) :: m,n,j,i + n=assert_eq2(size(source),size(dest_index),'scatter_max_d') + m=size(dest) + do j=1,n + i=dest_index(j) + if (i > 0 .and. i <= m) dest(i)=max(dest(i),source(j)) + end do + END SUBROUTINE scatter_max_d +!BL + SUBROUTINE diagadd_rv(mat,diag) + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + REAL(SP), DIMENSION(:), INTENT(IN) :: diag + INTEGER(I4B) :: j,n + n = assert_eq2(size(diag),min(size(mat,1),size(mat,2)),'diagadd_rv') + do j=1,n + mat(j,j)=mat(j,j)+diag(j) + end do + END SUBROUTINE diagadd_rv +!BL + SUBROUTINE diagadd_r(mat,diag) + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + REAL(SP), INTENT(IN) :: diag + INTEGER(I4B) :: j,n + n = min(size(mat,1),size(mat,2)) + do j=1,n + mat(j,j)=mat(j,j)+diag + end do + END SUBROUTINE diagadd_r +!BL + SUBROUTINE diagmult_rv(mat,diag) + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + REAL(SP), DIMENSION(:), INTENT(IN) :: diag + INTEGER(I4B) :: j,n + n = assert_eq2(size(diag),min(size(mat,1),size(mat,2)),'diagmult_rv') + do j=1,n + mat(j,j)=mat(j,j)*diag(j) + end do + END SUBROUTINE diagmult_rv +!BL + SUBROUTINE diagmult_r(mat,diag) + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + REAL(SP), INTENT(IN) :: diag + INTEGER(I4B) :: j,n + n = min(size(mat,1),size(mat,2)) + do j=1,n + mat(j,j)=mat(j,j)*diag + end do + END SUBROUTINE diagmult_r +!BL + FUNCTION get_diag_rv(mat) + REAL(SP), DIMENSION(:,:), INTENT(IN) :: mat + REAL(SP), DIMENSION(size(mat,1)) :: get_diag_rv + INTEGER(I4B) :: j + j=assert_eq2(size(mat,1),size(mat,2),'get_diag_rv') + do j=1,size(mat,1) + get_diag_rv(j)=mat(j,j) + end do + END FUNCTION get_diag_rv +!BL + FUNCTION get_diag_dv(mat) + REAL(DP), DIMENSION(:,:), INTENT(IN) :: mat + REAL(DP), DIMENSION(size(mat,1)) :: get_diag_dv + INTEGER(I4B) :: j + j=assert_eq2(size(mat,1),size(mat,2),'get_diag_dv') + do j=1,size(mat,1) + get_diag_dv(j)=mat(j,j) + end do + END FUNCTION get_diag_dv +!BL + SUBROUTINE put_diag_rv(diagv,mat) + REAL(SP), DIMENSION(:), INTENT(IN) :: diagv + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + INTEGER(I4B) :: j,n + n=assert_eq2(size(diagv),min(size(mat,1),size(mat,2)),'put_diag_rv') + do j=1,n + mat(j,j)=diagv(j) + end do + END SUBROUTINE put_diag_rv +!BL + SUBROUTINE put_diag_r(scal,mat) + REAL(SP), INTENT(IN) :: scal + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: mat + INTEGER(I4B) :: j,n + n = min(size(mat,1),size(mat,2)) + do j=1,n + mat(j,j)=scal + end do + END SUBROUTINE put_diag_r +!BL + SUBROUTINE unit_matrix(mat) + REAL(SP), DIMENSION(:,:), INTENT(OUT) :: mat + INTEGER(I4B) :: i,n + n=min(size(mat,1),size(mat,2)) + mat(:,:)=0.0_sp + do i=1,n + mat(i,i)=1.0_sp + end do + END SUBROUTINE unit_matrix +!BL + FUNCTION upper_triangle(j,k,extra) + INTEGER(I4B), INTENT(IN) :: j,k + INTEGER(I4B), OPTIONAL, INTENT(IN) :: extra + LOGICAL(LGT), DIMENSION(j,k) :: upper_triangle + INTEGER(I4B) :: n + n=0 + if (present(extra)) n=extra + upper_triangle=(outerdiff(arth_i(1,1,j),arth_i(1,1,k)) < n) + END FUNCTION upper_triangle +!BL + FUNCTION lower_triangle(j,k,extra) + INTEGER(I4B), INTENT(IN) :: j,k + INTEGER(I4B), OPTIONAL, INTENT(IN) :: extra + LOGICAL(LGT), DIMENSION(j,k) :: lower_triangle + INTEGER(I4B) :: n + n=0 + if (present(extra)) n=extra + lower_triangle=(outerdiff(arth_i(1,1,j),arth_i(1,1,k)) > -n) + END FUNCTION lower_triangle +!BL + FUNCTION vabs(v) + REAL(SP), DIMENSION(:), INTENT(IN) :: v + REAL(SP) :: vabs + vabs=sqrt(dot_product(v,v)) + END FUNCTION vabs +!BL +END MODULE nrutil diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/old_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/old_mod.f90 new file mode 100644 index 000000000..b20de8938 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/old_mod.f90 @@ -0,0 +1,860 @@ +module old_mod + use donnees_mod + use tab_mod + use remaillage_mod + use interpolation_mod +contains + + + + subroutine crea_part_old + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z,m + + m=cutoff*maxval(sqrt(omgx**2+omgy**2+omgz**2)) + npart=0 + numpg=0 + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + if (sqrt(omgx(i,j,k)**2+omgy(i,j,k)**2+omgz(i,j,k)**2)>=m) then + npart=npart+1 + numpg(i,j,k)=npart + xp(npart)=x + yp(npart)=y + zp(npart)=z + vx(npart)=vxg(i,j,k) + vy(npart)=vyg(i,j,k) + vz(npart)=vzg(i,j,k) + omx(npart)=omgx(i,j,k) + omy(npart)=omgy(i,j,k) + omz(npart)=omgz(i,j,k) + stx(npart)=stxg(i,j,k) + sty(npart)=styg(i,j,k) + stz(npart)=stzg(i,j,k) + end if + end do + end do + end do + + end subroutine crea_part_old + + + + + subroutine advection_old() + implicit none + + real(kind=8),dimension(:),pointer :: xp0,yp0,zp0,omx0,omy0,omz0 + integer :: i,ib + + allocate (xp0(1:npart),yp0(1:npart),zp0(1:npart)) + + !mise en memoire de la position initiale + !---------------------------------------- + do i=1,npart + xp0(i)=xp(i) + yp0(i)=yp(i) + zp0(i)=zp(i) + + !advection de la moitie d'un pas de temps : sous ite RK + !------------------------------------------------------ + + xp(i)=xp0(i)+0.5*dt*vx(i) + yp(i)=yp0(i)+0.5*dt*vy(i) + zp(i)=zp0(i)+0.5*dt*vz(i) + + end do + + + call interpo_l3_3d(vxg,xp,yp,zp,vx) + call interpo_l3_3d(vyg,xp,yp,zp,vy) + call interpo_l3_3d(vzg,xp,yp,zp,vz) + + call interpo_l3_3d(stxg,xp,yp,zp,stx) + call interpo_l3_3d(styg,xp,yp,zp,sty) + call interpo_l3_3d(stzg,xp,yp,zp,stz) + + + !advection depuis position initiale avec cette nouvelle vitesse : seconde ite de RK + !---------------------------------------------------------------------------------- + do i=1,npart + xp(i)=xp0(i)+dt*vx(i) + yp(i)=yp0(i)+dt*vy(i) + zp(i)=zp0(i)+dt*vz(i) + + omx(i)=omx(i)+dt*stx(i) + omy(i)=omy(i)+dt*sty(i) + omz(i)=omz(i)+dt*stz(i) + end do + + + deallocate(xp0,yp0,zp0) + + end subroutine advection_old + + + subroutine penal_exacte + implicit none + real(kind=8) :: dyvecez,dzvecey,dzvecex,dxvecez,dxvecey,dyvecex + integer :: i,j,k + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + real(kind=8),dimension(1:3) :: tx,ty,tz + real(kind=8) :: facx,facy,facz + + + !PENALISATION + !-------------- + ! si (on est dans l'obstacle ou derive(chi)/=0)) alors + ! omega = rot (vitesse*exp(-lambda*chi*dt) ) + + + + + + do k=1,nz ! ordre 4 + do j=1,ny + do i=1,nx + + !calcul penalisation uniquement dans l'obstacle et environs + if (.not.((chi(i,j,k)==0.).and.(derivx(chi,i,j,k)==0.) & + .and.(derivy(chi,i,j,k)==0.).and.(derivz(chi,i,j,k)==0.))) then + + + + if((i/=2).and.(i/=1).and.(i/=nx-1).and.(i/=nx).and.(j/=2) & + .and.(j/=1).and.(j/=ny-1).and.(j/=ny).and.(k/=2).and.(k/=1) & + .and.(k/=nz-1).and.(k/=nz))then + !schema centre au milieu du domaine + + omgx(i,j,k)=1./(12.*dy)*(1.*penz(i,j-2,k)-8.*penz(i,j-1,k) & + +8.*penz(i,j+1,k)-1.*penz(i,j+2,k))-(1./(12.*dz)*(1.*peny(i,j,k-2)-8.*peny(i,j,k-1) & + +8.*peny(i,j,k+1)-1.*peny(i,j,k+2))) + omgy(i,j,k)=1./(12.*dz)*(1.*penx(i,j,k-2)-8.*penx(i,j,k-1) & + +8.*penx(i,j,k+1)-1.*penx(i,j,k+2))-(1./(12.*dx)*(1.*penz(i-2,j,k)-8.*penz(i-1,j,k) & + +8.*penz(i+1,j,k)-1.*penz(i+2,j,k))) + omgz(i,j,k)=1./(12.*dx)*(1.*peny(i-2,j,k)-8.*peny(i-1,j,k) & + +8.*peny(i+1,j,k)-1.*peny(i+2,j,k))-(1./(12.*dy)*(1.*penx(i,j-2,k)-8.*penx(i,j-1,k) & + +8.*penx(i,j+1,k)-1.*penx(i,j+2,k))) + + else + + dxvecey=1./(12.*dx)*(1.*peny(i-2,j,k)-8.*peny(i-1,j,k)+8.*peny(i+1,j,k)-1.*peny(i+2,j,k)) + dxvecez=1./(12.*dx)*(1.*penz(i-2,j,k)-8.*penz(i-1,j,k)+8.*penz(i+1,j,k)-1.*penz(i+2,j,k)) + dyvecex=1./(12.*dy)*(1.*penx(i,j-2,k)-8.*penx(i,j-1,k)+8.*penx(i,j+1,k)-1.*penx(i,j+2,k)) + dyvecez=1./(12.*dy)*(1.*penz(i,j-2,k)-8.*penz(i,j-1,k)+8.*penz(i,j+1,k)-1.*penz(i,j+2,k)) + dzvecex=1./(12.*dz)*(1.*penx(i,j,k-2)-8.*penx(i,j,k-1)+8.*penx(i,j,k+1)-1.*penx(i,j,k+2)) + dzvecey=1./(12.*dz)*(1.*peny(i,j,k-2)-8.*peny(i,j,k-1)+8.*peny(i,j,k+1)-1.*peny(i,j,k+2)) + + + + if((i==1).or.(i==2))then + dxvecey=1./(12.*dx)*(-25.*peny(i,j,k)+48.*peny(i+1,j,k)-36.*peny(i+2,j,k) & + +16.*peny(i+3,j,k)-3.*peny(i+4,j,k)) + dxvecez=1./(12.*dx)*(-25.*penz(i,j,k)+48.*penz(i+1,j,k)-36.*penz(i+2,j,k) & + +16.*penz(i+3,j,k)-3.*penz(i+4,j,k)) + end if + + if((i==nx).or.(i==nx-1))then + dxvecey=1./(12.*dx)*(25.*peny(i,j,k)-48.*peny(i-1,j,k)+36.*peny(i-2,j,k) & + -16.*peny(i-3,j,k)+3.*peny(i-4,j,k)) + dxvecez=1./(12.*dx)*(25.*penz(i,j,k)-48.*penz(i-1,j,k)+36.*penz(i-2,j,k) & + -16.*penz(i-3,j,k)+3.*penz(i-4,j,k)) + endif + + if((j==1).or.(j==2))then + dyvecez=1./(12.*dy)*(-25.*penz(i,j,k)+48.*penz(i,j+1,k)-36.*penz(i,j+2,k) & + +16.*penz(i,j+3,k)-3.*penz(i,j+4,k)) + dyvecex=1./(12.*dy)*(-25.*penx(i,j,k)+48.*penx(i,j+1,k)-36.*penx(i,j+2,k) & + +16.*penx(i,j+3,k)-3.*penx(i,j+4,k)) + end if + + if((j==ny).or.(j==ny-1))then + dyvecez=1./(12.*dy)*(+25.*penz(i,j,k)-48.*penz(i,j-1,k)+36.*penz(i,j-2,k) & + -16.*penz(i,j-3,k)+3.*penz(i,j-4,k)) + dyvecex=1./(12.*dy)*(+25.*penx(i,j,k)-48.*penx(i,j-1,k)+36.*penx(i,j-2,k) & + -16.*penx(i,j-3,k)+3.*penx(i,j-4,k)) + endif + + if((k==1).or.(k==2))then + dzvecex=1./(12.*dz)*(-25.*penx(i,j,k)+48.*penx(i,j,k+1)-36.*penx(i,j,k+2) & + +16.*penx(i,j,k+3)-3.*penx(i,j,k+4)) + dzvecey=1./(12.*dz)*(-25.*peny(i,j,k)+48.*peny(i,j,k+1)-36.*peny(i,j,k+2) & + +16.*peny(i,j,k+3)-3.*peny(i,j,k+4)) + end if + + if((k==nz).or.(k==nz-1))then + dzvecex=1./(12.*dz)*(25.*penx(i,j,k)-48.*penx(i,j,k-1)+36.*penx(i,j,k-2) & + -16.*penx(i,j,k-3)+3.*penx(i,j,k-4)) + dzvecey=1./(12.*dz)*(25.*peny(i,j,k)-48.*peny(i,j,k-1)+36.*peny(i,j,k-2) & + -16.*peny(i,j,k-3)+3.*peny(i,j,k-4)) + endif + + + + omgx(i,j,k)=dyvecez-dzvecey + omgy(i,j,k)=dzvecex-dxvecez + omgz(i,j,k)=dxvecey-dyvecex + + end if + + end if + end do + end do + end do + + contains + + function penx (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penx + + + !penx=vxg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + penx=vxg(l,m,n)/(1.+lambda(l,m,n)*chi(l,m,n)*dt) + + end function penx + + function peny (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: peny + + + !peny=vyg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + peny=vyg(l,m,n)/(1.+lambda(l,m,n)*chi(l,m,n)*dt) + + end function peny + + function penz (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penz + + + !penz=vzg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + penz=vzg(l,m,n)/(1.+lambda(l,m,n)*chi(l,m,n)*dt) + + end function penz + + end subroutine penal_exacte + + + + + function derivx (var,i,j,k) result (vars) ! calcul derive en x de var (decentre au bord, centre milieu) !ordre4 + implicit none + real(kind=8),dimension(:,:,:) :: var + integer :: i,j,k + real(kind=8) :: vars + + if((i/=2).and.(i/=1).and.(i/=nx-1).and.(i/=nx))then + !schema centre au milieu du domaine + vars=1./(12.*dx)*(1.*var(i-2,j,k)-8.*var(i-1,j,k)+8.*var(i+1,j,k)-1.*var(i+2,j,k)) + else + if((i==1).or.(i==2))then + vars=1./(12.*dx)*(-25.*var(i,j,k)+48.*var(i+1,j,k)-36.*var(i+2,j,k)+16.*var(i+3,j,k)-3.*var(i+4,j,k)) + end if + if((i==nx).or.(i==nx-1))then + vars=1./(12.*dx)*(+25.*var(i,j,k)-48.*var(i-1,j,k)+36.*var(i-2,j,k)-16.*var(i-3,j,k)+3.*var(i-4,j,k)) + endif + end if + end function derivx + + function derivy (var,i,j,k) result(vars) ! calcul derive en y de var (decentre au bord, centre milieu) !ordre4 + implicit none + real(kind=8),dimension(:,:,:) :: var + integer :: i,j,k + real(kind=8) :: vars + + if((j/=2).and.(j/=1).and.(j/=ny-1).and.(j/=ny))then + !schema centre au milieu du domaine + vars=1./(12.*dy)*(1.*var(i,j-2,k)-8.*var(i,j-1,k)+8.*var(i,j+1,k)-1.*var(i,j+2,k)) + else + if((j==1).or.(j==2))then + vars=1./(12.*dy)*(-25.*var(i,j,k)+48.*var(i,j+1,k)-36.*var(i,j+2,k)+16.*var(i,j+3,k)-3.*var(i,j+4,k)) + end if + if((j==ny).or.(j==ny-1))then + vars=1./(12.*dy)*(+25.*var(i,j,k)-48.*var(i,j-1,k)+36.*var(i,j-2,k)-16.*var(i,j-3,k)+3.*var(i,j-4,k)) + endif + end if + end function derivy + + function derivz (var,i,j,k) result(vars) ! calcul derive en z de var (decentre au bord, centre milieu) !ordre4 + implicit none + real(kind=8),dimension(:,:,:) :: var + integer :: i,j,k + real(kind=8) :: vars + + if((k/=2).and.(k/=1).and.(k/=nz-1).and.(k/=nz))then + !schema centre au milieu du domaine + vars=1./(12.*dz)*(1.*var(i,j,k-2)-8.*var(i,j,k-1)+8.*var(i,j,k+1)-1.*var(i,j,k+2)) + else + if((k==1).or.(k==2))then + vars=1./(12.*dz)*(-25.*var(i,j,k)+48.*var(i,j,k+1)-36.*var(i,j,k+2)+16.*var(i,j,k+3)-3.*var(i,j,k+4)) + end if + if((k==ny).or.(k==ny-1))then + vars=1./(12.*dz)*(+25.*var(i,j,k)-48.*var(i,j,k-1)+36.*var(i,j,k-2)-16.*var(i,j,k-3)+3.*var(i,j,k-4)) + endif + end if + end function derivz + + + + + + subroutine strech_old() + implicit none + integer :: i,j,k + real(kind=8),dimension(1:3) :: tx,ty,tz + real(kind=8) :: x,y,z + + !forme conservative : div(w:u) + + do k=1,nz + do j=1,ny + do i=1,nx + +!!$ tx(1)=dx_c_4(vxg*omgx,i,j,k,dx) +!!$ tx(2)=dx_c_4(vyg*omgx,i,j,k,dx) +!!$ tx(3)=dx_c_4(vzg*omgx,i,j,k,dx) +!!$ +!!$ ty(1)=dy_c_4(vxg*omgy,i,j,k,dy) +!!$ ty(2)=dy_c_4(vyg*omgy,i,j,k,dy) +!!$ ty(3)=dy_c_4(vzg*omgy,i,j,k,dy) +!!$ +!!$ tz(1)=dz_c_4(vxg*omgz,i,j,k,dz) +!!$ tz(2)=dz_c_4(vyg*omgz,i,j,k,dz) +!!$ tz(3)=dz_c_4(vzg*omgz,i,j,k,dz) + + tx(1)=1./(12.*dx)*(1.*omgx(i-2,j,k)*vxg(i-2,j,k)-8.*omgx(i-1,j,k)*vxg(i-1,j,k) & + +8.*omgx(i+1,j,k)*vxg(i+1,j,k)-1.*omgx(i+2,j,k)*vxg(i+2,j,k)) + tx(2)=1./(12.*dx)*(1.*omgx(i-2,j,k)*vyg(i-2,j,k)-8.*omgx(i-1,j,k)*vyg(i-1,j,k) & + +8.*omgx(i+1,j,k)*vyg(i+1,j,k)-1.*omgx(i+2,j,k)*vyg(i+2,j,k)) + tx(3)=1./(12.*dx)*(1.*omgx(i-2,j,k)*vzg(i-2,j,k)-8.*omgx(i-1,j,k)*vzg(i-1,j,k) & + +8.*omgx(i+1,j,k)*vzg(i+1,j,k)-1.*omgx(i+2,j,k)*vzg(i+2,j,k)) + + ty(1)=1./(12.*dy)*(1.*omgy(i,j-2,k)*vxg(i,j-2,k)-8.*omgy(i,j-1,k)*vxg(i,j-1,k) & + +8.*omgy(i,j+1,k)*vxg(i,j+1,k)-1.*omgy(i,j+2,k)*vxg(i,j+2,k)) + ty(2)=1./(12.*dy)*(1.*omgy(i,j-2,k)*vyg(i,j-2,k)-8.*omgy(i,j-1,k)*vyg(i,j-1,k) & + +8.*omgy(i,j+1,k)*vyg(i,j+1,k)-1.*omgy(i,j+2,k)*vyg(i,j+2,k)) + ty(3)=1./(12.*dy)*(1.*omgy(i,j-2,k)*vzg(i,j-2,k)-8.*omgy(i,j-1,k)*vzg(i,j-1,k) & + +8.*omgy(i,j+1,k)*vzg(i,j+1,k)-1.*omgy(i,j+2,k)*vzg(i,j+2,k)) + + tz(1)=1./(12.*dz)*(1.*omgz(i,j,k-2)*vxg(i,j,k-2)-8.*omgz(i,j,k-1)*vxg(i,j,k-1) & + +8.*omgz(i,j,k+1)*vxg(i,j,k+1)-1.*omgz(i,j,k+2)*vxg(i,j,k+2)) + tz(2)=1./(12.*dz)*(1.*omgz(i,j,k-2)*vyg(i,j,k-2)-8.*omgz(i,j,k-1)*vyg(i,j,k-1) & + +8.*omgz(i,j,k+1)*vyg(i,j,k+1)-1.*omgz(i,j,k+2)*vyg(i,j,k+2)) + tz(3)=1./(12.*dz)*(1.*omgz(i,j,k-2)*vzg(i,j,k-2)-8.*omgz(i,j,k-1)*vzg(i,j,k-1) & + +8.*omgz(i,j,k+1)*vzg(i,j,k+1)-1.*omgz(i,j,k+2)*vzg(i,j,k+2)) + +!!$ !schema decentre au bord +!!$ if((i==1).or.(i==2))then +!!$ tx(1)=dx_dr_5(vxg*omgx,i,j,k,dx) +!!$ tx(2)=dx_dr_5(vyg*omgx,i,j,k,dx) +!!$ tx(3)=dx_dr_5(vzg*omgx,i,j,k,dx) +!!$ end if +!!$ +!!$ if((i==nx).or.(i==nx-1))then +!!$ tx(1)=dx_ga_5(vxg*omgx,i,j,k,dx) +!!$ tx(2)=dx_ga_5(vyg*omgx,i,j,k,dx) +!!$ tx(3)=dx_ga_5(vzg*omgx,i,j,k,dx) +!!$ endif +!!$ +!!$ if((j==1).or.(j==2))then +!!$ ty(1)=dy_dr_5(vxg*omgy,i,j,k,dy) +!!$ ty(2)=dy_dr_5(vyg*omgy,i,j,k,dy) +!!$ ty(3)=dy_dr_5(vzg*omgy,i,j,k,dy) +!!$ end if +!!$ +!!$ if((j==ny).or.(j==ny-1))then +!!$ ty(1)=dy_ga_5(vxg*omgy,i,j,k,dy) +!!$ ty(2)=dy_ga_5(vyg*omgy,i,j,k,dy) +!!$ ty(3)=dy_ga_5(vzg*omgy,i,j,k,dy) +!!$ endif +!!$ +!!$ if((k==1).or.(k==2))then +!!$ tz(1)=dz_ha_5(vxg*omgz,i,j,k,dz) +!!$ tz(2)=dz_ha_5(vyg*omgz,i,j,k,dz) +!!$ tz(3)=dz_ha_5(vzg*omgz,i,j,k,dz) +!!$ end if +!!$ +!!$ if((k==nz).or.(k==nz-1))then +!!$ tz(1)=dz_ba_5(vxg*omgz,i,j,k,dz) +!!$ tz(2)=dz_ba_5(vyg*omgz,i,j,k,dz) +!!$ tz(3)=dz_ba_5(vzg*omgz,i,j,k,dz) +!!$ endif + + !schema decentre au bord + if((i==1).or.(i==2))then + tx(1)=1./(12.*dx)*(-25.*omgx(i,j,k)*vxg(i,j,k)+48.*omgx(i+1,j,k)*vxg(i+1,j,k) & + -36.*omgx(i+2,j,k)*vxg(i+2,j,k)+16.*omgx(i+3,j,k)*vxg(i+3,j,k)-3.*omgx(i+4,j,k)*vxg(i+4,j,k)) + tx(2)=1./(12.*dx)*(-25.*omgx(i,j,k)*vyg(i,j,k)+48.*omgx(i+1,j,k)*vyg(i+1,j,k) & + -36.*omgx(i+2,j,k)*vyg(i+2,j,k)+16.*omgx(i+3,j,k)*vyg(i+3,j,k)-3.*omgx(i+4,j,k)*vyg(i+4,j,k)) + tx(3)=1./(12.*dx)*(-25.*omgx(i,j,k)*vzg(i,j,k)+48.*omgx(i+1,j,k)*vzg(i+1,j,k) & + -36.*omgx(i+2,j,k)*vzg(i+2,j,k)+16.*omgx(i+3,j,k)*vzg(i+3,j,k)-3.*omgx(i+4,j,k)*vzg(i+4,j,k)) + end if + + if((i==nx).or.(i==nx-1))then + tx(1)=1./(12.*dx)*(-25.*omgx(i,j,k)*vxg(i,j,k)+48.*omgx(i-1,j,k)*vxg(i-1,j,k) & + -36.*omgx(i-2,j,k)*vxg(i-2,j,k)+16.*omgx(i-3,j,k)*vxg(i-3,j,k)-3.*omgx(i-4,j,k)*vxg(i-4,j,k)) + tx(2)=1./(12.*dx)*(-25.*omgx(i,j,k)*vyg(i,j,k)+48.*omgx(i-1,j,k)*vyg(i-1,j,k) & + -36.*omgx(i-2,j,k)*vyg(i-2,j,k)+16.*omgx(i-3,j,k)*vyg(i-3,j,k)-3.*omgx(i-4,j,k)*vyg(i-4,j,k)) + tx(3)=1./(12.*dx)*(-25.*omgx(i,j,k)*vzg(i,j,k)+48.*omgx(i-1,j,k)*vzg(i-1,j,k) & + -36.*omgx(i-2,j,k)*vzg(i-2,j,k)+16.*omgx(i-3,j,k)*vzg(i-3,j,k)-3.*omgx(i-4,j,k)*vzg(i-4,j,k)) + endif + + if((j==1).or.(j==2))then + ty(1)=1./(12.*dy)*(-25.*omgy(i,j,k)*vxg(i,j,k)+48.*omgy(i,j+1,k)*vxg(i,j+1,k) & + -36.*omgy(i,j+2,k)*vxg(i,j+2,k)+16.*omgy(i,j+3,k)*vxg(i,j+3,k)-3.*omgy(i,j+4,k)*vxg(i,j+4,k)) + ty(2)=1./(12.*dy)*(-25.*omgy(i,j,k)*vyg(i,j,k)+48.*omgy(i,j+1,k)*vyg(i,j+1,k) & + -36.*omgy(i,j+2,k)*vyg(i,j+2,k)+16.*omgy(i,j+3,k)*vyg(i,j+3,k)-3.*omgy(i,j+4,k)*vyg(i,j+4,k)) + ty(3)=1./(12.*dy)*(-25.*omgy(i,j,k)*vzg(i,j,k)+48.*omgy(i,j+1,k)*vzg(i,j+1,k) & + -36.*omgy(i,j+2,k)*vzg(i,j+2,k)+16.*omgy(i,j+3,k)*vzg(i,j+3,k)-3.*omgy(i,j+4,k)*vzg(i,j+4,k)) + end if + + if((j==ny).or.(j==ny-1))then + ty(1)=1./(12.*dy)*(-25.*omgy(i,j,k)*vxg(i,j,k)+48.*omgy(i,j-1,k)*vxg(i,j-1,k) & + -36.*omgy(i,j-2,k)*vxg(i,j-2,k)+16.*omgy(i,j-3,k)*vxg(i,j-3,k)-3.*omgy(i,j-4,k)*vxg(i,j-4,k)) + ty(2)=1./(12.*dy)*(-25.*omgy(i,j,k)*vyg(i,j,k)+48.*omgy(i,j-1,k)*vyg(i,j-1,k) & + -36.*omgy(i,j-2,k)*vyg(i,j-2,k)+16.*omgy(i,j-3,k)*vyg(i,j-3,k)-3.*omgy(i,j-4,k)*vyg(i,j-4,k)) + ty(3)=1./(12.*dy)*(-25.*omgy(i,j,k)*vzg(i,j,k)+48.*omgy(i,j-1,k)*vzg(i,j-1,k) & + -36.*omgy(i,j-2,k)*vzg(i,j-2,k)+16.*omgy(i,j-3,k)*vzg(i,j-3,k)-3.*omgy(i,j-4,k)*vzg(i,j-4,k)) + endif + + if((k==1).or.(k==2))then + tz(1)=1./(12.*dz)*(-25.*omgz(i,j,k)*vxg(i,j,k)+48.*omgz(i,j,k+1)*vxg(i,j,k+1) & + -36.*omgz(i,j,k+2)*vxg(i,j,k+2)+16.*omgz(i,j,k+3)*vxg(i,j,k+3)-3.*omgz(i,j,k+4)*vxg(i,j,k+4)) + tz(2)=1./(12.*dz)*(-25.*omgz(i,j,k)*vyg(i,j,k)+48.*omgz(i,j,k+1)*vyg(i,j,k+1) & + -36.*omgz(i,j,k+2)*vyg(i,j,k+2)+16.*omgz(i,j,k+3)*vyg(i,j,k+3)-3.*omgz(i,j,k+4)*vyg(i,j,k+4)) + tz(3)=1./(12.*dz)*(-25.*omgz(i,j,k)*vzg(i,j,k)+48.*omgz(i,j,k+1)*vzg(i,j,k+1) & + -36.*omgz(i,j,k+2)*vzg(i,j,k+2)+16.*omgz(i,j,k+3)*vzg(i,j,k+3)-3.*omgz(i,j,k+4)*vzg(i,j,k+4)) + end if + + if((k==nz).or.(k==nz-1))then + tz(1)=1./(12.*dz)*(-25.*omgz(i,j,k)*vxg(i,j,k)+48.*omgz(i,j,k-1)*vxg(i,j,k-1) & + -36.*omgz(i,j,k-2)*vxg(i,j,k-2)+16.*omgz(i,j,k-3)*vxg(i,j,k-3)-3.*omgz(i,j,k-4)*vxg(i,j,k-4)) + tz(2)=1./(12.*dz)*(-25.*omgz(i,j,k)*vyg(i,j,k)+48.*omgz(i,j,k-1)*vyg(i,j,k-1) & + -36.*omgz(i,j,k-2)*vyg(i,j,k-2)+16.*omgz(i,j,k-3)*vyg(i,j,k-3)-3.*omgz(i,j,k-4)*vyg(i,j,k-4)) + tz(3)=1./(12.*dz)*(-25.*omgz(i,j,k)*vzg(i,j,k)+48.*omgz(i,j,k-1)*vzg(i,j,k-1) & + -36.*omgz(i,j,k-2)*vzg(i,j,k-2)+16.*omgz(i,j,k-3)*vzg(i,j,k-3)-3.*omgz(i,j,k-4)*vzg(i,j,k-4)) + endif + + x=xg+(i-1)*dx + y=yb+(j-1)*dy + z=zd+(k-1)*dz + + + + stxg(i,j,k)=tx(1)+ty(1)+tz(1) + styg(i,j,k)=tx(2)+ty(2)+tz(2) + stzg(i,j,k)=tx(3)+ty(3)+tz(3) + end do + end do + end do + + end subroutine strech_old + + + subroutine diffusion_old + implicit none + real(kind=8),dimension(1:3,1:nx,1:ny,1:nz) :: diffusion + integer :: i,j,k + real(kind=8) :: facx,facy,facz + real(kind=8),dimension(1:3) :: tx,ty,tz + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + + facx=1.D0/(12.D0*dx**2) + facy=1.D0/(12.D0*dy**2) + facz=1.D0/(12.D0*dz**2) + + do k=1,nz + do j=1,ny + do i=1,nx + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + !ordre4 + tx(1)=facx*(-omgx(ip2,j,k)+16.D0*omgx(ip1,j,k)-30.D0*omgx(i,j,k)+16.D0*omgx(im1,j,k)-omgx(im2,j,k)) + tx(2)=facx*(-omgy(ip2,j,k)+16.D0*omgy(ip1,j,k)-30.D0*omgy(i,j,k)+16.D0*omgy(im1,j,k)-omgy(im2,j,k)) + tx(3)=facx*(-omgz(ip2,j,k)+16.D0*omgz(ip1,j,k)-30.D0*omgz(i,j,k)+16.D0*omgz(im1,j,k)-omgz(im2,j,k)) + + ty(1)=facy*(-omgx(i,jp2,k)+16.D0*omgx(i,jp1,k)-30.D0*omgx(i,j,k)+16.D0*omgx(i,jm1,k)-omgx(i,jm2,k)) + ty(2)=facy*(-omgy(i,jp2,k)+16.D0*omgy(i,jp1,k)-30.D0*omgy(i,j,k)+16.D0*omgy(i,jm1,k)-omgy(i,jm2,k)) + ty(3)=facy*(-omgz(i,jp2,k)+16.D0*omgz(i,jp1,k)-30.D0*omgz(i,j,k)+16.D0*omgz(i,jm1,k)-omgz(i,jm2,k)) + + tz(1)=facz*(-omgx(i,j,kp2)+16.D0*omgx(i,j,kp1)-30.D0*omgx(i,j,k)+16.D0*omgx(i,j,km1)-omgx(i,j,km2)) + tz(2)=facz*(-omgy(i,j,kp2)+16.D0*omgy(i,j,kp1)-30.D0*omgy(i,j,k)+16.D0*omgy(i,j,km1)-omgy(i,j,km2)) + tz(3)=facz*(-omgz(i,j,kp2)+16.D0*omgz(i,j,kp1)-30.D0*omgz(i,j,k)+16.D0*omgz(i,j,km1)-omgz(i,j,km2)) + + + + diffusion(1,i,j,k)=tx(1)+ty(1)+tz(1) + diffusion(2,i,j,k)=tx(2)+ty(2)+tz(2) + diffusion(3,i,j,k)=tx(3)+ty(3)+tz(3) + end do + end do + end do + + do k=1,nz + do j=1,ny + do i=1,nx + omgx(i,j,k)=omgx(i,j,k)+ nu*dt*diffusion(1,i,j,k) + omgy(i,j,k)=omgy(i,j,k)+ nu*dt*diffusion(2,i,j,k) + omgz(i,j,k)=omgz(i,j,k)+ nu*dt*diffusion(3,i,j,k) + end do + end do + end do + + end subroutine diffusion_old + + + subroutine strech_diff_penal + implicit none + integer :: i,j,k + real(kind=8),dimension(1:3) :: tx,ty,tz + real(kind=8) :: x,y,z + real(kind=8) :: facx,facy,facz + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + + + + + do k=1,nz + do j=1,ny + do i=1,nx + + + facx=1.D0/(12.D0*dx) + facy=1.D0/(12.D0*dy) + facz=1.D0/(12.D0*dz) + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + !strech + !------ + tx(1)=facx*(omgx(im2,j,k)*vxg(im2,j,k)-8.D0*omgx(im1,j,k)*vxg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vxg(ip1,j,k)-omgx(ip2,j,k)*vxg(ip2,j,k)) + tx(2)=facx*(omgx(im2,j,k)*vyg(im2,j,k)-8.D0*omgx(im1,j,k)*vyg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vyg(ip1,j,k)-omgx(ip2,j,k)*vyg(ip2,j,k)) + tx(3)=facx*(omgx(im2,j,k)*vzg(im2,j,k)-8.D0*omgx(im1,j,k)*vzg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vzg(ip1,j,k)-omgx(ip2,j,k)*vzg(ip2,j,k)) + + ty(1)=facy*(omgy(i,jm2,k)*vxg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vxg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vxg(i,jp1,k)-omgy(i,jp2,k)*vxg(i,jp2,k)) + ty(2)=facy*(omgy(i,jm2,k)*vyg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vyg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vyg(i,jp1,k)-omgy(i,jp2,k)*vyg(i,jp2,k)) + ty(3)=facy*(omgy(i,jm2,k)*vzg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vzg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vzg(i,jp1,k)-omgy(i,jp2,k)*vzg(i,jp2,k)) + + tz(1)=facz*(omgz(i,j,km2)*vxg(i,j,km2)-8.D0*omgz(i,j,km1)*vxg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vxg(i,j,kp1)-omgz(i,j,kp2)*vxg(i,j,kp2)) + tz(2)=facz*(omgz(i,j,km2)*vyg(i,j,km2)-8.D0*omgz(i,j,km1)*vyg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vyg(i,j,kp1)-omgz(i,j,kp2)*vyg(i,j,kp2)) + tz(3)=facz*(omgz(i,j,km2)*vzg(i,j,km2)-8.D0*omgz(i,j,km1)*vzg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vzg(i,j,kp1)-omgz(i,j,kp2)*vzg(i,j,kp2)) + + + + stxg(i,j,k)=tx(1)+ty(1)+tz(1) + styg(i,j,k)=tx(2)+ty(2)+tz(2) + stzg(i,j,k)=tx(3)+ty(3)+tz(3) + + + !diffusion + !---------- + facx=1.D0/(12.D0*dx**2) + facy=1.D0/(12.D0*dy**2) + facz=1.D0/(12.D0*dz**2) + + tx(1)=facx*(-omgx(ip2,j,k)+16.D0*omgx(ip1,j,k)-30.D0*omgx(i,j,k)+16.D0*omgx(im1,j,k)-omgx(im2,j,k)) + tx(2)=facx*(-omgy(ip2,j,k)+16.D0*omgy(ip1,j,k)-30.D0*omgy(i,j,k)+16.D0*omgy(im1,j,k)-omgy(im2,j,k)) + tx(3)=facx*(-omgz(ip2,j,k)+16.D0*omgz(ip1,j,k)-30.D0*omgz(i,j,k)+16.D0*omgz(im1,j,k)-omgz(im2,j,k)) + + ty(1)=facy*(-omgx(i,jp2,k)+16.D0*omgx(i,jp1,k)-30.D0*omgx(i,j,k)+16.D0*omgx(i,jm1,k)-omgx(i,jm2,k)) + ty(2)=facy*(-omgy(i,jp2,k)+16.D0*omgy(i,jp1,k)-30.D0*omgy(i,j,k)+16.D0*omgy(i,jm1,k)-omgy(i,jm2,k)) + ty(3)=facy*(-omgz(i,jp2,k)+16.D0*omgz(i,jp1,k)-30.D0*omgz(i,j,k)+16.D0*omgz(i,jm1,k)-omgz(i,jm2,k)) + + tz(1)=facz*(-omgx(i,j,kp2)+16.D0*omgx(i,j,kp1)-30.D0*omgx(i,j,k)+16.D0*omgx(i,j,km1)-omgx(i,j,km2)) + tz(2)=facz*(-omgy(i,j,kp2)+16.D0*omgy(i,j,kp1)-30.D0*omgy(i,j,k)+16.D0*omgy(i,j,km1)-omgy(i,j,km2)) + tz(3)=facz*(-omgz(i,j,kp2)+16.D0*omgz(i,j,kp1)-30.D0*omgz(i,j,k)+16.D0*omgz(i,j,km1)-omgz(i,j,km2)) + + + + stxg(i,j,k)=stxg(i,j,k)+nu*(tx(1)+ty(1)+tz(1)) + styg(i,j,k)=styg(i,j,k)+nu*(tx(2)+ty(2)+tz(2)) + stzg(i,j,k)=stzg(i,j,k)+nu*(tx(3)+ty(3)+tz(3)) + +!!$ if (.not.((chi(i,j,k)==0.).and.(derivx(chi,i,j,k)==0.).and.(derivy(chi,i,j,k)==0.).and.(derivz(chi,i,j,k)==0.))) then + !penal + !----- +!!$ facx=1.D0/(12.D0*dx) +!!$ facy=1.D0/(12.D0*dy) +!!$ facz=1.D0/(12.D0*dz) +!!$ +!!$ tx(2)=facx*(peny(im2,j,k)-8.D0*peny(im1,j,k)+8.D0*peny(ip1,j,k)-peny(ip2,j,k)) +!!$ tx(3)=facx*(penz(im2,j,k)-8.D0*penz(im1,j,k)+8.D0*penz(ip1,j,k)-penz(ip2,j,k)) +!!$ +!!$ ty(1)=facy*(penx(i,jm2,k)-8.D0*penx(i,jm1,k)+8.D0*penx(i,jp1,k)-penx(i,jp2,k)) +!!$ ty(3)=facy*(penz(i,jm2,k)-8.D0*penz(i,jm1,k)+8.D0*penz(i,jp1,k)-penz(i,jp2,k)) +!!$ +!!$ +!!$ tz(1)=facz*(penx(i,j,km2)-8.D0*penx(i,j,km1)+8.D0*penx(i,j,kp1)-penx(i,j,kp2)) +!!$ tz(2)=facz*(peny(i,j,km2)-8.D0*peny(i,j,km1)+8.D0*peny(i,j,kp1)-peny(i,j,kp2)) + + +!!$ +!!$ !stxg(i,j,k)=stxg(i,j,k)+ty(3)-tz(2) +!!$ !styg(i,j,k)=styg(i,j,k)+tz(1)-tx(3) +!!$ !stzg(i,j,k)=stzg(i,j,k)+tx(2)-ty(1) +!!$ +!!$ omgx(i,j,k)=ty(3)-tz(2) +!!$ omgy(i,j,k)=tz(1)-tx(3) +!!$ omgz(i,j,k)=tx(2)-ty(1) +!!$ +!!$ !explicite +!!$ !omgx(i,j,k)=omgx(i,j,k)+dt*(ty(3)-tz(2)) +!!$ !omgy(i,j,k)=omgy(i,j,k)+dt*(tz(1)-tx(3)) +!!$ !omgz(i,j,k)=omgz(i,j,k)+dt*(tx(2)-ty(1)) + +!!$ tx=rot_vec_gradsca(vxg,vyg,vzg,exp(-lambda*chi*dt),i,j,k) +!!$ +!!$ omgx(i,j,k)=omgx(i,j,k)*exp(-lambda*chi(i,j,k)*dt)-tx(1) +!!$ omgy(i,j,k)=omgy(i,j,k)*exp(-lambda*chi(i,j,k)*dt)-tx(2) +!!$ omgz(i,j,k)=omgz(i,j,k)*exp(-lambda*chi(i,j,k)*dt)-tx(3) + +!!$ tx=rot_vec_gradsca(vxg,vyg,vzg,1./(1.+lambda*dt*chi),i,j,k) +!!$ +!!$ omgx(i,j,k)=omgx(i,j,k)/(1.+lambda*chi(i,j,k)*dt)-tx(1) +!!$ omgy(i,j,k)=omgy(i,j,k)/(1.+lambda*chi(i,j,k)*dt)-tx(2) +!!$ omgz(i,j,k)=omgz(i,j,k)/(1.+lambda*chi(i,j,k)*dt)-tx(3) + +!!$ tx=rot_vec_gradsca(vxg,vyg,vzg,1./(1.+lambda*dt*chi),i,j,k) +!!$ +!!$ omgx(i,j,k)=omgx(i,j,k)*(1.-lambda*chi(i,j,k)*dt)-lambda*dt*tx(1) +!!$ omgy(i,j,k)=omgy(i,j,k)*(1.-lambda*chi(i,j,k)*dt)-lambda*dt*tx(2) +!!$ omgz(i,j,k)=omgz(i,j,k)*(1.-lambda*chi(i,j,k)*dt)-lambda*dt*tx(3) + + +!!$ tx=rot_vec_gradsca(vxg,vyg,vzg,chi,i,j,k) +!!$ +!!$ omgx(i,j,k)=omgx(i,j,k)+dt*lambda*tx(1) +!!$ omgy(i,j,k)=omgy(i,j,k)+dt*lambda*tx(2) +!!$ omgz(i,j,k)=omgz(i,j,k)+dt*lambda*tx(3) +!!$ +!!$ +!!$ end if + end do + end do + end do + + contains + function penx (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penx + + + penx=vxg(l,m,n)*exp(-lambda(l,m,n)*chi(l,m,n)*dt) + !penx=vxg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + !penx=-lambda*chi(l,m,n)*vxg(l,m,n) + !penx=vxg(l,m,n) + + end function penx + + function peny (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: peny + + + peny=vyg(l,m,n)*exp(-lambda(l,m,n)*chi(l,m,n)*dt) + !peny=vyg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + !peny=-lambda*chi(l,m,n)*vyg(l,m,n) + !peny=vyg(l,m,n) + + end function peny + + function penz (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penz + + + penz=vzg(l,m,n)*exp(-lambda(l,m,n)*chi(l,m,n)*dt) + !penz=vzg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + !penz=-lambda*chi(l,m,n)*vzg(l,m,n) + !penz=vzg(l,m,n) + + end function penz + + + function rot_vec_gradsca(vecx,vecy,vecz,sca,l,m,n) result(r) + implicit none + real(kind=8),dimension(:,:,:) :: vecx,vecy,vecz,sca + integer :: l,m,n + real(kind=8),dimension(1:3) :: r + + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + real(kind=8) :: facx,facy,facz,dxsca,dysca,dzsca + + facx=1.D0/(12.D0*dx) + facy=1.D0/(12.D0*dy) + facz=1.D0/(12.D0*dz) + + ip1=mod(l+1+nx-1,nx)+1 + im1=mod(l-1+nx-1,nx)+1 + ip2=mod(l+2+nx-1,nx)+1 + im2=mod(l-2+nx-1,nx)+1 + + jp1=mod(m+1+ny-1,ny)+1 + jm1=mod(m-1+ny-1,ny)+1 + jp2=mod(m+2+ny-1,ny)+1 + jm2=mod(m-2+ny-1,ny)+1 + + kp1=mod(n+1+nz-1,nz)+1 + km1=mod(n-1+nz-1,nz)+1 + kp2=mod(n+2+nz-1,nz)+1 + km2=mod(n-2+nz-1,nz)+1 + + dxsca=facx*(sca(im2,j,k)-8.*sca(im1,j,k)+8.*sca(ip1,j,k)-sca(ip2,j,k)) + dysca=facy*(sca(i,jm2,k)-8.*sca(i,jm1,k)+8.*sca(i,jp1,k)-sca(i,jp2,k)) + dzsca=facz*(sca(i,j,km2)-8.*sca(i,j,km1)+8.*sca(i,j,kp1)-sca(i,j,kp2)) + + r(1)=vecy(l,m,n)*dzsca-vecz(l,m,n)*dysca + r(2)=vecz(l,m,n)*dxsca-vecx(l,m,n)*dzsca + r(3)=vecx(l,m,n)*dysca-vecy(l,m,n)*dxsca + + end function rot_vec_gradsca + + + end subroutine strech_diff_penal + + + + + subroutine rotv_df4 + implicit none + integer :: l,m,n,i,j,k + + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + real(kind=8) :: facx,facy,facz,dxsca,dysca,dzsca + + !omgx = dy vz - dz vy + !omgy = dz vx - dx vz + !omgz = dx vy - dy vx + + facx=1.D0/(12.D0*dx) + facy=1.D0/(12.D0*dy) + facz=1.D0/(12.D0*dz) + + do k=1,nz + do j=1,ny + do i=1,nx + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + omgx(i,j,k)=facy*(vzg(i,jm2,k)-8.*vzg(i,jm1,k)+8.*vzg(i,jp1,k)-vzg(i,jp2,k)) & + -facz*(vyg(i,j,km2)-8.*vyg(i,j,km1)+8.*vyg(i,j,kp1)-vyg(i,j,kp2)) + omgy(i,j,k)=facz*(vxg(i,j,km2)-8.*vxg(i,j,km1)+8.*vxg(i,j,kp1)-vxg(i,j,kp2)) & + -facx*(vzg(im2,j,k)-8.*vzg(im1,j,k)+8.*vzg(ip1,j,k)-vzg(ip2,j,k)) + omgz(i,j,k)=facx*(vyg(im2,j,k)-8.*vyg(im1,j,k)+8.*vyg(ip1,j,k)-vyg(ip2,j,k)) & + -facy*(vxg(i,jm2,k)-8.*vxg(i,jm1,k)+8.*vxg(i,jp1,k)-vxg(i,jp2,k)) + end do + end do + end do + + end subroutine rotv_df4 + + subroutine rotv_df2 + implicit none + integer :: l,m,n,i,j,k + + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + real(kind=8) :: facx,facy,facz,dxsca,dysca,dzsca + + !omgx = dy vz - dz vy + !omgy = dz vx - dx vz + !omgz = dx vy - dy vx + + facx=1.D0/(2.D0*dx) + facy=1.D0/(2.D0*dy) + facz=1.D0/(2.D0*dz) + + do k=1,nz + do j=1,ny + do i=1,nx + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + + omgx(i,j,k)=facy*(-vzg(i,jm1,k)+vzg(i,jp1,k)) & + -facz*(-vyg(i,j,km1)+vyg(i,j,kp1)) + omgy(i,j,k)=facz*(-vxg(i,j,km1)+vxg(i,j,kp1)) & + -facx*(-vzg(im1,j,k)+vzg(ip1,j,k)) + omgz(i,j,k)=facx*(-vyg(im1,j,k)+vyg(ip1,j,k)) & + -facy*(-vxg(i,jm1,k)+vxg(i,jp1,k)) + end do + end do + end do + + end subroutine rotv_df2 + + + + + + + +end module old_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/penal_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/penal_mod.f90 new file mode 100644 index 000000000..a828611d0 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/penal_mod.f90 @@ -0,0 +1,235 @@ +module penal_mod + use donnees_mod + use tab_mod + use nrtype + USE nrutil + USE nr +contains + + subroutine make_chi + implicit none + + integer :: i,j,k + real(kind=8) :: x,y,z,d,rayon,centrex,centrey,centrez,epaisseur !,dist + + do i=1,nx + x=xtab(i) + do j=1,ny + y=ytab(j) + do k=1,nz + z=ztab(k) + + centrex=0. + centrey=0. + centrez=0. + + !======================================== + ! sphere + !======================================== +!!$ rayon=0.5 +!!$ d=dist(centrex,centrey,centrez,rayon,x,y,z) +!!$ chi(i,j,k)=carac(d,0.*dx) + + !======================================== + ! poiseuil + !======================================== +!!$ chi(i,j,k)=0. +!!$ if ( (z>1.).or.(z<-1.) ) then +!!$ chi(i,j,k)=1. +!!$ end if + + !======================================== + ! poiseuil/Sphere + !======================================== + chi(i,j,k)=0. +! if ( (y<(1./0.4844)).and.(y>-(1./0.4844)) ) then + if ( (y<=0.).and.(y>-(1./0.4844)) ) then + !chi(i,j,k)=0. + rayon=0.5 + d=dist(centrex,centrey,centrez,rayon,x,y,z) + chi(i,j,k)=carac(d,0.*dx) + end if + + chi_sphere(i,j,k)=0. +! if ( (y<(1./0.4844)).and.(y>-(1./0.4844)) ) then + if ( (y<=0.).and.(y>-(1./0.4844)) ) then + rayon=0.5 + d=dist(centrex,centrey,centrez,rayon,x,y,z) + chi_sphere(i,j,k)=carac(d,0.*dx) + end if + + lambda(i,j,k)=lambda_flu + rayon=0.5 + epaisseur=2*rayon*0.1 + !dist=sqrt((x-centrex)**2+(y-centrey)**2+(z-centrez)**2) + if ( (y<=0.).and.(sqrt((x-centrex)**2+(y-centrey)**2+(z-centrez)**2)<=(rayon-epaisseur)) ) then + lambda(i,j,k)=lambda_sol + else + if ( (y<=0.).and.(sqrt((x-centrex)**2+(y-centrey)**2+(z-centrez)**2)>(rayon-epaisseur)) & + .and.(sqrt((x-centrex)**2+(y-centrey)**2+(z-centrez)**2)<=rayon) ) then + lambda(i,j,k)=lambda_por + end if + end if + +!!$ !======================================== +!!$ ! rien +!!$ !======================================== +!!$ chi(i,j,k)=0. + + !======================================== + ! sphere en dirichlet + !======================================== +!!$ chi(i,j,k)=0. +!!$ if ( (z<2.0645).or.(z>-2.0645) ) then +!!$ rayon=0.5 +!!$ d=dist(centrex,centrey,centrez,rayon,x,y,z) +!!$ chi(i,j,k)=carac(d,0.*dx) +!!$ end if + + end do + end do + end do + + end subroutine make_chi + + + function carac(d,eps_c) + implicit none + real(kind=8),intent(in) :: d,eps_c + real(kind=8) :: carac + pi=4.*atan(1.0) + + if (d<=-eps_c) carac= 1. + if (d>eps_c) carac= 0. + if((d<=eps_c).and.(d>-eps_c)) carac=0.5-0.5*d/eps_c-sin(pi*d/eps_c)/(2.*pi) + + !if((d<=eps_c).and.(d>-eps_c)) carac=sin(pi*(eps_c-d)/(4.*eps_c)) + + end function carac + + function dist (cx,cy,cz,r,px,py,pz) + implicit none + + real(kind=8),intent(in) :: cx,cy,cz,r,px,py,pz + real(kind=8) :: dist + + dist=sqrt((cx-px)**2+(py-cy)**2+(pz-cz)**2)-r + + end function dist + + + + + subroutine penal_fft + implicit none + + complex(kind=8),dimension(:,:,:),pointer :: sf1x, sf1y, sf1z + complex(kind=8),dimension(:,:,:),pointer :: su1x, su1y, su1z + complex(kind=8),dimension(:,:),pointer :: sf2x, sf2y, sf2z + complex(kind=8),dimension(:,:),pointer :: su2x, su2y, su2z + + integer :: i,j,k,m,n,p + real(kind=8) :: fac,x,y,z,l1,l2,l3,kx,ky,kz,r2,coeff,uinfx,uinfy,tmp + complex(kind=8) :: coef + + + l1=(xd-xg) + l2=(yh-yb) + l3=(zf-zd) + + allocate (sf1x(1:nx/2,1:ny,1:nz),su1x(1:nx/2,1:ny,1:nz) ) + allocate (sf1y(1:nx/2,1:ny,1:nz),su1y(1:nx/2,1:ny,1:nz) ) + allocate (sf1z(1:nx/2,1:ny,1:nz),su1z(1:nx/2,1:ny,1:nz) ) + allocate (sf2x(1:ny,1:nz),su2x(1:ny,1:nz) ) + allocate (sf2y(1:ny,1:nz),su2y(1:ny,1:nz) ) + allocate (sf2z(1:ny,1:nz),su2z(1:ny,1:nz) ) + + + !fft forward + call rlft3(vxg,sf1x,sf2x,1) + call rlft3(vyg,sf1y,sf2y,1) + call rlft3(vzg,sf1z,sf2z,1) + + !frequence=0 : n=0 + !0<f<fc : 1<=n<=N/2-1 + !f=fc=-fc : n=N/2 + !-fc<f<0 : N/2+1<=n<=N-1 + + fac=2./(nx*ny*nz) ! pour normalisation de la fft inverse + coef=-fac*cmplx(0.,1.)*2.*pi + + !calcul de la solution dans l'espace des frequences + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + do m=1,nx/2 + + if ( (m-1)<=(nx/2) ) then + kx=(m-1)/l1 + else + kx=(m-1-nx)/l1 + end if + + + + su1x(m,n,p)=coef*(ky*sf1z(m,n,p)-kz*sf1y(m,n,p)) + su1y(m,n,p)=coef*(kz*sf1x(m,n,p)-kx*sf1z(m,n,p)) + su1z(m,n,p)=coef*(kx*sf1y(m,n,p)-ky*sf1x(m,n,p)) + + end do + end do + end do + + m=nx/2+1 + kx=(m-1)/l1 + do p=1,nz + if ( (p-1)<=(nz/2) ) then + kz=(p-1)/l3 + else + kz=(p-1-nz)/l3 + end if + do n=1,ny + + if ( (n-1)<=(ny/2) ) then + ky=(n-1)/l2 + else + ky=(n-1-ny)/l2 + end if + + + su2x(n,p)=coef*(ky*sf2z(n,p)-kz*sf2y(n,p)) + su2y(n,p)=coef*(kz*sf2x(n,p)-kx*sf2z(n,p)) + su2z(n,p)=coef*(kx*sf2y(n,p)-ky*sf2x(n,p)) + + + + end do + end do + + !fft backward + + call rlft3(omgx,su1x,su2x,-1) + call rlft3(omgy,su1y,su2y,-1) + call rlft3(omgz,su1z,su2z,-1) + + deallocate(sf1x,su1x) + deallocate(sf1y,su1y) + deallocate(sf1z,su1z) + deallocate(sf2x,su2x) + deallocate(sf2y,su2y) + deallocate(sf2z,su2z) + + + end subroutine penal_fft + + +end module penal_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/remaillage_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/remaillage_mod.f90 new file mode 100644 index 000000000..38b81e05d --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/remaillage_mod.f90 @@ -0,0 +1,1820 @@ +module remaillage_mod + use donnees_mod + use tab_mod +contains + + subroutine remaill_l2 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(1:4) :: ip,jp,kp + real(kind=8),dimension(1:4) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0.D0 + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + + jp(2) = floor((posy(i)-yb)/dy) + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + + kp(2) = floor((posz(i)-zd)/dz) + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=1,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=1,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=1,4 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx1<=0.5D0) then + + poidx(1)=-0.5D0*xx1*(1.D0-xx1) + poidx(2)=1.D0-xx1**2 + poidx(3)=0.5D0*xx1*(1.D0+xx1) + poidx(4)=0.D0 + + else + + poidx(1)=0.D0 + poidx(2)=0.5D0*(xx1-1.D0)*(xx1-2.D0) + poidx(3)=xx1*(2.D0-xx1) + poidx(4)=0.5D0*xx1*(xx1-1.D0) + + end if + + if (yy1<=0.5D0) then + + poidy(1)=-0.5D0*yy1*(1.D0-yy1) + poidy(2)=1.D0-yy1**2 + poidy(3)=0.5D0*yy1*(1.D0+yy1) + poidy(4)=0.D0 + + else + + poidy(1)=0.D0 + poidy(2)=0.5D0*(yy1-1.D0)*(yy1-2.D0) + poidy(3)=yy1*(2.D0-yy1) + poidy(4)=0.5D0*yy1*(yy1-1.D0) + + end if + + if (zz1<=0.5D0) then + + poidz(1)=-0.5D0*zz1*(1.D0-zz1) + poidz(2)=1.D0-zz1**2 + poidz(3)=0.5D0*zz1*(1.D0+zz1) + poidz(4)=0.D0 + + else + + poidz(1)=0.D0 + poidz(2)=0.5D0*(zz1-1.D0)*(zz1-2.D0) + poidz(3)=zz1*(2.D0-zz1) + poidz(4)=0.5D0*zz1*(zz1-1.D0) + + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=1,4 + do d=1,4 + do c=1,4 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l2 + + subroutine remaill_l4 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:5) :: ip,jp,kp + real(kind=8),dimension(0:5) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0.D0 + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + kp(2) = floor((posz(i)-zd)/dz) + kp(0) = kp(2) - 2 + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + kp(5) = kp(2) + 3 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + + if (xx1<=0.5D0) then + poidx(0)=(2.D0*xx1-x2-2.D0*x3+x4)/24.D0 + poidx(1)=(-4.D0*xx1+4.D0*x2+x3-x4)/6.D0 + poidx(2)=1.D0+(-5.D0*x2+x4)/4.D0 + poidx(3)=(4.D0*xx1+4.D0*x2-x3-x4)/6.D0 + poidx(4)=(-2.D0*xx1-x2+2.D0*x3+x4)/24.D0 + poidx(5)=0.D0 + else + poidx(0)=0.D0 + poidx(1)=(-6.D0*xx1+11.D0*x2-6.D0*x3+x4)/24.D0 + poidx(2)=1.D0+(-5.D0*xx1-5.D0*x2+5.D0*x3-x4)/6.D0 + poidx(3)=(6.D0*xx1+x2-4.D0*x3+x4)/4.D0 + poidx(4)=(-3.D0*xx1+x2+3.D0*x3-x4)/6.D0 + poidx(5)=(2.D0*xx1-x2-2.D0*x3+x4)/24.D0 + end if + + if (yy1<=0.5D0) then + poidy(0)=(2.D0*yy1-y2-2.D0*y3+y4)/24.D0 + poidy(1)=(-4.D0*yy1+4.D0*y2+y3-y4)/6.D0 + poidy(2)=1.D0+(-5.D0*y2+y4)/4.D0 + poidy(3)=(4.D0*yy1+4.D0*y2-y3-y4)/6.D0 + poidy(4)=(-2.D0*yy1-y2+2.D0*y3+y4)/24.D0 + poidy(5)=0.D0 + else + poidy(0)=0.D0 + poidy(1)=(-6.D0*yy1+11.D0*y2-6.D0*y3+y4)/24.D0 + poidy(2)=1.D0+(-5.D0*yy1-5.D0*y2+5.D0*y3-y4)/6.D0 + poidy(3)=(6.D0*yy1+y2-4.D0*y3+y4)/4.D0 + poidy(4)=(-3.D0*yy1+y2+3.D0*y3-y4)/6.D0 + poidy(5)=(2.D0*yy1-y2-2.D0*y3+y4)/24.D0 + end if + if (zz1<=0.5D0) then + poidz(0)=(2.D0*zz1-z2-2.D0*z3+z4)/24.D0 + poidz(1)=(-4.D0*zz1+4.D0*z2+z3-z4)/6.D0 + poidz(2)=1.D0+(-5.D0*z2+z4)/4.D0 + poidz(3)=(4.D0*zz1+4.D0*z2-z3-z4)/6.D0 + poidz(4)=(-2.D0*zz1-z2+2.D0*z3+z4)/24.D0 + poidz(5)=0.D0 + else + poidz(0)=0.D0 + poidz(1)=(-6.D0*zz1+11.D0*z2-6.D0*z3+z4)/24.D0 + poidz(2)=1.D0+(-5.D0*zz1-5.D0*z2+5.D0*z3-z4)/6.D0 + poidz(3)=(6.D0*zz1+z2-4.D0*z3+z4)/4.D0 + poidz(4)=(-3.D0*zz1+z2+3.D0*z3-z4)/6.D0 + poidz(5)=(2.D0*zz1-z2-2.D0*z3+z4)/24.D0 + end if + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,5 + do d=0,5 + do c=0,5 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l4 + + subroutine remaill_l5 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(0:5) :: ip,jp,kp + real(kind=8),dimension(0:5) :: poidx,poidy,poidz + real(kind=8) :: xx1,yy1,zz1,x2,x3,x4,x5,y2,y3,y4,y5,z2,z3,z4,z5 + + remaille=0.D0 + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + jp(2) = floor((posy(i)-yb)/dy) + jp(0) = jp(2) - 2 + jp(1) = jp(2) - 1 + jp(3) = jp(2) + 1 + jp(4) = jp(2) + 2 + jp(5) = jp(2) + 3 + + kp(2) = floor((posz(i)-zd)/dz) + kp(0) = kp(2) - 2 + kp(1) = kp(2) - 1 + kp(3) = kp(2) + 1 + kp(4) = kp(2) + 2 + kp(5) = kp(2) + 3 + + + + !distance de la particule à remailler au second point + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + yy1 = (posy(i) - real(jp(2),kind=8)*dy-yb)/dy + zz1 = (posz(i) - real(kp(2),kind=8)*dz-zd)/dz + + + !conditions au bord + !------------------ + !periodique: + + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=0,5 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=0,5 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + y2=yy1**2 + y3=yy1**3 + y4=yy1**4 + y5=yy1**5 + z2=zz1**2 + z3=zz1**3 + z4=zz1**4 + z5=zz1**5 + + poidx(0)=xx1/20.D0-x2/24.D0-x3/24.D0+x4/24.D0-x5/120.D0 + poidx(1)=-xx1/2.D0+2.D0*x2/3.D0-x3/24.D0-x4/6.D0+x5/24.D0 + poidx(2)=1.D0-xx1/3.D0-5*x2/4.D0+5.D0*x3/12.D0+x4/4.D0-x5/12.D0 + poidx(3)=xx1+2.D0*x2/3.D0-7.D0*x3/12.D0-x4/6.D0+x5/12.D0 + poidx(4)=-xx1/4.D0-x2/24.D0+7.D0*x3/24.D0+x4/24.D0-x5/24.D0 + poidx(5)=xx1/30.D0-x3/24.D0+x5/120.D0 + + poidy(0)=yy1/20.D0-y2/24.D0-y3/24.D0+y4/24.D0-y5/120.D0 + poidy(1)=-yy1/2.D0+2.D0*y2/3.D0-y3/24.D0-y4/6.D0+y5/24.D0 + poidy(2)=1.D0-yy1/3.D0-5*y2/4.D0+5.D0*y3/12.D0+y4/4.D0-y5/12.D0 + poidy(3)=yy1+2.D0*y2/3.D0-7.D0*y3/12.D0-y4/6.D0+y5/12.D0 + poidy(4)=-yy1/4.D0-y2/24.D0+7.D0*y3/24.D0+y4/24.D0-y5/24.D0 + poidy(5)=yy1/30.D0-y3/24.D0+y5/120.D0 + + poidz(0)=zz1/20.D0-z2/24.D0-z3/24.D0+z4/24.D0-z5/120.D0 + poidz(1)=-zz1/2.D0+2.D0*z2/3.D0-z3/24.D0-z4/6.D0+z5/24.D0 + poidz(2)=1.D0-zz1/3.D0-5*z2/4.D0+5.D0*z3/12.D0+z4/4.D0-z5/12.D0 + poidz(3)=zz1+2.D0*z2/3.D0-7.D0*z3/12.D0-z4/6.D0+z5/12.D0 + poidz(4)=-zz1/4.D0-z2/24.D0+7.D0*z3/24.D0+z4/24.D0-z5/24.D0 + poidz(5)=zz1/30.D0-z3/24.D0+z5/120.D0 + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=0,5 + do d=0,5 + do c=0,5 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + end subroutine remaill_l5 + + + subroutine remaill_l5_x(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0.D0 + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posx(i)-xg)/dx) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posx(i) - real(ip(2),kind=8)*dx-xg)/dx + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.D0-x2/24.D0-x3/24.D0+x4/24.D0-x5/120.D0 + poidx(1)=-xx1/2.D0+2.D0*x2/3.D0-x3/24.D0-x4/6.D0+x5/24.D0 + poidx(2)=1.D0-xx1/3.D0-5*x2/4.D0+5.D0*x3/12.D0+x4/4.D0-x5/12.D0 + poidx(3)=xx1+2.D0*x2/3.D0-7.D0*x3/12.D0-x4/6.D0+x5/12.D0 + poidx(4)=-xx1/4.D0-x2/24.D0+7.D0*x3/24.D0+x4/24.D0-x5/24.D0 + poidx(5)=xx1/30.D0-x3/24.D0+x5/120.D0 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ip(c)+1,j,kvar)=remaille(ip(c)+1,j,kvar)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_x + + + subroutine remaill_l5_y(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0.D0 + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posy(i)-yb)/dy) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posy(i) - real(ip(2),kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.D0-x2/24.D0-x3/24.D0+x4/24.D0-x5/120.D0 + poidx(1)=-xx1/2.D0+2.D0*x2/3.D0-x3/24.D0-x4/6.D0+x5/24.D0 + poidx(2)=1.D0-xx1/3.D0-5*x2/4.D0+5.D0*x3/12.D0+x4/4.D0-x5/12.D0 + poidx(3)=xx1+2.D0*x2/3.D0-7.D0*x3/12.D0-x4/6.D0+x5/12.D0 + poidx(4)=-xx1/4.D0-x2/24.D0+7.D0*x3/24.D0+x4/24.D0-x5/24.D0 + poidx(5)=xx1/30.D0-x3/24.D0+x5/120.D0 + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_y + + + subroutine remaill_l5_z(donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,ivar,k,kvar,jvar + integer,dimension(0:5) :: ip + real(kind=8),dimension(0:5) :: poidx + real(kind=8) :: xx1,x2,x3,x4,x5 + + remaille=0.D0 + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(2) = floor((posz(i)-zd)/dz) + ip(0) = ip(2) - 2 + ip(1) = ip(2) - 1 + ip(3) = ip(2) + 1 + ip(4) = ip(2) + 2 + ip(5) = ip(2) + 3 + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx1 = (posz(i) - real(ip(2),kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + + !periodique: + do c=0,5 + ip(c)=mod(ip(c)+nz,nz) + end do + + + + !calcul des poids + !---------------- + x2=xx1**2 + x3=xx1**3 + x4=xx1**4 + x5=xx1**5 + + poidx(0)=xx1/20.D0-x2/24.D0-x3/24.D0+x4/24.D0-x5/120.D0 + poidx(1)=-xx1/2.D0+2.D0*x2/3.D0-x3/24.D0-x4/6.D0+x5/24.D0 + poidx(2)=1.D0-xx1/3.D0-5*x2/4.D0+5.D0*x3/12.D0+x4/4.D0-x5/12.D0 + poidx(3)=xx1+2.D0*x2/3.D0-7.D0*x3/12.D0-x4/6.D0+x5/12.D0 + poidx(4)=-xx1/4.D0-x2/24.D0+7.D0*x3/24.D0+x4/24.D0-x5/24.D0 + poidx(5)=xx1/30.D0-x3/24.D0+x5/120.D0 + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=0,5 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poidx(c) + end do + + + end do + + end subroutine remaill_l5_z + + + + + + + + + + + + + + + subroutine remaill_l6 (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb + integer,dimension(-3:4) :: ip,jp,kp + real(kind=8),dimension(-3:4) :: poidx,poidy,poidz + real(kind=8) :: xx,yy,zz + + remaille=0.D0 + + + do i=1,npart + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + jp(0) = floor((posy(i)-yb)/dy) + jp(-1) = jp(0) - 1 + jp(-2) = jp(0) - 2 + jp(-3) = jp(0) - 3 + jp(1) = jp(0) + 1 + jp(2) = jp(0) + 2 + jp(3) = jp(0) + 3 + jp(4) = jp(0) + 4 + + kp(0) = floor((posz(i)-zd)/dz) + kp(-1) = kp(0) - 1 + kp(-2) = kp(0) - 2 + kp(-3) = kp(0) - 3 + kp(1) = kp(0) + 1 + kp(2) = kp(0) + 2 + kp(3) = kp(0) + 3 + kp(4) = kp(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + yy = (posy(i) - real(jp(0),kind=8)*dy-yb)/dy !relatif + zz = (posz(i) - real(kp(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + do c=-3,4 + jp(c)=mod(jp(c)+ny,ny) + end do + + do c=-3,4 + kp(c)=mod(kp(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5D0) then + poidx(-3)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + poidx(-2)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+3.D0)/120.D0 + poidx(-1)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(0)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/36.D0 + poidx(1)=(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(2)=-(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/120.D0 + poidx(3)=(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/720.D0 + poidx(4)=0.D0 + else + poidx(-3)=0.D0 + poidx(-2)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)/720.D0 + poidx(-1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)/120.D0 + poidx(0)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)/36.D0 + poidx(2)=(xx-4.D0)*(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(3)=-(xx-4.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/120.D0 + poidx(4)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + end if + + if (yy<=0.5D0) then + poidy(-3)=(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)/720.D0 + poidy(-2)=-(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+3.D0)/120.D0 + poidy(-1)=(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+2.D0)*(yy+3.D0)/48.D0 + poidy(0)=-(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*(yy+1.D0)*(yy+2.D0)*(yy+3.D0)/36.D0 + poidy(1)=(yy-3.D0)*(yy-2.D0)*yy*(yy+1.D0)*(yy+2.D0)*(yy+3.D0)/48.D0 + poidy(2)=-(yy-3.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)*(yy+3.D0)/120.D0 + poidy(3)=(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)*(yy+3.D0)/720.D0 + poidy(4)=0.D0 + else + poidy(-3)=0.D0 + poidy(-2)=(yy-4.D0)*(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)/720.D0 + poidy(-1)=-(yy-4.D0)*(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+2.D0)/120.D0 + poidy(0)=(yy-4.D0)*(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*(yy+1.D0)*(yy+2.D0)/48.D0 + poidy(1)=-(yy-4.D0)*(yy-3.D0)*(yy-2.D0)*yy*(yy+1.D0)*(yy+2.D0)/36.D0 + poidy(2)=(yy-4.D0)*(yy-3.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)/48.D0 + poidy(3)=-(yy-4.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)/120.D0 + poidy(4)=(yy-3.D0)*(yy-2.D0)*(yy-1.D0)*yy*(yy+1.D0)*(yy+2.D0)/720.D0 + end if + + if (zz<=0.5D0) then + poidz(-3)=(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)/720.D0 + poidz(-2)=-(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+3.D0)/120.D0 + poidz(-1)=(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+2.D0)*(zz+3.D0)/48.D0 + poidz(0)=-(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*(zz+1.D0)*(zz+2.D0)*(zz+3.D0)/36.D0 + poidz(1)=(zz-3.D0)*(zz-2.D0)*zz*(zz+1.D0)*(zz+2.D0)*(zz+3.D0)/48.D0 + poidz(2)=-(zz-3.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)*(zz+3.D0)/120.D0 + poidz(3)=(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)*(zz+3.D0)/720.D0 + poidz(4)=0.D0 + else + poidz(-3)=0.D0 + poidz(-2)=(zz-4.D0)*(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)/720.D0 + poidz(-1)=-(zz-4.D0)*(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+2.D0)/120.D0 + poidz(0)=(zz-4.D0)*(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*(zz+1.D0)*(zz+2.D0)/48.D0 + poidz(1)=-(zz-4.D0)*(zz-3.D0)*(zz-2.D0)*zz*(zz+1.D0)*(zz+2.D0)/36.D0 + poidz(2)=(zz-4.D0)*(zz-3.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)/48.D0 + poidz(3)=-(zz-4.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)/120.D0 + poidz(4)=(zz-3.D0)*(zz-2.D0)*(zz-1.D0)*zz*(zz+1.D0)*(zz+2.D0)/720.D0 + end if + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do e=-3,4 + do d=-3,4 + do c=-3,4 + remaille(ip(c)+1,jp(d)+1,kp(e)+1)=remaille(ip(c)+1,jp(d)+1,kp(e)+1)+donne(i)*poidx(c)*poidy(d)*poidz(e) + end do + end do + end do + end do + + end subroutine remaill_l6 + + subroutine remaill_l6_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + + remaille=0.D0 + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posx(i) - real(ip(0),kind=8)*dx-xg)/dx !relatif + + + + + !conditions au bord + !------------------ + !periodique: + do c=-3,4 + ip(c)=mod(ip(c)+nx,nx) + end do + + + + !calcul des poids + !---------------- + if (xx<=0.5D0) then + poidx(-3)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + poidx(-2)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+3.D0)/120.D0 + poidx(-1)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(0)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/36.D0 + poidx(1)=(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(2)=-(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/120.D0 + poidx(3)=(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/720.D0 + poidx(4)=0.D0 + else + poidx(-3)=0.D0 + poidx(-2)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)/720.D0 + poidx(-1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)/120.D0 + poidx(0)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)/36.D0 + poidx(2)=(xx-4.D0)*(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(3)=-(xx-4.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/120.D0 + poidx(4)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,4 + remaille(ip(c)+1,jvar,kvar)=remaille(ip(c)+1,jvar,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_x + + + + subroutine remaill_l6_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + + remaille=0.D0 + + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + kvar=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + + xx = (posy(i) - real(ip(0),kind=8)*dy-yb)/dy !relatif + + + + + !conditions au bord + !------------------ + + + do c=-3,4 + ip(c)=mod(ip(c)+ny,ny) + end do + + + + + !calcul des poids + !---------------- + if (xx<=0.5D0) then + poidx(-3)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + poidx(-2)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+3.D0)/120.D0 + poidx(-1)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(0)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/36.D0 + poidx(1)=(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(2)=-(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/120.D0 + poidx(3)=(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/720.D0 + poidx(4)=0.D0 + else + poidx(-3)=0.D0 + poidx(-2)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)/720.D0 + poidx(-1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)/120.D0 + poidx(0)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)/36.D0 + poidx(2)=(xx-4.D0)*(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(3)=-(xx-4.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/120.D0 + poidx(4)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-3,4 + remaille(ivar,ip(c)+1,kvar)=remaille(ivar,ip(c)+1,kvar)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_y + + subroutine remaill_l6_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(1:npart),intent(in) :: donne + real(kind=8),dimension(1:npart),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,e,ib,jb,kb,ivar,jvar,kvar + integer,dimension(-3:4) :: ip + real(kind=8),dimension(-3:4) :: poidx + real(kind=8) :: xx + + remaille=0.D0 + + + do i=1,npart + + jvar=nint((posy(i)-yb)/dy)+1 + ivar=nint((posx(i)-xg)/dx)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-1) = ip(0) - 1 + ip(-2) = ip(0) - 2 + ip(-3) = ip(0) - 3 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + ip(4) = ip(0) + 4 + + + + + + + !distance de la particule à remailler au second point (des quatres utilisés pour le remaillage) + !---------------------------------------------------- + xx = (posz(i) - real(ip(0),kind=8)*dz-zd)/dz !relatif + + + + !conditions au bord + !------------------ + !periodique: + + do c=-3,4 + ip(c)=mod(ip(c)+nz,nz) + end do + + + !calcul des poids + !---------------- + if (xx<=0.5D0) then + poidx(-3)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + poidx(-2)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+3.D0)/120.D0 + poidx(-1)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(0)=-(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/36.D0 + poidx(1)=(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/48.D0 + poidx(2)=-(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/120.D0 + poidx(3)=(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/720.D0 + poidx(4)=0.D0 + else + poidx(-3)=0.D0 + poidx(-2)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)/720.D0 + poidx(-1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+2.D0)/120.D0 + poidx(0)=(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(1)=-(xx-4.D0)*(xx-3.D0)*(xx-2.D0)*xx*(xx+1.D0)*(xx+2.D0)/36.D0 + poidx(2)=(xx-4.D0)*(xx-3.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/48.D0 + poidx(3)=-(xx-4.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/120.D0 + poidx(4)=(xx-3.D0)*(xx-2.D0)*(xx-1.D0)*xx*(xx+1.D0)*(xx+2.D0)/720.D0 + end if + + + + + + !remaillage à l' interrieur domaine + !--------------------------------- + + do c=-3,4 + remaille(ivar,jvar,ip(c)+1)=remaille(ivar,jvar,ip(c)+1)+donne(i)*poidx(c) + end do + + end do + + end subroutine remaill_l6_z + + + + + subroutine remaill_l2_bloc_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,k,per + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0.D0 + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0.D0 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + else + poids(0)=0.5D0*(1.D0-xx)*(2.D0-xx) + end if + case(1) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + case(2) + poids(0)=1.D0-0.5D0*xx*(1.D0+xx) + case(3) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx + case(4) + poids(-2)=0.5D0*xx*(1.D0+xx) + poids(-1)=-xx + poids(0)=1.D0-xx**2 + case(5) + poids(-1)=-0.5D0*xx+0.5D0*xx**2 + poids(0)=1.D0-poids(-1) + + end select + + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + poids(1)=0.5D0*xx*(1.D0+xx) + else + poids(1)=2.D0*xx-xx**2 + poids(2)=0.5D0*(xx-1.D0)*xx + end if + case(1) + poids(1)=0.5D0*xx*(1.D0+xx) + case(2) + poids(1)=xx + poids(2)=0.5D0*xx*(xx-1.D0) + case(3) + poids(1)=3.D0*0.5D0*xx-0.5D0*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_x + + + subroutine remaill_l2_bloc_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0.D0 + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0.D0 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + else + poids(0)=0.5D0*(1.D0-xx)*(2.D0-xx) + end if + case(1) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + case(2) + poids(0)=1.D0-0.5D0*xx*(1.D0+xx) + case(3) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx + case(4) + poids(-2)=0.5D0*xx*(1.D0+xx) + poids(-1)=-xx + poids(0)=1.D0-xx**2 + case(5) + poids(-1)=-0.5D0*xx+0.5D0*xx**2 + poids(0)=1.D0-poids(-1) + + end select + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + poids(1)=0.5D0*xx*(1.D0+xx) + else + poids(1)=2.D0*xx-xx**2 + poids(2)=0.5D0*(xx-1.D0)*xx + end if + case(1) + poids(1)=0.5D0*xx*(1.D0+xx) + case(2) + poids(1)=xx + poids(2)=0.5D0*xx*(xx-1.D0) + case(3) + poids(1)=3.D0*0.5D0*xx-0.5D0*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_y + + subroutine remaill_l2_bloc_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-2:2) :: ip + real(kind=8),dimension(-2:2) :: poids + real(kind=8) :: xx,tmp_pos + + remaille=0.D0 + + do i=1,npart + + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + poids=0.D0 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + !periodique: + do c=-2,2 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poids + !---------------- + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + else + poids(0)=0.5D0*(1.D0-xx)*(2.D0-xx) + end if + case(1) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx**2 + case(2) + poids(0)=1.D0-0.5D0*xx*(1.D0+xx) + case(3) + poids(-1)=0.5D0*xx*(xx-1.D0) + poids(0)=1.D0-xx + case(4) + poids(-2)=0.5D0*xx*(1.D0+xx) + poids(-1)=-xx + poids(0)=1.D0-xx**2 + case(5) + poids(-1)=-0.5D0*xx+0.5D0*xx**2 + poids(0)=1.D0-poids(-1) + + end select + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + poids(1)=0.5D0*xx*(1.D0+xx) + else + poids(1)=2.D0*xx-xx**2 + poids(2)=0.5D0*(xx-1.D0)*xx + end if + case(1) + poids(1)=0.5D0*xx*(1.D0+xx) + case(2) + poids(1)=xx + poids(2)=0.5D0*xx*(xx-1.D0) + case(3) + poids(1)=3.D0*0.5D0*xx-0.5D0*xx**2 + case(4) + + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-2,2 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l2_bloc_z + + + subroutine remaill_l4_bloc_x (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,j,per,k + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0.D0 + + + do i=1,npart + + j=nint((posy(i)-yb)/dy)+1 + k=nint((posz(i)-zd)/dz)+1 + poids=0.D0 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posx(i)-xg)/dx) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posx(i) - real(ip(0) ,kind=8)*dx-xg)/dx + + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+nx,nx) + end do + + !calcul des poids + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + else + t1=(xx-1.D0)*(xx-2.D0)*(xx-3.D0) + poids(-1)=t1*xx/24.D0 + poids(0)=-t1*(xx+1.D0)/6.D0 + end if + case(1) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + + case(2) + t1=(xx-1.D0)*(xx-2.D0)/12.D0 + poids(-1)=t1*xx*(xx-3)/2.D0 + poids(0)=t1*(xx+6.D0)*(xx+1.D0) + case(3) + t1=0.5D0*(xx-1.D0)*(xx-2.D0) + poids(-2)=t1*xx/12.D0*(xx+1.D0) + poids(-1)=-t1*xx/3.D0*(xx+2.D0) + poids(0)=t1*(xx+1.D0) + case(4) + t2=(xx**2-1.D0) + t1=xx*(xx+2.D0)*0.5D0 + poids(-3)=t2*t1/12.D0 + poids(-2)=-t2*xx/6.D0*(xx+3.D0) + poids(-1)=t1*(xx-1.D0) + poids(0)=t2*(xx**2-4.D0)/4.D0 + case(5) + t1=(xx-2.D0)*(xx-1.D0)/4.D0 + poids(-1)=-t1*xx/6.D0*(3*xx+7.D0) + poids(0)=t1*(xx+2.D0)*(xx+1.D0) + case(6) + t1= (xx-1.D0)*(xx-2.D0)/6.D0 + t2=t1*(xx+1.D0) + poids(-2)=t2*xx/4.D0 + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.D0) + case(7) + t1=(xx-1.D0)*(xx+2.D0) + t2=xx*(xx+1)/6.D0 + poids(-3)=t1*t2/4.D0 + poids(-2)=-t2*(xx-1.D0) + poids(-1)=-xx*t1/6.D0*(xx-2.D0) + poids(0)=t1*(xx-2.D0)/4.D0*(xx+1.D0) + case(8) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=(xx-6.D0)*(xx+2.D0)*(xx**2-1.D0)/12.D0 + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + else + t1=xx*(xx+1.D0)*(xx-3.D0) + poids(1)=t1*(xx-2.D0)/4.D0 + poids(2)=-t1*(xx-1.D0)/6.D0 + poids(3)=xx*(xx-2.D0)*(xx**2-1.D0)/24.D0 + end if + case(1) + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + case(2) + t1=xx*(xx+1.D0)*0.5D0 + t2=t1*(xx-1.D0) + poids(1)=-t1*(xx-2.D0) + poids(2)=-t2/3.D0*(xx-3.D0) + poids(3)=t2*(xx-2.D0)/12.D0 + case(3) + t1=xx*(xx+1.D0)/12.D0 + poids(1)=t1*(xx-2.D0)*(xx-7.D0) + poids(2)=t1*(xx+2.D0)*(xx-1.D0)/2.D0 + case(4) + t1=xx*(xx+1.D0) + t2=t1*(xx-1.D0)/6.D0 + poids(1)=-t1*(xx+2.D0)*(xx-2.D0)/6.D0 + poids(2)=t2 + poids(3)=t2*(xx-2.D0)/4.D0 + case(5) + poids(1)=-xx/24.D0*(3.D0*xx-7.D0)*(xx+2.D0)*(xx+1.D0) + case(6) + t1=xx*(xx+1.D0)/4.D0 + poids(1)=t1*(xx-3.D0)*(xx-2.D0) + poids(2)=-t1*(3.D0*xx-10.D0)*(xx-1.D0)/6.D0 + case(7) + poids(1)=xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/24.D0 + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ip(c)+1,j,k)=remaille(ip(c)+1,j,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_x + + + subroutine remaill_l4_bloc_y (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,k + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0.D0 + + do i=1,npart + + poids=0.D0 + ivar=nint((posx(i)-xg)/dx)+1 + k=nint((posz(i)-zd)/dz)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posy(i)-yb)/dy) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posy(i) - real(ip(0) ,kind=8)*dy-yb)/dy + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+ny,ny) + end do + + !calcul des poidss + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + else + t1=(xx-1.D0)*(xx-2.D0)*(xx-3.D0) + poids(-1)=t1*xx/24.D0 + poids(0)=-t1*(xx+1.D0)/6.D0 + end if + case(1) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + + case(2) + t1=(xx-1.D0)*(xx-2.D0)/12.D0 + poids(-1)=t1*xx*(xx-3)/2.D0 + poids(0)=t1*(xx+6.D0)*(xx+1.D0) + case(3) + t1=0.5D0*(xx-1.D0)*(xx-2.D0) + poids(-2)=t1*xx/12.D0*(xx+1.D0) + poids(-1)=-t1*xx/3.D0*(xx+2.D0) + poids(0)=t1*(xx+1.D0) + case(4) + t2=(xx**2-1.D0) + t1=xx*(xx+2.D0)*0.5D0 + poids(-3)=t2*t1/12.D0 + poids(-2)=-t2*xx/6.D0*(xx+3.D0) + poids(-1)=t1*(xx-1.D0) + poids(0)=t2*(xx**2-4.D0)/4.D0 + case(5) + t1=(xx-2.D0)*(xx-1.D0)/4.D0 + poids(-1)=-t1*xx/6.D0*(3*xx+7.D0) + poids(0)=t1*(xx+2.D0)*(xx+1.D0) + case(6) + t1= (xx-1.D0)*(xx-2.D0)/6.D0 + t2=t1*(xx+1.D0) + poids(-2)=t2*xx/4.D0 + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.D0) + case(7) + t1=(xx-1.D0)*(xx+2.D0) + t2=xx*(xx+1)/6.D0 + poids(-3)=t1*t2/4.D0 + poids(-2)=-t2*(xx-1.D0) + poids(-1)=-xx*t1/6.D0*(xx-2.D0) + poids(0)=t1*(xx-2.D0)/4.D0*(xx+1.D0) + case(8) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=(xx-6.D0)*(xx+2.D0)*(xx**2-1.D0)/12.D0 + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + else + t1=xx*(xx+1.D0)*(xx-3.D0) + poids(1)=t1*(xx-2.D0)/4.D0 + poids(2)=-t1*(xx-1.D0)/6.D0 + poids(3)=xx*(xx-2.D0)*(xx**2-1.D0)/24.D0 + end if + case(1) + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + case(2) + t1=xx*(xx+1.D0)*0.5D0 + t2=t1*(xx-1.D0) + poids(1)=-t1*(xx-2.D0) + poids(2)=-t2/3.D0*(xx-3.D0) + poids(3)=t2*(xx-2.D0)/12.D0 + case(3) + t1=xx*(xx+1.D0)/12.D0 + poids(1)=t1*(xx-2.D0)*(xx-7.D0) + poids(2)=t1*(xx+2.D0)*(xx-1.D0)/2.D0 + case(4) + t1=xx*(xx+1.D0) + t2=t1*(xx-1.D0)/6.D0 + poids(1)=-t1*(xx+2.D0)*(xx-2.D0)/6.D0 + poids(2)=t2 + poids(3)=t2*(xx-2.D0)/4.D0 + case(5) + poids(1)=-xx/24.D0*(3.D0*xx-7.D0)*(xx+2.D0)*(xx+1.D0) + case(6) + t1=xx*(xx+1.D0)/4.D0 + poids(1)=t1*(xx-3.D0)*(xx-2.D0) + poids(2)=-t1*(3.D0*xx-10.D0)*(xx-1.D0)/6.D0 + case(7) + poids(1)=xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/24.D0 + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ivar,ip(c)+1,k)=remaille(ivar,ip(c)+1,k)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_y + + + subroutine remaill_l4_bloc_z (donne,posx,posy,posz,remaille) + implicit none + real(kind=8),dimension(:),intent(in) :: donne + real(kind=8),dimension(:),intent(in) :: posx,posy,posz + real(kind=8),dimension(1:nx,1:ny,1:nz),intent(out) :: remaille + integer :: i,c,d,ib,ivar,per,j + integer,dimension(-3:3) :: ip + real(kind=8),dimension(-3:3) :: poids + real(kind=8) :: xx,tmp_pos,t1,t2,t3 + + remaille=0.D0 + + do i=1,npart + + poids=0.D0 + ivar=nint((posx(i)-xg)/dx)+1 + j=nint((posy(i)-yb)/dy)+1 + + !numero des points sur le maillage + !-------------------------------- + ip(0) = floor((posz(i)-zd)/dz) + ip(-3) = ip(0) - 3 + ip(-2) = ip(0) - 2 + ip(-1) = ip(0) - 1 + ip(1) = ip(0) + 1 + ip(2) = ip(0) + 2 + ip(3) = ip(0) + 3 + + + + !distance de la particule à remailler au point de grille de gauche + !----------------------------------------------------------------- + xx = (posz(i) - real(ip(0) ,kind=8)*dz-zd)/dz + + !conditions au bord + !------------------ + do c=-3,3 + ip(c)=mod(ip(c)+nz,nz) + end do + + !calcul des poidss + !---------------- + + + select case (blocg(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + else + t1=(xx-1.D0)*(xx-2.D0)*(xx-3.D0) + poids(-1)=t1*xx/24.D0 + poids(0)=-t1*(xx+1.D0)/6.D0 + end if + case(1) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=t2/4.D0*(xx**2-1.D0) + + case(2) + t1=(xx-1.D0)*(xx-2.D0)/12.D0 + poids(-1)=t1*xx*(xx-3)/2.D0 + poids(0)=t1*(xx+6.D0)*(xx+1.D0) + case(3) + t1=0.5D0*(xx-1.D0)*(xx-2.D0) + poids(-2)=t1*xx/12.D0*(xx+1.D0) + poids(-1)=-t1*xx/3.D0*(xx+2.D0) + poids(0)=t1*(xx+1.D0) + case(4) + t2=(xx**2-1.D0) + t1=xx*(xx+2.D0)*0.5D0 + poids(-3)=t2*t1/12.D0 + poids(-2)=-t2*xx/6.D0*(xx+3.D0) + poids(-1)=t1*(xx-1.D0) + poids(0)=t2*(xx**2-4.D0)/4.D0 + case(5) + t1=(xx-2.D0)*(xx-1.D0)/4.D0 + poids(-1)=-t1*xx/6.D0*(3*xx+7.D0) + poids(0)=t1*(xx+2.D0)*(xx+1.D0) + case(6) + t1= (xx-1.D0)*(xx-2.D0)/6.D0 + t2=t1*(xx+1.D0) + poids(-2)=t2*xx/4.D0 + poids(-1)=-t1*xx + poids(0)=-t2*(xx-3.D0) + case(7) + t1=(xx-1.D0)*(xx+2.D0) + t2=xx*(xx+1)/6.D0 + poids(-3)=t1*t2/4.D0 + poids(-2)=-t2*(xx-1.D0) + poids(-1)=-xx*t1/6.D0*(xx-2.D0) + poids(0)=t1*(xx-2.D0)/4.D0*(xx+1.D0) + case(8) + t1=xx*(xx-1.D0) + t2=xx**2-4.D0 + poids(-2)=t1/24.D0*(xx-2.D0)*(xx+1.D0) + poids(-1)=-t1/6.D0*t2 + poids(0)=(xx-6.D0)*(xx+2.D0)*(xx**2-1.D0)/12.D0 + end select + + + + + + select case (blocd(i)) + + case(0) + if (xx<=0.5D0) then + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + else + t1=xx*(xx+1.D0)*(xx-3.D0) + poids(1)=t1*(xx-2.D0)/4.D0 + poids(2)=-t1*(xx-1.D0)/6.D0 + poids(3)=xx*(xx-2.D0)*(xx**2-1.D0)/24.D0 + end if + case(1) + t1=xx*(xx+1.D0)*(xx+2.D0) + poids(1)=-t1*(xx-2.D0)/6.D0 + poids(2)=t1*(xx-1.D0)/24.D0 + case(2) + t1=xx*(xx+1.D0)*0.5D0 + t2=t1*(xx-1.D0) + poids(1)=-t1*(xx-2.D0) + poids(2)=-t2/3.D0*(xx-3.D0) + poids(3)=t2*(xx-2.D0)/12.D0 + case(3) + t1=xx*(xx+1.D0)/12.D0 + poids(1)=t1*(xx-2.D0)*(xx-7.D0) + poids(2)=t1*(xx+2.D0)*(xx-1.D0)/2.D0 + case(4) + t1=xx*(xx+1.D0) + t2=t1*(xx-1.D0)/6.D0 + poids(1)=-t1*(xx+2.D0)*(xx-2.D0)/6.D0 + poids(2)=t2 + poids(3)=t2*(xx-2.D0)/4.D0 + case(5) + poids(1)=-xx/24.D0*(3.D0*xx-7.D0)*(xx+2.D0)*(xx+1.D0) + case(6) + t1=xx*(xx+1.D0)/4.D0 + poids(1)=t1*(xx-3.D0)*(xx-2.D0) + poids(2)=-t1*(3.D0*xx-10.D0)*(xx-1.D0)/6.D0 + case(7) + poids(1)=xx*(xx+1.D0)*(xx+2.D0)*(xx+3.D0)/24.D0 + end select + + + !remaillage à l' interrieur domaine + !--------------------------------- + do c=-3,3 + remaille(ivar,j,ip(c)+1)=remaille(ivar,j,ip(c)+1)+donne(i)*poids(c) + end do + + + end do + + end subroutine remaill_l4_bloc_z + + + + + + + + +end module remaillage_mod + + diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/resultats_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/resultats_mod.f90 new file mode 100644 index 000000000..464458af0 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/resultats_mod.f90 @@ -0,0 +1,300 @@ +module resultats_mod + use donnees_mod + use tab_mod +contains + + + + + + subroutine res_vtk (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A8)')"" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A15)') "VECTORS omg FLOAT" + write(11,'(A20)') "LOOKUP_TABLE DEFAULT" + + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(f20.9)') real(omgx(i,j,k)),real(omgy(i,j,k)),real(omgz(i,j,k)) + end do + end do + end do + + write(11,'(A21)') "" + write(11,'(A21)') "VECTORS vitesse FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j,k)),real(vyg(i,j,k)),real(vzg(i,j,k)) + end do + end do + end do + + close (11) + + end subroutine res_vtk + + + subroutine res_vtk_test (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A21)') "VECTORS vg FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j,k)),real(vyg(i,j,k)),real(vzg(i,j,k)) + end do + end do + end do + + write(11,'(A21)') "VECTORS omg FLOAT" + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(sqrt(omgx(i,j,k)**2+omgy(i,j,k)**2+omgz(i,j,k)**2)),real(omgy(i,j,k)),real(omgz(i,j,k)) + end do + end do + end do + + close (11) + end subroutine res_vtk_test + + + subroutine res_vtk_omgx (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(24,file=nom_fich) + WRITE(24,'(A)') "# vtk DataFile Version 3.0" + WRITE(24,'(A)') "Scalar" + WRITE(24,'(A)') "ASCII" + WRITE(24,'(A)') "DATASET STRUCTURED_POINTS" + WRITE(24,'(A,I3,A,I3,A,I3)') "DIMENSIONS ",nx," ",ny," ",nz + WRITE(24,'(A,A,A,A)') "ORIGIN"," 0"," 0 "," 0" + WRITE(24,*) "SPACING"," ",dx," ",dy," ",dz + WRITE(24,*) "POINT_DATA ",nx*ny*nz + WRITE(24,'(A)') "SCALARS omgx float" + WRITE(24,'(A)') "LOOKUP_TABLE DEFAULT" + do k=1,nz + do j=1,ny + do i=1,nx + write(24,*) real(omgx(i,j,k)) + enddo + enddo + enddo + close(24) +end subroutine res_vtk_omgx + + + subroutine res_vtk_nite(nom_fich_omg,nom_fich_vit,nombre_ite,t) + implicit none + character(len=*),intent(in) :: nom_fich_omg,nom_fich_vit + integer,intent(in) :: nombre_ite + real(kind=8),intent(in) :: t + character(len=60) :: name_vit,name_omg,char_nite + + if (cpt_ite<=20) then + write(char_nite,'(I1)') cpt_ite + write(name_vit,'(A)') trim(nom_fich_vit)//trim(char_nite)//".vtk" + write(name_omg,'(A)') trim(nom_fich_omg)//trim(char_nite)//".vtk" + call res_vtk_vit(trim(name_vit)) + call res_vtk_omega(trim(name_omg)) + elseif (mod(cpt_ite,40)==0) then +! if (mod(cpt_ite,nombre_ite)==0) then +! if (cpt_ite<10) write(char_nite,'(I1)') cpt_ite + if ((cpt_ite>9).and.(cpt_ite<100)) write(char_nite,'(I2)') cpt_ite + if ((cpt_ite>99).and.(cpt_ite<1000)) write(char_nite,'(I3)') cpt_ite + if ((cpt_ite>999).and.(cpt_ite<10000)) write(char_nite,'(I4)') cpt_ite + if ((cpt_ite>9999).and.(cpt_ite<100000)) write(char_nite,'(I5)') cpt_ite + if ((cpt_ite>99999).and.(cpt_ite<1000000)) write(char_nite,'(I6)') cpt_ite + if ((cpt_ite>999999).and.(cpt_ite<10000000)) write(char_nite,'(I7)') cpt_ite + write(name_vit,'(A)') trim(nom_fich_vit)//trim(char_nite)//".vtk" + write(name_omg,'(A)') trim(nom_fich_omg)//trim(char_nite)//".vtk" + call res_vtk_vit(trim(name_vit)) + call res_vtk_omega(trim(name_omg)) + end if + + end subroutine res_vtk_nite + + subroutine res_omg_nite(nom_fich_omg,nom_fich_vit,nombre_ite,t) + implicit none + character(len=*),intent(in) :: nom_fich_omg,nom_fich_vit + integer,intent(in) :: nombre_ite + real(kind=8),intent(in) :: t + character(len=60) :: name_vit,name_omg,char_nite + + if (mod(cpt_ite,nombre_ite)==0) then + if (cpt_ite<10) write(char_nite,'(I1)') cpt_ite + if ((cpt_ite>9).and.(cpt_ite<100)) write(char_nite,'(I2)') cpt_ite + if ((cpt_ite>99).and.(cpt_ite<1000)) write(char_nite,'(I3)') cpt_ite + if ((cpt_ite>999).and.(cpt_ite<10000)) write(char_nite,'(I4)') cpt_ite + if ((cpt_ite>9999).and.(cpt_ite<100000)) write(char_nite,'(I5)') cpt_ite + if ((cpt_ite>99999).and.(cpt_ite<1000000)) write(char_nite,'(I6)') cpt_ite + if ((cpt_ite>999999).and.(cpt_ite<10000000)) write(char_nite,'(I7)') cpt_ite + write(name_vit,'(A)') trim(nom_fich_vit)//trim(char_nite)//".vtk" + write(name_omg,'(A)') trim(nom_fich_omg)//trim(char_nite)//".vtk" + call res_vtk_omega(trim(name_omg)) + end if + + end subroutine res_omg_nite + + subroutine res_vtk_vit (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A21)') "VECTORS vg FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(vxg(i,j,k)),real(vyg(i,j,k)),real(vzg(i,j,k)) + end do + end do + end do + close (11) + end subroutine res_vtk_vit + + subroutine res_vtk_omega (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A21)') "VECTORS omg FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(omgx(i,j,k)),real(omgy(i,j,k)),real(omgz(i,j,k)) + end do + end do + end do + close (11) + end subroutine res_vtk_omega + + subroutine res_vtk_chi (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A21)') "VECTORS chi FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(chi(i,j,k)),real(chi(i,j,k)),real(chi(i,j,k)) + end do + end do + end do + close (11) + end subroutine res_vtk_chi + + subroutine res_vtk_lambda (nom_fich) + implicit none + character(len=*),intent(in) :: nom_fich + integer :: i,j,k + real(kind=8) :: x,y,z + + open(unit=11,file=nom_fich,form="formatted") + + write(11,'(A26)')"# vtk DataFile Version 3.0" + write(11,'(A7)')"vecteur" + write(11,'(A5)')"ASCII" + write(11,'(A25)')"DATASET STRUCTURED_POINTS" + write(11,'(A10,3(i4,1x))')"DIMENSIONS",nx,ny,nz + write(11,'(a6,3(f10.5))')"ORIGIN",xg,yb,zd + write(11,'(A7,3(f10.5))')"SPACING",dx,dy,dz + + + write(11,'(A10,i10)') "POINT_DATA",nx*ny*nz + write(11,'(A21)') "VECTORS lambda FLOAT" + + do k=1,nz + do j=1,ny + do i=1,nx + write(11,'(3(f20.9))') real(lambda(i,j,k)),real(lambda(i,j,k)),real(lambda(i,j,k)) + end do + end do + end do + close (11) + end subroutine res_vtk_lambda + + + + +end module resultats_mod + diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/rlft2.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/rlft2.f90 new file mode 100644 index 000000000..9f828ce33 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/rlft2.f90 @@ -0,0 +1,52 @@ + SUBROUTINE rlft2(data,spec,speq,isign) + USE nrtype; USE nrutil, ONLY : assert,assert_eq + USE nr, ONLY : four2 + REAL(SP), DIMENSION(:,:), INTENT(INOUT) :: data + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: spec + COMPLEX(SPC), DIMENSION(:), INTENT(INOUT) :: speq + INTEGER(I4B), INTENT(IN) :: isign + INTEGER :: i1,j1,nn1,nn2 + REAL(DP) :: theta + COMPLEX(SPC) :: c1=(0.5_sp,0.0_sp),c2,h1,h2,w + COMPLEX(SPC), DIMENSION(size(data,2)-1) :: h1a,h2a + COMPLEX(DPC) :: ww,wp + nn1=assert_eq(size(data,1),2*size(spec,1),'rlft2: nn1') + nn2=assert_eq(size(data,2),size(spec,2),size(speq),'rlft2: nn2') + call assert(iand((/nn1,nn2/),(/nn1,nn2/)-1)==0, & + 'dimensions must be powers of 2 in rlft2') + c2=cmplx(0.0_sp,-0.5_sp*isign,kind=spc) + theta=TWOPI_D/(isign*nn1) + wp=cmplx(-2.0_dp*sin(0.5_dp*theta)**2,sin(theta),kind=spc) + if (isign == 1) then + spec(:,:)=cmplx(data(1:nn1:2,:),data(2:nn1:2,:),kind=spc) + call four2(spec,isign) + speq=spec(1,:) + end if + h1=c1*(spec(1,1)+conjg(speq(1))) + h1a=c1*(spec(1,2:nn2)+conjg(speq(nn2:2:-1))) + h2=c2*(spec(1,1)-conjg(speq(1))) + h2a=c2*(spec(1,2:nn2)-conjg(speq(nn2:2:-1))) + spec(1,1)=h1+h2 + spec(1,2:nn2)=h1a+h2a + speq(1)=conjg(h1-h2) + speq(nn2:2:-1)=conjg(h1a-h2a) + ww=cmplx(1.0_dp,0.0_dp,kind=dpc) + do i1=2,nn1/4+1 + j1=nn1/2-i1+2 + ww=ww*wp+ww + w=ww + h1=c1*(spec(i1,1)+conjg(spec(j1,1))) + h1a=c1*(spec(i1,2:nn2)+conjg(spec(j1,nn2:2:-1))) + h2=c2*(spec(i1,1)-conjg(spec(j1,1))) + h2a=c2*(spec(i1,2:nn2)-conjg(spec(j1,nn2:2:-1))) + spec(i1,1)=h1+w*h2 + spec(i1,2:nn2)=h1a+w*h2a + spec(j1,1)=conjg(h1-w*h2) + spec(j1,nn2:2:-1)=conjg(h1a-w*h2a) + end do + if (isign == -1) then + call four2(spec,isign) + data(1:nn1:2,:)=real(spec) + data(2:nn1:2,:)=aimag(spec) + end if + END SUBROUTINE rlft2 diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/rlft3.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/rlft3.f90 new file mode 100644 index 000000000..e0e0e5647 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/rlft3.f90 @@ -0,0 +1,70 @@ + SUBROUTINE rlft3(data,spec,speq,isign) + USE nrtype; USE nrutil, ONLY : assert,assert_eq + USE nr, ONLY : four3 + REAL(SP), DIMENSION(:,:,:), INTENT(INOUT) :: data + COMPLEX(SPC), DIMENSION(:,:,:), INTENT(INOUT) :: spec + COMPLEX(SPC), DIMENSION(:,:), INTENT(INOUT) :: speq + INTEGER(I4B), INTENT(IN) :: isign + INTEGER :: i1,i3,j1,j3,nn1,nn2,nn3 + REAL(DP) :: theta + COMPLEX(SPC) :: c1=(0.5_sp,0.0_sp),c2,h1,h2,w + COMPLEX(SPC), DIMENSION(size(data,2)-1) :: h1a,h2a + COMPLEX(DPC) :: ww,wp + +!!$Given a three-dimensional real array data(1:L,1:M,1:N), this routine returns (for +!!$isign=1) the complex Fourier transform as two complex arrays: On output, the zero and +!!$positive frequency values of the first frequency component are in spec(1:L/2,1:M,1:N), +!!$while speq(1:M,1:N) contains the Nyquist critical frequency values of the first frequency +!!$component. The second and third frequency components are stored for zero, positive, and +!!$negative frequencies, in standard wrap-around order. For isign=-1, the inverse transform +!!$(times L à M à N/2 as a constant multiplicative factor) is performed, with output data +!!$deriving from input spec and speq. For inverse transforms on data not generated first by a +!!$forward transform, make sure the complex input data array satisfies property (12.5.2). The +!!$size of all arrays must always be integer powers of 2. + + + c2=cmplx(0.0_sp,-0.5_sp*isign,kind=spc) + nn1=assert_eq(size(data,1),2*size(spec,1),'rlft2: nn1') + nn2=assert_eq(size(data,2),size(spec,2),size(speq,1),'rlft2: nn2') + nn3=assert_eq(size(data,3),size(spec,3),size(speq,2),'rlft2: nn3') + call assert(iand((/nn1,nn2,nn3/),(/nn1,nn2,nn3/)-1)==0, & + 'dimensions must be powers of 2 in rlft3') + theta=TWOPI_D/(isign*nn1) + wp=cmplx(-2.0_dp*sin(0.5_dp*theta)**2,sin(theta),kind=dpc) + if (isign == 1) then + spec(:,:,:)=cmplx(data(1:nn1:2,:,:),data(2:nn1:2,:,:),kind=spc) + call four3(spec,isign) + speq=spec(1,:,:) + end if + do i3=1,nn3 + j3=1 + if (i3 /= 1) j3=nn3-i3+2 + h1=c1*(spec(1,1,i3)+conjg(speq(1,j3))) + h1a=c1*(spec(1,2:nn2,i3)+conjg(speq(nn2:2:-1,j3))) + h2=c2*(spec(1,1,i3)-conjg(speq(1,j3))) + h2a=c2*(spec(1,2:nn2,i3)-conjg(speq(nn2:2:-1,j3))) + spec(1,1,i3)=h1+h2 + spec(1,2:nn2,i3)=h1a+h2a + speq(1,j3)=conjg(h1-h2) + speq(nn2:2:-1,j3)=conjg(h1a-h2a) + ww=cmplx(1.0_dp,0.0_dp,kind=dpc) + do i1=2,nn1/4+1 + j1=nn1/2-i1+2 + ww=ww*wp+ww + w=ww + h1=c1*(spec(i1,1,i3)+conjg(spec(j1,1,j3))) + h1a=c1*(spec(i1,2:nn2,i3)+conjg(spec(j1,nn2:2:-1,j3))) + h2=c2*(spec(i1,1,i3)-conjg(spec(j1,1,j3))) + h2a=c2*(spec(i1,2:nn2,i3)-conjg(spec(j1,nn2:2:-1,j3))) + spec(i1,1,i3)=h1+w*h2 + spec(i1,2:nn2,i3)=h1a+w*h2a + spec(j1,1,j3)=conjg(h1-w*h2) + spec(j1,nn2:2:-1,j3)=conjg(h1a-w*h2a) + end do + end do + if (isign == -1) then + call four3(spec,isign) + data(1:nn1:2,:,:)=real(spec) + data(2:nn1:2,:,:)=aimag(spec) + end if + END SUBROUTINE rlft3 diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/source_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/source_mod.f90 new file mode 100644 index 000000000..c7ac16aca --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/source_mod.f90 @@ -0,0 +1,521 @@ +module source_mod + use donnees_mod + use tab_mod + +contains + + !resolution du terme source : + !div(u:omega)+Delta(omega)/Re+rot(v*exp(-lambda*chi*dt)) + !par DF d'ordre4 decentre sur les bords + + subroutine source_split_1 + implicit none + integer :: i + real(kind=8),dimension(1:3) :: ts,tsa + + !ordre2 + !------ + do i=1,npart + !qp(i)=qp(i)+0.5D0*dt*tsource(time,xp(i),yp(i),zp(i)) + + ts=strech( nint((xp(i)-xg)/dx+1),nint((yp(i)-yb)/dy+1),nint((zp(i)-zd)/dz+1) )& + +nu*diffusion( nint((xp(i)-xg)/dx+1),nint((yp(i)-yb)/dy+1),nint((zp(i)-zd)/dz+1) )& + +penal( nint((xp(i)-xg)/dx+1),nint((yp(i)-yb)/dy+1),nint((zp(i)-zd)/dz+1) ) + + !call source_anal(tsa, xp(i),yp(i),zp(i) ) + + !omx(i)=omx(i)+0.5D0*dt*(ts(1)+tsa(1)) + !omy(i)=omy(i)+0.5D0*dt*(ts(2)+tsa(2)) + !omz(i)=omz(i)+0.5D0*dt*(ts(3)+tsa(3)) + + omx(i)=omx(i)+0.5*dt*ts(1) + omy(i)=omy(i)+0.5*dt*ts(2) + omz(i)=omz(i)+0.5*dt*ts(3) + + end do + + end subroutine source_split_1 + + subroutine source_split_2 + implicit none + integer :: i,j,k + real(kind=8) :: x,y,z + real(kind=8),dimension(1:3) :: ts,tsa + real(kind=8),dimension(:,:,:),pointer :: omgx_tmp,omgy_tmp,omgz_tmp + + real(kind=8) :: cx,c2x,cy,c2y,cz,c2z,sx,s2x,sy,s2y,sz,s2z,ct,st,c2t,s2t + + allocate(omgx_tmp(1:nx,1:ny,1:nz),omgy_tmp(1:nx,1:ny,1:nz),omgz_tmp(1:nx,1:ny,1:nz)) + omgx_tmp=0. + omgy_tmp=0. + omgz_tmp=0. + + !ordre2 + !------ + do k=1,nz + z=ztab(k) + do j=1,ny + y=ytab(j) + do i=1,nx + x=xtab(i) + + !qg(i,j,k)=qg(i,j,k)+0.5D0*dt*tsource(time+dt,x,y,z) + + ts=strech(i,j,k)+nu*diffusion(i,j,k)+penal(i,j,k) + + !call source_anal(tsa,x,y,z) + + + !pour l'instant en t + !omgx_tmp(i,j,k)=omgx_tmp(i,j,k)+0.5D0*dt*(ts(1)+tsa(1)) + !omgy_tmp(i,j,k)=omgy_tmp(i,j,k)+0.5D0*dt*(ts(2)+tsa(2)) + !omgz_tmp(i,j,k)=omgz_tmp(i,j,k)+0.5D0*dt*(ts(3)+tsa(3)) + + omgx_tmp(i,j,k)=omgx_tmp(i,j,k)+0.5D0*dt*ts(1) + omgy_tmp(i,j,k)=omgy_tmp(i,j,k)+0.5D0*dt*ts(2) + omgz_tmp(i,j,k)=omgz_tmp(i,j,k)+0.5D0*dt*ts(3) + + + + end do + end do + end do + + omgx=omgx+omgx_tmp + omgy=omgy+omgy_tmp + omgz=omgz+omgz_tmp + + deallocate(omgx_tmp,omgy_tmp,omgz_tmp) + + + end subroutine source_split_2 + + + + function strech (i,j,k) + implicit none + real(kind=8),dimension(1:3) :: strech + integer,intent(in) :: i,j,k + real(kind=8),dimension(1:3) :: tx,ty,tz + real(kind=8) :: facx,facy,facz + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + + !forme conservative : div(w:u) + + facx=1.D0/(12.D0*dx) + facy=1.D0/(12.D0*dy) + facz=1.D0/(12.D0*dz) + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + !conditions periodiques + !----------------------- + tx(1)=facx*(omgx(im2,j,k)*vxg(im2,j,k)-8.D0*omgx(im1,j,k)*vxg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vxg(ip1,j,k)-omgx(ip2,j,k)*vxg(ip2,j,k)) + tx(2)=facx*(omgx(im2,j,k)*vyg(im2,j,k)-8.D0*omgx(im1,j,k)*vyg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vyg(ip1,j,k)-omgx(ip2,j,k)*vyg(ip2,j,k)) + tx(3)=facx*(omgx(im2,j,k)*vzg(im2,j,k)-8.D0*omgx(im1,j,k)*vzg(im1,j,k) & + +8.D0*omgx(ip1,j,k)*vzg(ip1,j,k)-omgx(ip2,j,k)*vzg(ip2,j,k)) + + ty(1)=facy*(omgy(i,jm2,k)*vxg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vxg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vxg(i,jp1,k)-omgy(i,jp2,k)*vxg(i,jp2,k)) + ty(2)=facy*(omgy(i,jm2,k)*vyg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vyg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vyg(i,jp1,k)-omgy(i,jp2,k)*vyg(i,jp2,k)) + ty(3)=facy*(omgy(i,jm2,k)*vzg(i,jm2,k)-8.D0*omgy(i,jm1,k)*vzg(i,jm1,k) & + +8.D0*omgy(i,jp1,k)*vzg(i,jp1,k)-omgy(i,jp2,k)*vzg(i,jp2,k)) + + tz(1)=facz*(omgz(i,j,km2)*vxg(i,j,km2)-8.D0*omgz(i,j,km1)*vxg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vxg(i,j,kp1)-omgz(i,j,kp2)*vxg(i,j,kp2)) + tz(2)=facz*(omgz(i,j,km2)*vyg(i,j,km2)-8.D0*omgz(i,j,km1)*vyg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vyg(i,j,kp1)-omgz(i,j,kp2)*vyg(i,j,kp2)) + tz(3)=facz*(omgz(i,j,km2)*vzg(i,j,km2)-8.D0*omgz(i,j,km1)*vzg(i,j,km1) & + +8.D0*omgz(i,j,kp1)*vzg(i,j,kp1)-omgz(i,j,kp2)*vzg(i,j,kp2)) + + !conditions non periodiques + !-------------------------- +!!$ if((i/=1).and.(i/=2).and.(i/=nx).and.(i/=nx-1).and.(j/=1).and.(j/=2).and.(j/=ny).and.(j/=ny-1).and.(k/=1).and.(k/=2).and.(k/=nz).and.(k/=nz-1))then +!!$ !schema centre d'ordre4 +!!$ +!!$ tx(1)=facx*(omgx(i-2,j,k)*vxg(i-2,j,k)-8.D0*omgx(i-1,j,k)*vxg(i-1,j,k)+8.D0*omgx(i+1,j,k)*vxg(i+1,j,k)-omgx(i+2,j,k)*vxg(i+2,j,k)) +!!$ tx(2)=facx*(omgx(i-2,j,k)*vyg(i-2,j,k)-8.D0*omgx(i-1,j,k)*vyg(i-1,j,k)+8.D0*omgx(i+1,j,k)*vyg(i+1,j,k)-omgx(i+2,j,k)*vyg(i+2,j,k)) +!!$ tx(3)=facx*(omgx(i-2,j,k)*vzg(i-2,j,k)-8.D0*omgx(i-1,j,k)*vzg(i-1,j,k)+8.D0*omgx(i+1,j,k)*vzg(i+1,j,k)-omgx(i+2,j,k)*vzg(i+2,j,k)) +!!$ +!!$ ty(1)=facy*(omgy(i,j-2,k)*vxg(i,j-2,k)-8.D0*omgy(i,j-1,k)*vxg(i,j-1,k)+8.D0*omgy(i,j+1,k)*vxg(i,j+1,k)-omgy(i,j+2,k)*vxg(i,j+2,k)) +!!$ ty(2)=facy*(omgy(i,j-2,k)*vyg(i,j-2,k)-8.D0*omgy(i,j-1,k)*vyg(i,j-1,k)+8.D0*omgy(i,j+1,k)*vyg(i,j+1,k)-omgy(i,j+2,k)*vyg(i,j+2,k)) +!!$ ty(3)=facy*(omgy(i,j-2,k)*vzg(i,j-2,k)-8.D0*omgy(i,j-1,k)*vzg(i,j-1,k)+8.D0*omgy(i,j+1,k)*vzg(i,j+1,k)-omgy(i,j+2,k)*vzg(i,j+2,k)) +!!$ +!!$ tz(1)=facz*(omgz(i,j,k-2)*vxg(i,j,k-2)-8.D0*omgz(i,j,k-1)*vxg(i,j,k-1)+8.D0*omgz(i,j,k+1)*vxg(i,j,k+1)-omgz(i,j,k+2)*vxg(i,j,k+2)) +!!$ tz(2)=facz*(omgz(i,j,k-2)*vyg(i,j,k-2)-8.D0*omgz(i,j,k-1)*vyg(i,j,k-1)+8.D0*omgz(i,j,k+1)*vyg(i,j,k+1)-omgz(i,j,k+2)*vyg(i,j,k+2)) +!!$ tz(3)=facz*(omgz(i,j,k-2)*vzg(i,j,k-2)-8.D0*omgz(i,j,k-1)*vzg(i,j,k-1)+8.D0*omgz(i,j,k+1)*vzg(i,j,k+1)-omgz(i,j,k+2)*vzg(i,j,k+2)) +!!$ +!!$ else +!!$ +!!$ !schema decentre au bord (ordre4) +!!$ if((i==1).or.(i==2))then +!!$ tx(1)=facx*(-25.D0*omgx(i,j,k)*vxg(i,j,k)+48.D0*omgx(i+1,j,k)*vxg(i+1,j,k)-36.D0*omgx(i+2,j,k)*vxg(i+2,j,k)+16.D0*omgx(i+3,j,k)*vxg(i+3,j,k)-3.D0*omgx(i+4,j,k)*vxg(i+4,j,k)) +!!$ tx(2)=facx*(-25.D0*omgx(i,j,k)*vyg(i,j,k)+48.D0*omgx(i+1,j,k)*vyg(i+1,j,k)-36.D0*omgx(i+2,j,k)*vyg(i+2,j,k)+16.D0*omgx(i+3,j,k)*vyg(i+3,j,k)-3.D0*omgx(i+4,j,k)*vyg(i+4,j,k)) +!!$ tx(3)=facx*(-25.D0*omgx(i,j,k)*vzg(i,j,k)+48.D0*omgx(i+1,j,k)*vzg(i+1,j,k)-36.D0*omgx(i+2,j,k)*vzg(i+2,j,k)+16.D0*omgx(i+3,j,k)*vzg(i+3,j,k)-3.D0*omgx(i+4,j,k)*vzg(i+4,j,k)) +!!$ end if +!!$ +!!$ if((i==nx).or.(i==nx-1))then +!!$ tx(1)=facx*(-25.D0*omgx(i,j,k)*vxg(i,j,k)+48.D0*omgx(i-1,j,k)*vxg(i-1,j,k)-36.D0*omgx(i-2,j,k)*vxg(i-2,j,k)+16.D0*omgx(i-3,j,k)*vxg(i-3,j,k)-3.D0*omgx(i-4,j,k)*vxg(i-4,j,k)) +!!$ tx(2)=facx*(-25.D0*omgx(i,j,k)*vyg(i,j,k)+48.D0*omgx(i-1,j,k)*vyg(i-1,j,k)-36.D0*omgx(i-2,j,k)*vyg(i-2,j,k)+16.D0*omgx(i-3,j,k)*vyg(i-3,j,k)-3.D0*omgx(i-4,j,k)*vyg(i-4,j,k)) +!!$ tx(3)=facx*(-25.D0*omgx(i,j,k)*vzg(i,j,k)+48.D0*omgx(i-1,j,k)*vzg(i-1,j,k)-36.D0*omgx(i-2,j,k)*vzg(i-2,j,k)+16.D0*omgx(i-3,j,k)*vzg(i-3,j,k)-3.D0*omgx(i-4,j,k)*vzg(i-4,j,k)) +!!$ endif +!!$ +!!$ if((j==1).or.(j==2))then +!!$ ty(1)=facy*(-25.D0*omgy(i,j,k)*vxg(i,j,k)+48.D0*omgy(i,j+1,k)*vxg(i,j+1,k)-36.D0*omgy(i,j+2,k)*vxg(i,j+2,k)+16.D0*omgy(i,j+3,k)*vxg(i,j+3,k)-3.D0*omgy(i,j+4,k)*vxg(i,j+4,k)) +!!$ ty(2)=facy*(-25.D0*omgy(i,j,k)*vyg(i,j,k)+48.D0*omgy(i,j+1,k)*vyg(i,j+1,k)-36.D0*omgy(i,j+2,k)*vyg(i,j+2,k)+16.D0*omgy(i,j+3,k)*vyg(i,j+3,k)-3.D0*omgy(i,j+4,k)*vyg(i,j+4,k)) +!!$ ty(3)=facy*(-25.D0*omgy(i,j,k)*vzg(i,j,k)+48.D0*omgy(i,j+1,k)*vzg(i,j+1,k)-36.D0*omgy(i,j+2,k)*vzg(i,j+2,k)+16.D0*omgy(i,j+3,k)*vzg(i,j+3,k)-3.D0*omgy(i,j+4,k)*vzg(i,j+4,k)) +!!$ end if +!!$ +!!$ if((j==ny).or.(j==ny-1))then +!!$ ty(1)=facy*(-25.D0*omgy(i,j,k)*vxg(i,j,k)+48.D0*omgy(i,j-1,k)*vxg(i,j-1,k)-36.D0*omgy(i,j-2,k)*vxg(i,j-2,k)+16.D0*omgy(i,j-3,k)*vxg(i,j-3,k)-3.D0*omgy(i,j-4,k)*vxg(i,j-4,k)) +!!$ ty(2)=facy*(-25.D0*omgy(i,j,k)*vyg(i,j,k)+48.D0*omgy(i,j-1,k)*vyg(i,j-1,k)-36.D0*omgy(i,j-2,k)*vyg(i,j-2,k)+16.D0*omgy(i,j-3,k)*vyg(i,j-3,k)-3.D0*omgy(i,j-4,k)*vyg(i,j-4,k)) +!!$ ty(3)=facy*(-25.D0*omgy(i,j,k)*vzg(i,j,k)+48.D0*omgy(i,j-1,k)*vzg(i,j-1,k)-36.D0*omgy(i,j-2,k)*vzg(i,j-2,k)+16.D0*omgy(i,j-3,k)*vzg(i,j-3,k)-3.D0*omgy(i,j-4,k)*vzg(i,j-4,k)) +!!$ endif +!!$ +!!$ if((k==1).or.(k==2))then +!!$ tz(1)=facz*(-25.D0*omgz(i,j,k)*vxg(i,j,k)+48.D0*omgz(i,j,k+1)*vxg(i,j,k+1)-36.D0*omgz(i,j,k+2)*vxg(i,j,k+2)+16.D0*omgz(i,j,k+3)*vxg(i,j,k+3)-3.D0*omgz(i,j,k+4)*vxg(i,j,k+4)) +!!$ tz(2)=facz*(-25.D0*omgz(i,j,k)*vyg(i,j,k)+48.D0*omgz(i,j,k+1)*vyg(i,j,k+1)-36.D0*omgz(i,j,k+2)*vyg(i,j,k+2)+16.D0*omgz(i,j,k+3)*vyg(i,j,k+3)-3.D0*omgz(i,j,k+4)*vyg(i,j,k+4)) +!!$ tz(3)=facz*(-25.D0*omgz(i,j,k)*vzg(i,j,k)+48.D0*omgz(i,j,k+1)*vzg(i,j,k+1)-36.D0*omgz(i,j,k+2)*vzg(i,j,k+2)+16.D0*omgz(i,j,k+3)*vzg(i,j,k+3)-3.D0*omgz(i,j,k+4)*vzg(i,j,k+4)) +!!$ end if +!!$ +!!$ if((k==nz).or.(k==nz-1))then +!!$ tz(1)=facz*(-25.D0*omgz(i,j,k)*vxg(i,j,k)+48.D0*omgz(i,j,k-1)*vxg(i,j,k-1)-36.D0*omgz(i,j,k-2)*vxg(i,j,k-2)+16.D0*omgz(i,j,k-3)*vxg(i,j,k-3)-3.D0*omgz(i,j,k-4)*vxg(i,j,k-4)) +!!$ tz(2)=facz*(-25.D0*omgz(i,j,k)*vyg(i,j,k)+48.D0*omgz(i,j,k-1)*vyg(i,j,k-1)-36.D0*omgz(i,j,k-2)*vyg(i,j,k-2)+16.D0*omgz(i,j,k-3)*vyg(i,j,k-3)-3.D0*omgz(i,j,k-4)*vyg(i,j,k-4)) +!!$ tz(3)=facz*(-25.D0*omgz(i,j,k)*vzg(i,j,k)+48.D0*omgz(i,j,k-1)*vzg(i,j,k-1)-36.D0*omgz(i,j,k-2)*vzg(i,j,k-2)+16.D0*omgz(i,j,k-3)*vzg(i,j,k-3)-3.D0*omgz(i,j,k-4)*vzg(i,j,k-4)) +!!$ endif +!!$ +!!$ end if + + strech(1)=tx(1)+ty(1)+tz(1) + strech(2)=tx(2)+ty(2)+tz(2) + strech(3)=tx(3)+ty(3)+tz(3) + + end function strech + + + function diffusion (i,j,k) + implicit none + real(kind=8),dimension(1:3) :: diffusion + integer,intent(in) :: i,j,k + real(kind=8) :: facx,facy,facz + real(kind=8),dimension(1:3) :: tx,ty,tz + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + + facx=1.D0/(12.D0*dx**2) + facy=1.D0/(12.D0*dy**2) + facz=1.D0/(12.D0*dz**2) + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + !ordre4 + tx(1)=facx*(-omgx(ip2,j,k)+16.D0*omgx(ip1,j,k)-30.D0*omgx(i,j,k)+16.D0*omgx(im1,j,k)-omgx(im2,j,k)) + tx(2)=facx*(-omgy(ip2,j,k)+16.D0*omgy(ip1,j,k)-30.D0*omgy(i,j,k)+16.D0*omgy(im1,j,k)-omgy(im2,j,k)) + tx(3)=facx*(-omgz(ip2,j,k)+16.D0*omgz(ip1,j,k)-30.D0*omgz(i,j,k)+16.D0*omgz(im1,j,k)-omgz(im2,j,k)) + + ty(1)=facy*(-omgx(i,jp2,k)+16.D0*omgx(i,jp1,k)-30.D0*omgx(i,j,k)+16.D0*omgx(i,jm1,k)-omgx(i,jm2,k)) + ty(2)=facy*(-omgy(i,jp2,k)+16.D0*omgy(i,jp1,k)-30.D0*omgy(i,j,k)+16.D0*omgy(i,jm1,k)-omgy(i,jm2,k)) + ty(3)=facy*(-omgz(i,jp2,k)+16.D0*omgz(i,jp1,k)-30.D0*omgz(i,j,k)+16.D0*omgz(i,jm1,k)-omgz(i,jm2,k)) + + tz(1)=facz*(-omgx(i,j,kp2)+16.D0*omgx(i,j,kp1)-30.D0*omgx(i,j,k)+16.D0*omgx(i,j,km1)-omgx(i,j,km2)) + tz(2)=facz*(-omgy(i,j,kp2)+16.D0*omgy(i,j,kp1)-30.D0*omgy(i,j,k)+16.D0*omgy(i,j,km1)-omgy(i,j,km2)) + tz(3)=facz*(-omgz(i,j,kp2)+16.D0*omgz(i,j,kp1)-30.D0*omgz(i,j,k)+16.D0*omgz(i,j,km1)-omgz(i,j,km2)) +!!$ +!!$ !ordre2 +!!$ facx=1.D0/(dx**2) +!!$ facy=1.D0/(dy**2) +!!$ facz=1.D0/(dz**2) +!!$ +!!$ tx(1)=facx*(omgx(ip1,j,k)-2.*omgx(i,j,k)+omgx(im1,j,k)) +!!$ tx(2)=facx*(omgy(ip1,j,k)-2.*omgy(i,j,k)+omgy(im1,j,k)) +!!$ tx(3)=facx*(omgz(ip1,j,k)-2.*omgz(i,j,k)+omgz(im1,j,k)) +!!$ +!!$ ty(1)=facy*(omgx(i,jp1,k)-2.*omgx(i,j,k)+omgx(i,jm1,k)) +!!$ ty(2)=facy*(omgy(i,jp1,k)-2.*omgy(i,j,k)+omgy(i,jm1,k)) +!!$ ty(3)=facy*(omgz(i,jp1,k)-2.*omgz(i,j,k)+omgz(i,jm1,k)) +!!$ +!!$ tz(1)=facz*(omgx(i,j,kp1)-2.*omgx(i,j,k)+omgx(i,j,km1)) +!!$ tz(2)=facz*(omgy(i,j,kp1)-2.*omgy(i,j,k)+omgy(i,j,km1)) +!!$ tz(3)=facz*(omgz(i,j,kp1)-2.*omgz(i,j,k)+omgz(i,j,km1)) + + + + diffusion(1)=tx(1)+ty(1)+tz(1) + diffusion(2)=tx(2)+ty(2)+tz(2) + diffusion(3)=tx(3)+ty(3)+tz(3) + + + end function diffusion + + + + + + + + + + function penal(i,j,k) + implicit none + real(kind=8),dimension(1:3) :: penal + integer,intent(in) :: i,j,k + real(kind=8),dimension(1:3) :: tx,ty,tz + real(kind=8) :: facx,facy,facz + integer :: ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2 + + !forme conservative : div(w:u) + + facx=1.D0/(12.D0*dx) + facy=1.D0/(12.D0*dy) + facz=1.D0/(12.D0*dz) + + ip1=mod(i+1+nx-1,nx)+1 + im1=mod(i-1+nx-1,nx)+1 + ip2=mod(i+2+nx-1,nx)+1 + im2=mod(i-2+nx-1,nx)+1 + + jp1=mod(j+1+ny-1,ny)+1 + jm1=mod(j-1+ny-1,ny)+1 + jp2=mod(j+2+ny-1,ny)+1 + jm2=mod(j-2+ny-1,ny)+1 + + kp1=mod(k+1+nz-1,nz)+1 + km1=mod(k-1+nz-1,nz)+1 + kp2=mod(k+2+nz-1,nz)+1 + km2=mod(k-2+nz-1,nz)+1 + + !conditions periodiques + !----------------------- + + tx(2)=facx*(peny(im2,j,k)-8.D0*peny(im1,j,k)+8.D0*peny(ip1,j,k)-peny(ip2,j,k)) + tx(3)=facx*(penz(im2,j,k)-8.D0*penz(im1,j,k)+8.D0*penz(ip1,j,k)-penz(ip2,j,k)) + + ty(1)=facy*(penx(i,jm2,k)-8.D0*penx(i,jm1,k)+8.D0*penx(i,jp1,k)-penx(i,jp2,k)) + ty(3)=facy*(penz(i,jm2,k)-8.D0*penz(i,jm1,k)+8.D0*penz(i,jp1,k)-penz(i,jp2,k)) + + + tz(1)=facz*(penx(i,j,km2)-8.D0*penx(i,j,km1)+8.D0*penx(i,j,kp1)-penx(i,j,kp2)) + tz(2)=facz*(peny(i,j,km2)-8.D0*peny(i,j,km1)+8.D0*peny(i,j,kp1)-peny(i,j,kp2)) + + + penal(1)=ty(3)-tz(2) + penal(2)=tz(1)-tx(3) + penal(3)=tx(2)-ty(1) + + contains + function penx (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penx + + + !penx=vxg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + !penx=vxg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + + !explicite + !penx=-lambda*chi(l,m,n)*vxg(l,m,n) + penx=vxg(l,m,n) + + end function penx + + function peny (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: peny + + + !peny=vyg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + !peny=vyg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + + !explicite + !peny=-lambda*chi(l,m,n)*vyg(l,m,n) + peny=vyg(l,m,n) + + end function peny + + function penz (l,m,n) + implicit none + integer, intent(in) :: l,m,n + real(kind=8) :: penz + + + !penz=vzg(l,m,n)*exp(-lambda*chi(l,m,n)*dt) + !penz=vzg(l,m,n)/(1.+lambda*chi(l,m,n)*dt) + + !explicite + !penz=-lambda*chi(l,m,n)*vzg(l,m,n) + penz=vzg(l,m,n) + + end function penz + + end function penal + + + + + + + subroutine source_anal (s,x,y,z) + !pour test terme source pour sol de NS + implicit none + real(kind=8),dimension(1:3),intent(out) :: s + real(kind=8),intent(in) :: x,y,z + real(kind=8) :: cx,c2x,cy,c2y,cz,c2z,sx,s2x,sy,s2y,sz,s2z,ct,st,c2t,s2t + + real(kind=8) :: t1,t2,t3,c1,c2,c3 + + + !================= + !sur [0,1]**3 + !================= + + cx=cos(pi*x) + c2x=cos(2.*pi*x) + sx=sin(pi*x) + s2x=sin(2.*pi*x) + + cy=cos(pi*y) + c2y=cos(2.*pi*y) + sy=sin(pi*y) + s2y=sin(2.*pi*y) + + cz=cos(pi*z) + c2z=cos(2.*pi*z) + sz=sin(pi*z) + s2z=sin(2.*pi*z) + + ct=cos(pi*time) + c2t=cos(2.*pi*time) + st=sin(pi*time) + s2t=sin(2.*pi*time) + + !sol analytique instationnaire + !----------------------------- +!!$ s(1)=2.*pi**2*(s2x*c2y*sz**2*st& +!!$ -s2x*sy**2*c2z*st& +!!$ -8.*sx**2*s2y*s2z*ct**2*c2x*c2y*sz**2& +!!$ +8.*sx**2*s2y*s2z*ct**2*c2x*sy**2*c2z& +!!$ -2.*s2x**2*sy**3*s2z*ct**2*c2z*cy& +!!$ +2.*s2x**2*s2y*sz**3*ct**2*c2y*cz& +!!$ +4.*sx*s2y*s2z*ct**2*cx*s2x*c2y*sz**2& +!!$ -4.*sx*s2y*s2z*ct**2*cx*s2x*sy**2*c2z& + !!$ -10.*s2x*c2y*pi*sz**2*ct& +!!$ +10.*s2x*sy**2*c2z*pi*ct& +!!$ -2.*s2x*cy**2*pi*c2z*ct& +!!$ +2.*s2x*c2y*pi*cz**2*ct) +!!$ +!!$ s(2)=2.*pi**2*(-2.*sx**2*s2y*c2z*st - c2x*s2y*sz**2*st & +!!$ +8.*sx**3*s2y**2*s2z*ct**2*c2z*cx - 8.*s2x*sy**2*s2z*ct**2*sx**2*c2y*c2z & +!!$ -4.*s2x*sy**2*s2z*ct**2*c2x*c2y*sz**2 - 2.*s2x*s2y**2*sz**3*ct**2*c2x*cz & +!!$ +4.*s2x*sy*s2z*ct**2*cy*sx**2*s2y*c2z & +!!$ +2.*s2x*sy*s2z*ct**2*cy*c2x*s2y*sz**2 - 4.*cx**2*pi*s2y*c2z*ct & +!!$ +20.*sx**2*s2y*c2z*pi*ct + 10.*c2x*pi*s2y*sz**2*ct - 2.*cx*pi*s2y*cz**2*ct) +!!$ +!!$ s(3)=-2.*pi**2*(-c2x*sy**2*s2z*st - 2.*sx**2*c2y*s2z*st & +!!$ +8.*sx**3*s2y*s2z**2*ct**2*c2y*cx - 2.*s2x*sy**3*s2z**2*ct**2*c2x*cy & +!!$ -4.* s2x*s2y*sz**2*ct**2*c2x*sy**2*c2z - 8.*s2x*s2y*sz**2*ct**2*sx**2*c2y*c2z & +!!$ +2.*s2x*s2y*sz*ct**2*cz*c2x*sy**2*s2z & +!!$ +4.*s2x*s2y*sz*ct**2*cz*sx**2*c2y*s2z& +!!$ +10.*c2x*pi*sy**2*s2z*ct - 4.*cx**2*pi*c2y*s2z*ct& +!!$ +20.*sx**2*c2y*pi*s2z*ct - 2.*c2x*pi*cy**2*s2z*ct) + + + !sol analytique stationnaire + !--------------------------- + s(1)=4.*pi**2*(-4.*sx**2*s2y*s2z*c2x*c2y*sz**2 & + +4.*sx**2*s2y*s2z*c2x*sy**2*c2z - s2x**2*sy**3*s2z*c2z*cy& + +s2x**2*s2y*sz**3*c2y*cz& + +2.*sx*s2y*s2z*cx*s2x*c2y*sz**2 - 2.*sx*s2y*s2z*cx*s2x*sy**2*c2z& + -5.*nu*s2x*c2y*pi*sz**2 + 5.*nu*s2x*sy**2*c2z*pi - nu*s2x*cy**2*pi*c2z + nu*s2x*c2y*pi*cz**2) + + s(2)=4.*pi**2*(4.*sx**3*s2y**2*s2z*c2z*cx - 4.*s2x*sy**2*s2z*sx**2*c2y*c2z & + -2.*s2x*sy**2*s2z*c2x*c2y*sz**2 - s2x*s2y**2*sz**3*c2x*cz & + +2.*s2x*sy*s2z*cy*sx**2*s2y*c2z& + +s2x*sy*s2z*cy*c2x*s2y*sz**2 - 2.*nu*cx**2*pi*s2y*c2z + 10.*nu*sx**2*s2y*c2z*pi& + +5.*nu*c2x*pi*s2y*sz**2 - nu*c2x*pi*s2y*cz**2) + + s(3)=-4.*pi**2*(4.*sx**3*s2y*s2z**2*c2y*cx - s2x*sy**3*s2z**2*c2x*cy& + -2.*s2x*s2y*sz**2*c2x*sy**2*c2z - 4.*s2x*s2y*sz**2*sx**2*c2y*c2z& + +s2x*s2y*sz*cz*c2x*sy**2*s2z + 2.*s2x*s2y*sz*cz*sx**2*c2y*s2z& + +5.*nu*c2x*pi*sy**2*s2z - 2.*nu*cx**2*pi*c2y*s2z + 10.*nu*sx**2*c2y*pi*s2z - nu*c2x*pi*cy**2*s2z) + + !sol analytique stationnaire: sans strech ni diffusion + !------------------------------------------------------- +!!$ s(1)=4.*pi**2*(-2.*sx**2*s2y*s2z*c2x*c2y*sz**2& +!!$ +2.*sx**2*s2y*s2z*c2x*sy**2*c2z - s2x**2*sy**3*s2z*c2z*cy& +!!$ +s2x**2*s2y*sz**3*c2y*cz) +!!$ +!!$ s(2)=4.*pi**2*(4.*sx**3*s2y**2*s2z*c2z*cx - 2.*s2x*sy**2*s2z*sx**2*c2y*c2z & +!!$ -s2x*sy**2*s2z*c2x*c2y*sz**2 - s2x*s2y**2*sz**3*c2x*cz) +!!$ +!!$ s(3)=-4.*pi**2*(4.*sx**3*s2y*s2z**2*c2y*cx - s2x*sy**3*s2z**2*c2x*cy& +!!$ -s2x*s2y*sz**2*c2x*sy**2*c2z - 2.*s2x*s2y*sz**2*sx**2*c2y*c2z) + + + !sol analytique stationnaire: que diffusion + !--------------------------------------------- +!!$ s(1)=4.*pi**2*(-2.*sx**2*s2y*s2z*c2x*c2y*sz**2 & +!!$ +2.*sx**2*s2y*s2z*c2x*sy**2*c2z - s2x**2*sy**3*s2z*c2z*cy& +!!$ +s2x**2*s2y*sz**3*c2y*cz - 5.*nu*s2x*c2y*pi*sz**2& +!!$ + 5.*nu*s2x*sy**2*c2z*pi - nu*s2x*cy**2*pi*c2z + nu*s2x*c2y*pi*cz**2) +!!$ +!!$ +!!$ s(2)=4.*pi**2*(4.*sx**3*s2y**2*s2z*c2z*cx - 2.*s2x*sy**2*s2z*sx**2*c2y*c2z & +!!$ -s2x*sy**2*s2z*c2x*c2y*sz**2 - s2x*s2y**2*sz**3*c2x*cz & +!!$ - 2.*nu*cx**2*pi*s2y*c2z + 10.*nu*sx**2*s2y*c2z*pi& +!!$ +5.*nu*c2x*pi*s2y*sz**2 - nu*c2x*pi*s2y*cz**2) +!!$ +!!$ s(3)=-4.*pi**2*(4.*sx**3*s2y*s2z**2*c2y*cx - s2x*sy**3*s2z**2*c2x*cy& +!!$ -s2x*s2y*sz**2*c2x*sy**2*c2z - 2.*s2x*s2y*sz**2*sx**2*c2y*c2z& +!!$ +5.*nu*c2x*pi*sy**2*s2z - 2.*nu*cx**2*pi*c2y*s2z + 10.*nu*sx**2*c2y*pi*s2z - nu*c2x*pi*cy**2*s2z) + + !sol analytique stationnaire: que strech + !---------------------------------------- +!!$ s(1)=4.*pi**2*(-4.*sx**2*s2y*s2z*c2x*c2y*sz**2 & +!!$ +4.*sx**2*s2y*s2z*c2x*sy**2*c2z - s2x**2*sy**3*s2z*c2z*cy& +!!$ +s2x**2*s2y*sz**3*c2y*cz& +!!$ +2.*sx*s2y*s2z*cx*s2x*c2y*sz**2 - 2.*sx*s2y*s2z*cx*s2x*sy**2*c2z) +!!$ +!!$ s(2)=4.*pi**2*(4.*sx**3*s2y**2*s2z*c2z*cx - 4.*s2x*sy**2*s2z*sx**2*c2y*c2z & +!!$ -2.*s2x*sy**2*s2z*c2x*c2y*sz**2 - s2x*s2y**2*sz**3*c2x*cz & +!!$ +2.*s2x*sy*s2z*cy*sx**2*s2y*c2z& +!!$ +s2x*sy*s2z*cy*c2x*s2y*sz**2) +!!$ +!!$ s(3)=-4.*pi**2*(4.*sx**3*s2y*s2z**2*c2y*cx - s2x*sy**3*s2z**2*c2x*cy& +!!$ -2.*s2x*s2y*sz**2*c2x*sy**2*c2z - 4.*s2x*s2y*sz**2*sx**2*c2y*c2z& +!!$ +s2x*s2y*sz*cz*c2x*sy**2*s2z + 2.*s2x*s2y*sz*cz*sx**2*c2y*s2z) + + + end subroutine source_anal + + + +end module source_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/tab_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/tab_mod.f90 new file mode 100644 index 000000000..49d94467e --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/tab_mod.f90 @@ -0,0 +1,23 @@ +module tab_mod + + !grille + real(kind=8),dimension(:,:,:),pointer :: vxg,vyg,vzg,vxg1,vyg1,vzg1,vxg2,vyg2,vzg2,vxg3,vyg3,vzg3,vxg4,vyg4,vzg4 + real(kind=8),dimension(:,:,:),pointer :: chi,chi_sphere,lambda + real(kind=8),dimension(:,:,:),pointer :: omgx,omgy,omgz,deb1,deb2,deb3 + real(kind=8),dimension(:),pointer :: xtab,ytab,ztab + integer,dimension(:,:,:),pointer :: numpg + !particule + real(kind=8),dimension(:),pointer :: xp,yp,zp,qp,vx,vy,vz,xp0,xp1,xp2,xp3,yp0,yp1,yp2,yp3,zp0,zp1,zp2,zp3 + real(kind=8),dimension(:),pointer :: vx0,vx1,vx2,vx3,vx4,vx5,vy0,vy1,vy2,vy3,vy4,vy5,vz0,vz1,vz2,vz3,vz4,vz5 + real(kind=8),dimension(:),pointer :: omx,omy,omz + integer,dimension(:),pointer :: blocg,blocd,Nbloc + + + real,dimension(:,:,:),pointer :: omgxr,omgyr,omgzr,vxgr,vygr,vzgr + + real(kind=8),dimension(:,:,:),pointer ::stxg,styg,stzg + real(kind=8),dimension(:),pointer ::stx,sty,stz + + + +end module tab_mod diff --git a/CodesEnVrac/NavierStokes3D-Penalization/src/utile_mod.f90 b/CodesEnVrac/NavierStokes3D-Penalization/src/utile_mod.f90 new file mode 100644 index 000000000..acdcffae2 --- /dev/null +++ b/CodesEnVrac/NavierStokes3D-Penalization/src/utile_mod.f90 @@ -0,0 +1,369 @@ +module utile_mod + use donnees_mod + use tab_mod +contains + + + subroutine make_grille + implicit none + integer :: i,j,k + + do k=1,nz + ztab(k)=zd+(k-1)*dz + end do + do j=1,ny + ytab(j)=yb+(j-1)*dy + end do + do i=1,nx + xtab(i)=xg+(i-1)*dx + end do + + end subroutine make_grille + + + + subroutine make_bloc(esp) + use donnees_mod + implicit none + integer,intent(in) :: esp + integer :: fin,ib,i,j,k,l,im,ip,dim1,dim2,dim3 + logical :: zero + real(kind=8) :: pas + + select case(esp) + case(1) + dim1=nx + dim2=ny + dim3=nz + pas=dx + case(2) + dim1=ny + dim2=nz + dim3=nx + pas=dy + case(3) + dim1=nz + dim2=nx + dim3=ny + pas=dz + end select + + + !----------------------------------------------------------------------------------------- + !Determine la nature des blocs + !Donne un flag correspondant au type de remaillage necessaire (centre,decentre ou modifie) + !------------------------------------------------------------------------------------------ + + blocg(1:npart)=1 + blocd(1:npart)=1 + + direction1: do l=1,dim3 + + direction2: do j=1,dim2 + + !peut calculer la longeur -> gain si longeur eleve + + !parcours la grille, bloc par bloc:determine le type des bloc + !--------------------------------- + + blocg(0)=100 + blocd(0)=100 + Nbloc(0)=100 + + type_bloc:do i=1,dim1,long_bloc+1 + + + if ( (i+long_bloc)<(dim1-1) ) then + fin=i+long_bloc + call sub_typeb + else + !parcours le bloc plus premier point du bloc suivant + fin=dim1-1 + call sub_typeb + blocg(pg(dim1,j,l))=blocg(pg(dim1-1,j,l)) + blocd(pg(dim1,j,l))=blocd(pg(dim1-1,j,l)) + Nbloc(pg(dim1,j,l))=Nbloc(pg(dim1-1,j,l)) + end if + + end do type_bloc + + + !parcours la grille, bloc par bloc:determine si modif de remaillage necessaire a l'intersection des blocs + !--------------------------------- + type_remaill:do i=1,dim1,long_bloc+1 + + if (((i+long_bloc)<dim1).and.(i>1+long_bloc)) then + fin=i+long_bloc + call sub_remb + else + if (i<=1+long_bloc)then + !premier bloc + !------------- + fin=i+long_bloc + call sub_remb + + else + !dernier bloc + !------------- + fin=dim1 + call sub_remb + + end if + + end if + + end do type_remaill + end do direction2 + end do direction1 + + contains + + subroutine sub_typeb + + integer :: ni,N + real(kind=8) :: li + logical :: pasfait + + + !parcours une premiere fois le bloc pour savoir si c'est un bloc en 0 ou 1/2 + !---------------------------------- + pasfait=.true. + zero=.true. + do_zero:do ib=i,fin+1 !eviter cas change de bloc quand maille vide + if (pg(ib,j,l)/=0) then + if (pasfait) then !le N doit etre le meme pour tout le bloc ! + li=dt/pas*vit(pg(ib,j,l)) + ni=floor(li+0.5D0) + pasfait=.false. + end if + li=dt/pas*vit(pg(ib,j,l)) + if ( ((li)<(ni-0.5D0)).or.((li)>(ni+0.5D0)) ) then + zero=.false. + exit do_zero + end if + end if + end do do_zero + + + !parcours a nouveau le bloc + !------------------------- + !affecte le type de bloc a toute les part du bloc + + pasfait=.true. + bloc2:do ib=i,fin + + if (pg(ib,j,l)/=0) then + + !calcul de N + !------------ + if (pasfait) then + if (zero) then + N=floor(dt/pas*vit(pg(ib,j,l))+0.5D0) + pasfait=.false. + else + N=floor(dt/pas*vit(pg(ib,j,l))) + pasfait=.false. + end if + end if + + if (zero) then + !bloc pour lambda2 centre + blocg(pg(ib,j,l))=0 + blocd(pg(ib,j,l))=0 + end if + + !affecte la constante N + Nbloc(pg(ib,j,l))=N + + end if + end do bloc2 + + end subroutine sub_typeb + + + subroutine sub_remb + implicit none + + integer,dimension(-2:2) :: iper + integer :: k + + + !parcours a nvx le bloc + !----------------------- + !detecte s'il y aura une correction de remaillage a apporter à l'intersection de ces blocs + + bloc3:do ib=i,fin,fin-i + + if (pg(ib,j,l)/=0) then + + !si fin de bloc en 0. : + !---------------------- + do k=-2,2 + iper(k)=pg(mod(ib+k+dim1-1,dim1)+1,j,l) + end do + + + if ((ib==fin).and.(blocd(pg(ib,j,l))==0).and.((blocg(iper(1))==1) & + .or.(blocg(iper(2))==1)).and.((Nbloc(iper(1))==Nbloc(pg(ib,j,l))-1) & + .or.(Nbloc(iper(2))==Nbloc(pg(ib,j,l))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j,l))<=Nbloc(pg(ib,j,l)) ) then + blocg(iper(1))=2 + blocd(pg(ib,j,l))=3 + else + blocg(iper(1))=2 + blocd(pg(ib,j,l))=4 + blocg(pg(ib,j,l))=5 + end if + + else + blocg(iper(1))=2 + blocg(iper(2))=5 + + if ( dt/pas*vit(pg(ib,j,l))<=Nbloc(pg(ib,j,l)) ) then + blocd(pg(ib,j,l))=3 + else + blocd(pg(ib,j,l))=7 + blocg(pg(ib,j,l))=8 + end if + + if ( dt/pas*vit(iper(-1))<=Nbloc(pg(ib,j,l)) ) then + blocd(iper(-1))=6 + else + blocd(iper(-1))=5 + end if + end if + + end if + + + !si debut de bloc en 0 : detecte quelle correction il faudra apporter + !---------------------- + if ((ib==i) .and.(blocg(pg(ib,j,l))==0).and.((blocd(iper(-1))==1) & + .or.(blocd(iper(-2))==1)).and.((Nbloc(iper(-1))==Nbloc(pg(ib,j,l))-1) & + .or. (Nbloc(iper(-2))==Nbloc(pg(ib,j,l))-1) ) ) then + + if (type_b==2) then + + if ( dt/pas*vit(pg(ib,j,l))>Nbloc(pg(ib,j,l)) ) then + blocd(iper(-1))=2 + blocg(pg(ib,j,l))=4 + else + blocd(iper(-1))=2 + blocg(pg(ib,j,l))=3 + end if + + else + + blocd(iper(-1))=2 + blocd(iper(-2))=4 + + if ( dt/pas*vit(pg(ib,j,l))>Nbloc(pg(ib,j,l)) ) then + blocg(pg(ib,j,l))=4 + else + blocg(pg(ib,j,l))=3 + end if + + if ( dt/pas*vit(iper(1))>Nbloc(pg(ib,j,l)) ) then + blocg(iper(1))=7 + else + blocg(iper(1))=6 + end if + + end if + end if + + + + end if + end do bloc3 + + end subroutine sub_remb + + function pg(a,b,c) + implicit none + integer,intent(in) :: a,b,c + integer :: pg + + select case (esp) + case(1) + pg=numpg(a,b,c) + case(2) + pg=numpg(c,a,b) + case(3) + pg=numpg(b,c,a) + end select + + end function pg + + function vit(ind) + implicit none + integer,intent(in) :: ind + real(kind=8) :: vit + + select case (esp) + case(1) + vit=vx(ind) + case(2) + vit=vy(ind) + case(3) + vit=vz(ind) + end select + + end function vit + + + end subroutine make_bloc + + + subroutine imposer_debit(u,debit,dimx,dimy,dimz,deltax,deltay,deltaz) + implicit none + real(kind=8),dimension(:,:,:),intent(inout) :: u + real(kind=8),intent(in) :: debit,deltax,deltay,deltaz + integer,intent(in) :: dimx,dimy,dimz + real(kind=8) :: debit0 + integer :: i,j,k + + !calcul du debit volumique actuel: int_x int_y int_z u dx dy dz + !--------------------------------- + debit0=0. + + do k=1,dimz + do j=1,dimy + debit0=debit0+u(1,j,k) + end do + end do + debit0=debit0*deltay*deltaz + + !on impose le débit voulu + !------------------------ + do i=1,dimx + do k=1,dimz + do j=1,dimy + u(i,j,k)=u(i,j,k)-debit0/(dimy*dimz*deltay*deltaz)!soustraction du debit actuel + u(i,j,k)=u(i,j,k)+debit/(dimy*dimz*deltay*deltaz)!affectation de la valeur du débit désirée + end do + end do + end do + + !ON a ainsi: + !------------ + ! + !int u(nouveau) dx dy dz = dx dy dz sum u (nouveau) + ! = dx dy dz sum u (old) - debit0 + debit = debit + ! + ! + + + end subroutine imposer_debit + + + + + + + end module utile_mod + + diff --git a/CodesEnVrac/Remesh/4GB/arrays.h b/CodesEnVrac/Remesh/4GB/arrays.h new file mode 100644 index 000000000..e45762cf0 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/arrays.h @@ -0,0 +1,10 @@ + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),vx(npg) + + diff --git a/CodesEnVrac/Remesh/4GB/param.h b/CodesEnVrac/Remesh/4GB/param.h new file mode 100644 index 000000000..e6e8a2c9d --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/param.h @@ -0,0 +1,3 @@ + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,dx1 + common nx2,ny2,nz2,dx2,nx3 + common circlim,cfl,nx,dx \ No newline at end of file diff --git a/CodesEnVrac/Remesh/4GB/param.i b/CodesEnVrac/Remesh/4GB/param.i new file mode 100644 index 000000000..bb8dbac4a --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/param.i @@ -0,0 +1,3 @@ + parameter(npm=2100000,npgx=256,npgy=256,npgz=256) + parameter(npg=256) + diff --git a/CodesEnVrac/Remesh/4GB/remeshx_l2.f b/CodesEnVrac/Remesh/4GB/remeshx_l2.f new file mode 100644 index 000000000..51e6cdf6b --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshx_l2.f @@ -0,0 +1,96 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + endif + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/4GB/remeshx_tag.f b/CodesEnVrac/Remesh/4GB/remeshx_tag.f new file mode 100644 index 000000000..1c789564f --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshx_tag.f @@ -0,0 +1,86 @@ + subroutine remeshx_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag-1,2 + i=itag(n) +c ii=mod(i,nx2)+1 + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +c case (c) and (d) +c +c if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+xx1*u1-yy1*u2 + ug(ip3,jj,kk)=ug(ip3,jj,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(ip4,jj,kk)=ug(ip4,jj,kk)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c else +c case (d) +c endif + else +c case (c') and (d') +c +c if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(ip0,jj,kk)=ug(ip0,jj,kk)+a0*u1 + ug(ip1,jj,kk)=ug(ip1,jj,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(ip2,jj,kk)=ug(ip2,jj,kk)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +c else +c case (d') +c endif + endif + enddo + + return + end + + diff --git a/CodesEnVrac/Remesh/4GB/remeshy_l2.f b/CodesEnVrac/Remesh/4GB/remeshy_l2.f new file mode 100644 index 000000000..001f52cf2 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshy_l2.f @@ -0,0 +1,82 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx + + do i=1,nx + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/4GB/remeshy_tag.f b/CodesEnVrac/Remesh/4GB/remeshy_tag.f new file mode 100644 index 000000000..9330ef922 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshy_tag.f @@ -0,0 +1,86 @@ + subroutine remeshy_tag(ntag,itag,itype,icfl,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +c case (c) and (d) +c +c if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+xx1*u1-yy1*u2 + ug(jj,ip3,kk)=ug(jj,ip3,kk)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(jj,ip4,kk)=ug(jj,ip4,kk)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c else +c case (d) +c endif + else +c case (c') and (d') +c +c if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(jj,ip0,kk)=ug(jj,ip0,kk)+a0*u1 + ug(jj,ip1,kk)=ug(jj,ip1,kk)+(1.-a0)*u1+(1.-b2)*u2 + ug(jj,ip2,kk)=ug(jj,ip2,kk)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +c else +c case (d') +c endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/Remesh/4GB/remeshz_l2.f b/CodesEnVrac/Remesh/4GB/remeshz_l2.f new file mode 100644 index 000000000..301471c39 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshz_l2.f @@ -0,0 +1,82 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx + + do i=1,nx + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/4GB/remeshz_tag.f b/CodesEnVrac/Remesh/4GB/remeshz_tag.f new file mode 100644 index 000000000..805bf055c --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/remeshz_tag.f @@ -0,0 +1,86 @@ + subroutine remeshz_tag(ntag,itag,itype,icfl,kk,jj) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer itag(*),itype(*),icfl(*) + + dxinv=1./dx2 + x0=xmin + + do n=1,ntag,2 + i=itag(n) + ii=itag(n+1) + x=xp(i) + y=xp(ii) + u1=up(i) + u2=up(ii) + if (itype(i).eq.0) then +c case (c) and (d) +c +c if (vx(ii)*cfl-icfl(ii).lt.0) then + ip1 = int((x-x0)*dxinv) + jp1 = nint((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + yy0=yy1+1 + yy2=1-yy1 + ip0=ip1-1 + ip2=ip1+1 + ip3=ip1+2 + ip4=ip1+3 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + ip3=mod(ip3+nx2,nx2) +1 + ip4=mod(ip4+nx2,nx2) +1 + a0=-xx1*xx2/2. + a1=xx0*xx2 + b1=yy0*yy2 + b2=yy0*yy1/2. + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+a1*u1+(1.+yy1-b1-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+xx1*u1-yy1*u2 + ug(kk,jj,ip3)=ug(kk,jj,ip3)+(1.-a0-a1-xx1)*u1+b1*u2 + ug(kk,jj,ip4)=ug(kk,jj,ip4)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 +c else +c case (d) +c endif + else +c case (c') and (d') +c +c if (vx(i)*cfl-icfl(i).lt.0) then + ip1 = nint((x-x0)*dxinv) + jp1 = int((y-x0)*dxinv) + xx1 = (x - float(ip1)*dx2-x0)*dxinv + yy1 = (y - float(jp1)*dx2-x0)*dxinv + xx2=1-xx1 + yy0=yy1+1 + ip0=ip1-1 + ip2=ip1+1 + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + a0=-0.5*xx1*xx2 + b2=0.5*yy0*yy1 + ug(kk,jj,ip0)=ug(kk,jj,ip0)+a0*u1 + ug(kk,jj,ip1)=ug(kk,jj,ip1)+(1.-a0)*u1+(1.-b2)*u2 + ug(kk,jj,ip2)=ug(kk,jj,ip2)+b2*u2 +c print*, 'REMESH_TAG ',n,i,ii,ip1,jp1 + +c else +c case (d') +c endif + endif + enddo + + + return + end + + diff --git a/CodesEnVrac/Remesh/4GB/tag_particles.f b/CodesEnVrac/Remesh/4GB/tag_particles.f new file mode 100644 index 000000000..b2a5d0fff --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/tag_particles.f @@ -0,0 +1,181 @@ + subroutine tag_particles(npart,npart_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + include 'param.i' + include 'param.h' + + common/remesh/xp(npg),xp1(npg),up(npg),vx(npg) + + integer icfl(*),itype(*),itype_aux(*),itag(*) + dimension xp_aux(*),up_aux(*),vx_aux(*) + + integer ntype(npg),ncfl(npg),npart_bl(npg),i_nbl(npg) + dimension amin_lambda(npg) + + +c ntype(nbl) : type de bloc (1=centre ou 0=left) pour choix de la formule +c remaillage +c itype(npart) : idem pour les particules de ces blocks +c ncfl(nbl)=cfl-nint ou cfl-int selon le type +c icfl(npart) : idem pour particules de cs blocks +c xp_aux(npart_aux): particles inside the blocks, for plain remeshing +c itype_aux(npart_aux) : type de block pour ces particules +c ntag: number of tagged particles, for special remeshing +c itag(ntag): pointer for tagged particles +c i_nbl(nbl) indice de la derniere particule du bloc nbl + +c cfl=delt/dx + + x0=xmin + + + m=np_bl+1 + nblock=nx/(m) + dx_bl=float(m)*dx + dx_bl_inv=1./dx_bl + +c on range les partucles par block +c et on calcule lambda moyen pour chaque block + + do nbl=1,nblock + amin_lambda(nbl)=111. + npart_bl(nbl)=0 + i_nbl(nbl)=0 + enddo + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(i)*cfl) + npart_bl(nbl)=npart_bl(nbl)+1 + i_nbl(nbl)=i + enddo + +c on ajoute la particule a droite du bloc (si elle existe) pour calculer +c le amin_lambda, pour eviter pbms a l'interface entre blocs de meme type +c (a corriger: pour l'instant je ne regarde pas le dernier bloc avec xp(1) + + do nbl=1,nblock-1 + if (i_nbl(nbl).ne.0) then + ii=i_nbl(nbl) + if ((ii.lt.npart).and.(xp(ii+1).lt.xp(ii)+1.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(ii+1)*cfl) + endif + endif + enddo + +c le dernier bloc (a la main ..) + + nbl=nblock + if (i_nbl(nbl).ne.0) then + if ((xp(npart).ge.xmax-1.5*dx).and.(xp(1).lt.xmin+0.5*dx)) then + amin_lambda(nbl)=amin1(amin_lambda(nbl),vx(1)*cfl) + endif + endif + + +c et on en deduit type de block (1=centre vs 0=left) et l'indice du bloc + + + do nbl=1,nblock + if (amin_lambda(nbl).lt.nint(amin_lambda(nbl))) then + ntype(nbl)=1 + ncfl(nbl)=nint(amin_lambda(nbl)) + else + ntype(nbl)=0 + ncfl(nbl)=int(amin_lambda(nbl)) + if (amin_lambda(nbl).lt.0) ncfl(nbl)=int(amin_lambda(nbl))-1 + endif + +c print*,'nbl et type',nbl, ntype(nbl),amin_lambda(nbl) + enddo +c +c on affecte le type et l'indice cfl du bloc sur ses particules + + + do i=1,npart + nbl=1+int((xp(i)-x0+0.00001)*dx_bl_inv) + itype(i)=ntype(nbl) + icfl(i)=ncfl(nbl) +c print*,'nbl et type',nbl,i, itype(i),icfl(i) + enddo + + +c on tagge les particules entre les blocs successifs non vides qui: +c sont de type et indice cfl differents +c (cases b,c,b',c' du papier) + + ntag=0 + npart_aux=0 + j=2 + jc=0 + do i=2,npart-1 + j=j+jc + if (j.ge.npart) go to 111 + jj=j+1 +c print*,j,icfl(j),icfl(jj),itype(j),itype(jj) + if ((icfl(j).ne.icfl(jj)).and.(itype(j).ne.itype(jj)) + 1 .and.(xp(jj).le.xp(j)+1.5*dx)) then + ntag=ntag+1 + itag(ntag)=j + ntag=ntag+1 + itag(ntag)=j+1 +c print*,' **** TAGGED ',j,xp(j),itype(j),icfl(j),vx(j)*delt/dx, +c 1 nint(vx(j)*delt/dx) +c print*,' **** TAGGED ',jj,xp(jj),itype(jj),icfl(jj),vx(jj)*delt/dx, +c 1 nint(vx(jj)*delt/dx) + jc=2 + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(j) + up_aux(npart_aux)=up(j) + vx_aux(npart_aux)=vx(j) + itype_aux(npart_aux)=itype(j) +c print*,'REGULAR',npart_aux,xp_aux(npart_aux),up_aux(npart_aux) +c 1 ,vx_aux(j)*delt/dx,icfl(j) + jc=1 + endif + enddo + +111 continue + +c on regarde a part la premiere et la derniere particule +c (je ne sais pas faire autrement pour l'instant) + + if (npart.ge.1) then + + if ((icfl(1).ne.icfl(npart)).and.(itype(1).ne.itype(npart)) + 1 .and.(xp(npart).ge.xp(1)+(float(nx)-1.5)*dx) + 1 .and.(itag(ntag).ne.npart)) then +c 1 ) then + ntag=ntag+1 + itag(ntag)=npart + ntag=ntag+1 + itag(ntag)=1 +c print*,' TAGGED ',j,xp(j),icfl(j) + else + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(1) + up_aux(npart_aux)=up(1) + vx_aux(npart_aux)=vx(1) + itype_aux(npart_aux)=itype(1) +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + if (npart.gt.1) then + npart_aux=npart_aux+1 + xp_aux(npart_aux)=xp(npart) + up_aux(npart_aux)=up(npart) + vx_aux(npart_aux)=vx(npart) + itype_aux(npart_aux)=itype(npart) + endif +c print*, ' REGULAR ',npart_aux,up_aux(npart_aux),xp_aux(npart_aux) + endif + + endif + + + +c if (ntag.ne.0) print*,'npart,NTAG, NPART_AUX = ',npart,ntag,npart_aux + + + return + end diff --git a/CodesEnVrac/Remesh/4GB/velox_x.f b/CodesEnVrac/Remesh/4GB/velox_x.f new file mode 100644 index 000000000..19d7d5e9f --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/velox_x.f @@ -0,0 +1,106 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_x(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g1(npg) + + do 10 i=1,npart + g1(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/4GB/velox_y.f b/CodesEnVrac/Remesh/4GB/velox_y.f new file mode 100644 index 000000000..524952436 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/velox_y.f @@ -0,0 +1,104 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_y(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),gg2(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g2(npg) + + do 10 i=1,npart + g2(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g2(i)= g2(i) + gg2(jp1,ip1,kp1)*a1*b1*c1 + g2(i)= g2(i) + gg2(jp1,ip2,kp1)*a2*b1*c1 + g2(i)= g2(i) + gg2(jp2,ip1,kp1)*a1*b2*c1 + g2(i)= g2(i) + gg2(jp2,ip2,kp1)*a2*b2*c1 + g2(i)= g2(i) + gg2(jp1,ip1,kp2)*a1*b1*c2 + g2(i)= g2(i) + gg2(jp1,ip2,kp2)*a2*b1*c2 + g2(i)= g2(i) + gg2(jp2,ip1,kp2)*a1*b2*c2 + g2(i)= g2(i) + gg2(jp2,ip2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/4GB/velox_z.f b/CodesEnVrac/Remesh/4GB/velox_z.f new file mode 100644 index 000000000..1130201e8 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/velox_z.f @@ -0,0 +1,105 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_z(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g3(npg) + + + do 10 i=1,npart + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g3(i)= g3(i) + gg3(jp1,kp1,ip1)*a1*b1*c1 + g3(i)= g3(i) + gg3(jp1,kp1,ip2)*a2*b1*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip1)*a1*b2*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip2)*a2*b2*c1 + g3(i)= g3(i) + gg3(jp1,kp2,ip1)*a1*b1*c2 + g3(i)= g3(i) + gg3(jp1,kp2,ip2)*a2*b1*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip1)*a1*b2*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip2)*a2*b2*c2 + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/4GB/x_advect.f b/CodesEnVrac/Remesh/4GB/x_advect.f new file mode 100644 index 000000000..7414f8c38 --- /dev/null +++ b/CodesEnVrac/Remesh/4GB/x_advect.f @@ -0,0 +1,107 @@ + subroutine x_advect(dt,np_bl) + +c version pour GB + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +c routine d'advection en x : +c parcours des lignes horozontales +c intilisation de particules +c calcul des vitesses par RK2 +c tag des particules en focntion des varaitions de cfl +c push and remesh + +c cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +c 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +c initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + +c GB modif pour laversion avec correction: +c mettre en c les lignes qui suivent +c et remplacer par call tag_particles +c modifs simlaires a faire dans y_advect et z_advect + + call velox_x(np,j,k) +cc do n=1,np +cc xp_aux(n)=xp0(n) +cc vx_aux(n)=vx(n) +c itype(n)=1 +c enddo + + call tag_particles(np,np_aux,ntag,np_bl, + 1 icfl,itype,itype_aux,itag, + 1 xp_aux,up_aux,vx_aux) + + if (ntag.ne.0) then + do n=1,ntag + ii=itag(n) + xp(ii)=xp0(ii)+dt*vx(ii) + if (xp(ii).gt.xmax) xp(ii)=xp(ii)-xmax+xmin + enddo + endif + +222 continue +c GB: changer dans les lignes qui suivent np en np_aux : + do n=1,np_aux + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np_aux,xp_aux,up_aux,itype,jr,kr) +c +c GB : remesh des particules tagguees: +c appeler remeshx_tag et mettre pour les 2 derniers arguments +c les memes parametres que dans remeshx (remeshy ou remeshz si y_advect +c ou z_advect) + if (ntag.ne.0) call remeshx_tag(ntag,itag,itype,icfl,jr,kr) + +c fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/arrays.h b/CodesEnVrac/Remesh/FFTPAR/4GB/arrays.h new file mode 100755 index 000000000..e45762cf0 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/arrays.h @@ -0,0 +1,10 @@ + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),vx(npg) + + diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/param.h b/CodesEnVrac/Remesh/FFTPAR/4GB/param.h new file mode 100755 index 000000000..e6e8a2c9d --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/param.h @@ -0,0 +1,3 @@ + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,dx1 + common nx2,ny2,nz2,dx2,nx3 + common circlim,cfl,nx,dx \ No newline at end of file diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/param.i b/CodesEnVrac/Remesh/FFTPAR/4GB/param.i new file mode 100755 index 000000000..bb8dbac4a --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/param.i @@ -0,0 +1,3 @@ + parameter(npm=2100000,npgx=256,npgy=256,npgz=256) + parameter(npg=256) + diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/remeshx_l2.f b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshx_l2.f new file mode 100755 index 000000000..51e6cdf6b --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshx_l2.f @@ -0,0 +1,96 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + endif + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/remeshy_l2.f b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshy_l2.f new file mode 100755 index 000000000..001f52cf2 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshy_l2.f @@ -0,0 +1,82 @@ + subroutine remeshy(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx + + do i=1,nx + ug(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,ip0,kk) = ug(jj,ip0,kk) + g1*a0 + ug(jj,ip1,kk) = ug(jj,ip1,kk) + g1*a1 + ug(jj,ip2,kk) = ug(jj,ip2,kk) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/remeshz_l2.f b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshz_l2.f new file mode 100755 index 000000000..301471c39 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/remeshz_l2.f @@ -0,0 +1,82 @@ + subroutine remeshz(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx + + do i=1,nx + ug(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx,nx) +1 + ip0=mod(ip0+nx,nx) +1 + ip2=mod(ip2+nx,nx) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(jj,kk,ip0) = ug(jj,kk,ip0) + g1*a0 + ug(jj,kk,ip1) = ug(jj,kk,ip1) + g1*a1 + ug(jj,kk,ip2) = ug(jj,kk,ip2) + g1*a2 + + endif + enddo + + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/velox_x.f b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_x.f new file mode 100755 index 000000000..19d7d5e9f --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_x.f @@ -0,0 +1,106 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_x(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g1(npg) + + do 10 i=1,npart + g1(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/velox_y.f b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_y.f new file mode 100755 index 000000000..524952436 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_y.f @@ -0,0 +1,104 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_y(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),gg2(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g2(npg) + + do 10 i=1,npart + g2(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g2(i)= g2(i) + gg2(jp1,ip1,kp1)*a1*b1*c1 + g2(i)= g2(i) + gg2(jp1,ip2,kp1)*a2*b1*c1 + g2(i)= g2(i) + gg2(jp2,ip1,kp1)*a1*b2*c1 + g2(i)= g2(i) + gg2(jp2,ip2,kp1)*a2*b2*c1 + g2(i)= g2(i) + gg2(jp1,ip1,kp2)*a1*b1*c2 + g2(i)= g2(i) + gg2(jp1,ip2,kp2)*a2*b1*c2 + g2(i)= g2(i) + gg2(jp2,ip1,kp2)*a1*b2*c2 + g2(i)= g2(i) + gg2(jp2,ip2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/velox_z.f b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_z.f new file mode 100755 index 000000000..1130201e8 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/velox_z.f @@ -0,0 +1,105 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_z(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),gg3(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g3(npg) + + + do 10 i=1,npart + g3(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g3(i)= g3(i) + gg3(jp1,kp1,ip1)*a1*b1*c1 + g3(i)= g3(i) + gg3(jp1,kp1,ip2)*a2*b1*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip1)*a1*b2*c1 + g3(i)= g3(i) + gg3(jp2,kp1,ip2)*a2*b2*c1 + g3(i)= g3(i) + gg3(jp1,kp2,ip1)*a1*b1*c2 + g3(i)= g3(i) + gg3(jp1,kp2,ip2)*a2*b1*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip1)*a1*b2*c2 + g3(i)= g3(i) + gg3(jp2,kp2,ip2)*a2*b2*c2 + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/x_advect.f b/CodesEnVrac/Remesh/FFTPAR/4GB/x_advect.f new file mode 100755 index 000000000..04ca4196c --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/x_advect.f @@ -0,0 +1,80 @@ + subroutine x_advect(dt,np_bl) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +c routine d'advection en x : +c parcours des lignes horozontales +c intilisation de particules +c calcul des vitesses par RK2 +c tag des particules en focntion des varaitions de cfl +c push and remesh + +c cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +c 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +c initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np,xp_aux,up_aux,itype,jr,kr) + +c fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/y_advect.f b/CodesEnVrac/Remesh/FFTPAR/4GB/y_advect.f new file mode 100755 index 000000000..d12899a84 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/y_advect.f @@ -0,0 +1,65 @@ + subroutine y_advect(dt,np_bl) + + include 'param.i' + include 'param.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + + external velox + + +c on balaie le lignes verticales + + do k=1,nx + zz=xmin+float(k-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do j=1,nx +c initiliasation particules sur la ligne j + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(j-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + do n=1,np + xx=xp_aux(n) + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np,xp_aux,up_aux,itype,ir,kr) +c fin de ligne i : + + endif + enddo + enddo + + return + end diff --git a/CodesEnVrac/Remesh/FFTPAR/4GB/z_advect.f b/CodesEnVrac/Remesh/FFTPAR/4GB/z_advect.f new file mode 100755 index 000000000..9708766ed --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/4GB/z_advect.f @@ -0,0 +1,64 @@ + subroutine z_advect(dt,np_bl) + + include 'param.i' + include 'param.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + + external velox + +c on balaie le lignes azimuthales + + do j=1,nx + zz=xmin+float(j-1)*dx + do i=1,nx + np=0 + yy=xmin+float(i-1)*dx + do k=1,nx +c initiliasation particules sur la ligne k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(k-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + do n=1,np + xx=xp_aux(n) + call velox_z(i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo ir=i + jr=j + call remeshz(np,xp_aux,up_aux,itype,ir,jr) +c fin de ligne k : + + endif + enddo + enddo + + return + end + diff --git a/CodesEnVrac/Remesh/FFTPAR/Makefile b/CodesEnVrac/Remesh/FFTPAR/Makefile new file mode 100755 index 000000000..061fa9d5f --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/Makefile @@ -0,0 +1,39 @@ +F90 = /opt/openmpi/bin/mpif90 +CODE = fft_2 +FILES = precision.f90 fileio.f90 string.f90 parser.f90 mpi_init.f90 data.f90 random.f90 transforms.f90 initscal.f90 parinit.f90 tg_init.f90 init_plane_jet.f90 init_test_case.f90 solver.f90 forcing.f90 tools.f90 main.f90 postprocesstools.f90 postprocess.f90 postprocess5.f90 postprocessparaview.f90 discretisation2.f90 postprocess6.f90 postprocess7.f90 discretisation3.f90 x_advec.f90 y_advec.f90 z_advec.f90 lesmodel.f90 +#lesmodel.f90 lesmodelsca.f90 lesmodelsca2.f90 lestools.f90 lesmodelsca3.f90 lesmodelsca4.f90 lesmodelsca5.f90 lesmodelsca6.f90 lesmodelsca7.f90 lesmodelsca8.f90 lesmodelsca9.f90 lesmodelsca10.f90 + +LIB = /opt/fftw/lib +LIBFFTW = -L$(LIB) -lfftw3 +FFTWINC = -I/opt/fftw/include + +BLAS_DIR = /opt/lapack/ +BLAS_LIB = -L$(BLAS_DIR) -lblas +LAPACK_DIR = /opt/lapack +LAPACK_LIB = -L$(LAPACK_DIR) -llapack + + +OFILES = $(FILES:.f90=.o) +MODFILES = $(FILES:.f90=.mod) + +FFLAGS = -O3 +# -qzerosize + +.SUFFIXES: .o .f90 + +default:Makefile + @make $(OFILES) + @make $(CODE) + + +$(CODE):$(OFILES) Makefile + $(F90) $(OFILES) $(FFLAGS) -o $(CODE) $(LIBFFTW) $(LAPACK_LIB) $(BLAS_LIB) + + + +clean: + rm -f *.o *.mod + + +.f90.o: + $(F90) $(FFTWINC) $(FFLAGS) -c $*.f90 diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/arrays.h b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/arrays.h new file mode 100755 index 000000000..e45762cf0 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/arrays.h @@ -0,0 +1,10 @@ + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & vxg(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),vx(npg) + + diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.h b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.h new file mode 100755 index 000000000..e6e8a2c9d --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.h @@ -0,0 +1,3 @@ + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,dx1 + common nx2,ny2,nz2,dx2,nx3 + common circlim,cfl,nx,dx \ No newline at end of file diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.i b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.i new file mode 100755 index 000000000..bb8dbac4a --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/param.i @@ -0,0 +1,3 @@ + parameter(npm=2100000,npgx=256,npgy=256,npgz=256) + parameter(npg=256) + diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/remeshx_l2.f b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/remeshx_l2.f new file mode 100755 index 000000000..51e6cdf6b --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/remeshx_l2.f @@ -0,0 +1,96 @@ + subroutine remeshx(np1,xp1,up1,itype,jj,kk) + + + include 'param.i' + include 'param.h' + include 'arrays.h' + + dimension xp1(*),up1(*),itype(*) + + + +c remaillage des particules fluides + + dxinv=1./dx2 + + do i=1,nx2 + ug(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up1(n) + x = xp1(n) + + if (itype(n).eq.0) then + + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + +c print*, ' IPO ..',n,xp1(n),ip0,ip1,ip2 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c left-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 +c +c center-Lambda2: +c + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + ug(ip0,jj,kk) = ug(ip0,jj,kk) + g1*a0 + ug(ip1,jj,kk) = ug(ip1,jj,kk) + g1*a1 + ug(ip2,jj,kk) = ug(ip2,jj,kk) + g1*a2 + + endif + enddo + + go to 222 + do k=3,nx2-2 + do j=1,nx2 + do i=1,nx2 + if (ug(i,j,k).gt.1.2) then + print*,'BOUM', i,j,k,ug(i,j,k) + goto 222 + endif + enddo + enddo + enddo + +222 continue + RETURN + END + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/velox_x.f b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/velox_x.f new file mode 100755 index 000000000..19d7d5e9f --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/velox_x.f @@ -0,0 +1,106 @@ +C~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + SUBROUTINE velox_x(npart,j,k) + +C +C Interpolation routine with M'4 +C +c geometry=unit box, periodic in x and y +c last ponits in z direction assume extension by continuity +c that is gg(i,j,0)=gg(i,j,1) gg(i,j,m+1)=gg(i,j,m) + + +c---------------------------------------------------------------- + + include 'param.i' + include 'param.h' + + + COMMON/GRID/ omg1(npgx,npgy,npgz), + & omg2(npgx,npgy,npgz),omg3(npgx,npgy,npgz), + & gg1(npgx,npgy,npgz),vyg(npgx,npgy,npgz),vzg(npgx,npgy,npgz), + & psi1(npgx,npgy,npgz),psi2(npgx,npgy,npgz),psi3(npgx,npgy,npgz), + & strg1(npgx,npgy,npgz),strg2(npgx,npgy,npgz), + & strg3(npgx,npgy,npgz),ug(npg,npg,npg) + + common/remesh/xp0(npg),xp(npg),up(npg),g1(npg) + + do 10 i=1,npart + g1(i)=0. +10 continue + + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + +c-------------------------------------------------------------------- +c- PART II : Determination of the circulation of each particle +c-------------------------------------------------------------------- + + x0=xmin + y0=ymin + z0=zmin + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2=1-yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2=1-zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + + DO 20 i = 1,npart + + x = XP(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + +C get the circulations from the nine neighboring cells + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 +C +C on repositionne les points de grille par periodicite +C entre 0 et m-1, puis on numerote de 1 a m +C + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 +C +C The M'4 scheme +C + a1 = xx2 + a2 = xx1 + g1(i)= g1(i) + gg1(ip1,jp1,kp1)*a1*b1*c1 + g1(i)= g1(i) + gg1(ip2,jp1,kp1)*a2*b1*c1 + g1(i)= g1(i) + gg1(ip1,jp2,kp1)*a1*b2*c1 + g1(i)= g1(i) + gg1(ip2,jp2,kp1)*a2*b2*c1 + g1(i)= g1(i) + gg1(ip1,jp1,kp2)*a1*b1*c2 + g1(i)= g1(i) + gg1(ip2,jp1,kp2)*a2*b1*c2 + g1(i)= g1(i) + gg1(ip1,jp2,kp2)*a1*b2*c2 + g1(i)= g1(i) + gg1(ip2,jp2,kp2)*a2*b2*c2 + + +20 CONTINUE + + + + RETURN + END diff --git a/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/x_advect.f b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/x_advect.f new file mode 100755 index 000000000..04ca4196c --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/SRC_COTTET/x_advect.f @@ -0,0 +1,80 @@ + subroutine x_advect(dt,np_bl) + + include 'param.i' + include 'param.h' + include 'arrays.h' + + integer icfl(npg),itype(npg),itype_aux(npg),itag(npg) + dimension xp_aux(npg),up_aux(npg),vx_aux(npg) + + +c routine d'advection en x : +c parcours des lignes horozontales +c intilisation de particules +c calcul des vitesses par RK2 +c tag des particules en focntion des varaitions de cfl +c push and remesh + +c cfl=dt/dx utilisee pour calucls de blocs /corrections + cfl=dt/dx + + npart=0 + ntag_total=0 + + +c 1) on balaie le tableau ug par lignes horizontales + + do k=1,nx + zz=xmin+float(k-1)*dx + do j=1,nx + np=0 + yy=xmin+float(j-1)*dx + do i=1,nx +c initiliasation particules sur la ligne j,k + if (abs(ug(i,j,k)).gt.circlim) then + np=np+1 + up(np)=ug(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=ug(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + endif + enddo +c tag, push and remesh sur la ligne + if (np.ne.0) then + +c evaluation des vitesse pour RK2 + + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_x(np,j,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + +222 continue + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + jr=j + kr=k + call remeshx(np,xp_aux,up_aux,itype,jr,kr) + +c fin de ligne j,k: + npart=npart+np + ntag_total=ntag_total+ntag + endif + enddo + enddo + + print*, 'NPART, NTAG ', npart,ntag_total + return + end diff --git a/CodesEnVrac/Remesh/FFTPAR/TAGS b/CodesEnVrac/Remesh/FFTPAR/TAGS new file mode 100644 index 000000000..5d11231d9 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/TAGS @@ -0,0 +1,242 @@ + +4GB/arrays.h,40 + & strg3(npgx,npgy,npgz),ug(6,292 + +4GB/param.h,504 + common xmin,1,0 + common xmin,xmax,1,0 + common xmin,xmax,ymin,1,0 + common xmin,xmax,ymin,ymax,1,0 + common xmin,xmax,ymin,ymax,zmin,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,1,0 + common nx2,2,58 + common nx2,ny2,2,58 + common nx2,ny2,nz2,2,58 + common nx2,ny2,nz2,dx2,2,58 + +4GB/remeshx_l2.f,32 + subroutine remeshx(1,0 + +4GB/remeshy_l2.f,32 + subroutine remeshy(1,0 + +4GB/remeshz_l2.f,32 + subroutine remeshz(1,0 + +4GB/velox_x.f,27 + SUBROUTINE velox_x(2,68 + +4GB/velox_y.f,27 + SUBROUTINE velox_y(2,68 + +4GB/velox_z.f,27 + SUBROUTINE velox_z(2,68 + +4GB/x_advect.f,26 + subroutine x_advect(1,0 + +4GB/y_advect.f,26 + subroutine y_advect(1,0 + +4GB/z_advect.f,26 + subroutine z_advect(1,0 + +data.f90,189 +subroutine data_init37,816 +subroutine data_write130,2848 +subroutine tab_write(205,5283 +subroutine tab_write_ne(264,6725 +subroutine data_read327,8255 +subroutine data_filter_sc389,9709 + +discretisation2.f90,32 +subroutine discretisation2(1,0 + +discretisation3.f90,32 +subroutine discretisation3(1,0 + +fileio.f90,67 + integer function iopen(16,283 + integer function iclose(44,918 + +forcing.f90,98 +subroutine forcing_init15,132 +subroutine force_compute93,1985 +function force_spectrum(162,4142 + +init_plane_jet.f90,30 +subroutine init_plane_jet1,0 + +init_test_case.f90,30 +subroutine init_test_case1,0 + +initscal.f90,27 +subroutine init_scalar1,0 + +lesmodel.f90,28 +subroutine dynsmagmodel1,0 + +main.f90,25 +subroutine main_init1,0 + +mpi_init.f90,95 +subroutine mpi_initialize32,544 +subroutine parallel_max(159,2557 +subroutine barrier175,2822 + +parinit.f90,24 +subroutine hit_init1,0 + +parser.f90,634 + subroutine parser_pack(30,838 + subroutine parser_spread47,1362 + subroutine parser_newentry(66,1873 + subroutine parser_fieldfortag(86,2422 + subroutine parser_is_defined(106,2946 + subroutine parser_readlogical(119,3276 + subroutine parser_readint(142,3938 + subroutine parser_readfloat(165,4586 + subroutine parser_readchar(188,5246 + subroutine parser_getsize(211,5930 + subroutine parser_readintarray(242,6964 + subroutine parser_readfloatarray(262,7516 + subroutine parser_readfloatarray2D(282,8139 + subroutine parser_readchararray(302,8712 +subroutine parser_init324,9327 +subroutine parser_parsefile(339,9613 + +postprocess.f90,27 +subroutine postprocess1,0 + +postprocess5.f90,28 +subroutine postprocess51,0 + +postprocess6.f90,28 +subroutine postprocess61,0 + +postprocess7.f90,28 +subroutine postprocess71,0 + +postprocessparaview.f90,134 +subroutine dump_data(1,0 +subroutine dump_geometry66,1777 +subroutine dump_geometry_scalar169,4594 +subroutine dump_data_sc(275,7511 + +postprocesstools.f90,1112 +subroutine cc_pdf(1,0 +subroutine c_pdf_sca(62,1572 +subroutine c_pdf_sca_fix(115,2951 +subroutine c_pdf(156,4146 +subroutine cn_pdf(209,5499 +subroutine cp_pdf(267,6937 +subroutine var_skew_fla(325,8374 +subroutine corre(345,8811 +subroutine moyen_reg1(365,9299 +subroutine moyen_reg2(393,10002 +subroutine moyensc(421,10706 +subroutine moyen(442,11151 +subroutine moyen_ysc(463,11578 +subroutine moyen_y(486,12053 +subroutine mean_cond_2(509,12504 +subroutine mean_cond(590,14960 +subroutine physboxfilter(646,16674 +subroutine specboxfiltersc(704,18225 +subroutine specboxfilter(755,20360 +subroutine speccutboxfilter2sc(805,22360 +subroutine speccutboxfilter2(866,24754 +subroutine speccutboxfilter(927,27007 +subroutine speccutboxfiltersc(988,29256 +subroutine specgaussfiltersc(1051,31648 +subroutine specgaussfilter(1081,32529 +subroutine curl(1111,33342 +subroutine gradntsc(1154,34803 +subroutine gradientsc(1191,35988 +subroutine gradient(1228,37128 +subroutine cutgradient(1265,38154 +subroutine speccutfilter(1310,39464 +subroutine speccutfiltersc(1345,40327 +subroutine turbulent_region(1379,41257 + +random.f90,32 +subroutine random_init100,4137 + +solver.f90,193 +subroutine solver_init58,1521 +subroutine solver_step242,6089 +subroutine non_linear404,10573 +subroutine get_timestep881,23079 +subroutine dealias923,23926 +subroutine fourier_write963,24870 + +SRC_COTTET/arrays.h,40 + & strg3(npgx,npgy,npgz),ug(6,292 + +SRC_COTTET/param.h,504 + common xmin,1,0 + common xmin,xmax,1,0 + common xmin,xmax,ymin,1,0 + common xmin,xmax,ymin,ymax,1,0 + common xmin,xmax,ymin,ymax,zmin,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,1,0 + common xmin,xmax,ymin,ymax,zmin,zmax,nx1,ny1,nz1,nt,1,0 + common nx2,2,58 + common nx2,ny2,2,58 + common nx2,ny2,nz2,2,58 + common nx2,ny2,nz2,dx2,2,58 + +SRC_COTTET/remeshx_l2.f,32 + subroutine remeshx(1,0 + +SRC_COTTET/velox_x.f,27 + SUBROUTINE velox_x(2,68 + +SRC_COTTET/x_advect.f,26 + subroutine x_advect(1,0 + +tg_init.f90,23 +subroutine tg_init1,0 + +tools.f90,187 +subroutine dns_stats1,0 +subroutine u_compute231,5617 +subroutine uz_compute253,6018 +subroutine get_spectrum(279,6541 +subroutine get_dns_numbers(416,9373 +subroutine tg_stats582,13668 + +transforms.f90,254 +subroutine forward_transform(15,391 +subroutine backward_transform(76,1692 +subroutine transpose_forward(134,2954 +subroutine transpose_backward(172,3696 +subroutine transform_init219,4446 +subroutine ftran_wrap(241,4801 +subroutine btran_wrap(283,5510 + +x_advec.f90,116 +subroutine x_advec_init25,560 +subroutine x_advec68,1124 +subroutine velox_x(133,2549 +subroutine remeshx(213,3996 + +y_advec.f90,80 +subroutine y_advec1,0 +subroutine velox_y(58,1319 +subroutine remeshy(138,2766 + +z_advec.f90,80 +subroutine z_advec1,0 +subroutine velox_z(58,1319 +subroutine remeshz(138,2766 + +string.f90,0 + +precision.f90,0 diff --git a/CodesEnVrac/Remesh/FFTPAR/data.f90 b/CodesEnVrac/Remesh/FFTPAR/data.f90 new file mode 100755 index 000000000..c73bb9768 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/data.f90 @@ -0,0 +1,605 @@ +module data + use parallel + use precision + use parser + use fileio + use string + implicit none + + + integer :: nvar + + real(WP) :: L + real(WP) :: Ut, le, ld, epsilon, mu,diff + character(len=str_short) :: spectrum + character(len=str_medium) :: spfilename,spfilename2 + + integer :: file_counter,file_fourier + + real(WP), dimension(:,:,:,:), pointer :: data_store + real(WP), dimension(:,:,:), pointer :: data_storesc + real(WP), dimension(:,:,:), pointer :: U + real(WP), dimension(:,:,:), pointer :: V + real(WP), dimension(:,:,:), pointer :: W + real(WP), dimension(:,:,:), pointer :: SC + + type MPI_IO_VAR + real(WP), dimension(:,:,:), pointer :: var + integer :: view + end type MPI_IO_VAR + + type(MPI_IO_VAR), dimension(:), pointer :: MPI_IO_DATA + + integer, dimension(4) :: dims_w + +end module data + +subroutine data_init + + use data + + implicit none + + integer :: gsizes(4),lsizes(4),var,start(4),ierr,nv_fourier + integer :: gsizessc(3),lsizessc(3),startsc(3) + real(WP) :: sch + +! call parser_read('Number of points',nx) +! call parser_read('Number of points for scalar',nxsc) + print*,'nx,nxsc',nx,nxsc + call parser_read('Length of domain', L) + call parser_read('Spectrum form',spectrum) + call parser_read('Viscosity',mu,1e-02_WP) + call parser_read('Schmidt number',sch,0.7_WP) + diff = mu/sch + + ny = nx + nz = nx + nvar = 3 + nv_fourier = 3 + nysc = nxsc + nzsc = nxsc + + allocate(data_store(ns1,ns2,ns3,nvar)) + allocate(data_storesc(ns1sc,ns2sc,ns3sc)) + + data_store = 0.0_WP + data_storesc = 0.0_WP + U => data_store(:,:,:,1); ! names(1) = 'U' + V => data_store(:,:,:,2); ! names(2) = 'V' + W => data_store(:,:,:,3); ! names(3) = 'W' + SC => data_storesc(:,:,:); ! names(4) = 'P' + + + dims_w(1) = nx + dims_w(2) = ny + dims_w(3) = nz + dims_w(4) = 3 + + allocate(MPI_IO_DATA(dims_w(4)+1)) + + do var = 1,dims_w(4) + MPI_IO_DATA(var)%var => data_store(:,:,:,var) + enddo + MPI_IO_DATA(4)%var => data_storesc(:,:,:) + + gsizes(1) = nx + gsizes(2) = ny + gsizes(3) = nz + gsizes(4) = dims_w(4) + + lsizes(1) = ns1 + lsizes(2) = ns2 + lsizes(3) = ns3 + lsizes(4) = 1 + + start(1) = nxs-1 + start(2) = nys-1 + start(3) = nzs-1 + + + do var = 1, dims_w(4) + start(4) = var -1 + call MPI_TYPE_CREATE_SUBARRAY(4,gsizes,lsizes,start,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,MPI_IO_DATA(var)%view,ierr) + call MPI_TYPE_COMMIT(MPI_IO_DATA(var)%view,ierr) + end do + + gsizessc(1) = nxsc + gsizessc(2) = nysc + gsizessc(3) = nzsc + + lsizessc(1) = ns1sc + lsizessc(2) = ns2sc + lsizessc(3) = ns3sc + + startsc(1) = nxssc-1 + startsc(2) = nyssc-1 + startsc(3) = nzssc-1 + + + call MPI_TYPE_CREATE_SUBARRAY(3,gsizessc,lsizessc,startsc,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,MPI_IO_DATA(4)%view,ierr) + call MPI_TYPE_COMMIT(MPI_IO_DATA(4)%view,ierr) + + + file_counter = 0 + file_fourier = 0 +end subroutine data_init + +subroutine data_write + + use parallel + use data + implicit none + + + integer :: ifile, ierr, var, data_size + integer, dimension(MPI_STATUS_SIZE) :: status + integer(KIND=MPI_OFFSET_KIND) :: disp + character(len=str_medium) :: filename,buffer + + logical :: file_is_there + + file_counter = file_counter+1 + + call parser_read('Data file to write',filename) + write(buffer,'(I3)') file_counter + spfilename = trim(adjustl(filename))//'_sp_'//trim(adjustl(buffer)) + spfilename2 = trim(adjustl(filename))//'_sz_'//trim(adjustl(buffer)) + call get_dns_numbers(0) + + filename = trim(filename) + write(buffer,'(I3)') file_counter + filename = trim(adjustl(filename))//'-'//trim(adjustl(buffer)) + + + inquire(file=filename, exist=file_is_there) + if (file_is_there) call MPI_FILE_DELETE(filename,MPI_INFO_NULL,ierr) + call MPI_FILE_OPEN(MPI_COMM_WORLD,filename,MPI_MODE_WRONLY+MPI_MODE_CREATE, & + MPI_INFO_NULL,ifile,ierr) + + ! Write header + if (rank.eq.0) then + ! Write dimensions + call MPI_FILE_WRITE(ifile,dims_w,4,MPI_INTEGER,status,ierr) + end if +!!$ print*,dims_w + +!!$ if (rank.eq.0) then +!!$ print *,' Computed values before writing ',MPI_IO_DATA(2)%var(1:5,1,3) +!!$ print *,' data values from datastore ', data_store(nxs:nxs+5,nys,nzs,2) +!!$ endif + + disp = 4*4 + data_size = ns1*ns2*ns3 + do var = 1,dims_w(4) + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,MPI_IO_DATA(var)%view,& + &"native",MPI_INFO_NULL,ierr) + call MPI_FILE_WRITE_ALL(ifile,MPI_IO_DATA(var)%var,data_size,& + &MPI_REAL_WP,status,ierr) + enddo + + disp = 4_MPI_OFFSET_KIND*4 + 8_MPI_OFFSET_KIND*ns1*ns1*ns1*3 + data_size = ns1sc*ns2sc*ns3sc + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,MPI_IO_DATA(4)%view,& + &"native",MPI_INFO_NULL,ierr) + call MPI_FILE_WRITE_ALL(ifile,MPI_IO_DATA(4)%var,data_size,& + &MPI_REAL_WP,status,ierr) +! if(rank.eq.0) print*,' size data write 1 : ',4*4 + 8*ns1*ns1*ns1*3 + 8*nproc*ns1sc*ns2sc*ns3sc +! if(rank.eq.0) print*,' size data write 2 : ',ns1,nproc,ns1sc,ns2sc,ns3sc +! if(rank.eq.0) print*,' size data write 3 : ',disp + +!!$ if (rank.eq.0) then +!!$ print *,' test writing ',MPI_IO_DATA(1)%var(1,1,1) +!!$ print *,' test writing ',MPI_IO_DATA(2)%var(1,1,1) +!!$ print *,' test writing ',MPI_IO_DATA(3)%var(1,1,1) +!!$ print *,' test writing ',MPI_IO_DATA(4)%var(1,1,1) +!!$ endif + + call MPI_FILE_CLOSE(ifile,ierr) + +end subroutine data_write + + +subroutine tab_write(tab,filename) + + use parallel + use data + implicit none + + real(WP) :: tab(ns1,ns2,ns3) + + integer :: ifile, ierr, var, data_size, view1 + integer :: gsize1(4),lsize1(4),start1(4) + integer, dimension(MPI_STATUS_SIZE) :: status + integer(KIND=MPI_OFFSET_KIND) :: disp + character*13 :: filename,buffer + + logical :: file_is_there + + inquire(file=filename, exist=file_is_there) + if (file_is_there) call MPI_FILE_DELETE(filename,MPI_INFO_NULL,ierr) + + call MPI_FILE_OPEN(MPI_COMM_WORLD,filename,MPI_MODE_WRONLY+MPI_MODE_CREATE, & + MPI_INFO_NULL,ifile,ierr) + disp = 4*4 + data_size = ns1*ns2*ns3 + + gsize1(1) = nx + gsize1(2) = ny + gsize1(3) = nz + gsize1(4) = 1 + + lsize1(1) = ns1 + lsize1(2) = ns2 + lsize1(3) = ns3 + lsize1(4) = 1 + + start1(1) = nxs-1 + start1(2) = nys-1 + start1(3) = nzs-1 + start1(4) = 0 + + call MPI_TYPE_CREATE_SUBARRAY(4,gsize1,lsize1,start1,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,view1,ierr) + call MPI_TYPE_COMMIT(view1,ierr) + + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,view1,& + &"native",MPI_INFO_NULL,ierr) + + call MPI_FILE_WRITE_ALL(ifile,tab,data_size,& + &MPI_REAL_WP,status,ierr) + + + !if(rank.eq.0) print*,'1',' 1',' 1',tab(1,1,1) + !if(rank.eq.0) print*,'1',' 1',' 32',tab(1,1,32) + !if(rank.eq.7) print*,'1',' 1',' 256',tab(1,1,32) + !if(rank.eq.7) print*,'1',' 128',' 256',tab(1,128,32) + + call MPI_FILE_CLOSE(ifile,ierr) + +end subroutine tab_write + +subroutine tab_write_ne(tab,filename,ns1ne,ns2ne,ns3ne) + + use parallel + use data + implicit none + + + integer :: ns1ne,ns2ne,ns3ne + real(WP) :: tab(ns1ne,ns2ne,ns3ne) + + integer :: ifile, ierr, var, data_size, view1 + integer :: gsize1(4),lsize1(4),start1(4) + integer, dimension(MPI_STATUS_SIZE) :: status + integer(KIND=MPI_OFFSET_KIND) :: disp + character*13 :: filename,buffer + + logical :: file_is_there + + inquire(file=filename, exist=file_is_there) + if (file_is_there) call MPI_FILE_DELETE(filename,MPI_INFO_NULL,ierr) + + call MPI_FILE_OPEN(MPI_COMM_WORLD,filename,MPI_MODE_WRONLY+MPI_MODE_CREATE, & + MPI_INFO_NULL,ifile,ierr) + disp = 4*4 + data_size = ns1ne*ns2ne*ns3ne + + gsize1(1) = ns1ne + gsize1(2) = ns1ne + gsize1(3) = ns1ne + gsize1(4) = 1 + + lsize1(1) = ns1ne + lsize1(2) = ns2ne + lsize1(3) = ns3ne + lsize1(4) = 1 + + start1(1) = 0 + start1(2) = 0 + start1(3) = (rank)*ns3ne + start1(4) = 0 + + call MPI_TYPE_CREATE_SUBARRAY(4,gsize1,lsize1,start1,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,view1,ierr) + call MPI_TYPE_COMMIT(view1,ierr) + + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,view1,& + &"native",MPI_INFO_NULL,ierr) + + call MPI_FILE_WRITE_ALL(ifile,tab,data_size,& + &MPI_REAL_WP,status,ierr) + + + !if(rank.eq.0) print*,'1',' 1',' 1',tab(1,1,1) + !if(rank.eq.0) print*,'1',' 1',' 32',tab(1,1,32) + !if(rank.eq.7) print*,'1',' 1',' 256',tab(1,1,32) + !if(rank.eq.7) print*,'1',' 128',' 256',tab(1,128,32) + + call MPI_FILE_CLOSE(ifile,ierr) + +end subroutine tab_write_ne + + + +subroutine data_read + + use parallel + use data + implicit none + + + integer :: ifile, ierr, var, data_size + integer, dimension(MPI_STATUS_SIZE) :: status + integer(KIND=MPI_OFFSET_KIND) :: disp + character(len=str_medium) :: filename,buffer + + logical :: file_is_there + + + + call parser_read('Data file to read',filename) + filename = trim(filename) + call MPI_FILE_OPEN(MPI_COMM_WORLD,filename,MPI_MODE_RDONLY, & + MPI_INFO_NULL,ifile,ierr) + + ! Write header + if (rank.eq.0) then + ! Write dimensions + call MPI_FILE_READ(ifile,dims_w,4,MPI_INTEGER,status,ierr) + end if + +!!$ if (rank.eq.0) then +!!$ print *,' Computed values before writing ',MPI_IO_DATA(2)%var(1:5,1,3) +!!$ print *,' data values from datastore ', data_store(nxs:nxs+5,nys,nzs,2) +!!$ endif + + + + disp = 4*4 + data_size = ns1*ns2*ns3 + do var = 1,dims_w(4) + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,MPI_IO_DATA(var)%view,& + &"native",MPI_INFO_NULL,ierr) + call MPI_FILE_READ_ALL(ifile,MPI_IO_DATA(var)%var,data_size,& + &MPI_REAL_WP,status,ierr) + enddo + + + disp = 4_MPI_OFFSET_KIND*4 + 8_MPI_OFFSET_KIND*ns1*ns1*ns1*3 + data_size = ns1sc*ns2sc*ns3sc + + + call MPI_FILE_SET_VIEW(ifile,disp,MPI_REAL_WP,MPI_IO_DATA(4)%view,& + &"native",MPI_INFO_NULL,ierr) + + + call MPI_FILE_READ_ALL(ifile,MPI_IO_DATA(4)%var,data_size,& + &MPI_REAL_WP,status,ierr) + + + call MPI_FILE_CLOSE(ifile,ierr) + + +end subroutine data_read + + +subroutine data_filter_sc + + use parallel + use data + + implicit none + + integer :: nx2,ny2,nz2 + integer :: ns1f,ns2f,ns3f + integer :: i,j,k,jl + integer :: nk2, fnys2,fnye2,nkk + + real(WP) :: dk2, pi,kk,grms,buf, xx + + real(WP), dimension(:,:,:), pointer :: tab + real(WP), dimension(:,:,:), pointer :: SCF, UF, VF, WF + + integer :: gsizes(4),lsizes(4),var,start(4),ierr,nv_fourier,ifilter + integer :: gsizessc(3),lsizessc(3),startsc(3) + + call parser_read('final number of points',nx2) + call parser_read('filter',ifilter,0) + + ny2 = nx2 + nz2 = nx2 + + ns1f = nx2 + ns2f = nx2 + ns3f = nx2/nproc + + ! -- filtering operation >> UF, VF, WF, SCF + allocate(SCF(ns1f,ns2f,ns3f)) + allocate(UF(ns1,ns2,ns3)) + allocate(VF(ns1,ns2,ns3)) + allocate(WF(ns1,ns2,ns3)) + + !-- -- -- compute the fourier coefficient + pi = acos(-1.0_WP) + dk2 = 2.0_WP*pi/L + + nk2 = nx2/2+1 + nkk = nxsc/2+1 + + !-- -- -- SPECTRAL SPACE : SC_nx -> SCF_nx2 + + allocate(tab(ns1sc,ns2sc,ns3sc)) + tab=SC**2 + buf=0. + do k=1,ns3sc + do j=1,ns2sc + do i=1,ns1sc + buf=buf+tab(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,grms,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + if (rank.eq.0) print*," U rms =",grms/(2.0*ns1sc**3) + deallocate(tab) + +if (nk2.le.nkk) then + +! do i = 1, ns1sc +! xx = (i-1)*L/(ns1sc-1) +! SC(i,:,:) = sin(xx) +! print*,xx,SC(i,1,1) +! end do + + call discretisation3(SC,SCF,ns1sc,ns2sc,ns3sc,ns1f,ns2f,ns3f) + + UF = U + VF = V + WF = W + call barrier + if (rank.eq.0) print*,'SC done' + +! do i = 1, ns1f +! xx = (i-1)*L/(ns1f-1) +! print*,xx,SCF(i,2,2) +! end do + +else + + call discretisation2(SC,SCF,ns1sc,ns2sc,ns3sc,ns1f,ns2f,ns3f) + UF = U + VF = V + WF = W + +end if + + ns1sc = ns1f + ns2sc = ns2f + ns3sc = ns3f + + allocate(tab(ns1sc,ns2sc,ns3sc)) + tab=SCF**2 + buf=0. + do k=1,ns3sc + do j=1,ns2sc + do i=1,ns1sc + buf=buf+tab(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,grms,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + print*," U rms =",grms/(2.0*ns1sc**3.),ns1sc,ns1f + deallocate(tab) + +!! do i = 1, ns1sc +!! do j = 1, ns2sc +!! do k = 1, ns3sc +!! SCF(i,j,k) = 100*i + 10*j + k +!! print*,'SCF',i,j,k,SCF(i,j,k) +!! end do +!! end do +!! end do + + + ! -- end filtering operation + + deallocate(data_storesc) + deallocate(data_store) + + nxsc = nx2 + nysc = ny2 + nzsc = nz2 + + nxssc = 1 + nxesc = nxsc + nyssc = 1 + nyesc = nysc + nzssc = 1 +(rank)*ns3sc + nzesc = (rank+1)*ns3sc + + allocate(data_store(ns1,ns2,ns3,nvar)) + allocate(data_storesc(ns1sc,ns2sc,ns3sc)) + + data_store = 0.0_WP + data_storesc = 0.0_WP + U => data_store(:,:,:,1); ! names(1) = 'U' + V => data_store(:,:,:,2); ! names(2) = 'V' + W => data_store(:,:,:,3); ! names(3) = 'W' + SC => data_storesc(:,:,:); ! names(4) = 'P' + + + dims_w(1) = nx + dims_w(2) = ny + dims_w(3) = nz + dims_w(4) = 3 + + deallocate(MPI_IO_DATA) + allocate(MPI_IO_DATA(dims_w(4)+1)) + + do var = 1,dims_w(4) + MPI_IO_DATA(var)%var => data_store(:,:,:,var) + enddo + MPI_IO_DATA(4)%var => data_storesc(:,:,:) + + gsizes(1) = nx + gsizes(2) = ny + gsizes(3) = nz + gsizes(4) = dims_w(4) + + lsizes(1) = ns1 + lsizes(2) = ns2 + lsizes(3) = ns3 + lsizes(4) = 1 + + start(1) = nxs-1 + start(2) = nys-1 + start(3) = nzs-1 + + + do var = 1, dims_w(4) + start(4) = var -1 + call MPI_TYPE_CREATE_SUBARRAY(4,gsizes,lsizes,start,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,MPI_IO_DATA(var)%view,ierr) + call MPI_TYPE_COMMIT(MPI_IO_DATA(var)%view,ierr) + end do + + gsizessc(1) = nxsc + gsizessc(2) = nysc + gsizessc(3) = nzsc + + lsizessc(1) = ns1sc + lsizessc(2) = ns2sc + lsizessc(3) = ns3sc + + startsc(1) = nxssc-1 + startsc(2) = nyssc-1 + startsc(3) = nzssc-1 + + + call MPI_TYPE_CREATE_SUBARRAY(3,gsizessc,lsizessc,startsc,& + &MPI_ORDER_FORTRAN,MPI_REAL_WP,MPI_IO_DATA(4)%view,ierr) + call MPI_TYPE_COMMIT(MPI_IO_DATA(4)%view,ierr) + + SC = SCF + U = UF + V = VF + W = WF + deallocate(SCF) + deallocate(UF) + deallocate(VF) + deallocate(WF) +!! do i = 1, ns1sc +!! do j = 1, ns2sc +!! do k = 1, ns3sc +!! print*,'SC',i,j,k,SC(i,j,k) +!! end do +!! end do +!! end do + + file_counter = 0 +end subroutine data_filter_sc + diff --git a/CodesEnVrac/Remesh/FFTPAR/discretisation2.f90 b/CodesEnVrac/Remesh/FFTPAR/discretisation2.f90 new file mode 100755 index 000000000..80e03addb --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/discretisation2.f90 @@ -0,0 +1,157 @@ +subroutine discretisation2(U1,U2,ns1old,ns2old,ns3old,ns1new,ns2new,ns3new) + + use solver + use parallel +! use data + + implicit none + + integer :: ns1old,ns2old,ns3old,ns1new,ns2new,ns3new + integer :: fns1old,fns2old,fns3old,fns1new,fns2new,fns3new + real(WP) :: U1(ns1old,ns2old,ns3old) + real(WP) :: U2(ns1new,ns2new,ns3new) + complex(WP), dimension(:,:,:), allocatable :: U1k, U2k, U1kscloc, U1ksc, tabbuf + integer :: sizemess, tag, ierr, status(MPI_STATUS_SIZE), i, j, k + integer :: yeloc, ysloc, yelocsc, yslocsc, rank2send1, rank2send2, fs1, fe1, fs2, fe2, fnysrank, fnyerank, cptrank + + fns1old = ns1old/2+1 + fns2old = ns1old/nproc + fns3old = ns1old + + fns1new = ns1new/2+1 + fns2new = ns1new/nproc + fns3new = ns1new + + allocate(U1k(fns1old,fns2old,fns3old)) + call ftran_wrap(U1,U1k,ns1old,ns2old,ns3old,fns1old,fns2old,fns3old) + U1k = U1k/real(ns1old**3.0,WP) + + allocate(U1kscloc(fns1old,fns2new,fns3old)) + U1kscloc = 0. + + ! Communication + do cptrank = 0, nproc-1 + + fnysrank = 1 + cptrank*fns2old + fnyerank = (1+cptrank)*fns2old + + ! Envoi + if (fnyerank.le.ns1old/2+1) then ! envoi j de 1 à <nk + rank2send1 = floor(real(fnyerank-1)/real(fns2new)) + rank2send2 = floor(real(fnysrank-1)/real(fns2new)) + fs1 = max(fnysrank,1+rank2send1*fns2new) + fe1 = min(fnyerank,(1+rank2send1)*fns2new) + fs2 = max(fnysrank,1+rank2send2*fns2new) + fe2 = min(fnyerank,(1+rank2send2)*fns2new) + else if(fnysrank.gt.ns1old/2+1) then ! envoi j de >nk à nx + rank2send1 = floor(real(fnyerank+ns1new-ns1old-1)/real(fns2new)) + rank2send2 = floor(real(fnysrank+ns1new-ns1old-1)/real(fns2new)) + fs1 = max(fnysrank,1+rank2send1*fns2new+ns1old-ns1new) + fe1 = min(fnyerank,(1+rank2send1)*fns2new+ns1old-ns1new) + fs2 = max(fnysrank,1+rank2send2*fns2new+ns1old-ns1new) + fe2 = min(fnyerank,(1+rank2send2)*fns2new+ns1old-ns1new) + else if(fnysrank.le.ns1old/2+1.and.fnyerank.gt.ns1old/2+1) then + rank2send1 = floor(real(fnyerank+ns1new-ns1old-1)/real(fns2new)) + rank2send2 = floor(real(fnysrank-1)/real(fns2new)) + fs1 = max(ns1old/2+2,1+rank2send1*fns2new+ns1old-ns1new) + fe1 = min(fnyerank,(1+rank2send1)*fns2new+ns1old-ns1new) + fs2 = max(fnysrank,1+rank2send2*fns2new) + fe2 = min(ns1old/2+1,(1+rank2send2)*fns2new) + end if + if (rank.eq.cptrank) then + ysloc = fs1 - rank * fns2old + yeloc = fe1 - rank * fns2old + if(cptrank.ne.rank2send1) then + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tabbuf(:,:,:) = U1k(:,ysloc:yeloc,:) + tag = fs1+1000*fe1+1000000*1 + call MPI_SEND(tabbuf,sizemess,MPI_COMPLEX_WP,rank2send1,tag,MPI_COMM_WORLD,ierr) + deallocate(tabbuf) + else + if (fnye.le.ns1old/2+1) then + yslocsc = fs1 - rank * fns2new + yelocsc = fe1 - rank * fns2new + else + yslocsc = fs1 - rank * fns2new - ns1old + ns1new + yelocsc = fe1 - rank * fns2new - ns1old + ns1new + end if + U1kscloc(:,yslocsc:yelocsc,:) = U1k(:,ysloc:yeloc,:) + end if + if (rank2send1.ne.rank2send2) then + ysloc = fs2 - rank * fns2old + yeloc = fe2 - rank * fns2old + if (cptrank.ne.rank2send2) then + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tabbuf(:,:,:) = U1k(:,ysloc:yeloc,:) + tag = fs2+1000*fe2+1000000*1 + call MPI_SEND(tabbuf,sizemess,MPI_COMPLEX_WP,rank2send2,tag,MPI_COMM_WORLD,ierr) + deallocate(tabbuf) + else + if (fnye.le.ns1old/2+1) then + yslocsc = fs2 - rank * fns2new + yelocsc = fe2 - rank * fns2new + else + yslocsc = fs2 - rank * fns2new - ns1old + ns1new + yelocsc = fe2 - rank * fns2new - ns1old + ns1new + end if + U1kscloc(:,yslocsc:yelocsc,:) = U1k(:,ysloc:yeloc,:) + end if + end if + else if (rank.eq.rank2send1.and.rank2send1.ne.cptrank) then + fnysrank = 1 + rank*fns2new + fnyerank = (1+rank)*fns2new + if (fnyerank.gt.(ns1new-ns1old+ns1old/2+1)) then + ysloc = fs1 - rank * fns2new + ns1new - ns1old + yeloc = fe1 - rank * fns2new + ns1new - ns1old + else + ysloc = fs1 - rank * fns2new + yeloc = fe1 - rank * fns2new + end if + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs1+1000*fe1+1000000*1 + call MPI_RECV(tabbuf,sizemess,MPI_COMPLEX_WP,cptrank,tag,MPI_COMM_WORLD,status,ierr) + U1kscloc(:,ysloc:yeloc,:) = tabbuf(:,:,:) + deallocate(tabbuf) + else if (rank.eq.rank2send2.and.rank2send2.ne.cptrank.and.rank2send2.ne.rank2send1) then + fnysrank = 1 + rank*fns2new + fnyerank = (1+rank)*fns2new + if (fnyerank.gt.(ns1new-ns1old+ns1old/2+1)) then + ysloc = fs2 - rank * fns2new + ns1new - ns1old + yeloc = fe2 - rank * fns2new + ns1new - ns1old + else + ysloc = fs2 - rank * fns2new + yeloc = fe2 - rank * fns2new + end if + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs2+1000*fe2+1000000*1 + call MPI_RECV(tabbuf,sizemess,MPI_COMPLEX_WP,cptrank,tag,MPI_COMM_WORLD,status,ierr) + U1kscloc(:,ysloc:yeloc,:) = tabbuf(:,:,:) + deallocate(tabbuf) + end if + end do + call MPI_BARRIER(MPI_COMM_WORLD,ierr) + + allocate(U1ksc(fns1new,fns2new,fns3new)) + U1ksc = 0. + + do i = 1 , ns1old/2 + 1 + do k = 1 , ns1old/2 + 1 + U1ksc(i,:,k) = U1kscloc(i,:,k) + end do + do k = ns1new-ns1old/2+2 , ns1new + U1ksc(i,:,k) = U1kscloc(i,:,ns1old-ns1new+k) + end do + end do + deallocate(U1kscloc) + + call btran_wrap(U1ksc,U2,ns1new,ns2new,ns3new,fns1new,fns2new,fns3new) + + deallocate(U1ksc) + +end subroutine discretisation2 + + diff --git a/CodesEnVrac/Remesh/FFTPAR/discretisation3.f90 b/CodesEnVrac/Remesh/FFTPAR/discretisation3.f90 new file mode 100755 index 000000000..930dbc3b3 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/discretisation3.f90 @@ -0,0 +1,222 @@ +subroutine discretisation3(U1,U2,ns1old,ns2old,ns3old,ns1new,ns2new,ns3new) + + ! fns1new < fns1old + + use solver + use parallel + + implicit none + + integer :: ns1old,ns2old,ns3old,ns1new,ns2new,ns3new + integer :: fns1old,fns2old,fns3old,fns1new,fns2new,fns3new,fs,fe,fsold,feold,yminnew,ymaxnew,yminold,ymaxold + real(WP) :: U1(ns1old,ns2old,ns3old) + real(WP) :: U2(ns1new,ns2new,ns3new) + complex(WP), dimension(:,:,:), allocatable :: U1k, U2k, U1kscloc, U1ksc, tabbuf + integer :: sizemess, tag, ierr, status(MPI_STATUS_SIZE), i, j, k, itest + integer :: yeloc, ysloc, yelocsc, yslocsc, rank2send1, rank2send2, fs1, fe1, fs2, fe2, fnysrank, fnyerank, cptrank, rank2send + +! print*,ns1old,ns2old,ns3old,ns1new,ns2new,ns3new + + fns1old = ns1old/2+1 + fns2old = ns1old/nproc + fns3old = ns1old + + fns1new = ns1new/2+1 + fns2new = ns1new/nproc + fns3new = ns1new + + allocate(U1k(fns1old,fns2old,fns3old)) + call ftran_wrap(U1,U1k,ns1old,ns2old,ns3old,fns1old,fns2old,fns3old) + U1k = U1k/real(ns1old**3.0,WP) + + allocate(U1ksc(fns1new,fns2new,fns3new)) + U1ksc = 0. + + if (nproc.ne.1) then + + allocate(U1kscloc(fns1old,fns2new,fns3old)) + U1kscloc = 0. + + ! Communication + do cptrank = 0, nproc-1 + + fnysrank = 1 + cptrank*fns2new + fnyerank = (1+cptrank)*fns2new + + ! Envoi + if (fnyerank.le.ns1new/2+1) then ! envoi j de 1 à <nk + + rank2send1 = floor(real(fnyerank-1)/real(fns2old)) + rank2send2 = floor(real(fnysrank-1)/real(fns2old)) + fs1 = max(fnysrank,1+rank2send1*fns2old) + fe1 = min(fnyerank,(1+rank2send1)*fns2old) + fs2 = max(fnysrank,1+rank2send2*fns2old) + fe2 = min(fnyerank,(1+rank2send2)*fns2old) + + else if(fnysrank.gt.ns1new/2+1) then ! envoi j de >nk à nx + + rank2send1 = floor(real(fnyerank+ns1old-ns1new-1)/real(fns2old)) + rank2send2 = floor(real(fnysrank+ns1old-ns1new-1)/real(fns2old)) + fs1 = max(fnysrank,1+rank2send1*fns2old+ns1new-ns1old) + fe1 = min(fnyerank,(1+rank2send1)*fns2old+ns1new-ns1old) + fs2 = max(fnysrank,1+rank2send2*fns2old+ns1new-ns1old) + fe2 = min(fnyerank,(1+rank2send2)*fns2old+ns1new-ns1old) + + else if(fnysrank.le.ns1new/2+1.and.fnyerank.gt.ns1new/2+1) then + + rank2send1 = floor(real(fnyerank+ns1old-ns1new-1)/real(fns2old)) + rank2send2 = floor(real(fnysrank-1)/real(fns2old)) + fs1 = max(ns1new/2+2,1+rank2send1*fns2old+ns1new-ns1old) + fe1 = min(fnyerank,(1+rank2send1)*fns2old+ns1new-ns1old) + fs2 = max(fnysrank,1+rank2send2*fns2old) + fe2 = min(ns1new/2+1,(1+rank2send2)*fns2old) + + end if + + ! ENVOIE + if (rank.eq.rank2send1.and.rank2send1.ne.cptrank) then + + fnysrank = 1 + rank*fns2old + fnyerank = (1+rank)*fns2old + + if (fnyerank.gt.(ns1old-ns1new+ns1new/2+1)) then + ysloc = fs1 - rank * fns2old + ns1old - ns1new + yeloc = fe1 - rank * fns2old + ns1old - ns1new + else + ysloc = fs1 - rank * fns2old + yeloc = fe1 - rank * fns2old + end if + + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs1+1000*fe1+1000000*1 + tabbuf(:,:,:) = U1k(:,ysloc:yeloc,:) + call MPI_SEND(tabbuf,sizemess,MPI_COMPLEX_WP,cptrank,tag,MPI_COMM_WORLD,ierr) + deallocate(tabbuf) + + else if (rank.eq.rank2send2.and.rank2send2.ne.cptrank.and.rank2send2.ne.rank2send1) then + + fnysrank = 1 + rank*fns2old + fnyerank = (1+rank)*fns2old + + if (fnyerank.gt.(ns1old-ns1new+ns1new/2+1)) then + ysloc = fs2 - rank * fns2old + ns1old - ns1new + yeloc = fe2 - rank * fns2old + ns1old - ns1new + else + ysloc = fs2 - rank * fns2old + yeloc = fe2 - rank * fns2old + end if + + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs2+1000*fe2+1000000*1 + tabbuf(:,:,:) = U1k(:,ysloc:yeloc,:) + call MPI_SEND(tabbuf,sizemess,MPI_COMPLEX_WP,cptrank,tag,MPI_COMM_WORLD,ierr) + deallocate(tabbuf) + + ! RECEPTION + else if (rank.eq.cptrank) then + + ysloc = fs1 - rank * fns2new + yeloc = fe1 - rank * fns2new + + if(cptrank.ne.rank2send1) then + + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs1+1000*fe1+1000000*1 + call MPI_RECV(tabbuf,sizemess,MPI_COMPLEX_WP,rank2send1,tag,MPI_COMM_WORLD,status,ierr) + U1kscloc(:,ysloc:yeloc,:) = tabbuf(:,:,:) + deallocate(tabbuf) + + else + + if (fnyerank.le.ns1new/2+1) then + yslocsc = fs1 - rank * fns2old + yelocsc = fe1 - rank * fns2old + else + yslocsc = fs1 - rank * fns2old - ns1new + ns1old + yelocsc = fe1 - rank * fns2old - ns1new + ns1old + end if + + U1kscloc(:,ysloc:yeloc,:) = U1k(:,yslocsc:yelocsc,:) + + end if + + if (rank2send1.ne.rank2send2) then + + ysloc = fs2 - rank * fns2new + yeloc = fe2 - rank * fns2new + + if (cptrank.ne.rank2send2) then + + sizemess = fns1old*fns3old*(yeloc-ysloc+1) + allocate(tabbuf(fns1old,yeloc-ysloc+1,fns3old)) + tag = fs2+1000*fe2+1000000*1 + call MPI_RECV(tabbuf,sizemess,MPI_COMPLEX_WP,rank2send2,tag,MPI_COMM_WORLD,status,ierr) + U1kscloc(:,ysloc:yeloc,:) = tabbuf(:,:,:) + deallocate(tabbuf) + + else + + if (fnyerank.le.ns1new/2+1) then + yslocsc = fs2 - rank * fns2old + yelocsc = fe2 - rank * fns2old + else + yslocsc = fs2 - rank * fns2old - ns1new + ns1old + yelocsc = fe2 - rank * fns2old - ns1new + ns1old + end if + + U1kscloc(:,ysloc:yeloc,:) = U1k(:,yslocsc:yelocsc,:) + + end if + + end if + + end if + + end do + call MPI_BARRIER(MPI_COMM_WORLD,ierr) + + + do i = 1 , ns1new/2 + 1 + do k = 1 , ns1new/2 + 1 + U1ksc(i,:,k) = U1kscloc(i,:,k) + end do + do k = ns1new, ns1new-ns1new/2+2, -1 + U1ksc(i,:,k) = U1kscloc(i,:,ns1old-ns1new+k) + end do + end do + deallocate(U1kscloc) + + else + + do i = 1 , ns1new/2 + 1 + do j = 1, ns1new/2 + 1 + do k = 1 , ns1new/2 + 1 + U1ksc(i,j,k) = U1k(i,j,k) + end do + do k = ns1new, ns1new-ns1new/2+2, -1 + U1ksc(i,j,k) = U1k(i,j,ns1old-ns1new+k) + end do + end do + do j = ns1new, ns1new-ns1new/2+2, -1 + do k = 1 , ns1new/2 + 1 + U1ksc(i,j,k) = U1k(i,ns1old-ns1new+j,k) + end do + do k = ns1new, ns1new-ns1new/2+2, -1 + U1ksc(i,j,k) = U1k(i,ns1old-ns1new+j,ns1old-ns1new+k) + end do + end do + end do + + end if + + call btran_wrap(U1ksc,U2,ns1new,ns2new,ns3new,fns1new,fns2new,fns3new) + + deallocate(U1ksc) + deallocate(U1k) + +end subroutine discretisation3 + + diff --git a/CodesEnVrac/Remesh/FFTPAR/fft_2 b/CodesEnVrac/Remesh/FFTPAR/fft_2 new file mode 100755 index 0000000000000000000000000000000000000000..912b2b8c033a0e58bb8b50565fb9b273c2309952 GIT binary patch literal 1313096 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%0A+=LUYcFR?mC6YtP_^8$HaXmo# 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�eN-3BbsHGNLutq&$uN(Fv% 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%0D7^JP{kYK;3o2MLGXEc%vQ5N<-~2 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 OPNEtNJDXagYW*Me1mH&i literal 0 HcmV?d00001 diff --git a/CodesEnVrac/Remesh/FFTPAR/fftpar.tar b/CodesEnVrac/Remesh/FFTPAR/fftpar.tar new file mode 100755 index 0000000000000000000000000000000000000000..9d6e494af11d8cb794d0778a2370a955638965e4 GIT binary patch literal 219648 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 N#DOOc{Bv>O{{uT9pTYnD literal 0 HcmV?d00001 diff --git a/CodesEnVrac/Remesh/FFTPAR/fileio.f90 b/CodesEnVrac/Remesh/FFTPAR/fileio.f90 new file mode 100755 index 000000000..4e695fca3 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/fileio.f90 @@ -0,0 +1,59 @@ +module fileio + use precision + implicit none + + ! File index + integer :: fileindex + integer, dimension(128) :: iunits + +contains + + ! ====================== ! + ! File index management: ! + ! - open a file ! + ! - add it to the list ! + ! ====================== ! + integer function iopen() + implicit none + + integer, save :: icall = 1 + integer :: i + + if (icall .eq. 1) then + fileindex = 1 + icall = 0 + end if + iunits(fileindex) = 0 + do i=1,fileindex + if (iunits(i) .eq. 0) exit + end do + if (i .eq. fileindex) then + fileindex = fileindex + 1 + if (fileindex .ge. 128) stop "iopen: maximum units number exceeded" + end if + iunits(i) = 1 + iopen = i + 10 + return + end function iopen + + ! ======================= ! + ! File index management: ! + ! - close a file ! + ! - remove it from list ! + ! ======================= ! + integer function iclose(iu) + implicit none + + integer :: iu + + iu = iu - 10 + if (iu .gt. 0 .and. iu .lt. fileindex) then + iunits(iu) = 0 + iclose = iu + 10 + else + iclose = -1 + end if + return + end function iclose + +end module fileio diff --git a/CodesEnVrac/Remesh/FFTPAR/forcing.f90 b/CodesEnVrac/Remesh/FFTPAR/forcing.f90 new file mode 100755 index 000000000..a6f4dad82 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/forcing.f90 @@ -0,0 +1,173 @@ +module forcing + + use solver + use parallel + + implicit none + + real(WP) :: kf,ka,kb,c + real(WP) :: A + + +end module forcing + + +subroutine forcing_init + + use forcing + use parser + + implicit none + + integer :: i,j,k + + real(WP) :: kk + real(WP) :: force_sum,force_spectrum + real(WP) :: P + real(WP) :: keta + real(WP) :: eta + real(WP) :: pi + real(WP) :: Rlm,tke + real(WP) :: Pf + real(WP) :: B,nnodes + real(WP), dimension(:), allocatable :: s,stotal + integer :: nsize + integer :: ierr,ik + + + pi = acos(-1.0_WP) + + call parser_read('Kmax eta', keta) + call parser_read('Number of points',nsize) + call parser_read('R Lambda',Rlm) + eta = (2.0_WP*keta)/real(nsize,WP) + P = mu_solver**3.0_WP/eta**4.0_WP + + kf = (2.0_WP*pi)/((3.0_WP/20.0_WP*Rlm*Rlm)**0.75_WP*eta) +! kf = (2.0_WP*pi)/((3.0_WP/20.0_WP*Rlm*Rlm)**0.75_WP*eta)-1. + + call parser_read('Power factor',Pf,1.0_WP) + kf = kf/Pf + + if (rank.eq.0) print *,' Forcing wavenumber ', kf + c = 0.5_WP + ka = max(1e-10_WP,kf-2._WP) ! max(1e-10_WP,kf-0.5_WP) + kb = kf+1._WP + + force_sum = 0.0_WP + nnodes = 0.0_WP + + allocate(s(ns1+1),stotal(ns1+1)) + s = 0.0_WP + stotal = 0.0_WP + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) + ik = 1+idint(kk + 0.5_WP) + if (kk.ge.ka.and.kk.le.kb) then + force_sum = force_sum + force_spectrum(kk,kf,c)/(2.0_WP*pi*kk**2.0_WP) + s(ik) = s(ik) + force_spectrum(kk,kf,c)/(2.0_WP*pi*kk**2.0_WP) + nnodes = nnodes + 1.0_WP + endif + enddo + enddo + enddo + + call MPI_ALLREDUCE(force_sum,A,1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(nnodes,B,1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(s,stotal,ns1+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + + A = P/A + + if (rank.eq.0) print *,' Pre-multiplier for forcing term + nnodes', A,B + + +end subroutine forcing_init + + +subroutine force_compute + + use forcing + + implicit none + + integer :: i,j,k + + real(WP) :: rand,pi,kk,force_spectrum + real(WP) :: phi,psi,theta1,theta2 + + real(WP) :: e1x,e1y,e1z + real(WP) :: e2x,e2y,e2z + real(WP) :: kk2,ga,gb + complex(WP) :: xi1,xi2,af,bf + real(WP) :: rxi1,ixi1,rxi2,ixi2 + real(WP) :: num,den,f + + + + pi = acos(-1.0_WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + + kk = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) + kk2 = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP) + if (kk2.gt.1e-10_WP.and.kk.gt.1e-10_WP) then + if (kk.ge.ka.and.kk.le.kb) then + call random_number(rand) + phi = pi*rand + call random_number(rand) + psi = 2.0_WP*pi*rand + + e1x = ky(j)/kk2 + e1y = -kx(i)/kk2 + e1z = 0.0_WP + e2x = kx(i)*kz(k)/(kk*kk2) + e2y = ky(j)*kz(k)/(kk*kk2) + e2z = -(kk2)/kk + xi1 = Uk(i,j,k)*e1x + Vk(i,j,k)*e1y + Wk(i,j,k)*e1z + xi2 = Uk(i,j,k)*e2x + Vk(i,j,k)*e2y + Wk(i,j,k)*e2z + rxi1 = real(0.5_WP*(xi1 + conjg(xi1)),WP) + rxi2 = real(0.5_WP*(xi2 + conjg(xi2)),WP) + ixi1 = real(0.5_WP*(-ii)*(xi1 - conjg(xi1)),WP) + ixi2 = real(0.5_WP*(-ii)*(xi2 - conjg(xi2)),WP) + ga = sin(2.0_WP*phi) + gb = cos(2.0_WP*phi) + num = ga*rxi1 + gb*(sin(psi)*ixi2 + cos(psi)*rxi2) + den = -ga*ixi1 + gb*(sin(psi)*rxi2 - cos(psi)*ixi2) + theta1 = atan(num/den) + theta2 = psi + theta1 + f = A/dt*force_spectrum(kk,kf,c)/(2.0_WP*pi*kk**2.0_WP) + af = f**0.5_WP*exp(ii*theta1)*ga + bf = f**0.5_WP*exp(ii*theta2)*gb + nlx(i,j,k) = nlx(i,j,k) + (af*e1x+bf*e2x) + nly(i,j,k) = nly(i,j,k) + (af*e1y+bf*e2y) + nlz(i,j,k) = nlz(i,j,k) + (bf*e2z) + endif + endif + enddo + enddo + enddo + + +end subroutine force_compute + +function force_spectrum(kk,kf,c) + + use precision + implicit none + + real(WP) :: force_spectrum + real(WP) :: kk,kf,c + + + force_spectrum = exp(-(kk-kf)**2.0_WP/c) + +end function force_spectrum diff --git a/CodesEnVrac/Remesh/FFTPAR/init_plane_jet.f90 b/CodesEnVrac/Remesh/FFTPAR/init_plane_jet.f90 new file mode 100755 index 000000000..ed065a134 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/init_plane_jet.f90 @@ -0,0 +1,53 @@ +subroutine init_plane_jet + + use parallel + use data + + implicit none + + real(WP), dimension(:,:,:), pointer :: Ub, Vb, Wb + real(WP) :: dx, yy, epsil, Htheta, U1, U2, ubm, vbm, wbm + integer :: j + + call hit_init + + allocate(Ub(ns1,ns2,ns3)) + allocate(Vb(ns1,ns2,ns3)) + allocate(Wb(ns1,ns2,ns3)) + Ub = U + Vb = V + Wb = W + + U = 0.0 + V = 0.0 + W = 0.0 + + dx = L/(real(nx)) + + call parser_read('H/theta',Htheta) + call parser_read('Jet velocity',U1) + call parser_read('Co-flow velocity',U2) + call parser_read('noise level',epsil) + + do j = 1,ns2 + yy = real(j)*dx - L/2.0 + U(:,j,:) = (U1+U2)/2.0 + (U1-U2)/2.0 * tanh( 0.25 * Htheta * (1 - 2*abs(yy) ) ) + SC(:,j,:) = 1.0/2.0 + 1.0/2.0 * tanh( 0.25 * Htheta * (1 - 2*abs(yy) ) ) + if (abs(yy).gt.0.7.or.abs(yy).lt.0.3) then + Ub(:,j,:) = 0. + Vb(:,j,:) = 0. + Wb(:,j,:) = 0. + end if + if( rank.eq.0) print*,yy,Ub(1,j,1) + end do + ubm = maxval(abs(Ub)) + vbm = maxval(abs(Vb)) + wbm = maxval(abs(Wb)) + Ub = Ub/ubm + Vb = Vb/vbm + Wb = Wb/wbm + U = U + epsil*Ub + V = V + epsil*Vb + W = W + epsil*Wb + +end subroutine init_plane_jet diff --git a/CodesEnVrac/Remesh/FFTPAR/init_test_case.f90 b/CodesEnVrac/Remesh/FFTPAR/init_test_case.f90 new file mode 100755 index 000000000..afe628edf --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/init_test_case.f90 @@ -0,0 +1,39 @@ +subroutine init_test_case + + use parallel + use data + + implicit none + + real(WP) :: xx, yy, zz, rr + integer :: i, j, k, direction + + call hit_init + +! call parser_read('Scalar direction', direction) + + do i = 1, ns1sc + do j = 1, ns2sc + do k = 1, ns3sc + xx = i*L/ns1sc - L/2 + yy = j*L/ns2sc - L/2 + zz = k*L/ns3sc - L/2 +! SC(i,j,k) = sqrt(xx**2.0 + yy**2.0 + zz**2.0) +! SC(i,j,k) = SC(i,j,k)/SC(1,1,1) +! if (direction.eq.1) SC(i,j,k) = sin(xx) +! if (direction.eq.2) SC(i,j,k) = sin(yy) +! if (direction.eq.3) SC(i,j,k) = sin(zz) + rr = sqrt(xx**2.0 + yy**2.0 + zz**2.0) + !if (rr.gt.L/6) then + ! SC(i,j,k) = 0.0 + !else + ! SC(i,j,k) = 1.0 + !end if + SC(i,j,k) = rr -L/6. + !SC(i,j,k) = sin(xx) + end do + end do + end do + + +end subroutine init_test_case diff --git a/CodesEnVrac/Remesh/FFTPAR/initscal.f90 b/CodesEnVrac/Remesh/FFTPAR/initscal.f90 new file mode 100755 index 000000000..46d50f10e --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/initscal.f90 @@ -0,0 +1,180 @@ +subroutine init_scalar + + use parallel + use random + use transform + use data + implicit none +! include 'fftw3.f' + + ! Spectrum computation + real(WP) :: psr,ps1,ps2 + real(WP) :: ke,kd,ks,dk,ksk0ratio,kc,kcksratio,kk,kx,ky,kz,kk2,kcut + real(WP) :: alpha,spec_amp,eps,amp_disc,f_phi,sch + integer :: kl,jl,il,impose + real(WP) :: e_total,energy_spec,diss_total,ndense + real(WP), dimension(:,:), pointer :: spect,sg + real(WP), dimension(:), pointer :: s1,s2 + complex(WP), dimension(:,:,:), pointer :: ak,bk + real(WP) :: scmean,scmean_global + ! Other + integer :: i,j,k,ik,iunit,dim + real(WP), dimension(:), pointer :: nnodes + complex(WP) :: ii=(0.0_WP,1.0_WP) + real(WP) :: rand,pi,spec,kfix + + real(WP) :: keta, Rlambda, L11, tke,L_large, dissipation,eta + real(WP) :: e_spec,d_spec, e_local, d_local, spec_factor + ! Fourier coefficients + real(WP) :: umax,vmax,wmax,cos,sin + complex(WP), dimension(:,:,:), pointer :: Uk,Vk,Wk,scalar + complex(WP), dimension(:,:,:), pointer :: Cbuf + real(WP), dimension(:,:,:), pointer :: Rbuf + + logical :: flg_inplace + + integer :: ierr,gg(3),iforce + integer,dimension(:,:,:),pointer :: node_index + integer(KIND=8) :: plan_c2r + +!!$ real(WP), dimension(:,:,:), pointer :: A +!!$ complex(WP), dimension(:,:,:), pointer :: B + + + ! Create pi + pi = acos(-1.0_WP) + dk = 2.0_WP*pi/L + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! Input for scalar field +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + call parser_read('ks/ko', ksk0ratio) + ks = ksk0ratio*dk +!!! Assume kc/ks to be 2 as in Eswaran and Pope + kc = 2.0_WP*ks + + + allocate(scalar(fns1,fns2,fns3)) + + scalar = (0.0_WP,0.0_WP) + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + il = i + fnxs - 1 + jl = j + fnys - 1 + kl = k + fnzs - 1 + + kx=real(il-1,WP)*dk + ky=real(jl-1,WP)*dk + if (jl.gt.nk) ky=-real(nx-jl+1,WP)*dk + kz=real(kl-1,WP)*dk + if (kl.gt.nk) kz=-real(nx-kl+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + kk2=sqrt(kx**2+ky**2) + if ((ks-dk/2.0_WP.le.kk).and.(kk.le.ks+dk/2.0_WP)) then + f_phi = 1.0_WP + else + f_phi = 0.0_WP + endif + call random_number(rand) + if (kk.lt.1e-10) then + scalar(i,j,k) = 0.0_WP + else + scalar(i,j,k) = sqrt(f_phi/(4.0_WP*pi*kk**2.0_WP))*exp(ii*2.0_WP*pi*rand) + endif + enddo + enddo + enddo + + call btran_wrap(scalar,SC,ns1,ns2,ns3,fns1,fns2,fns3) + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (SC(i,j,k).le.0.0_WP) then + SC(i,j,k) = 0.0_WP + else + SC(i,j,k) = 1.0_WP + endif + enddo + enddo + enddo + + call ftran_wrap(SC,scalar,ns1,ns2,ns3,fns1,fns2,fns3) + + kcut = sqrt(2.0_WP)*real(nx,WP)/3.0_WP + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + il = i + fnxs - 1 + jl = j + fnys - 1 + kl = k + fnzs - 1 + + kx=real(il-1,WP)*dk + ky=real(jl-1,WP)*dk + if (jl.gt.nk) ky=-real(nx-jl+1,WP)*dk + kz=real(kl-1,WP)*dk + if (kl.gt.nk) kz=-real(nx-kl+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + kk2=sqrt(kx**2+ky**2) + + if (kk.gt.kcut) scalar(i,j,k) = 0.0_WP + + if (kk.le.kc) then + scalar(i,j,k) = scalar(i,j,k) + else + scalar(i,j,k) = scalar(i,j,k)*(kc/kk)**2.0_WP + endif + enddo + enddo + enddo + + call btran_wrap(scalar,SC,ns1,ns2,ns3,fns1,fns2,fns3) + SC = SC/real(ns1**3.0,WP) + + + call parser_read('Imposing mean gradient',impose,0) + + + if (impose.eq.1) then + scmean = 0.0_WP + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + scmean = scmean + SC(i,j,k) + enddo + enddo + enddo + + call MPI_ALLREDUCE(scmean,scmean_global,1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + scmean = scmean_global/(real(nx,WP)**3.0_WP) + +!!!!!!!!!!!! Setting scalar to zero - see if it lies within bounds + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + SC(i,j,k) = 0.0_WP + enddo + enddo + enddo + + endif + + + + + ! Inverse Fourier transform + + ! Clean up + deallocate(scalar) + + + +end subroutine init_scalar + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/lesmodel.f90 b/CodesEnVrac/Remesh/FFTPAR/lesmodel.f90 new file mode 100755 index 000000000..a4098e425 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/lesmodel.f90 @@ -0,0 +1,321 @@ +subroutine dynsmagmodel + + use data + use parallel + use solver + + integer :: i,j,k + real(WP) :: deltx,deltt, cst1, cst2 + real(WP) :: Ekf,diss_sgs,diss_mu,tau12,mean_uv, nt + + complex(WP), dimension(:,:,:), pointer :: ddxk, ddyk, ddzk + real(WP), dimension(:,:,:), pointer :: ddx, ddy, ddz + + real(WP), dimension(:,:,:), pointer :: S11, S12, S13, S22, S23, S33 + real(WP), dimension(:,:,:), pointer :: L11, L12, L13, L22, L23, L33 + real(WP), dimension(:,:,:), pointer :: M11, M12, M13, M22, M23, M33 + real(WP), dimension(:,:,:), pointer :: T11, T12, T13, T22, T23, T33 + real(WP), dimension(:,:,:), pointer :: R11, R12, R13, R22, R23, R33 + real(WP), dimension(:,:,:), pointer :: V11, V12, V13, V22, V23, V33 + real(WP), dimension(:,:,:), pointer :: uft, vft, wft + real(WP), dimension(:,:,:), pointer :: dudx, dudy, dudz + real(WP), dimension(:,:,:), pointer :: dvdx, dvdy, dvdz + real(WP), dimension(:,:,:), pointer :: dwdx, dwdy, dwdz + real(WP), dimension(:,:,:), pointer :: normS, normR + real(WP), dimension(:,:), pointer :: SPEC1, SPEC11 + real(WP), dimension(:), pointer :: coefffy, cst1y, cst2y + + deltx = L/(real(nx)) + deltt = 2*deltx + nt = 2.0 + + call u_compute + + allocate(dudx(ns1,ns2,ns3)) + allocate(dudy(ns1,ns2,ns3)) + allocate(dudz(ns1,ns2,ns3)) + allocate(dvdx(ns1,ns2,ns3)) + allocate(dvdy(ns1,ns2,ns3)) + allocate(dvdz(ns1,ns2,ns3)) + allocate(dwdx(ns1,ns2,ns3)) + allocate(dwdy(ns1,ns2,ns3)) + allocate(dwdz(ns1,ns2,ns3)) + call gradient(U,0,dudx,dudy,dudz) + call gradient(V,0,dvdx,dvdy,dvdz) + call gradient(W,0,dwdx,dwdy,dwdz) + allocate(S11(ns1,ns2,ns3)) + allocate(S12(ns1,ns2,ns3)) + allocate(S13(ns1,ns2,ns3)) + allocate(S22(ns1,ns2,ns3)) + allocate(S23(ns1,ns2,ns3)) + allocate(S33(ns1,ns2,ns3)) + allocate(normS(ns1,ns2,ns3)) + S11 = dudx + S22 = dvdy + S33 = dwdz + S12 = 0.5*(dudy+dvdx) + S13 = 0.5*(dudz+dwdx) + S23 = 0.5*(dvdz+dwdy) + normS = sqrt(2.0*(S11*S11 + S22*S22 + S33*S33 + 2.0*S12*S12 + 2.0*S13*S13 + 2.0*S23*S23)) + + ! - dyn procedure + allocate(R11(ns1,ns2,ns3)) + allocate(R12(ns1,ns2,ns3)) + allocate(R13(ns1,ns2,ns3)) + allocate(R22(ns1,ns2,ns3)) + allocate(R23(ns1,ns2,ns3)) + allocate(R33(ns1,ns2,ns3)) + R11 = normS*S11 + R12 = normS*S12 + R13 = normS*S13 + R22 = normS*S22 + R23 = normS*S23 + R33 = normS*S33 + allocate(V11(ns1,ns2,ns3)) + allocate(V12(ns1,ns2,ns3)) + allocate(V13(ns1,ns2,ns3)) + allocate(V22(ns1,ns2,ns3)) + allocate(V23(ns1,ns2,ns3)) + allocate(V33(ns1,ns2,ns3)) + call specboxfilter(R11,V11,nt) + call specboxfilter(R12,V12,nt) + call specboxfilter(R13,V13,nt) + call specboxfilter(R22,V22,nt) + call specboxfilter(R23,V23,nt) + call specboxfilter(R33,V33,nt) + allocate(uft(ns1,ns2,ns3)) + allocate(vft(ns1,ns2,ns3)) + allocate(wft(ns1,ns2,ns3)) + call specboxfilter(U,uft,nt) + call specboxfilter(V,vft,nt) + call specboxfilter(W,wft,nt) + call gradient(uft,0,dudx,dudy,dudz) + call gradient(vft,0,dvdx,dvdy,dvdz) + call gradient(wft,0,dwdx,dwdy,dwdz) + R11 = dudx + R22 = dvdy + R33 = dwdz + R12 = 0.5*(dudy+dvdx) + R13 = 0.5*(dudz+dwdx) + R23 = 0.5*(dvdz+dwdy) + allocate(normR(ns1,ns2,ns3)) + normR = 2*sqrt(R11*R11 + R22*R22 + R33*R33 + 2.0*R12*R12 + 2.0*R13*R13 + 2.0*R23*R23) + deallocate(dudx) + deallocate(dudy) + deallocate(dudz) + deallocate(dvdx) + deallocate(dvdy) + deallocate(dvdz) + deallocate(dwdx) + deallocate(dwdy) + deallocate(dwdz) + R11 = normR*R11 + R12 = normR*R12 + R13 = normR*R13 + R22 = normR*R22 + R23 = normR*R23 + R33 = normR*R33 + deallocate(normR) + allocate(M11(ns1,ns2,ns3)) + allocate(M12(ns1,ns2,ns3)) + allocate(M13(ns1,ns2,ns3)) + allocate(M22(ns1,ns2,ns3)) + allocate(M23(ns1,ns2,ns3)) + allocate(M33(ns1,ns2,ns3)) + M11 = deltt**2.*R11 - deltx**2.*V11 + M22 = deltt**2.*R22 - deltx**2.*V22 + M33 = deltt**2.*R33 - deltx**2.*V33 + M12 = deltt**2.*R12 - deltx**2.*V12 + M13 = deltt**2.*R13 - deltx**2.*V13 + M23 = deltt**2.*R23 - deltx**2.*V23 + deallocate(V11) + deallocate(V22) + deallocate(V33) + deallocate(V12) + deallocate(V13) + deallocate(V23) + allocate(L11(ns1,ns2,ns3)) + allocate(L12(ns1,ns2,ns3)) + allocate(L13(ns1,ns2,ns3)) + allocate(L22(ns1,ns2,ns3)) + allocate(L23(ns1,ns2,ns3)) + allocate(L33(ns1,ns2,ns3)) + R11 = U*U + R22 = V*V + R33 = W*W + R12 = U*V + R13 = U*W + R23 = V*W + call specboxfilter(R11,L11,nt) + call specboxfilter(R12,L12,nt) + call specboxfilter(R13,L13,nt) + call specboxfilter(R22,L22,nt) + call specboxfilter(R23,L23,nt) + call specboxfilter(R33,L33,nt) + L11 = L11 - uft*uft + L22 = L22 - vft*vft + L33 = L33 - wft*wft + L12 = L12 - uft*vft + L13 = L13 - uft*wft + L23 = L23 - vft*wft + deallocate(R11) + deallocate(R22) + deallocate(R33) + deallocate(R12) + deallocate(R13) + deallocate(R23) + deallocate(uft) + deallocate(vft) + deallocate(wft) + L11 = L11*M11 + 2.*L12*M12 + 2.*L13*M13 + L22*M22 + 2.*L23*M23 + L33*M33 + M11 = M11*M11 + 2.*M12*M12 + 2.*M13*M13 + M22*M22 + 2.*M23*M23 + M33*M33 + allocate(cst1y(ns2)) + allocate(cst2y(ns2)) + allocate(coefffy(ns2)) + call moyen_y(L11,cst1y) + call moyen_y(M11,cst2y) + coefffy = cst1y / cst2y + deallocate(cst1y) + deallocate(cst2y) + deallocate(L11) + deallocate(L22) + deallocate(L33) + deallocate(L12) + deallocate(L13) + deallocate(L23) + deallocate(M11) + deallocate(M22) + deallocate(M33) + deallocate(M12) + deallocate(M13) + deallocate(M23) + allocate(T11(ns1,ns2,ns3)) + allocate(T12(ns1,ns2,ns3)) + allocate(T13(ns1,ns2,ns3)) + allocate(T22(ns1,ns2,ns3)) + allocate(T23(ns1,ns2,ns3)) + allocate(T33(ns1,ns2,ns3)) + do j=1,ns2 + T11(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S11(:,j,:) + T12(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S12(:,j,:) + T13(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S13(:,j,:) + T22(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S22(:,j,:) + T23(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S23(:,j,:) + T33(:,j,:) = coefffy(j) * deltx**2.0 * normS(:,j,:) * S33(:,j,:) + end do + deallocate(coefffy) + + ! postprocessing + ! Ekf + call moyen(U**2.+V**2.+W**2.,cst1) + Ekf = cst1/2 + ! SGS dissipation + normS = - ( T11*S11 + T22*S22 + T33*S33 + 2.*T12*S12 + 2.*T13*S13 + 2.*T23*S23 ) + call moyen(normS,diss_sgs) + + allocate(SPEC1(2,nx+1)) + allocate(SPEC11(2,nx+1)) + SPEC1 = 0.0 + SPEC11 = 0.0 +! call get_spectrum(normS,ns1,ns2,ns3,L,SPEC1,SPEC11) +! if (rank.eq.0) then +! open(14,file='spectrum_sgs_diss', form = 'formatted') +! do i = 1, nx+1 +! if ((SPEC1(1,i).ne.0.0).and.(SPEC1(2,i).ne.0.0)) then +! write(14,*) SPEC11(1,i), SPEC1(2,i) +! end if +! end do +! end if + deallocate(SPEC1) + deallocate(SPEC11) + ! mu dissipation + call moyen( ( S11*S11 + S22*S22 + S33*S33 + 2.*S12*S12 + 2.*S13*S13 + 2.*S23*S23 ),diss_mu) + diss_mu = mu_solver * diss_mu + ! tau12 + call moyen((T12)**2.,tau12) + ! <uv> + call moyen(U*V,mean_uv) + if (rank.eq.0) then + write(*,'(A10,10(E12.5,3X))') '',sim_time,Ekf,diss_sgs,diss_mu,tau12,mean_uv + end if + + deallocate(S11) + deallocate(S22) + deallocate(S33) + deallocate(S12) + deallocate(S13) + deallocate(S23) + deallocate(normS) + + allocate(ddx(ns1,ns2,ns3)) + allocate(ddy(ns1,ns2,ns3)) + allocate(ddz(ns1,ns2,ns3)) + allocate(ddxk(fns1,fns2,fns3)) + allocate(ddyk(fns1,fns2,fns3)) + allocate(ddzk(fns1,fns2,fns3)) + ! -- x + ddx = - T11 + ddy = - T12 + ddz = - T13 + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + ddxk = ddxk/real((ns1**3.0),WP) + ddyk = ddyk/real((ns1**3.0),WP) + ddzk = ddzk/real((ns1**3.0),WP) + do k = 1, fns3 + do j = 1, fns2 + do i = 1, fns1 + nlx(i,j,k) = nlx(i,j,k) - ii*kx(i)*ddxk(i,j,k) - ii*ky(j)*ddyk(i,j,k) - ii*kz(k)*ddzk(i,j,k) + end do + end do + end do + ! -- y + ddx = - T12 + ddy = - T22 + ddz = - T23 + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + ddxk = ddxk/real((ns1**3.0),WP) + ddyk = ddyk/real((ns1**3.0),WP) + ddzk = ddzk/real((ns1**3.0),WP) + do k = 1, fns3 + do j = 1, fns2 + do i = 1, fns1 + nly(i,j,k) = nly(i,j,k) - ii*kx(i)*ddxk(i,j,k) - ii*ky(j)*ddyk(i,j,k) - ii*kz(k)*ddzk(i,j,k) + end do + end do + end do + ! -- z + ddx = - T13 + ddy = - T23 + ddz = - T33 + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + ddxk = ddxk/real((ns1**3.0),WP) + ddyk = ddyk/real((ns1**3.0),WP) + ddzk = ddzk/real((ns1**3.0),WP) + do k = 1, fns3 + do j = 1, fns2 + do i = 1, fns1 + nlz(i,j,k) = nlz(i,j,k) - ii*kx(i)*ddxk(i,j,k) - ii*ky(j)*ddyk(i,j,k) - ii*kz(k)*ddzk(i,j,k) + end do + end do + end do + + deallocate(T11) + deallocate(T22) + deallocate(T33) + deallocate(T12) + deallocate(T13) + deallocate(T23) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(ddx) + deallocate(ddy) + deallocate(ddz) + +end subroutine dynsmagmodel diff --git a/CodesEnVrac/Remesh/FFTPAR/main.f90 b/CodesEnVrac/Remesh/FFTPAR/main.f90 new file mode 100755 index 000000000..64b8364e4 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/main.f90 @@ -0,0 +1,107 @@ +subroutine main_init + + use parallel + use parser + use string + implicit none + + character(len=str_long) :: sim_name + integer :: itype, ipost, iscal + + call parser_init + call parser_parsefile('input') + + call mpi_initialize + call random_init + call transform_init + call data_init + + call parser_read('Simulation name', sim_name) + call parser_read('Simulation type', itype) + call parser_read('Re-init scalar', iscal) + + + if (itype.eq.0) then !!!! Initialize and compute + if (trim(sim_name).eq.'Taylor Green') then + call tg_init + elseif(trim(sim_name).eq.'Isotropic turbulence') then + call hit_init + elseif(trim(sim_name).eq.'Plane jet') then + call init_plane_jet + elseif(trim(sim_name).eq.'Test case') then + call init_test_case + else + print *,' Unknown Simulation Name' + stop + endif + elseif (itype.eq.1) then + call data_read + if( iscal.eq.1) then + call init_test_case + endif + else + print *,' Unknown simulation type' + stop + endif + + call solver_init + + call x_advec_init + +! call parser_read('Postprocessing', ipost) +! if (ipost.eq.1) print*,'not yet implemented' + +end subroutine main_init + + +program main + + use parallel + use parser + use string + implicit none + integer :: i,n_iter + character(len=str_long) :: sim_name + integer :: ifreq, ipost,itest + + call main_init + + call parser_read('Postprocessing',ipost) + + call parser_read('Simulation iterations',n_iter) + call parser_read('Simulation name',sim_name) + call parser_read('Write frequency',ifreq,n_iter) + if (sim_name.eq.'Isotropic turbulence'.or.sim_name.eq.'Plane jet') call dns_stats + + + + if (ipost.eq.1) then + call postprocess + else if(ipost.eq.2) then + call data_filter_sc + call data_write + stop + else if(ipost.eq.5) then + call postprocess5 + stop + else if(ipost.eq.6) then + call postprocess6 + stop + else if(ipost.eq.7) then + call postprocess7 + stop + else + call data_write + do i = 1,n_iter + call solver_step + if (trim(sim_name).eq.'Taylor Green') then + call tg_stats + elseif (trim(sim_name).eq.'Isotropic turbulence'.or.sim_name.eq.'Plane jet') then + call dns_stats + endif + if (mod(i,ifreq).eq.0) call data_write + enddo +! call postprocess + end if + +end program main diff --git a/CodesEnVrac/Remesh/FFTPAR/mpi_init.f90 b/CodesEnVrac/Remesh/FFTPAR/mpi_init.f90 new file mode 100755 index 000000000..5b7845d17 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/mpi_init.f90 @@ -0,0 +1,185 @@ +module parallel + + implicit none + include 'mpif.h' + + integer :: nproc, rank + + integer :: nx,ny,nz + integer :: nxsc,nysc,nzsc + + integer :: ns1,ns2,ns3,nk + integer :: fns1, fns2, fns3 + + integer :: ns1sc,ns2sc,ns3sc,nksc + integer :: fns1sc, fns2sc, fns3sc + + integer :: nxs,nxe,nys,nye,nzs,nze + integer :: fnxs,fnxe,fnys,fnye,fnzs,fnze + + integer :: nxssc,nxesc,nyssc,nyesc,nzssc,nzesc + integer :: fnxssc,fnxesc,fnyssc,fnyesc,fnzssc,fnzesc + + + integer :: ndim + + integer :: MPI_REAL_WP + integer :: MPI_COMPLEX_WP + +end module parallel + + +subroutine mpi_initialize + + use precision + use parallel + use parser + implicit none + + integer :: ierr + integer :: size_dp + + + call MPI_INIT(ierr) + call MPI_COMM_SIZE(MPI_COMM_WORLD,nproc,ierr) + call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr) + + + + call parser_read('Number of points',nx) + ny = nx + nz = nx + + if (mod(nz,nproc).ne.0) then + print *,' NX should be exactly divided by the number of processors' + stop + endif + + nk = nx/2+1 + + ns1 = nx + ns2 = ny + ns3 = nz/nproc + + nxs = 1 + nxe = nx + + nys = 1 + nye = ny + + nzs = 1 +(rank)*ns3 + nze = (rank+1)*ns3 + + + fns1 = nk + fns2 = ny/nproc + fns3 = nz + + fnxs = 1 + fnxe = nk + + fnys = 1 + (rank)*fns2 + fnye = (rank+1)*fns2 + + fnzs = 1 + fnze = fns3 + +!!$ +!!$ print *,' After getdims 11', rank, nxs,nxe,ns1 +!!$ print *,' After getdims 12', rank, nys,nye,ns2 +!!$ print *,' After getdims 13', rank, nzs,nze,ns3 +!!$ +!!$ +!!$ +!!$ print *,' dimensions 31', rank, fnxs, fnxe, fns1 +!!$ print *,' dimensions 32', rank, fnys, fnye, fns2 +!!$ print *,' dimensions 33', rank, fnzs, fnze, fns3 +!!$ + + + + call parser_read('Number of points for scalar',nxsc) + nysc = nxsc + nzsc = nxsc + + if (mod(nzsc,nproc).ne.0) then + print *,' NXSC should be exactly divided by the number of processors' + stop + endif + + nksc = nxsc/2+1 + + ns1sc = nxsc + ns2sc = nysc + ns3sc = nzsc/nproc + + nxssc = 1 + nxesc = nxsc + + nyssc = 1 + nyesc = nysc + + nzssc = 1 +(rank)*ns3sc + nzesc = (rank+1)*ns3sc + + fns1sc = nksc + fns2sc = nysc/nproc + fns3sc = nzsc + + fnxssc = 1 + fnxesc = nksc + + fnyssc = 1 + (rank)*fns2sc + fnyesc = (rank+1)*fns2sc + + fnzssc = 1 + fnzesc = fns3sc + + + + call MPI_TYPE_SIZE(MPI_DOUBLE_PRECISION,size_dp,ierr) + if (WP.eq.size_dp) then + MPI_REAL_WP = MPI_DOUBLE_PRECISION + else + MPI_REAL_WP = MPI_REAL + endif + + call MPI_TYPE_SIZE(MPI_DOUBLE_COMPLEX,size_dp,ierr) + + if ((2*WP).eq.size_dp) then + MPI_COMPLEX_WP = MPI_DOUBLE_COMPLEX + else + MPI_COMPLEX_WP = MPI_COMPLEX + endif + + +end subroutine mpi_initialize + + +subroutine parallel_max(gmax,mdummy) + + use parallel + use precision + implicit none + + real(WP) :: gmax, mdummy + integer :: ierr + + call MPI_ALLREDUCE(gmax,mdummy,1,MPI_REAL_WP,MPI_MAX,& + &MPI_COMM_WORLD,ierr) + + gmax = mdummy + +end subroutine parallel_max + +subroutine barrier + + use parallel + + implicit none + + integer :: ierr + + call MPI_BARRIER(MPI_COMM_WORLD,ierr) + +end subroutine barrier diff --git a/CodesEnVrac/Remesh/FFTPAR/parinit.f90 b/CodesEnVrac/Remesh/FFTPAR/parinit.f90 new file mode 100755 index 000000000..fb92674d9 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/parinit.f90 @@ -0,0 +1,602 @@ +subroutine hit_init + + use parallel + use random + use transform + use data + implicit none +! include 'fftw3.f' + + ! Spectrum computation + real(WP) :: psr,ps1,ps2, xx, yy, zz + real(WP) :: ke,kd,ks,dk,ksk0ratio,kc,kcksratio,kk,kx,ky,kz,kk2,kcut + real(WP) :: alpha,spec_amp,eps,amp_disc,f_phi,sch + integer :: kl,jl,il,impose,itype + real(WP) :: e_total,energy_spec,diss_total,ndense + real(WP), dimension(:,:), pointer :: spect,sg + real(WP), dimension(:), pointer :: s1,tabs2 + complex(WP), dimension(:,:,:), pointer :: ak,bk + real(WP) :: scmean,scmean_global + ! Other + integer :: i,j,k,ik,iunit,dim + real(WP), dimension(:), pointer :: nnodes + complex(WP) :: ii=(0.0_WP,1.0_WP) + real(WP) :: rand,pi,spec,kfix + + real(WP) :: keta, Rlambda, L11, tke,L_large, dissipation,eta + real(WP) :: e_spec,d_spec, e_local, d_local, spec_factor + ! Fourier coefficients + real(WP) :: umax,vmax,wmax,cos,sin + complex(WP), dimension(:,:,:), pointer :: Uk,Vk,Wk,scalar + complex(WP), dimension(:,:,:), pointer :: Cbuf + real(WP), dimension(:,:,:), pointer :: Rbuf + + logical :: flg_inplace + + integer :: ierr,gg(3),iforce,iscal + integer,dimension(:,:,:),pointer :: node_index + integer(KIND=8) :: plan_c2r + +!!$ real(WP), dimension(:,:,:), pointer :: A +!!$ complex(WP), dimension(:,:,:), pointer :: B + + call parser_read('Kmax eta', keta) + call parser_read('R Lambda', Rlambda) + call parser_read('Forcing', iforce) + + if (trim(spectrum).eq.'VKP') then + call parser_read('Dissipative scale',ld) + call parser_read('Dissipation',epsilon) + end if + + ! Create pi + pi = acos(-1.0_WP) + +!!$ ! ================= +!!$ ! Velocity Spectrum +!!$ +!!$ ! Spectrum computation +!!$ ke = 2.0_WP*pi/le +!!$ if (trim(spectrum).eq.'VKP') kd = 2.0_WP*pi/ld +!!$ dk = 2.0_WP*pi/L +!!$ kc = real(nx/2,WP)*dk +!!$ eps=ke/1000000.0_WP +!!$ if (trim(spectrum).eq.'PP') then +!!$ spec_amp = 16.0_WP*sqrt(2.0_WP/pi)*Ut**2/ke +!!$ else if (trim(spectrum).eq.'VKP') then +!!$ alpha=1.5_WP +!!$ spec_amp = 1.5_WP*Ut**5/epsilon +!!$ end if +!!$ amp_disc = sqrt(dk)**3 + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!! Modified Input for the Spectral Code +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +!!!! Need to input Viscosity, kmax X eta, R_Lambda + +!!!!! Assumes high-reynolds limit to determine the largest eddy +!!!!! Equations for Pope's book, chapter 6 + + + + eta = (2.0_WP*keta)/real(nx,WP) + L_large = eta*(3.0_WP/20.0_WP*Rlambda*Rlambda)**(3.0/4.0) + + L11 = L_large*0.43 + + ke = 1.3_WP/L11 + + if (ke.lt.1) then + print *,' Peak wavenumber not in the box, reduce R Lambda' + call parser_read('Re-init scalar', iscal) + if(iscal.eq.0) then + stop + end if + endif + + + dk = 2.0_WP*pi/L + kc = pi*real(nx,WP)/L + eps = kc/10000000_WP + + + e_spec = 0.0_WP + d_spec = 0.0_WP + + ndense = 0.0_WP + + do k = fnzs,fnze + do j = fnys,fnye + do i = fnxs,fnxe + kx=real(i-1,WP)*dk + ky=real(j-1,WP)*dk + if (j.gt.nk) ky=-real(nx+1-j,WP)*dk + kz=real(k-1,WP)*dk + if (k.gt.nk) kz=-real(nx+1-k,WP)*dk + kk=sqrt(kx**2+ky**2+kz**2) + if ((kk.gt.eps).and.(kk.le.kc)) then + ndense = ndense + 1.0_WP + energy_spec = (kk/ke)**4.0_WP*exp(-2.0_WP*(kk/ke)**2.0_WP)/(4.0_WP*pi*kk**2.0_WP) + e_spec = e_spec + dk*energy_spec + d_spec = d_spec + dk*kk**2.0_WP*energy_spec + endif + enddo + enddo + enddo + + e_local = e_spec + d_local = d_spec + call MPI_ALLREDUCE(e_local,e_spec,1,MPI_REAL_WP,MPI_SUM,& + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(d_local,d_spec,1,MPI_REAL_WP,MPI_SUM,& + & MPI_COMM_WORLD,ierr) + + + spec_amp = 3.0_WP/10.0_WP*Rlambda**2.0_WP*mu**2.0_WP*d_spec/e_spec**2.0_WP + +!mu = sqrt(e_spec**2.0_WP/d_spec*(10.0_WP/(3.0_WP*Rlambda**2.0_WP))) + tke = spec_amp*e_spec + + Ut = sqrt(tke/1.5_WP) !Rlambda*mu/(sqrt(10.0_WP)*eta**(2.0_WP/3.0_WP)*L_large**(1.0_WP/3.0_WP)) +! tke = 1.5_WP*Ut*Ut + dissipation = 2.0_WP*mu*spec_amp*d_spec + amp_disc = sqrt(dk)**3.0_WP + + + if (rank.eq.0) then + print *, '------------------------------------------------------------------' + print *, '------------------------------------------------------------------' + print *,' L11 ', L11 + print *,' L_large ', L_large + print *,' kc ', kc + print *,' ke ', ke + print *,' eta ', eta + print *,' Ut ', Ut + print *,' kinetic energy ', tke + print *,' dissipation ', dissipation + print *,' spec_amp ', spec_amp + print *,' amp_disc ', amp_disc + print *,' viscosity', mu + print *,' e_spec ', e_spec + print *,' d_spec ', d_spec + print *,' Number of modes', ndense + print *,' R lambda calculated', sqrt(20.0_WP/3.0_WP*tke**2.0/(dissipation*mu)) + print *, '------------------------------------------------------------------' + print *, '------------------------------------------------------------------' + endif + + + + ! Output spectrum for comparison + allocate(spect(2,nx+1)) + e_total=0.0_WP + diss_total = 0.0_WP + spect = 0.0_WP + + + ! Compute spectrum + + allocate(ak(fnxs:fnxe,fnys:fnye,fnzs:fnze),bk(fnxs:fnxe,fnys:fnye,fnzs:fnze)) + !allocate(nnodes(nx+1)) + !nnodes = 0.0_WP + ndense = 0.0_WP + do k=fnzs,fnze + do j=fnys,fnye + do i=fnxs,fnxe + ! Random numbers + call random_number(rand) + psr= 2.0_WP*pi*rand !2.0_WP*pi*(rand-0.5_WP) + call random_number(rand) + ps1=2.0_WP*pi*rand !*(rand-0.5_WP) + call random_number(rand) + ps2=2.0_WP*pi*rand !(rand-0.5_WP) + ! Wavenumbers + kx=real(i-1,WP)*dk + ky=real(j-1,WP)*dk + if (j.gt.nk) ky=-real(nx+1-j,WP)*dk + kz=real(k-1,WP)*dk + if (k.gt.nk) kz=-real(nx+1-k,WP)*dk + kk=sqrt(kx**2.+ky**2.+kz**2.) + ! Spectrums + energy_spec=spec_amp*(kk/ke)**4.0_WP*exp(-2.0_WP*(kk/ke)**2.0_WP) + ! Coeff + ik = 1+idint(kk/dk + 0.5_WP) + if ((kk.gt.eps).and.(kk.le.kc)) then + ndense = ndense + 1.0_WP + ak(i,j,k)= amp_disc*sqrt(energy_spec/(4.0_WP*pi*kk**2.0_WP))*exp(ii*ps1)*cos(psr) + bk(i,j,k)= amp_disc*sqrt(energy_spec/(4.0_WP*pi*kk**2.0_WP))*exp(ii*ps2)*sin(psr) + spect(2,ik) = spect(2,ik) + real(ak(i,j,k)*conjg(ak(i,j,k))) + real(bk(i,j,k)*conjg(bk(i,j,k))) + e_total = e_total + dk*(real(ak(i,j,k)*conjg(ak(i,j,k))) + real(bk(i,j,k)*conjg(bk(i,j,k)))) + diss_total = diss_total + dk*2.0_WP*mu*kk**2.0_WP*(real(ak(i,j,k)*conjg(ak(i,j,k)))& + & + real(bk(i,j,k)*conjg(bk(i,j,k)))) + end if + end do + end do + end do + + e_local = e_total + d_local = diss_total + allocate(tabs2(1:nx+1)) + tabs2 = 0.0_WP + call MPI_ALLREDUCE(spect(2,:),tabs2,nx+1,MPI_REAL_WP,MPI_SUM,MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(e_local,e_total,1,MPI_REAL_WP,MPI_SUM,& + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(d_local,diss_total,1,MPI_REAL_WP,MPI_SUM,& + & MPI_COMM_WORLD,ierr) + spect(2,:) = tabs2 + deallocate(tabs2) + + +!!$ if (rank.eq.0) then +!!$ print *,' Total energy ', e_total, tke +!!$ print *,' Total dissipation ', diss_total, dissipation +!!$ print *,' Number of modes ', ndense +!!$ endif + + iunit=iopen() + open(iunit,file='spectrum.analytic',form='formatted') + do i=1,nx+1 + spect(1,i) = real(i-1,WP)*dk + if ((spect(1,i).ne.0.0_WP).and.(spect(2,i).ne.0.0_WP)) then + write(11,*) spect(1,i),',',spect(2,i) + end if + end do + close(iclose(iunit)) + + + + ! Compute 3D velocity field + allocate(Uk(fns1,fns2,fns3)) + allocate(Vk(fns1,fns2,fns3)) + allocate(Wk(fns1,fns2,fns3)) + + Uk=(0.0_WP,0.0_WP) + Vk=(0.0_WP,0.0_WP) + Wk=(0.0_WP,0.0_WP) + + + + ! Compute the Fourier coefficients + do k=fnzs,fnze + kl = k - fnzs + 1 + do j=fnys,fnye + jl = j - fnys +1 + do i=fnxs,fnxe + + ! Wavenumbers + kx=real(i-1,WP)*dk + ky=real(j-1,WP)*dk + if (j.gt.nk) ky=-real(nx-j+1,WP)*dk + kz=real(k-1,WP)*dk + if (k.gt.nk) kz=-real(nx-k+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + kk2=sqrt(kx**2+ky**2) + + il = i - fnxs+1 + ! Compute the Fourier coefficients + if ((kk.gt.eps).and.(kk.le.kc)) then + if (kk2.lt.eps) then + Uk(il,jl,kl)=(ak(i,j,k)+bk(i,j,k))/sqrt(2.0_WP) + else + Uk(il,jl,kl)=(ak(i,j,k)*kk*ky+bk(i,j,k)*kx*kz)/(kk*kk2) + end if + if (kk2.lt.eps) then + Vk(il,jl,kl)=(bk(i,j,k)-ak(i,j,k))/sqrt(2.0_WP) + else + Vk(il,jl,kl)=(bk(i,j,k)*ky*kz-ak(i,j,k)*kk*kx)/(kk*kk2) + end if + Wk(il,jl,kl)=-bk(i,j,k)*kk2/kk + end if + end do + end do + end do + + deallocate(ak) + deallocate(bk) + + + +!!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!$!!!! ODDBALL NOT PROPERLY HANDLED - NEED TO BE FIXED +!!$!!!! FOR NOW - ONLY THE SIMPLE BOUNDARY (1,1,K) HANDLED +!!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!$ +!!$ ! Oddball +!!$ do k=2,nx +!!$ do j=nk+1,nx +!!$ Uk(1,j,k)=conjg(Uk(1,ny+2-j,nz+2-k)) +!!$ Vk(1,j,k)=conjg(Vk(1,ny+2-j,nz+2-k)) +!!$ Wk(1,j,k)=conjg(Wk(1,ny+2-j,nz+2-k)) +!!$ end do +!!$ end do + + do k=nk+1,fns3 + Uk(1,1,k)=conjg(Uk(1,1,nz+2-k)) + Vk(1,1,k)=conjg(Vk(1,1,nz+2-k)) + Wk(1,1,k)=conjg(Wk(1,1,nz+2-k)) + end do +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + call parser_read('Simulation type',itype) + if(itype.eq.0) then + + call btran_wrap(Uk,U,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,V,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,W,ns1,ns2,ns3,fns1,fns2,fns3) + +!!!!!!!!! +!! Simple correction to enforce energy spectrum after transform +!! Convert back to wavenumber space and force spectrum +!!!!!!!!! + + + + call ftran_wrap(U,Uk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(V,Vk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(W,Wk,ns1,ns2,ns3,fns1,fns2,fns3) + end if + + Uk = Uk/real(ns1**3.0_WP,WP) + Vk = Vk/real(ns1**3.0_WP,WP) + Wk = Wk/real(ns1**3.0_WP,WP) + + + allocate(sg(2,nx+1),s1(nx+1)) + s1 = 0.0_WP + !nnodes = 0 + + allocate(node_index(fns1,fns2,fns3)) + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + il = i + fnxs -1 + jl = j + fnys -1 + kl = k + fnzs -1 + kx=real(il-1,WP)*dk + ky=real(jl-1,WP)*dk + if (jl.gt.nk) ky=-real(nx-jl+1,WP)*dk + kz=real(kl-1,WP)*dk + if (kl.gt.nk) kz=-real(nx-kl+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + ik = 1+idint(kk/dk + 0.5_WP) + node_index(i,j,k) = ik + if (kk.gt.eps.and.kk.le.kc) then + s1(ik) = s1(ik) + real(Uk(i,j,k)*conjg(Uk(i,j,k))) + & + & real(Vk(i,j,k)*conjg(Vk(i,j,k))) +& + & real(Wk(i,j,k)*conjg(Wk(i,j,k))) + + endif + enddo + enddo + enddo + + + call MPI_ALLREDUCE(s1,sg(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + do i = 1,nx+1 + sg(1,i) = real(i-1,WP)*dk + if (sg(2,i).gt.1e-20_WP) then + sg(2,i) = spect(2,i)/sg(2,i) + else + sg(2,i) = 1.0_WP + endif + enddo + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + Uk(i,j,k) = Uk(i,j,k)*sqrt(sg(2,node_index(i,j,k))) + Vk(i,j,k) = Vk(i,j,k)*sqrt(sg(2,node_index(i,j,k))) + Wk(i,j,k) = Wk(i,j,k)*sqrt(sg(2,node_index(i,j,k))) + enddo + enddo + enddo + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! End of correction +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + call parallel_max(maxval(abs(Uk)),umax) + call parallel_max(maxval(abs(Vk)),vmax) + call parallel_max(maxval(abs(Wk)),wmax) + + +!!$ if (rank.eq.0) then +!!$ print *,' Maximum U,V,W after transforms',umax,vmax,wmax +!!$ endif +!!$ if (umax.eq.maxval(abs(Uk))) then +!!$ print *,' In processor rank ', rank +!!$ print *,' Location of maximum ', maxloc(abs(Uk)) +!!$ gg = maxloc(abs(Uk)) +!!$ print *,' Maximum value ', Uk(gg(1),gg(2),gg(3)) +!!$ endif +!!$ if (wmax.eq.maxval(abs(Wk))) then +!!$ print *,' In processor rank ', rank +!!$ print *,' Location of maximum ', maxloc(abs(Wk)) +!!$ gg = maxloc(abs(Wk)) +!!$ print *,' Maximum value ', Wk(gg(1),gg(2),gg(3)) +!!$ endif + +!!$ call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + + if(itype.eq.0) then + + call btran_wrap(Uk,U,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,V,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,W,ns1,ns2,ns3,fns1,fns2,fns3) + + end if + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! End of velocity initialization +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! Input for scalar field +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + call parser_read('ks/ko', ksk0ratio) + ks = ksk0ratio*dk +!!! Assume kc/ks to be 2 as in Eswaran and Pope + kc = 2.0_WP*ks + + + allocate(scalar(fns1sc,fns2sc,fns3sc)) + + scalar = (0.0_WP,0.0_WP) + if(rank.eq.0) print*,'test nksc',nksc + + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + il = i + fnxssc - 1 + jl = j + fnyssc - 1 + kl = k + fnzssc - 1 + + kx=real(il-1,WP)*dk + ky=real(jl-1,WP)*dk + if (jl.gt.nksc) ky=-real(nxsc-jl+1,WP)*dk + kz=real(kl-1,WP)*dk + if (kl.gt.nksc) kz=-real(nxsc-kl+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + kk2=sqrt(kx**2+ky**2) + if ((ks-dk/2.0_WP.le.kk).and.(kk.le.ks+dk/2.0_WP)) then + f_phi = 1.0_WP + else + f_phi = 0.0_WP + endif + call random_number(rand) + if (kk.lt.1e-10) then + scalar(i,j,k) = 0.0_WP + else + scalar(i,j,k) = sqrt(f_phi/(4.0_WP*pi*kk**2.0_WP))*exp(ii*2.0_WP*pi*rand) + endif + enddo + enddo + enddo + + + call btran_wrap(scalar,SC,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + SC = SC/real(ns1sc**3.0,WP) + + do k = 1,ns3sc + do j = 1,ns2sc + do i = 1,ns1sc + if (SC(i,j,k).le.0.0_WP) then + SC(i,j,k) = 0.0_WP + else + SC(i,j,k) = 1.0_WP + endif + enddo + enddo + enddo + + call ftran_wrap(SC,scalar,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + +! kcut = sqrt(2.0_WP)*real(nxsc,WP)/3.0_WP + kcut = real(nx,WP)/2.0_WP +! kcut = real(nxsc,WP)/2.0_WP + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + il = i + fnxssc - 1 + jl = j + fnyssc - 1 + kl = k + fnzssc - 1 + + kx=real(il-1,WP)*dk + ky=real(jl-1,WP)*dk + if (jl.gt.nksc) ky=-real(nxsc-jl+1,WP)*dk + kz=real(kl-1,WP)*dk + if (kl.gt.nksc) kz=-real(nxsc-kl+1,WP)*dk + kk =sqrt(kx**2+ky**2+kz**2) + kk2=sqrt(kx**2+ky**2) + + if (kk.gt.kcut) scalar(i,j,k) = 0.0_WP + + if (kk.le.kc) then + scalar(i,j,k) = scalar(i,j,k) + else + scalar(i,j,k) = scalar(i,j,k)*(kc/kk)**2.0_WP + endif + enddo + enddo + enddo + + call btran_wrap(scalar,SC,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + SC = SC/real(ns1sc**3.0,WP) + + + call parser_read('Imposing mean gradient',impose,0) + + +! if (impose.eq.1) then +! scmean = 0.0_WP +! do k = 1,ns3 +! do j = 1,ns2 +! do i = 1,ns1 +! scmean = scmean + SC(i,j,k) +! enddo +! enddo +! enddo + +! call MPI_ALLREDUCE(scmean,scmean_global,1,MPI_REAL_WP,MPI_SUM,& +! &MPI_COMM_WORLD,ierr) + +! scmean = scmean_global/(real(nx,WP)**3.0_WP) + +!!!!!!!!!!!! Setting scalar to zero - see if it lies within bounds +! do k = 1,ns3 +! do j = 1,ns2 +! do i = 1,ns1 +! SC(i,j,k) = 0.0_WP +! enddo +! enddo +! enddo + +! endif + + + ! Inverse Fourier transform + + ! Clean up + deallocate(Uk) + deallocate(Vk) + deallocate(Wk) + deallocate(scalar) + deallocate(node_index) + deallocate(s1) + deallocate(sg) + deallocate(spect) + + spfilename = 'spectrum_init' + spfilename2 = 'spectrum_init.scalar' + call get_dns_numbers(1) + +! do i = 1, ns1sc +! do j = 1, ns2sc +! do k = 1, ns3sc +! xx = i*L/ns1sc - L/2 +! yy = j*L/ns2sc - L/2 +! zz = k*L/ns3sc - L/2 +! SC(i,j,k) = sqrt(xx**2.0 + yy**2.0 + zz**2.0) +! end do +! end do +! end do + + + +! do i = 1, nxsc +! SC(i,:,:) = sin(real(i)/real(nxsc)*L) +! end do + + + +end subroutine hit_init + + diff --git a/CodesEnVrac/Remesh/FFTPAR/parser.f90 b/CodesEnVrac/Remesh/FFTPAR/parser.f90 new file mode 100755 index 000000000..c9b19f039 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/parser.f90 @@ -0,0 +1,428 @@ +module parser + use precision + implicit none + + ! Input values storage + integer, parameter :: tag_length=128 + integer, parameter :: line_length=40960 + integer :: nfields + type entry_type + character(tag_length) :: tag + character(line_length) :: value + end type entry_type + type(entry_type), pointer, dimension(:) :: entries + + ! Define interface for reading + interface parser_read + module procedure parser_readlogical + module procedure parser_readint + module procedure parser_readintarray + module procedure parser_readfloat + module procedure parser_readfloatarray + module procedure parser_readfloatarray2D + module procedure parser_readchar + module procedure parser_readchararray + end interface + +contains + + ! Pack the structure ----------------------------------------------------- + subroutine parser_pack(myfield) + implicit none + integer,intent(in) :: myfield + type(entry_type), pointer, dimension(:) :: entries_new + + allocate(entries_new(nfields-1)) + entries_new(1:myfield-1) = entries(1:myfield-1) + entries_new(myfield:nfields-1) = entries(myfield+1:nfields) + deallocate(entries) + nullify(entries) + entries => entries_new + nfields = nfields-1 + + return + end subroutine parser_pack + + ! Spread the structure --------------------------------------------------- + subroutine parser_spread + implicit none + type(entry_type), pointer, dimension(:) :: entries_new + + if (nfields .ne. 0) then + allocate(entries_new(nfields+1)) + entries_new(1:nfields) = entries(1:nfields) + deallocate(entries) + nullify(entries) + entries => entries_new + else + allocate(entries(1)) + end if + nfields = nfields+1 + + return + end subroutine parser_spread + + ! Add a new entry in the structure ---------------------------------------- + subroutine parser_newentry(mytag,myvalue) + implicit none + character(*),intent(in) :: mytag + character(*),intent(in) :: myvalue + integer :: ifield + logical :: isdef + + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + call parser_spread() + entries(nfields)%tag=mytag + entries(nfields)%value=myvalue + else + entries(ifield)%value=myvalue + end if + + return + end subroutine parser_newentry + + ! Get filed number from tag ---------------------------------------------- + subroutine parser_fieldfortag(mytag,myfield,isdef) + implicit none + character(*),intent(in) :: mytag + integer,intent(out) :: myfield + logical,optional,intent(out) :: isdef + integer :: ifield + + isdef = .false. + do ifield=1,nfields + if (entries(ifield)%tag==mytag) then + myfield=ifield + isdef = .true. + return + end if + end do + + return + end subroutine parser_fieldfortag + + ! Check whether the field is defined ------------------------------------- + subroutine parser_is_defined(mytag,isdef) + implicit none + + character(*),intent(in) :: mytag + logical,intent(out) :: isdef + integer :: ifield + + call parser_fieldfortag(mytag,ifield,isdef) + + return + end subroutine parser_is_defined + + ! Read logicals --------------------------------------------- + subroutine parser_readlogical(mytag,value,default) + implicit none + + character(*),intent(in) :: mytag + logical,intent(out) :: value + logical,optional,intent(in) :: default + integer :: ifield + logical :: isdef + + call parser_fieldfortag(mytag,ifield,isdef) + if (.not.isdef .AND. present(default)) then + value = default + else if (.not.isdef .AND. .not.present(default)) then + print*,'Parser : '// mytag //' not defined' + stop + else + read(entries(ifield)%value,*) value + end if + + return + end subroutine parser_readlogical + + ! Read integers --------------------------------------------- + subroutine parser_readint(mytag,value,default) + implicit none + + character(*),intent(in) :: mytag + integer,intent(out) :: value + integer,optional,intent(in) :: default + integer :: ifield + logical :: isdef + + call parser_fieldfortag(mytag,ifield,isdef) + if (.not.isdef .AND. present(default)) then + value = default + else if (.not.isdef .AND. .not.present(default)) then + print*,'Parser : '// mytag //' not defined' + stop + else + read(entries(ifield)%value,*) value + end if + + return + end subroutine parser_readint + + ! Read floats --------------------------------------------- + subroutine parser_readfloat(mytag,value,default) + implicit none + + character(*),intent(in) :: mytag + real(WP),intent(out) :: value + real(WP),optional,intent(in) :: default + integer :: ifield + logical :: isdef + + call parser_fieldfortag(mytag,ifield,isdef) + if (.not.isdef .AND. present(default)) then + value = default + else if (.not.isdef .AND. .not.present(default)) then + print*,'Parser : '// mytag //' not defined' + stop + else + read(entries(ifield)%value,*) value + end if + + return + end subroutine parser_readfloat + + ! Read characters --------------------------------------------- + subroutine parser_readchar(mytag,value,default) + implicit none + + character(*),intent(in) :: mytag + character(len=*),intent(out) :: value + character(len=*),optional,intent(in) :: default + integer :: ifield + logical :: isdef + + call parser_fieldfortag(mytag,ifield,isdef) + if (.not.isdef .AND. present(default)) then + value = default + else if (.not.isdef .AND. .not.present(default)) then + print*,'Parser : '// mytag //' not defined' + stop + else + read(entries(ifield)%value,'(a)') value + end if + + return + end subroutine parser_readchar + + ! Count size of the arrays ---------------------------------------- + subroutine parser_getsize(mytag,numb) + implicit none + + character(*),intent(in) :: mytag + integer,intent(out) :: numb + integer :: ifield + logical :: isdef + integer :: i + integer, dimension(line_length) :: counter + + ! Read it now + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + print*,'Parser : '// mytag //' not defined' + stop + end if + + ! Count the number of entries + counter = 0 + do i=1,len_trim(entries(ifield)%value) + if (entries(ifield)%value(i:i).EQ.' ') counter(i)=1 + end do + do i=1+1,len_trim(entries(ifield)%value) + if (counter(i).EQ.1 .AND. counter(i-1).EQ.1) counter(i-1)=0 + end do + numb = sum(counter)+1 + + return + end subroutine parser_getsize + + ! Read integer arrays --------------------------------------------- + subroutine parser_readintarray(mytag,value) + implicit none + + character(*),intent(in) :: mytag + integer,dimension(:),intent(out) :: value + integer :: ifield + logical :: isdef + + ! Read them + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + print*,'Parser : '// mytag //' not defined' + stop + end if + read(entries(ifield)%value,*) value + + return + end subroutine parser_readintarray + + ! Read float arrays --------------------------------------------- + subroutine parser_readfloatarray(mytag,value) + implicit none + + character(*),intent(in) :: mytag + real(WP),dimension(:),intent(out) :: value + integer :: ifield + logical :: isdef + + ! Read them + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + print*,'Parser : '// mytag //' not defined' + stop + end if + read(entries(ifield)%value,*) value + + return + end subroutine parser_readfloatarray + + ! Read float arrays --------------------------------------------- + subroutine parser_readfloatarray2D(mytag,value) + implicit none + + character(*),intent(in) :: mytag + real(WP),dimension(:,:),intent(out) :: value + integer :: ifield + logical :: isdef + + ! Read them + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + print*,'Parser : '// mytag //' not defined' + stop + end if + read(entries(ifield)%value,*) value + + return + end subroutine parser_readfloatarray2D + + ! Read float arrays --------------------------------------------- + subroutine parser_readchararray(mytag,value) + implicit none + + character(*),intent(in) :: mytag + character(*),dimension(:),intent(out) :: value + integer :: ifield + logical :: isdef + + ! Read them + call parser_fieldfortag(mytag,ifield,isdef) + if (.not. isdef) then + print*,'Parser : '// mytag //' not defined' + stop + end if + read(entries(ifield)%value,*) value + + return + end subroutine parser_readchararray + +end module parser + +! Initialize the parser --------------------------------------------- +subroutine parser_init + use parser + use fileio + implicit none + + nfields = 0 + if (associated(entries)) then + deallocate(entries) + nullify(entries) + end if + + return +end subroutine parser_init + +! Read & parse the input file --------------------------------------------- +subroutine parser_parsefile(input) + use parser + use fileio + + implicit none + integer :: iunit,ierr,limiter,nlines,i,j,ntags,comment + integer, dimension(:), allocatable :: limit,line + character(len=line_length) :: buffer + character(len=line_length), dimension(:), allocatable :: file + character(len=line_length) :: value + character(len=tag_length) :: tag + character(len=*) :: input + + ! Open the file + ierr = 0 + iunit = iopen() + open (iunit,file=input,form='formatted',status='old',iostat=ierr) + if (ierr .ne. 0) stop 'Parser : an input file is required' + + ! Count the number of lines in the file + ierr = 0 + nlines = 0 + do while (ierr .eq. 0) + read(iunit,'(a)',iostat=ierr) buffer + nlines = nlines + 1 + end do + rewind(iunit) + + ! Allocate to the right size + allocate(file(nlines+1),limit(nlines+1),line(nlines+1)) + + ! Read everything in the buffer + ierr = 0 + nlines = 0 + loop: do while (ierr .eq. 0) + read(iunit,'(a)',iostat=ierr) buffer + if (ierr.ne.0) exit loop + ! Remove the tabs + do j=1,line_length + if (ichar(buffer(j:j)).EQ.9) buffer(j:j)=' ' + end do + ! Find comments + comment = scan(buffer,'!#%') + ! Remove them + if (comment.NE.0) buffer(comment:) = '' + ! Trim + buffer = adjustl(buffer) + ! Add line + if (len_trim(buffer).NE.0) then + nlines = nlines + 1 + file(nlines) = buffer + end if + end do loop + + ! Close de file + close(iunit) + ierr = iclose(iunit) + + ! Get the tags + ntags = 0 + do i=1,nlines + limiter = index(file(i),':') + if (limiter.NE.0) then + ntags = ntags + 1 + line(ntags) = i + line(ntags+1) = nlines+1 + limit(ntags) = limiter + end if + end do + + ! Read everything now + do i=1,ntags + buffer = '' + do j=line(i),line(i+1)-1 + if (j==line(i)) then + buffer = trim(buffer) // trim(file(j)) + else + buffer = trim(buffer) // ' ' // trim(file(j)) + end if + end do + read(buffer(1:limit(i)-1),'(a)') tag + read(buffer(limit(i)+1:),'(a)') value + if (len_trim(value).NE.0) then + value = adjustl(value) + call parser_newentry(tag,value) + end if + end do + + return +end subroutine parser_parsefile diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocess.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocess.f90 new file mode 100755 index 000000000..4d2deef28 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocess.f90 @@ -0,0 +1,219 @@ +subroutine postprocess + + use solver + use parallel + use data + + implicit none + integer :: i,j,k,pas, nxo,nxoz + character(len=30) :: Filename,pdfufname + real(WP) :: nd,nut1,nut2,kt1,kt2 + real(WP) :: kk,h,nutm,ktm,Am,Bm,Cm,Dm,scht1,scht2,scht3,scht5,pdfscht5,CAm,DBm + integer :: ierr,ik,il,jl,kl,iunit + real(WP) :: pi,kc,eps,buf,epsil,u2,u3,u4,dudx,lambda,u1,epsil2,eta,sch,eta_B,mini,maxi + + real(WP), dimension(:,:,:), pointer :: Rbuf + real(WP), dimension(:,:,:), pointer :: Usc,Vsc,Wsc,Zsc !vitesses sous maillage du scalaire + real(WP), dimension(:,:,:), pointer :: T1,T2,T3,diss !flux scalaire + real(WP), dimension(:,:,:), pointer :: dZdx, dZdy, dZdz, dZdxsc, dZdysc, dZdzsc + real(WP), dimension(:,:,:), pointer :: NUT,SCHT,KT + real(WP), dimension(:,:,:), pointer :: tabA,tabB,tabC,tabD + real(WP), dimension(:), pointer :: cor,sf2,sf3 + complex(WP), dimension(:,:,:), pointer :: d11,d12,d13,d22,d23,d33 + real(WP), dimension(:,:), pointer :: S1,S2,S3,Sg + real(WP), dimension(:,:), pointer :: S11,S21,S31,Sg1 + + + real(WP), dimension(:,:,:), pointer :: z + real(WP), dimension(:), pointer :: xx,pdf + integer :: dime + + +!!! Uk, Vk, Wk and Zk the three component of velocity and scalar in spectral space + + dime = 200 + allocate(xx(dime)) + allocate(pdf(dime)) + call c_pdf_sca(xx,pdf,SC,dime) + if(rank.eq.0) then + open(14,file='pdf_z',form='formatted') + do i=1,dime-1 + write(14,*) xx(i), pdf(i) + enddo + close(14) + endif + deallocate(xx) + deallocate(pdf) + + +!!! Energy Spectrum + spfilename = 'spectrum.post' + spfilename2 = 'spectrum.post.scalar' + call get_dns_numbers(1) + + + if (ns1sc.eq.ns1) then + + call parser_read('Nx filter output',nxo,0) + + nd = real(ns1)/real(nxo) + !! on 256^3 just cutfilter + allocate(Usc(ns1,ns2,ns3)) + allocate(Vsc(ns1,ns2,ns3)) + allocate(Wsc(ns1,ns2,ns3)) + allocate(Zsc(ns1,ns2,ns3)) + allocate(T1(ns1,ns2,ns3)) + allocate(T2(ns1,ns2,ns3)) + allocate(T3(ns1,ns2,ns3)) + call speccutfilter(SC,Zsc,nd) + call speccutfilter(U,Usc,nd) + call speccutfilter(V,Vsc,nd) + call speccutfilter(W,Wsc,nd) + call speccutfilter(U*SC,T1,nd) + call speccutfilter(V*SC,T2,nd) + call speccutfilter(W*SC,T3,nd) + T1 = T1 - Usc*Zsc + T2 = T2 - Vsc*Zsc + T3 = T3 - Wsc*Zsc + allocate(dZdx(ns1,ns2,ns3)) + allocate(dZdy(ns1,ns2,ns3)) + allocate(dZdz(ns1,ns2,ns3)) + call gradient(Zsc,0.0,dZdx,dZdy,dZdz) + + allocate(diss(ns1,ns2,ns3)) + diss = T1*dZdx + T2*dZdy + T3*dZdz + + T1 = SC + SC = diss + file_counter = 1 + call data_write + SC = T1 + call moyensc(diss,nut1) + if (rank.eq.0) print*,'mean diss 256-1 :',nut1 + + + !! on 256^3 cutfilter + cutfilter of product + call speccutfilter(U*SC,T1,nd) + call speccutfilter(V*SC,T2,nd) + call speccutfilter(W*SC,T3,nd) + call speccutfilter(Usc*Zsc,diss,nd) + T1 = T1 - diss + call speccutfilter(Vsc*Zsc,diss,nd) + T2 = T2 - diss + call speccutfilter(Wsc*Zsc,diss,nd) + T3 = T3 - diss + call speccutfilter(T1*dZdx,Usc,nd) + call speccutfilter(T2*dZdy,Vsc,nd) + call speccutfilter(T3*dZdz,Wsc,nd) + diss = Usc + Vsc + Wsc + + T1 = SC + SC = diss + file_counter = 2 + call data_write + SC = T1 + call moyensc(diss,nut1) + if (rank.eq.0) print*,'mean diss 256-2 :',nut1 + + deallocate(diss) + deallocate(Usc) + deallocate(Vsc) + deallocate(Wsc) + deallocate(Zsc) + deallocate(T1) + deallocate(T2) + deallocate(T3) + + nxoz = nxo / nproc + allocate(Usc(nxo,nxo,nxoz)) + allocate(Vsc(nxo,nxo,nxoz)) + allocate(Wsc(nxo,nxo,nxoz)) + allocate(Zsc(nxo,nxo,nxoz)) + allocate(T1(nxo,nxo,nxoz)) + allocate(T2(nxo,nxo,nxoz)) + allocate(T3(nxo,nxo,nxoz)) + + call discretisation3(SC,Zsc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(U,Usc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(V,Vsc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(W,Wsc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(U*SC,T1,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(v*SC,T2,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(W*SC,T3,ns1,ns2,ns3,nxo,nxo,nxoz) + T1 = T1 - Usc*Zsc + T2 = T2 - Vsc*Zsc + T3 = T3 - Wsc*Zsc + + allocate(dZdxsc(nxo,nxo,nxoz)) + allocate(dZdysc(nxo,nxo,nxoz)) + allocate(dZdzsc(nxo,nxo,nxoz)) + call gradient(SC,0.0,dZdx,dZdy,dZdz) + call discretisation3(dZdx,dZdxsc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(dZdy,dZdysc,ns1,ns2,ns3,nxo,nxo,nxoz) + call discretisation3(dZdz,dZdzsc,ns1,ns2,ns3,nxo,nxo,nxoz) + + + allocate(diss(nxo,nxo,nxoz)) + diss = T1*dZdxsc + T2*dZdysc + T3*dZdzsc + + nxsc = nxo + nysc = nxsc + nzsc = nxsc + + if (mod(nzsc,nproc).ne.0) then + print *,' NXSC should be exactly divided by the number of processors' + stop + endif + + nksc = nxsc/2+1 + + ns1sc = nxsc + ns2sc = nysc + ns3sc = nzsc/nproc + + nxssc = 1 + nxesc = nxsc + + nyssc = 1 + nyesc = nysc + + nzssc = 1 +(rank)*ns3sc + nzesc = (rank+1)*ns3sc + + fns1sc = nksc + fns2sc = nysc/nproc + fns3sc = nzsc + + fnxssc = 1 + fnxesc = nksc + + fnyssc = 1 + (rank)*fns2sc + fnyesc = (rank+1)*fns2sc + + fnzssc = 1 + fnzesc = fns3sc + + call random_init + call transform_init + deallocate(data_storesc) + call data_init + + SC = diss + + print*,SC(1,1,1) + print*,SC(ns1sc,ns2sc,ns3sc) + + call moyensc(SC,nut1) + if (rank.eq.0) print*,'mean diss 64:',nut1 + + file_counter = 3 + call data_write + + else if (ns1sc.lt.ns1) then + + print*,'solver_step' + call solver_step + + end if + +end subroutine postprocess diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocess5.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocess5.f90 new file mode 100755 index 000000000..69e3b5f77 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocess5.f90 @@ -0,0 +1,89 @@ +subroutine postprocess5 +!!! FOR SGS STRESS MODEL + + use solver + use parallel + use data + + implicit none + integer :: i,j,k + real(WP) :: kk,h,nd,nb,ffsize + integer :: ierr,ik,il,jl,kl,iunit,dime,ndd,m1 + real(WP) :: pi,kc,eps,buf,epsil,u2,u3,u4,dx,cst1,cst2,cst3 + character*13 filexy1,filexy2,filexy3 + character*13 filepdf1,filepdf2,filepdf3 + character*13 filepdf4,filepdf5,filepdf6 + + real(WP) :: dudx(ns1,ns2,ns3) + real(WP) :: dudy(ns1,ns2,ns3) + real(WP) :: dudz(ns1,ns2,ns3) + real(WP) :: dvdx(ns1,ns2,ns3) + real(WP) :: dvdy(ns1,ns2,ns3) + real(WP) :: dvdz(ns1,ns2,ns3) + real(WP) :: dwdx(ns1,ns2,ns3) + real(WP) :: dwdy(ns1,ns2,ns3) + real(WP) :: dwdz(ns1,ns2,ns3) + real(WP) :: S11(ns1,ns2,ns3) + real(WP) :: S12(ns1,ns2,ns3) + real(WP) :: S13(ns1,ns2,ns3) + real(WP) :: S22(ns1,ns2,ns3) + real(WP) :: S23(ns1,ns2,ns3) + real(WP) :: S33(ns1,ns2,ns3) + real(WP) :: O11(ns1,ns2,ns3) + real(WP) :: O12(ns1,ns2,ns3) + real(WP) :: O13(ns1,ns2,ns3) + real(WP) :: O22(ns1,ns2,ns3) + real(WP) :: O23(ns1,ns2,ns3) + real(WP) :: O33(ns1,ns2,ns3) + real(WP) :: CQ(ns1,ns2,ns3) + real(WP) :: w1(ns1,ns2,ns3) + real(WP) :: w2(ns1,ns2,ns3) + real(WP) :: w3(ns1,ns2,ns3) + + real(WP) :: xx(500), pdf(500) + + dime = 500 + +!!! Uk, Vk, Wk and Zk the three component of velocity and scalar in spectral space + +!!! All in spatial space + + call gradient(U,0.,dudx,dudy,dudz) + call gradient(V,0.,dvdx,dvdy,dvdz) + call gradient(W,0.,dwdx,dwdy,dwdz) + + S11 = dudx + S22 = dvdy + S33 = dwdz + S12 = 0.5* (dudy + dvdx) + S13 = 0.5* (dudz + dwdx) + S23 = 0.5* (dvdz + dwdy) + O11 = 0. + O22 = 0. + O33 = 0. + O12 = 0.5* (dudy - dvdx) + O13 = 0.5* (dudz - dwdx) + O23 = 0.5* (dvdz - dwdy) + CQ = 0.5*(O11*O11 - S11*S11 + O22*O22 - S22*S22 + O33*O33 - S33*S33 + & + & 2.0*(O12*O12 - S12*S12 + O13*O13 - S13*S13 + O23*O23 - S23*S23)) + w1 = dwdy - dvdz + w2 = dudz - dwdx + w3 = dvdx - dudy + + if (rank.eq.0) call dump_geometry + if (rank.eq.0) call dump_geometry_scalar + call dump_data(U,'paravie_vel_1') + call dump_data(V,'paravie_vel_2') + call dump_data(W,'paravie_vel_3') + call dump_data(w1,'paravie_vor_1') + call dump_data(w2,'paravie_vor_2') + call dump_data(w3,'paravie_vor_3') + call dump_data(CQ,'paravie_critQ') + call dump_data_sc(SC,'paravie_scalr') + O11 = w1*w1 + w2*w2 + w3*w3 + O33 = U*U + V*V + W*W + call dump_data(O11,'paravie_vor_e') + call dump_data(O33,'paravie_vel_e') + + +end subroutine postprocess5 diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocess6.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocess6.f90 new file mode 100755 index 000000000..9d9b01a6e --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocess6.f90 @@ -0,0 +1,56 @@ +subroutine postprocess6 + + use solver + use parallel + use data + + implicit none + integer :: i,j,k,pas,ns1ne,ns2ne,ns3ne + character(len=30) :: Filename + integer :: ierr,ik,il,jl,kl,iunit + + real(WP), dimension(:,:,:), pointer :: Une,Vne,Wne,Zne ! vitesses pour nouveau maillage + integer :: dime + +!!! INTEGER + + call parser_read('New discretisation',ns1ne) + ns2ne = ns1ne + ns3ne = ns1ne/nproc + + +!!! TRANSFOMATION DE LA DISCRETISATION DE NX^3 EN NXNE^3 + + if (rank.eq.0) print*,'allocation des tableaux',ns1ne + allocate(Une(ns1ne,ns2ne,ns3ne)) + allocate(Vne(ns1ne,ns2ne,ns3ne)) + allocate(Wne(ns1ne,ns2ne,ns3ne)) + allocate(Zne(ns1ne,ns2ne,ns3ne)) + Une = 0.0 + Vne = 0.0 + Wne = 0.0 + Zne = 0.0 + if (rank.eq.0) print*,'changement de discretisation U' + call discretisation2(U,Une,ns1,ns2,ns3,ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'changement de discretisation V' + call discretisation2(V,Vne,ns1,ns2,ns3,ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'changement de discretisation W' + call discretisation2(W,Wne,ns1,ns2,ns3,ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'changement de discretisation Z' + call discretisation2(SC,Zne,ns1sc,ns2sc,ns3sc,ns1ne,ns2ne,ns3ne) + + if (rank.eq.0) print*,'enregistrement tabU' + call tab_write_ne(Une,'tabU.out',ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'enregistrement tabV' + call tab_write_ne(Vne,'tabV.out',ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'enregistrement tabW' + call tab_write_ne(Wne,'tabW.out',ns1ne,ns2ne,ns3ne) + if (rank.eq.0) print*,'enregistrement tabZ' + call tab_write_ne(Zne,'tabZ.out',ns1ne,ns2ne,ns3ne) + + deallocate(Une) + deallocate(Vne) + deallocate(Wne) + deallocate(Zne) + +end subroutine postprocess6 diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocess7.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocess7.f90 new file mode 100755 index 000000000..42946de56 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocess7.f90 @@ -0,0 +1,156 @@ +subroutine postprocess7 + + use solver + use parallel + use data + + implicit none + integer :: i,j,k,pas,ns1ne,ns2ne,ns3ne + character(len=30) :: Filename + integer :: ierr,ik,il,jl,kl,iunit + + real(WP), dimension(:), pointer :: xx,pdf + real(WP), dimension(:,:,:), pointer :: convU, convV, convW + real(WP), dimension(:,:,:), pointer :: Us1, Vs1, Ws1 , norme + real(WP), dimension(:,:,:), pointer :: dudx, dudy, dudz + real(WP), dimension(:,:,:), pointer :: dvdx, dvdy, dvdz + real(WP), dimension(:,:,:), pointer :: dwdx, dwdy, dwdz + integer :: dime + + dime = 200 + + !! STEP 1 + call solver_step + call dns_stats + if (rank.eq.0) print*,'STEP 1' + allocate(Us1(ns1,ns2,ns3)) + allocate(Vs1(ns1,ns2,ns3)) + allocate(Ws1(ns1,ns2,ns3)) + Us1 = U + Vs1 = V + Ws1 = W + + ! STEP 2 + if (rank.eq.0) print*,'STEP 2' + call solver_step + call dns_stats + allocate(dudx(ns1,ns2,ns3)) + allocate(dudy(ns1,ns2,ns3)) + allocate(dudz(ns1,ns2,ns3)) + allocate(dvdx(ns1,ns2,ns3)) + allocate(dvdy(ns1,ns2,ns3)) + allocate(dvdz(ns1,ns2,ns3)) + allocate(dwdx(ns1,ns2,ns3)) + allocate(dwdy(ns1,ns2,ns3)) + allocate(dwdz(ns1,ns2,ns3)) + + if (rank.eq.0) print*,'comput tab' + call gradient(U,0.,dudx,dudy,dudz) + call gradient(V,0.,dvdx,dvdy,dvdz) + call gradient(W,0.,dwdx,dwdy,dwdz) + + if (rank.eq.0) print*,'comput conv term' + allocate(convU(ns1,ns2,ns3)) + allocate(convV(ns1,ns2,ns3)) + allocate(convW(ns1,ns2,ns3)) + convU = U*dudx + V*dudy + W*dudz + convV = U*dvdx + V*dvdy + W*dvdz + convW = U*dwdx + V*dwdy + W*dwdz + deallocate(dudx) + deallocate(dudy) + deallocate(dudz) + deallocate(dvdx) + deallocate(dvdy) + deallocate(dvdz) + deallocate(dwdx) + deallocate(dwdy) + deallocate(dwdz) + + !! STEP 3 + if (rank.eq.0) print*,'STEP 3' + call solver_step + call dns_stats + + + if (rank.eq.0) print*,'acceleration term, dt =', dt + + Us1 = (U - Us1) / (2*dt) + convU + Vs1 = (V - Vs1) / (2*dt) + convV + Ws1 = (W - Ws1) / (2*dt) + convW + + if (rank.eq.0) print*,'norme' + allocate(norme(ns1,ns2,ns3)) + norme = (Us1*Us1 + Vs1*Vs1 + Ws1*Ws1)**(0.5) + + deallocate(convU) + deallocate(convV) + deallocate(convW) + + if (rank.eq.0) print*,'PDF' + allocate(xx(dime)) + allocate(pdf(dime)) + write(FileName,'(A,I2.2,A)') 'pdf_U' + call c_pdf(xx,pdf,Us1,dime) + if(rank.eq.0) then + open(14,file=Filename,form='formatted') + do i=1,dime-1 + write(14,*) xx(i), pdf(i) + enddo + close(14) + endif + write(FileName,'(A,I2.2,A)') 'pdf_V' + call c_pdf(xx,pdf,Vs1,dime) + if(rank.eq.0) then + open(14,file=Filename,form='formatted') + do i=1,dime-1 + write(14,*) xx(i), pdf(i) + enddo + close(14) + endif + write(FileName,'(A,I2.2,A)') 'pdf_W' + call c_pdf(xx,pdf,Ws1,dime) + if(rank.eq.0) then + open(14,file=Filename,form='formatted') + do i=1,dime-1 + write(14,*) xx(i), pdf(i) + enddo + close(14) + endif + write(FileName,'(A,I2.2,A)') 'pdf_nor' + call c_pdf(xx,pdf,norme,dime) + if(rank.eq.0) then + open(14,file=Filename,form='formatted') + do i=1,dime-1 + write(14,*) xx(i), pdf(i) + enddo + close(14) + endif + deallocate(xx) + deallocate(pdf) + + if (rank.eq.0) print*,'PARAVIEW' + call dump_data(Us1,'paravie_acc_1') + call dump_data(Vs1,'paravie_acc_2') + call dump_data(Ws1,'paravie_acc_3') + call dump_data(norme,'paravie_acc_n') + + if( rank.eq.0 ) print*,Us1(1,1,1) + if( rank.eq.nproc-1 ) print*,Us1(ns1,ns2,ns3) + call tab_write_ne(Us1,'tabaccU.out',ns1,ns2,ns3) + if( rank.eq.0 ) print*,Vs1(1,1,1) + if( rank.eq.nproc-1 ) print*,Vs1(ns1,ns2,ns3) + call tab_write_ne(Vs1,'tabaccV.out',ns1,ns2,ns3) + if( rank.eq.0 ) print*,Ws1(1,1,1) + if( rank.eq.nproc-1 ) print*,Ws1(ns1,ns2,ns3) + call tab_write_ne(Ws1,'tabaccW.out',ns1,ns2,ns3) + if( rank.eq.0 ) print*,norme(1,1,1) + if( rank.eq.nproc-1 ) print*,norme(ns1,ns2,ns3) + call tab_write_ne(norme,'tabaccnorme.out',ns1,ns2,ns3) + + + deallocate(norme) + deallocate(Us1) + deallocate(Vs1) + deallocate(Ws1) + +end subroutine postprocess7 diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocessparaview.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocessparaview.f90 new file mode 100755 index 000000000..67fc80a13 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocessparaview.f90 @@ -0,0 +1,338 @@ +subroutine dump_data(scalar,name) + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(ns1,ns2,ns3) :: scalar + character(len=13) :: name + character(len=80) :: buffer + integer :: iunit,ierr,size,ibuffer, k, kp + integer :: fileview,datasize,gdatasize + integer, dimension(MPI_STATUS_SIZE) :: status + integer(kind=MPI_OFFSET_KIND) :: disp + integer :: gsizes(3),lsizes(3),start(3) + real(SP), dimension(:,:,:), pointer :: tab + + call MPI_FILE_OPEN(MPI_COMM_WORLD,trim(name),MPI_MODE_WRONLY+MPI_MODE_CREATE,MPI_INFO_NULL,iunit,ierr) + + if (rank.eq.0) then + buffer = trim(name) + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + buffer = 'part' + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + ibuffer = 1 + size = 1 + call MPI_FILE_WRITE(iunit,ibuffer,size,MPI_INTEGER,status,ierr) + buffer = 'block' + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + end if + + + ! Create the view + gsizes(1) = nx + gsizes(2) = nx + gsizes(3) = nx + lsizes(1) = ns1 + lsizes(2) = ns2 + lsizes(3) = ns3 + start(1) = nxs - 1 + start(2) = nys - 1 + start(3) = nzs - 1 + datasize = lsizes(1)*lsizes(2)*lsizes(3) + gdatasize= gsizes(1)*gsizes(2)*gsizes(3) + + call MPI_TYPE_CREATE_SUBARRAY(3,gsizes,lsizes,start,MPI_ORDER_FORTRAN,MPI_REAL,fileview,ierr) + call MPI_TYPE_COMMIT(fileview,ierr) + + disp = 3*80+4 + allocate(tab(1:nx,1:nx,nzs:nze)) + do k = 1,ns3 + kp = k + rank*ns3 + tab(:,:,kp) = scalar(:,:,k) + end do + call MPI_FILE_SET_VIEW(iunit,disp,MPI_REAL,fileview,"native",MPI_INFO_NULL,ierr) + call MPI_FILE_WRITE_ALL(iunit,tab,datasize,MPI_REAL,status,ierr) + + call MPI_FILE_CLOSE(iunit,ierr) + +end subroutine dump_data + +subroutine dump_geometry + + use solver + use parallel + use data + + implicit none + + integer :: ierr,ipart,iunit,i,j,k + character(len=80) :: buffer + real(SP), dimension(:,:,:), pointer :: xbuf,ybuf,zbuf + integer, dimension(:,:,:), pointer :: iblank + real(SP) :: max_x,max_y,max_z + real(SP) :: min_x,min_y,min_z + + allocate(xbuf(1:nx+1,1:nx+1,1:nx+1),ybuf(1:nx+1,1:nx+1,1:nx+1),zbuf(1:nx+1,1:nx+1,1:nx+1)) + do i=1,nx+1 + do j=1,ny+1 + do k=1,nz+1 + xbuf(i,j,k)= (real(i)-1.5)*L/real(nx) + ybuf(i,j,k)= (real(j)-1.5)*L/real(nx) + zbuf(i,j,k)= (real(k)-1.5)*L/real(nx) + end do + end do + end do + max_x = maxval(xbuf) + max_y = maxval(ybuf) + max_z = maxval(zbuf) + min_x = minval(xbuf) + min_y = minval(ybuf) + min_z = minval(zbuf) + + ! Open the file + !call BINARY_FILE_OPEN(12345,"geometry","w",ierr) + OPEN(UNIT=12345, FILE='geometry', FORM='unformatted',access='stream') + REWIND(12345) + + ! Write the geometry + buffer = 'C Binary' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'Ensight Gold Geometry File' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'Structured Geometry from ARTS' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'node id off' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'element id off' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'part' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + ipart = 1 + !call BINARY_FILE_WRITE(12345,ipart,1,kind(ipart),ierr) + write(12345) ipart + + buffer = 'Complete geometry' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'block curvilinear iblanked' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + !call BINARY_FILE_WRITE(12345,nx+1,1,kind(nx),ierr) + !call BINARY_FILE_WRITE(12345,ny+1,1,kind(ny),ierr) + !call BINARY_FILE_WRITE(12345,nz+1,1,kind(nz),ierr) + write(12345) nx+1 + write(12345) ny+1 + write(12345) nz+1 + + + !call BINARY_FILE_WRITE(12345,xbuf,(nx+1)*(ny+1)*(nz+1),kind(xbuf),ierr) + !call BINARY_FILE_WRITE(12345,ybuf,(nx+1)*(ny+1)*(nz+1),kind(ybuf),ierr) + !call BINARY_FILE_WRITE(12345,zbuf,(nx+1)*(ny+1)*(nz+1),kind(zbuf),ierr) + write(12345) xbuf + write(12345) ybuf + write(12345) zbuf + + ! Get the iblank in 3D + allocate(iblank(nx+1,ny+1,nz+1)) + do k=1,nz+1 + iblank(1:nx+1,1:ny+1,k) = 1 + end do + !call BINARY_FILE_WRITE(12345,iblank,(nx+1)*(ny+1)*(nz+1),kind(iblank),ierr) + write(12345) iblank + + ! Close the file + !call BINARY_FILE_CLOSE(12345,ierr) + CLOSE(12345) + +end subroutine dump_geometry + +subroutine dump_geometry_scalar + + use solver + use parallel + use data + + implicit none + + integer :: ierr,ipart,iunit,i,j,k + character(len=80) :: buffer + real(SP), dimension(:,:,:), pointer :: xbuf,ybuf,zbuf + integer, dimension(:,:,:), pointer :: iblank + real(SP) :: max_x,max_y,max_z + real(SP) :: min_x,min_y,min_z + + allocate(xbuf(1:nxsc+1,1:nxsc+1,1:nxsc+1),ybuf(1:nxsc+1,1:nxsc+1,1:nxsc+1),zbuf(1:nxsc+1,1:nxsc+1,1:nxsc+1)) + do i=1,nxsc+1 + do j=1,nysc+1 + do k=1,nzsc+1 + xbuf(i,j,k)= (real(i)-1.5)*L/real(nxsc) + ybuf(i,j,k)= (real(j)-1.5)*L/real(nxsc) + zbuf(i,j,k)= (real(k)-1.5)*L/real(nxsc) + end do + end do + end do + max_x = maxval(xbuf) + max_y = maxval(ybuf) + max_z = maxval(zbuf) + min_x = minval(xbuf) + min_y = minval(ybuf) + min_z = minval(zbuf) + + print*,"j'y passe" + + ! Open the file + !call BINARY_FILE_OPEN(12345,"geomesca","w",ierr) + OPEN(UNIT=12345, FILE='geomesca', FORM='unformatted',access='stream') + REWIND(12345) + + ! Write the geometry + buffer = 'C Binary' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'Ensight Gold Geometry File' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'Structured Geometry from ARTS' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'node id off' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'element id off' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'part' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + ipart = 1 + !call BINARY_FILE_WRITE(12345,ipart,1,kind(ipart),ierr) + write(12345) ipart + + buffer = 'Complete geometry' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + buffer = 'block curvilinear iblanked' + !call BINARY_FILE_WRITE(12345,buffer,80,kind(buffer),ierr) + write(12345) buffer + + !call BINARY_FILE_WRITE(12345,nxsc+1,1,kind(nxsc),ierr) + !call BINARY_FILE_WRITE(12345,nysc+1,1,kind(nysc),ierr) + !call BINARY_FILE_WRITE(12345,nzsc+1,1,kind(nzsc),ierr) + write(12345) nxsc+1 + write(12345) nysc+1 + write(12345) nzsc+1 + + + !call BINARY_FILE_WRITE(12345,xbuf,2*(nysc+1)*(nzsc+1),kind(xbuf),ierr) + !call BINARY_FILE_WRITE(12345,ybuf,2*(nysc+1)*(nzsc+1),kind(ybuf),ierr) + !call BINARY_FILE_WRITE(12345,zbuf,2*(nysc+1)*(nzsc+1),kind(zbuf),ierr) + write(12345) xbuf + write(12345) ybuf + write(12345) zbuf + + ! Get the iblank in 3D + allocate(iblank(nxsc+1,nysc+1,nzsc+1)) + do k=1,nzsc+1 + iblank(1:nxsc+1,1:nysc+1,k) = 1 + end do + !call BINARY_FILE_WRITE(12345,iblank,(nxsc+1)*(nysc+1)*(nzsc+1),kind(iblank),ierr) + write(12345) iblank + + ! Close the file + !call BINARY_FILE_CLOSE(12345,ierr) + CLOSE(12345) + +end subroutine dump_geometry_scalar + + +subroutine dump_data_sc(scalar,name) + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(ns1sc,ns2sc,ns3sc) :: scalar + character(len=13) :: name + character(len=80) :: buffer + integer :: iunit,ierr,size,ibuffer, k, kp + integer :: fileview,datasize,gdatasize + integer, dimension(MPI_STATUS_SIZE) :: status + integer(kind=MPI_OFFSET_KIND) :: disp + integer :: gsizes(3),lsizes(3),start(3) + real(SP), dimension(:,:,:), pointer :: tab + + call MPI_FILE_OPEN(MPI_COMM_WORLD,trim(name),MPI_MODE_WRONLY+MPI_MODE_CREATE,MPI_INFO_NULL,iunit,ierr) + + if (rank.eq.0) then + buffer = trim(name) + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + buffer = 'part' + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + ibuffer = 1 + size = 1 + call MPI_FILE_WRITE(iunit,ibuffer,size,MPI_INTEGER,status,ierr) + buffer = 'block' + size = 80 + call MPI_FILE_WRITE(iunit,buffer,size,MPI_CHARACTER,status,ierr) + end if + + + ! Create the view + gsizes(1) = nxsc + gsizes(2) = nxsc + gsizes(3) = nxsc + lsizes(1) = ns1sc + lsizes(2) = ns2sc + lsizes(3) = ns3sc + start(1) = nxssc - 1 + start(2) = nyssc - 1 + start(3) = nzssc - 1 + datasize = lsizes(1)*lsizes(2)*lsizes(3) + gdatasize= gsizes(1)*gsizes(2)*gsizes(3) + + call MPI_TYPE_CREATE_SUBARRAY(3,gsizes,lsizes,start,MPI_ORDER_FORTRAN,MPI_REAL,fileview,ierr) + call MPI_TYPE_COMMIT(fileview,ierr) + + disp = 3*80+4 + allocate(tab(1:nxsc,1:nxsc,nzssc:nzesc)) + do k = 1,ns3sc + kp = k + rank*ns3sc + tab(:,:,kp) = scalar(:,:,k) + end do + call MPI_FILE_SET_VIEW(iunit,disp,MPI_REAL,fileview,"native",MPI_INFO_NULL,ierr) + call MPI_FILE_WRITE_ALL(iunit,tab,datasize,MPI_REAL,status,ierr) + + call MPI_FILE_CLOSE(iunit,ierr) + +end subroutine dump_data_sc diff --git a/CodesEnVrac/Remesh/FFTPAR/postprocesstools.f90 b/CodesEnVrac/Remesh/FFTPAR/postprocesstools.f90 new file mode 100755 index 000000000..7a5710b71 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/postprocesstools.f90 @@ -0,0 +1,1480 @@ +subroutine cc_pdf(xx,pdf,z,in2,value,dime) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr + real(WP) :: z(ns1,ns2,ns3),umin,umax,umin_recv,umax_recv,delta + integer :: in2(ns1,ns2,ns3), value, cpt2, cptt + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin=1.d33 + umax=-1.d33 + + Do k =1,ns3 + Do j = 1,ns2 + Do i=1,ns1 + if (in2(i,j,k).eq.value) then + umax = max(umax,z(i,j,k)) + umin = min(umin,z(i,j,k)) + end if + End Do + End Do + End Do + + !umax = 5 + !umin = -5 + + Call MPI_ALLREDUCE(umin, umin_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + umin = umin_recv + Call MPI_ALLREDUCE(umax, umax_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + umax = umax_recv + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (in2(i,j,k).eq.value) then + if (z(i,j,k) .gt. umin+(ll-1)*delta ) then + if (z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt+1 + end if + end if + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(cptt,cpt2,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + pdf=pdf/(delta*real(cpt2)) +end subroutine cc_pdf + +subroutine c_pdf_sca(xx,pdf,z,dime) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr, cpt2, cptt + real(WP) :: z(ns1sc,ns2sc,ns3sc),umin,umax,umin_recv,umax_recv,delta + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin=1.d33 + umax=-1.d33 + + Do k =1,ns3sc + Do j = 1,ns2sc + Do i=1,ns1sc + umax = max(umax,z(i,j,k)) + umin = min(umin,z(i,j,k)) + End Do + End Do + End Do + + Call MPI_ALLREDUCE(umin, umin_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + umin = umin_recv + Call MPI_ALLREDUCE(umax, umax_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + umax = umax_recv + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3sc + do j = 1,ns2sc + do i = 1,ns1sc + if( z(i,j,k) .gt. umin+(ll-1)*delta ) then + if( z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt + 1 + endif + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(cptt,cpt2,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + pdf=pdf/(delta*real(cpt2)) +end subroutine c_pdf_sca + +subroutine c_pdf_sca_fix(xx,pdf,z,dime,mini,maxi) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr, cpt2, cptt + real(WP) :: z(ns1sc,ns2sc,ns3sc),umin,umax,umin_recv,umax_recv,delta,mini,maxi + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin = mini + umax = maxi + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3sc + do j = 1,ns2sc + do i = 1,ns1sc + if( z(i,j,k) .gt. umin+(ll-1)*delta ) then + if( z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt + 1 + endif + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(cptt,cpt2,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) +! pdf=pdf/(delta*real(cpt2)) + if(rank.eq.0) print*,'nombre de point dans la pdf avec min =',mini, & + & ' et max =',maxi, ": ", real(cpt2)/ns1sc**3.*100.," pourcent de points" +end subroutine c_pdf_sca_fix + +subroutine c_pdf(xx,pdf,z,dime) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr, cpt2, cptt + real(WP) :: z(ns1,ns2,ns3),umin,umax,umin_recv,umax_recv,delta + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin=1.d33 + umax=-1.d33 + + Do k =1,ns3 + Do j = 1,ns2 + Do i=1,ns1 + umax = max(umax,z(i,j,k)) + umin = min(umin,z(i,j,k)) + End Do + End Do + End Do + + Call MPI_ALLREDUCE(umin, umin_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + umin = umin_recv + Call MPI_ALLREDUCE(umax, umax_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + umax = umax_recv + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if( z(i,j,k) .gt. umin+(ll-1)*delta ) then + if( z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt + 1 + endif + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(cptt,cpt2,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + pdf=pdf/(delta*real(cpt2)) +end subroutine c_pdf + +subroutine cn_pdf(xx,pdf,z,dnsdiss,dime) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr + real(WP) :: dnsdiss(ns1,ns2,ns3),z(ns1,ns2,ns3),umin,umax,umin_recv,umax_recv,delta,cptt + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin=1.d33 + umax=-1.d33 + + Do k =1,ns3 + Do j = 1,ns2 + Do i=1,ns1 + if (dnsdiss(i,j,k).le.0) then + umax = max(umax,z(i,j,k)) + umin = min(umin,z(i,j,k)) + end if + End Do + End Do + End Do + + Call MPI_ALLREDUCE(umin, umin_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + umin = umin_recv + Call MPI_ALLREDUCE(umax, umax_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + umax = umax_recv + + umax = 10. + umin = -10. + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (dnsdiss(i,j,k).le.0) then + if (z(i,j,k) .gt. umin+(ll-1)*delta ) then + if (z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt + 1 + endif + endif + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + pdf=pdf/(delta*real(cptt)) +end subroutine cn_pdf + +subroutine cp_pdf(xx,pdf,z,dnsdiss,dime) + use solver + use parallel + use data + implicit none + integer :: dime,i,j,k,ll,ierr + real(WP) :: dnsdiss(ns1,ns2,ns3),z(ns1,ns2,ns3),umin,umax,umin_recv,umax_recv,delta,cptt + real(WP) :: xx(dime), pdf(dime), pdfloc(dime) + + + umin=1.d33 + umax=-1.d33 + + Do k =1,ns3 + Do j = 1,ns2 + Do i=1,ns1 + if (dnsdiss(i,j,k).gt.0) then + umax = max(umax,z(i,j,k)) + umin = min(umin,z(i,j,k)) + end if + End Do + End Do + End Do + + Call MPI_ALLREDUCE(umin, umin_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + umin = umin_recv + Call MPI_ALLREDUCE(umax, umax_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + umax = umax_recv + + umax = 10. + umin = -10. + + pdfloc(:)=0.0 + cptt = 0 + delta=(umax-umin)/(dime-1.) + if(rank.eq.0) print*,delta,umin,umax + do ll = 1,dime-1 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (dnsdiss(i,j,k).gt.0) then + if (z(i,j,k) .gt. umin+(ll-1)*delta ) then + if (z(i,j,k) .le. umin+ll*delta ) then + pdfloc(ll)=pdfloc(ll)+1. + cptt = cptt + 1 + endif + endif + endif + enddo + enddo + enddo + xx(ll)=umin+(ll-0.5)*delta + enddo + call MPI_ALLREDUCE(pdfloc,pdf,dime,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + pdf=pdf/(delta*real(cpTt)) +end subroutine cp_pdf + +subroutine var_skew_fla(z,vv,s,f) + use solver + use parallel + use data + implicit none + real(WP) :: z(ns1,ns2,ns3) + real(WP) :: test(ns1,ns2,ns3) + real(WP) :: vv,s,f, buf1, buf2, buf3, buf4 + + call moyen(z,buf1) + call moyen(z**2,buf2) + vv = buf2-buf1**2 + test = (z-buf1)**3 + call moyen(test,buf3) + test = (z-buf1)**4 + call moyen(test,buf4) + s = buf3 / (buf2**(3./2.)) + f = buf4 / (buf2**(2.)) +end subroutine var_skew_fla + +subroutine corre(tab1,tab2,cor) + use solver + use parallel + use data + implicit none + real(WP) :: cor,moya,moyb + real(WP) :: varab,vara2,varb2 + real(WP) :: tab1(ns1,ns2,ns3) + real(WP) :: tab2(ns1,ns2,ns3) + call moyen(tab1,moya) + call moyen(tab2,moyb) + call moyen(tab1*tab2,varab) + varab = varab - moya*moyb + call moyen(tab1*tab1,vara2) + vara2 = vara2 - moya*moya + call moyen(tab2*tab2,varb2) + varb2 = varb2 - moyb*moyb + cor=varab/(sqrt(vara2*varb2)); +end subroutine corre + +subroutine moyen_reg1(in1,in2,out1,value) + use solver + use parallel + use data + implicit none + real(WP) :: out1,out2 + real(WP) :: in1(ns1,ns2,ns3) + integer :: in2(ns1,ns2,ns3) + integer :: i,j,k,ierr, value, cptt, cpt2 + out2 =0. + cpt2 = 0 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (in2(i,j,k).eq.value) then + out2=out2+in1(i,j,k) + cpt2 = cpt2 + 1 + end if + enddo + enddo + enddo + call MPI_ALLREDUCE(cpt2,cptt,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(out2,out1,1,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + out1=out1/(real(cptt)) +end subroutine moyen_reg1 + +subroutine moyen_reg2(in1,in2,out1,value) + use solver + use parallel + use data + implicit none + real(WP) :: out1,out2 + real(WP) :: in1(ns1,ns2,ns3) + integer :: in2(ns1,ns2,ns3) + integer :: i,j,k,ierr, value, cptt, cpt2 + out2 =0. + cpt2 = 0 + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + if (in2(i,j,k).eq.value) then + out2=out2+in1(i,j,k) + cpt2 = cpt2 + 1 + end if + enddo + enddo + enddo + call MPI_ALLREDUCE(cpt2,cptt,1,MPI_INTEGER,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(out2,out1,1,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + out1=out1/(real(nx**3)) +end subroutine moyen_reg2 + +subroutine moyensc(in1,out1) + use solver + use parallel + use data + implicit none + real(WP) :: out1,out2 + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + integer i,j,k,ierr + out2 =0. + do k = 1,ns3sc + do j = 1,ns2sc + do i = 1,ns1sc + out2=out2+in1(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(out2,out1,1,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + out1=out1/(real(nxsc**3.)) +end subroutine moyensc + +subroutine moyen(in1,out1) + use solver + use parallel + use data + implicit none + real(WP) :: out1,out2 + real(WP) :: in1(ns1,ns2,ns3) + integer i,j,k,ierr + out2 =0. + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + out2=out2+in1(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(out2,out1,1,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + out1=out1/(real(nx**3.)) +end subroutine moyen + +subroutine moyen_ysc(in1,out1) + use solver + use parallel + use data + implicit none + real(WP) :: out1(ns2sc),out2(ns2sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + integer i,j,k,ierr + out2 =0. + do k = 1,ns3sc + do j = 1,ns2sc + do i = 1,ns1sc + out2(j)=out2(j)+in1(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(out2,out1,ns2sc,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + + out1=out1/(real(nxsc**2.)) + +end subroutine moyen_ysc + +subroutine moyen_y(in1,out1) + use solver + use parallel + use data + implicit none + real(WP) :: out1(ns2),out2(ns2) + real(WP) :: in1(ns1,ns2,ns3) + integer i,j,k,ierr + out2 =0. + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + out2(j)=out2(j)+in1(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(out2,out1,ns2,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + + out1=out1/(real(nx**2.)) + +end subroutine moyen_y + +subroutine mean_cond_2(in,cond,cond2,out,nbr) + use solver + use parallel + use data + implicit none + integer :: nbr,i,j,k,jj,kk,ierr + real(WP) :: minix,maxix,delta + real(WP) :: minix2,maxix2,delta2 + real(WP) :: minix_recv,maxix_recv,minix2_recv,maxix2_recv + real(WP) :: value(nbr,nbr),valueloc(nbr,nbr) + real(WP) :: nombre(nbr,nbr),nombreloc(nbr,nbr) + real(WP) :: in(ns1,ns2,ns3) + real(WP) :: cond(ns1,ns2,ns3) + real(WP) :: cond2(ns1,ns2,ns3) + real(WP) :: out(ns1,ns2,ns3) + maxix=-1.d33 + minix=1.d33 + maxix2=-1.d33 + minix2=1.d33 + + Do k =1,ns3 + Do j = 1,ns2 + Do i=1,ns1 + maxix = max(maxix,cond(i,j,k)) + minix = min(minix,cond(i,j,k)) + maxix2 = max(maxix2,cond2(i,j,k)) + minix2 = min(minix2,cond2(i,j,k)) + End Do + End Do + End Do + + Call MPI_ALLREDUCE(minix, minix_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + minix = minix_recv + Call MPI_ALLREDUCE(minix2, minix2_recv, 1, MPI_REAL_WP,MPI_MIN, MPI_COMM_WORLD, ierr) + minix2 = minix2_recv + Call MPI_ALLREDUCE(maxix, maxix_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + maxix = maxix_recv + Call MPI_ALLREDUCE(maxix2, maxix2_recv, 1, MPI_REAL_WP,MPI_MAX, MPI_COMM_WORLD, ierr) + maxix2 = maxix2_recv + + delta = (maxix-minix)/real(nbr); + + delta2 = (maxix2-minix2)/real(nbr); + nombreloc=0. + valueloc =0. + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + do jj = 1,nbr + do kk = 1,nbr + if(cond(i,j,k)>minix+(jj-1)*delta.and.cond(i,j,k)<=minix+jj*delta & + & .and.cond2(i,j,k)>minix2+(kk-1)*delta2.and.cond2(i,j,k)<=minix2+kk*delta2 ) then + valueloc(jj,kk)=valueloc(jj,kk)+in(i,j,k); + nombreloc(jj,kk)=nombreloc(jj,kk)+1; + endif + enddo + enddo + enddo + enddo + enddo + call MPI_ALLREDUCE(valueloc,value,nbr*nbr,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(nombreloc,nombre,nbr*nbr,MPI_REAL_WP,MPI_SUM, & + & MPI_COMM_WORLD,ierr) + value=value/nombre + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + do jj = 1,nbr + do kk = 1,nbr + if(cond(i,j,k)>minix+(jj-1)*delta.and.cond(i,j,k)<=minix+jj*delta & + & .and.cond2(i,j,k)>minix2+(kk-1)*delta2.and.cond2(i,j,k)<=minix2+kk*delta2 ) then + out(i,j,k)=value(jj,kk) + endif + enddo + enddo + enddo + enddo + enddo +end subroutine mean_cond_2 + +subroutine mean_cond(in,cond,out,xx,value,nbr) + use solver + use parallel + use data + implicit none + integer :: nbr,i,j,k,jj,ierr + real(WP) :: minix,maxix,delta,maxixloc,minixloc + real(WP) :: value(nbr),valueloc(nbr),xx(nbr) + real(WP) :: nombre(nbr),nombreloc(nbr) + real(WP) :: in(ns1,ns2,ns3) + real(WP) :: cond(ns1,ns2,ns3) + real(WP) :: out(ns1,ns2,ns3) + maxixloc = maxval(cond) + call MPI_ALLREDUCE(maxixloc,maxix,1,MPI_REAL_WP,MPI_MAX, & + MPI_COMM_WORLD,ierr) + minixloc = minval(cond) + call MPI_ALLREDUCE(minixloc,minix,1,MPI_REAL_WP,MPI_MIN, & + MPI_COMM_WORLD,ierr) + delta = (maxix-minix)/real(nbr); +! if(rank.eq.0) print*,maxix +! if(rank.eq.0) print*,minix + nombreloc=0. + valueloc =0. + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + do jj = 1,nbr + if(cond(i,j,k)>minix+(jj-1)*delta.and.cond(i,j,k)<=minix+jj*delta ) then + valueloc(jj)=valueloc(jj)+in(i,j,k); + nombreloc(jj)=nombreloc(jj)+1; + endif + enddo + enddo + enddo + enddo + do jj = 1,nbr + xx(jj) = minix+(jj-0.5)*delta + enddo + call MPI_ALLREDUCE(valueloc,value,nbr,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(nombreloc,nombre,nbr,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + value=value/nombre + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + do jj = 1,nbr + if(cond(i,j,k)>minix+(jj-1)*delta.and.cond(i,j,k)<=minix+jj*delta ) then + out(i,j,k)=value(jj) + endif + enddo + enddo + enddo + enddo +end subroutine mean_cond + +subroutine physboxfilter(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + real(WP) :: dist,nd + integer i,j,k,nd2,number + integer iii,jj,kk + integer id,jd,kd + + nd2=int(nd/2) + do k=1,ns1 + do j=1,ns1 + do i=1,ns1 + out1(i,j,k)=0 + number=0 + do iii = i-nd2,i+nd2 + do jj = j-nd2,j+nd2 + do kk = k-nd2,k+nd2 + dist = sqrt((real(i)-real(iii))**2.+(real(j)-real(jj))**2.+(real(k)-real(kk))**2.) +! print*,dist,i,iii,j,jj,k,kk,nd2 + if (dist.le.real(nd2)) then + if(iii.lt.1) then + id = ns1+iii + elseif(iii.gt.ns1) then + id = iii-ns1 + else + id = iii + endif + if(jj.lt.1) then + jd = ns1+jj + elseif(j.gt.ns1) then + jd = jj-ns1 + else + jd = jj + endif + if(kk.lt.1) then + kd = ns1+kk + elseif(kk.gt.ns1) then + kd = kk-ns1 + else + kd = kk + endif + out1(i,j,k)=out1(i,j,k)+in1(id,jd,kd) + number=number+1 + endif + enddo + enddo + enddo + out1(i,j,k) = out1(i,j,k)/number + enddo + enddo + enddo + print*,'number of points',number +end subroutine physboxfilter + +subroutine specboxfiltersc(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx + real(WP) :: out1(ns1sc,ns2sc,ns3sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + + dx = L/(real(nxsc)) + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(outk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in1,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + delta = nd*dx + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + if(kxsc(i).eq.0.and.kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kxsc(i).eq.0.and.kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kxsc(i).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + elseif(kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i)) + elseif(kxsc(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + endif + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ink) + deallocate(outk) +end subroutine specboxfiltersc + +subroutine specboxfilter(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(outk(fns1,fns2,fns3)) + call ftran_wrap(in1,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + delta = nd*dx + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + if(kx(i).eq.0.and.ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kx(i).eq.0.and.ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kx(i).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + elseif(ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i)) + elseif(kx(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + endif + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ink) + deallocate(outk) +end subroutine specboxfilter + +subroutine speccutboxfilter2sc(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1sc,ns2sc,ns3sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(outk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in1,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + delta = nd*dx + kc = 2*3.141592654/delta + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + if(kxsc(i).eq.0.and.kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kxsc(i).eq.0.and.kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kxsc(i).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + elseif(kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i)) + elseif(kxsc(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + endif + enddo + enddo + enddo + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + kk = sqrt(kxsc(i)**2 + kysc(j)**2 + kzsc(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ink) + deallocate(outk) +end subroutine speccutboxfilter2sc + +subroutine speccutboxfilter2(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(outk(fns1,fns2,fns3)) + call ftran_wrap(in1,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + delta = nd*dx + kc = 2*3.141592654/delta + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + if(kx(i).eq.0.and.ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kx(i).eq.0.and.ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kx(i).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + elseif(ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i)) + elseif(kx(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + endif + enddo + enddo + enddo + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = sqrt(kx(i)**2 + ky(j)**2 + kz(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ink) + deallocate(outk) +end subroutine speccutboxfilter2 + +subroutine speccutboxfilter(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(outk(fns1,fns2,fns3)) + call ftran_wrap(in1,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + delta = nd*dx + kc = 3.141592654/delta + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + if(kx(i).eq.0.and.ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kx(i).eq.0.and.ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kx(i).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + elseif(ky(j).eq.0.and.kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i)) + elseif(kx(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(ky(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + elseif(kz(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kx(i))/(0.5*delta*kx(i))* & + & sin(0.5*delta*ky(j))/(0.5*delta*ky(j))* & + & sin(0.5*delta*kz(k))/(0.5*delta*kz(k)) + endif + enddo + enddo + enddo + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = sqrt(kx(i)**2 + ky(j)**2 + kz(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ink) + deallocate(outk) +end subroutine speccutboxfilter + +subroutine speccutboxfiltersc(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1sc,ns2sc,ns3sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(outk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in1,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + delta = nd*dx + kc = 3.141592654/delta + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + if(kxsc(i).eq.0.and.kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k) + elseif(kxsc(i).eq.0.and.kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kxsc(i).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + elseif(kysc(j).eq.0.and.kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i)) + elseif(kxsc(i).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kysc(j).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + elseif(kzsc(k).eq.0) then + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j)) + else + outk(i,j,k) = ink(i,j,k)*sin(0.5*delta*kxsc(i))/(0.5*delta*kxsc(i))* & + & sin(0.5*delta*kysc(j))/(0.5*delta*kysc(j))* & + & sin(0.5*delta*kzsc(k))/(0.5*delta*kzsc(k)) + endif + enddo + enddo + enddo + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + kk = sqrt(kxsc(i)**2 + kysc(j)**2 + kzsc(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ink) + deallocate(outk) +end subroutine speccutboxfiltersc + + + +subroutine specgaussfiltersc(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx + real(WP) :: out1(ns1sc,ns2sc,ns3sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nxsc)) + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(outk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in1,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + delta = nd*dx + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + kk = (kxsc(i)**2 + kysc(j)**2 + kzsc(k)**2)**(0.5) + outk(i,j,k) = ink(i,j,k)*exp(-(kk*delta)**2/24.) + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ink) + deallocate(outk) +end subroutine specgaussfiltersc + +subroutine specgaussfilter(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(nx)) + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(outk(fns1,fns2,fns3)) + call ftran_wrap(in1,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + delta = nd*dx + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = (kx(i)**2 + ky(j)**2 + kz(k)**2)**(0.5) + outk(i,j,k) = ink(i,j,k)*exp(-(kk*delta)**2/24.) + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ink) + deallocate(outk) +end subroutine specgaussfilter + +subroutine curl(inx,iny,inz,curlx,curly,curlz) + use solver + use parallel + use data + implicit none + integer :: i,j,k + real(WP) :: inx(ns1,ns2,ns3),iny(ns1,ns2,ns3),inz(ns1,ns2,ns3) + real(WP) :: curlx(ns1,ns2,ns3) + real(WP) :: curly(ns1,ns2,ns3) + real(WP) :: curlz(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: inxk,inyk,inzk,curlxk,curlyk,curlzk + ALLOCATE(inxk(fns1,fns2,fns3)) + ALLOCATE(inyk(fns1,fns2,fns3)) + ALLOCATE(inzk(fns1,fns2,fns3)) + ALLOCATE(curlxk(fns1,fns2,fns3)) + ALLOCATE(curlyk(fns1,fns2,fns3)) + ALLOCATE(curlzk(fns1,fns2,fns3)) + call ftran_wrap(inx,inxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(iny,inyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(inz,inzk,ns1,ns2,ns3,fns1,fns2,fns3) + inxk=inxk/(real(ns1)**3.) + inyk=inyk/(real(ns1)**3.) + inzk=inzk/(real(ns1)**3.) + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + curlxk(i,j,k) = ii*ky(j)*inzk(i,j,k) - ii*kz(k)*inyk(i,j,k) + curlyk(i,j,k) = ii*kz(k)*inxk(i,j,k) - ii*kx(i)*inzk(i,j,k) + curlzk(i,j,k) = ii*kx(i)*inyk(i,j,k) - ii*ky(j)*inxk(i,j,k) + enddo + enddo + enddo + call btran_wrap(curlxk,curlx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(curlyk,curly,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(curlzk,curlz,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(curlxk) + deallocate(curlyk) + deallocate(curlzk) + deallocate(inxk) + deallocate(inyk) + deallocate(inzk) +end subroutine curl + +subroutine gradntsc(in,nd,ddx,ddy,ddz,nt) + use solver + use parallel + use data + implicit none + integer :: i,j,k + integer :: nd, nt + + real(WP) :: in(ns1sc,ns2sc,ns3sc) + real(WP) :: ddx(ns1sc,ns2sc,ns3sc) + real(WP) :: ddy(ns1sc,ns2sc,ns3sc) + real(WP) :: ddz(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink,ddxk,ddyk,ddzk + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddxk(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddyk(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddzk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + ddxk(i,j,k)=(ii*kxsc(i))**(real(nt))*ink(i,j,k) + ddyk(i,j,k)=(ii*kysc(j))**(real(nt))*ink(i,j,k) + ddzk(i,j,k)=(ii*kzsc(k))**(real(nt))*ink(i,j,k) + enddo + enddo + enddo + call btran_wrap(ddxk,ddx,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + call btran_wrap(ddyk,ddy,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + call btran_wrap(ddzk,ddz,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(ink) +end subroutine gradntsc + +subroutine gradientsc(in,nd,ddx,ddy,ddz) + use solver + use parallel + use data + implicit none + integer :: i,j,k + integer :: nd + + real(WP) :: in(ns1sc,ns2sc,ns3sc) + real(WP) :: ddx(ns1sc,ns2sc,ns3sc) + real(WP) :: ddy(ns1sc,ns2sc,ns3sc) + real(WP) :: ddz(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink,ddxk,ddyk,ddzk + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddxk(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddyk(fns1sc,fns2sc,fns3sc)) + ALLOCATE(ddzk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + ddxk(i,j,k)=ii*kxsc(i)*ink(i,j,k) + ddyk(i,j,k)=ii*kysc(j)*ink(i,j,k) + ddzk(i,j,k)=ii*kzsc(k)*ink(i,j,k) + enddo + enddo + enddo + call btran_wrap(ddxk,ddx,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + call btran_wrap(ddyk,ddy,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + call btran_wrap(ddzk,ddz,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(ink) +end subroutine gradientsc + +subroutine gradient(in,nd,ddx,ddy,ddz) + use solver + use parallel + use data + implicit none + integer :: i,j,k + integer :: nd + + real(WP) :: in(ns1,ns2,ns3) + real(WP) :: ddx(ns1,ns2,ns3) + real(WP) :: ddy(ns1,ns2,ns3) + real(WP) :: ddz(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink,ddxk,ddyk,ddzk + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(ddxk(fns1,fns2,fns3)) + ALLOCATE(ddyk(fns1,fns2,fns3)) + ALLOCATE(ddzk(fns1,fns2,fns3)) + call ftran_wrap(in,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k)=ii*kx(i)*ink(i,j,k) + ddyk(i,j,k)=ii*ky(j)*ink(i,j,k) + ddzk(i,j,k)=ii*kz(k)*ink(i,j,k) + enddo + enddo + enddo + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(ink) +end subroutine gradient + +subroutine cutgradient(in,nd,ddx,ddy,ddz) + use solver + use parallel + use data + implicit none + integer :: i,j,k + real(WP) :: nd, kc, delta, dx, kk + real(WP) :: in(ns1,ns2,ns3) + real(WP) :: ddx(ns1,ns2,ns3) + real(WP) :: ddy(ns1,ns2,ns3) + real(WP) :: ddz(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink,ddxk,ddyk,ddzk + dx = L/(real(nx)) + delta = nd*dx + kc = 3.141592654/delta + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(ddxk(fns1,fns2,fns3)) + ALLOCATE(ddyk(fns1,fns2,fns3)) + ALLOCATE(ddzk(fns1,fns2,fns3)) + call ftran_wrap(in,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k)=ii*kx(i)*ink(i,j,k) + ddyk(i,j,k)=ii*ky(j)*ink(i,j,k) + ddzk(i,j,k)=ii*kz(k)*ink(i,j,k) + kk = sqrt(kx(i)**2 + ky(j)**2 + kz(k)**2) + if (kk.gt.kc) then + ddxk(i,j,k) = 0.0 + ddyk(i,j,k) = 0.0 + ddzk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(ink) +end subroutine cutgradient + +subroutine speccutfilter(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1,ns2,ns3) + real(WP) :: in1(ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(ns1)) + delta = nd*dx + kc = 3.141592654/delta + ALLOCATE(ink(fns1,fns2,fns3)) + ALLOCATE(outk(fns1,fns2,fns3)) + call ftran_wrap(in1,ink,ns1,ns2,ns3,fns1,fns2,fns3) + ink=ink/(real(ns1)**3.) + outk = ink + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = sqrt(kx(i)**2 + ky(j)**2 + kz(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1,ns2,ns3,fns1,fns2,fns3) + deallocate(ink) + deallocate(outk) +end subroutine speccutfilter + + +subroutine speccutfiltersc(in1,out1,nd) + use solver + use parallel + use data + implicit none + real(WP) :: kk,delta,nd,dx,kc + real(WP) :: out1(ns1sc,ns2sc,ns3sc) + real(WP) :: in1(ns1sc,ns2sc,ns3sc) + complex(WP), dimension(:,:,:), pointer :: ink + complex(WP), dimension(:,:,:), pointer :: outk + integer i,j,k + dx = L/(real(ns1sc)) + delta = nd*dx + kc = 3.141592654/delta + ALLOCATE(ink(fns1sc,fns2sc,fns3sc)) + ALLOCATE(outk(fns1sc,fns2sc,fns3sc)) + call ftran_wrap(in1,ink,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + ink=ink/(real(ns1sc)**3.) + outk = ink + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + kk = sqrt(kxsc(i)**2 + kysc(j)**2 + kzsc(k)**2) + if (kk.gt.kc) then + outk(i,j,k) = 0.0 + end if + enddo + enddo + enddo + call btran_wrap(outk,out1,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + deallocate(ink) + deallocate(outk) +end subroutine speccutfiltersc + +subroutine turbulent_region(t11,t12,t13,t22,t23,t33,ome1,ome2,ome3,out1) + use solver + use parallel + use data +! use f95_lapack, only: la_syevd + implicit none + + integer :: out1(ns1,ns2,ns3) + real(WP) :: t11(ns1,ns2,ns3) + real(WP) :: t12(ns1,ns2,ns3) + real(WP) :: t13(ns1,ns2,ns3) + real(WP) :: t22(ns1,ns2,ns3) + real(WP) :: t23(ns1,ns2,ns3) + real(WP) :: t33(ns1,ns2,ns3) + real(WP) :: ome1(ns1,ns2,ns3) + real(WP) :: ome2(ns1,ns2,ns3) + real(WP) :: ome3(ns1,ns2,ns3) + real(WP) :: tab(3,3) + real(WP) :: vec(3) + real(WP) :: norm, sca1, sca2, sca3, scamax, lp, lm + + integer :: i, j, k + + do k = 1, ns3 + do j = 1, ns2 + do i = 1, ns1 + norm = sqrt(ome1(i,j,k)**2.0 + ome2(i,j,k)**2.0 + ome3(i,j,k)**2.0) + ome1(i,j,k) = ome1(i,j,k) / norm + ome2(i,j,k) = ome2(i,j,k) / norm + ome3(i,j,k) = ome3(i,j,k) / norm + norm = sqrt(ome1(i,j,k)**2.0 + ome2(i,j,k)**2.0 + ome3(i,j,k)**2.0) + if ( norm.le.0.999.or.norm.ge.1.001) then + print*,'norm vorticity',sqrt(ome1(i,j,k)**2.0 + ome2(i,j,k)**2.0 + ome3(i,j,k)**2.0),i,j,k + end if + end do + end do + end do + + out1 = 0. + + do k = 1, ns3 + do j = 1, ns2 + do i = 1, ns1 + + tab(1,1) = t11(i,j,k) + tab(1,2) = t12(i,j,k) + tab(2,1) = t12(i,j,k) + tab(1,3) = t13(i,j,k) + tab(3,1) = t13(i,j,k) + tab(2,2) = t22(i,j,k) + tab(2,3) = t23(i,j,k) + tab(3,2) = t23(i,j,k) + tab(3,3) = t33(i,j,k) + vec = 0. + +! call la_syevd(tab,vec,'V') + + norm = sqrt( tab(1,1)**2.0 + tab(2,1)**2.0 + tab(3,1)**2.0 ) + if (norm.le.0.999.or.norm.ge.1.001) print*,'norm vec1', norm, i,j,k + norm = sqrt( tab(1,2)**2.0 + tab(2,2)**2.0 + tab(3,2)**2.0 ) + if (norm.le.0.999.or.norm.ge.1.001) print*,'norm vec2', norm, i,j,k + norm = sqrt( tab(1,3)**2.0 + tab(2,3)**2.0 + tab(3,3)**2.0 ) + if (norm.le.0.999.or.norm.ge.1.001) print*,'norm vec3', norm, i,j,k + + !if (rank.eq.0) then + ! print*,'eigenvector (',tab(1,1),tab(2,1),tab(3,1),') of eigenvector: ',vec(1) + ! print*,'eigenvector (',tab(1,2),tab(2,2),tab(3,2),') of eigenvector: ',vec(2) + ! print*,'eigenvector (',tab(1,3),tab(2,3),tab(3,3),') of eigenvector: ',vec(3) + !end if + if (vec(2).gt.vec(3).or.vec(2).lt.vec(1)) then + print*, 'pas le bon ordre pour les valeurs propres', rank,i,j,k + end if + + sca1 = ome1(i,j,k)*tab(1,1) + ome2(i,j,k)*tab(2,1) + ome3(i,j,k)*tab(3,1) + sca2 = ome1(i,j,k)*tab(1,2) + ome2(i,j,k)*tab(2,2) + ome3(i,j,k)*tab(3,2) + sca3 = ome1(i,j,k)*tab(1,3) + ome2(i,j,k)*tab(2,3) + ome3(i,j,k)*tab(3,3) + + scamax = max(abs(sca1),abs(sca2)) + scamax = max(scamax,abs(sca3)) + + if (scamax.le.0.5.or.scamax.ge.1.001) print*,'SCAMAX',scamax + + if (scamax.eq.sca1) then + lp = vec(3) + lm = vec(2) + else if (scamax.eq.sca2) then + lp = vec(3) + lm = vec(1) + else if (scamax.eq.sca3) then + lp = vec(2) + lm = vec(1) + end if + + if (lm.gt.0) out1(i,j,k)=1 ! strain dominated region + if (lp.ge.0.and.lm.le.0) out1(i,j,k)=2 !strain rate and vorticity comparable + if (lp.lt.0) out1(i,j,k)=3 ! vorticity dominated region + + end do + end do + end do + +end subroutine turbulent_region diff --git a/CodesEnVrac/Remesh/FFTPAR/precision.f90 b/CodesEnVrac/Remesh/FFTPAR/precision.f90 new file mode 100755 index 000000000..aeaef7322 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/precision.f90 @@ -0,0 +1,11 @@ +module precision + implicit none + integer, parameter :: SP = kind(1.0) + integer, parameter, private :: DP = kind(1.0d0) + integer, parameter :: WP = DP + real(WP), private :: sample_real_at_WP + real(WP), parameter :: MAX_REAL_WP = HUGE(sample_real_at_WP) + integer, private :: sample_int + integer, parameter :: MAX_INTEGER = HUGE(sample_int) + +end module precision diff --git a/CodesEnVrac/Remesh/FFTPAR/random.f90 b/CodesEnVrac/Remesh/FFTPAR/random.f90 new file mode 100755 index 000000000..e1741bebf --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/random.f90 @@ -0,0 +1,119 @@ +module random + use precision + implicit none + +contains + + ! ------------------------------------------------------------------ ! + ! Normal distribution ! + ! Adapted from the following Fortran 77 code ! + ! ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM. ! + ! THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE, ! + ! VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435. ! + ! The function random_normal() returns a normally distributed ! + ! pseudo-random number with zero mean and unit variance. ! + ! The algorithm uses the ratio of uniforms method of A.J. Kinderman ! + ! and J.F. Monahan augmented with quadratic bounding curves. ! + ! ------------------------------------------------------------------ ! + real(WP) function random_normal(m,sd) + implicit none + + real(WP), intent(in), optional :: m + real(WP), intent(in), optional :: sd + real(WP) :: s = 0.449871_WP + real(WP) :: t = -0.386595_WP + real(WP) :: a = 0.19600_WP + real(WP) :: b = 0.25472_WP + real(WP) :: r1 = 0.27597_WP + real(WP) :: r2 = 0.27846_WP + real(WP) :: u,v,x,y,q + + ! Generate P = (u,v) uniform in rectangle enclosing acceptance region + do + call random_number(u) + call random_number(v) + v=1.7156_WP*(v-0.5_WP) + ! Evaluate the quadratic form + x=u-s + y=abs(v)-t + q=x**2+y*(a*y-b*x) + ! Accept P if inside inner ellipse + if (q<r1) exit + ! Reject P if outside outer ellipse + if (q>r2) cycle + ! Reject P if outside acceptance region + if (v**2<-4.0_WP*log(u)*u**2) exit + end do + + ! Return ratio of P's coordinates as the normal deviate + random_normal = v/u + + ! Modify to give correct mean and standard deviation + if (present(sd)) random_normal = random_normal*sd + if (present(m)) random_normal = random_normal+m + + return + end function random_normal + + ! ---------------------------------------------------------------------------- ! + ! Log-normal distribution ! + ! If X has a lognormal distribution, then log(X) is normally distributed. ! + ! Here the logarithm is the natural logarithm, that is to base e, sometimes ! + ! denoted as ln. To generate random variates from this distribution, generate ! + ! a random deviate from the normal distribution with mean and variance equal ! + ! to the mean and variance of the logarithms of X, then take its exponential. ! + ! ! + ! Relationship between the mean & variance of log(X) and the mean & variance ! + ! of X, when X has a lognormal distribution. ! + ! Let m = mean of log(X), and s^2 = variance of log(X) ! + ! Then ! + ! mean of X = exp(m + 0.5s^2) ! + ! variance of X = (mean(X))^2.[exp(s^2) - 1] ! + ! ! + ! In the reverse direction ! + ! variance of log(X) = log[1 + var(X)/(mean(X))^2] ! + ! mean of log(X) = log(mean(X) - 0.5var(log(X)) ! + ! ---------------------------------------------------------------------------- ! + real(WP) function random_lognormal(m,sd) + implicit none + + real(WP), intent(in) :: m + real(WP), intent(in) :: sd + real(WP) :: x,mlog,sdlog + + sdlog = sqrt(log(1.0_WP+(sd/m)**2)) + mlog = log(m)-0.5_WP*sdlog**2 + x = random_normal(mlog,sdlog) + random_lognormal = exp(x) + + return + end function random_lognormal + +end module random + + +! ------------------------- ! +! Initialization of the RNG ! +! Seeded based on parallel ! +! partitioning ! +! ------------------------- ! +subroutine random_init + use parallel + use random + implicit none + + integer :: k + integer, dimension(:), allocatable :: seed + + call RANDOM_SEED(size=k) + allocate(seed(k)) + call system_clock(count=seed(1)) + seed(1:k) = seed(1:k)*(rank+1) + call RANDOM_SEED(put=seed) + deallocate(seed) + + + + return +end subroutine random_init + diff --git a/CodesEnVrac/Remesh/FFTPAR/solver.f90 b/CodesEnVrac/Remesh/FFTPAR/solver.f90 new file mode 100755 index 000000000..7d98b8c23 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/solver.f90 @@ -0,0 +1,970 @@ +module solver + + use precision + + implicit none + + real(WP), dimension(:), allocatable :: kx + real(WP), dimension(:), allocatable :: ky + real(WP), dimension(:), allocatable :: kz + + real(WP), dimension(:), allocatable :: kxsc + real(WP), dimension(:), allocatable :: kysc + real(WP), dimension(:), allocatable :: kzsc + + integer :: deal + real(WP) :: dk,kmax,kcut + real(WP) :: kmaxsc,kcutsc + + real(WP) :: mu_solver, diff_solver + real(WP) :: courant + + integer :: iforce,iscalar,iles,ilessc,ydir,ipost + + + complex(WP), dimension(:,:,:), allocatable :: Uk + complex(WP), dimension(:,:,:), allocatable :: Vk + complex(WP), dimension(:,:,:), allocatable :: Wk + complex(WP), dimension(:,:,:), allocatable :: Zk + + complex(WP), dimension(:,:,:),pointer :: Udummy + complex(WP), dimension(:,:,:),pointer :: Vdummy + complex(WP), dimension(:,:,:),pointer :: Wdummy + complex(WP), dimension(:,:,:),pointer :: Zdummy + + complex(WP), dimension(:,:,:), allocatable :: nlx + complex(WP), dimension(:,:,:), allocatable :: nly + complex(WP), dimension(:,:,:), allocatable :: nlz + complex(WP), dimension(:,:,:), allocatable :: nlmf + + complex(WP), dimension(:,:,:), allocatable :: nlu2x + complex(WP), dimension(:,:,:), allocatable :: nlu2y + complex(WP), dimension(:,:,:), allocatable :: nlu2z + + + + logical, parameter :: flg_inplace = .false. + complex(WP), parameter :: ii = (0.0_WP,1.0_WP) + real(WP), parameter :: kmin = 1e-06_WP + + real(WP) :: dt,sim_time + + integer :: impose + real(WP) :: cx,cy,cz + +end module solver + + +subroutine solver_init + + use parallel + use data + use solver + use transform + + implicit none + + integer :: i,j,k,il,jl,kl,gg(3),itype + real(WP) :: pi + real(WP) :: umax,vmax,wmax + + + allocate(kx(fns1)) + allocate(ky(fns2)) + allocate(kz(fns3)) + + allocate(kxsc(fns1sc)) + allocate(kysc(fns2sc)) + allocate(kzsc(fns3sc)) + + pi = acos(-1.0_WP) + dk = 2.0_WP*pi/L + + do i = fnxs,fnxe + il = i -fnxs+1 + kx(il) = real((i-1),WP)*dk + enddo + do i = fnxssc,fnxesc + il = i -fnxssc+1 + kxsc(il) = real((i-1),WP)*dk + enddo + + do j = fnys,fnye + jl = j - fnys +1 + ky(jl) = real((j-1),WP)*dk + if (j.gt.nk) ky(jl) = -real(nx+1-j,WP)*dk + enddo + do j = fnyssc,fnyesc + jl = j - fnyssc +1 + kysc(jl) = real((j-1),WP)*dk + if (j.gt.nksc) kysc(jl) = -real(nxsc+1-j,WP)*dk + enddo + + do k = fnzs,fnze + kl = k -fnzs+1 + kz(kl) = real((k-1),WP)*dk + if (k.gt.nk) kz(kl) = -real(nx+1-k,WP)*dk + enddo + do k = fnzssc,fnzesc + kl = k -fnzssc+1 + kzsc(kl) = real((k-1),WP)*dk + if (k.gt.nksc) kzsc(kl) = -real(nxsc+1-k,WP)*dk + enddo + + +! print *,'First checkpoint',rank + + + allocate(Uk(fns1,fns2,fns3)) + allocate(Vk(fns1,fns2,fns3)) + allocate(Wk(fns1,fns2,fns3)) + allocate(Zk(fns1sc,fns2sc,fns3sc)) + + allocate(Udummy(fns1,fns2,fns3)) + allocate(Vdummy(fns1,fns2,fns3)) + allocate(Wdummy(fns1,fns2,fns3)) +!!PAR!! allocate(Zdummy(fns1sc,fns2sc,fns3sc)) + + + + call ftran_wrap(U,Uk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(V,Vk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(W,Wk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(SC,Zk,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + + + Uk = Uk/real(nx**3.0,WP) + Vk = Vk/real(nx**3.0,WP) + Wk = Wk/real(nx**3.0,WP) + Zk = Zk/real(nxsc**3.0,WP) + + call parallel_max(maxval(abs(Uk)),umax) + call parallel_max(maxval(abs(Vk)),vmax) + call parallel_max(maxval(abs(Wk)),wmax) + + if (rank.eq.0) then + print *,' Maximum of U,V,W after trans',umax,vmax,wmax + endif + + + +!!$ call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + + allocate(nlx(fns1,fns2,fns3)) + allocate(nly(fns1,fns2,fns3)) + allocate(nlz(fns1,fns2,fns3)) +!!PAR!! allocate(nlmf(fns1sc,fns2sc,fns3sc)) + allocate(nlu2x(fns1,fns2,fns3)) + allocate(nlu2y(fns1,fns2,fns3)) + allocate(nlu2z(fns1,fns2,fns3)) + +!!$ +!!$ call parallel_max(maxval(abs(Uk)),umax) +!!$ call parallel_max(maxval(abs(Vk)),vmax) +!!$ call parallel_max(maxval(abs(Wk)),wmax) + +!!$ if (rank.eq.0) then +!!$ print *,' Maximum U,V,W in solver',umax,vmax,wmax +!!$ endif +!!$ +!!$ if (umax.eq.maxval(abs(Uk))) then +!!$ print *,' Maximum in rank', rank +!!$ print *,' location ', maxloc(abs(Uk)) +!!$ gg = maxloc(abs(Uk)) +!!$ print *,' max value for conformation', Uk(gg(1),gg(2),gg(3)) +!!$ endif +!!$ +!!$ if (wmax.eq.maxval(abs(Wk))) then +!!$ print *,' Maximum in rank W', rank +!!$ print *,' location W', maxloc(abs(Wk)) +!!$ gg = maxloc(abs(Wk)) +!!$ print *,' max value for W conformation', Wk(gg(1),gg(2),gg(3)) +!!$ endif + + sim_time = 0.0_WP + + call parser_read('Dealiasing',deal,0) + + kmax = sqrt(3.0_WP)*kx(nx/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) +!!PAR!! kmaxsc = sqrt(3.0_WP)*kxsc(nxsc/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) + if (deal.eq.1) then + kcut = 2.0_WP/3.0_WP*kmax +!!PAR!! kcutsc = 2.0_WP/3.0_WP*kmaxsc + else + kcut = 10000.0_WP +!!PAR!! kcutsc = 10000.0_WP + endif + + mu_solver = mu + diff_solver = diff + + call parser_read('LES model',iles,0) + call parser_read('LES scalar model',ilessc,0) + call parser_read('y inhomogeneity',ydir,0) + + call parser_read('Postprocessing',ipost,0) + + call parser_read('Forcing',iforce,0) + if (iforce.eq.1) call forcing_init + + call parser_read('Courant number', courant,0.5_WP) + +!!!! Determine if it is required to solver the scalar equation +!!!! If running from scratch with forcing, dont solver scalar equation + + call parser_read('Simulation type', itype) + call parser_read('Compute scalar', iscalar) + if (iscalar.eq.0) then + if (rank.eq.0) print *,'Not solving scalar transport equation .....' + endif + + call parser_read('Imposing mean gradient',impose,0) + if (impose.eq.1) then + call parser_read('X-gradient',cx,0.0_WP) + call parser_read('Y-gradient',cy,0.0_WP) + call parser_read('Z-gradient',cz,0.0_WP) + else + cx = 0.0_WP + cy = 0.0_WP + cz = 0.0_WP + endif + + spfilename = 'spectrum_solver.init' + spfilename2 = 'spectrum_solver.init.z' + call get_dns_numbers(0) + + print*,'test U init solver', U(1,1,1), V(1,1,1),W(1,1,1) + +end subroutine solver_init + + + +subroutine solver_step + + use solver + use parallel + use data + + implicit none + + complex(WP), dimension(:,:,:), allocatable :: Pressk + real(WP), dimension(:,:,:), allocatable :: tab + character(len=str_long) :: sim_name + real(WP) :: Ufz, Vfz, Wfz, xx + + integer :: i,j,k,ierr + + real(WP) :: kk,h, divumax + + + allocate(Pressk(fns1,fns2,fns3)) + allocate(tab(ns1,ns2,ns3)) + + +!!$ if (rank.eq.0) print *,' Viscosity', mu_solver +!!!! GEL DU CHAMP DE VITESSE POUR LES TEST !!!! +call parser_read('Simulation name', sim_name) +if (trim(sim_name).eq.'Test case') then + call parser_read('Frozen U', Ufz) + call parser_read('Frozen V', Vfz) + call parser_read('Frozen W', Wfz) + do i = 1, nx + xx = float(i-1)*L/nx + U(i,:,:) = Ufz + 0.5*sin(xx) + end do + V = Vfz + W = Wfz + print*,'1. U,V,W',U(1,1,1),V(1,1,1),W(1,1,1) !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! +endif + + call get_timestep + sim_time = sim_time +dt + +!!!!!!!!!!!! +!!! Second-order RK scheme +!!!!!!!!!!! + h = dt/2.0_WP + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + Udummy(i,j,k) = Uk(i,j,k) + Vdummy(i,j,k) = Vk(i,j,k) + Wdummy(i,j,k) = Wk(i,j,k) + enddo + enddo + enddo + + call non_linear + +! if (iforce.eq.1) call force_compute +!!!!!! Step 1 for RK scheme + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Uk(i,j,k) + h*nlx(i,j,k))/exp(mu_solver*kk*h) + Vk(i,j,k) = (Vk(i,j,k) + h*nly(i,j,k))/exp(mu_solver*kk*h) + Wk(i,j,k) = (Wk(i,j,k) + h*nlz(i,j,k))/exp(mu_solver*kk*h) + enddo + enddo + enddo + + +!!$ +!!$!!!!!!! Step 2 for RK scheme +!!$ + call non_linear + if (iforce.eq.1) call force_compute + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Udummy(i,j,k) + dt*nlx(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Vk(i,j,k) = (Vdummy(i,j,k) + dt*nly(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Wk(i,j,k) = (Wdummy(i,j,k) + dt*nlz(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + enddo + enddo + enddo + + ! Projection + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + if(kk.gt.0.0_WP) then + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) )/kk + end if + Uk(i,j,k) = Uk(i,j,k) - ii*kx(i)*Pressk(i,j,k) + Vk(i,j,k) = Vk(i,j,k) - ii*ky(j)*Pressk(i,j,k) + Wk(i,j,k) = Wk(i,j,k) - ii*kz(k)*Pressk(i,j,k) + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) ) + end do + end do + end do +! call btran_wrap(Pressk,tab,ns1,ns2,ns3,fns1,fns2,fns3) +! call parallel_max(maxval(abs(tab)),divumax) +! if (rank.eq.0) print*,'divergence max = ', divumax +! call parallel_max(maxval(abs(Uk)),divumax) +! if (rank.eq.0) print*,'abs(Uk) max = ', divumax + +!!PAR!! - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + call ftran_wrap(SC,Zk,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + Zk = Zk/real(nxsc**3.0,WP) + if (iscalar.ne.0) then + do k = 1,fns3sc + do j = 1,fns2sc + do i = 1,fns1sc + kk = kxsc(i)**2.0 + kysc(j)**2.0 + kzsc(k)**2.0 + Zk(i,j,k) = Zk(i,j,k)/exp(diff_solver*kk*dt) + enddo + enddo + enddo + end if + call btran_wrap(Zk,SC,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + if (nproc.ne.1) then + if (rank.eq.0) print*,'NOT AVAILABLE IN PARALLEL' + STOP + else + +!!PAR!! 1. on remet les vitesses dans l'espace physique + if (trim(sim_name).eq.'Test case') then + call parser_read('Frozen U', Ufz) + call parser_read('Frozen V', Vfz) + call parser_read('Frozen W', Wfz) + do i = 1, nx + xx = float(i-1)*L/nx + U(i,:,:) = Ufz+0.5*sin(xx) + end do + V = Vfz + W = Wfz + print*,'1b. U,V,W',U(1,1,1),V(1,1,1),W(1,1,1) !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + endif + if (trim(sim_name).ne.'Test case') call u_compute !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + if (trim(sim_name).eq.'Test case') print*,'2. U,V,W',U(1,1,1),V(1,1,1),W(1,1,1) !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + +!!PAR!! 2. appelle du transport particulaire + call x_advec + call y_advec + call z_advec + + end if +!!PAR!! - FIN - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + + + deallocate(Pressk) + deallocate(tab) + + +end subroutine solver_step + +subroutine non_linear + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(:,:,:),allocatable :: ddx,ddy,ddz,nis + real(WP), dimension(:,:,:),allocatable :: us,vs,ws + real(WP), dimension(:,:,:),allocatable :: uss,vss,wss + complex(WP), dimension(:,:,:),allocatable :: ddxk,ddyk,ddzk + ! LES + + complex(WP) :: knl + real(WP) :: kk + + integer :: i,j,k + real(WP) :: umax,vmax,wmax + + integer :: sizemess, tag, ierr, status(MPI_STATUS_SIZE) + integer :: yeloc, ysloc, yelocsc, yslocsc, rank2send1, rank2send2, fs1, fe1, fs2, fe2, fnysrank, fnyerank, cptrank + + + + allocate(ddx(ns1,ns2,ns3)) + allocate(ddy(ns1,ns2,ns3)) + allocate(ddz(ns1,ns2,ns3)) + allocate(nis(ns1,ns2,ns3)) + + allocate(ddxk(fns1,fns2,fns3)) + allocate(ddyk(fns1,fns2,fns3)) + allocate(ddzk(fns1,fns2,fns3)) + + + allocate(us(ns1,ns2,ns3)) + allocate(vs(ns1,ns2,ns3)) + allocate(ws(ns1,ns2,ns3)) + +!!!!!!!!!!! +!! Convert velocity to spatial coordinates +!!!!!!!!!! + + call btran_wrap(Uk,us,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,vs,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,ws,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ call parallel_max(maxval(abs(us)),umax) +!!$ call parallel_max(maxval(abs(vs)),vmax) +!!$ call parallel_max(maxval(abs(ws)),wmax) +!!$ +!!$! if (rank.eq.0) write(*,'(A10,3(E12.5,3X))') ' MAX VAL', umax,vmax,wmax + + +!!$ if (rank.eq.0) print *,' After velocity conversion' + + +!!!!!!!!!! +!! Form the first term in the skew-symmetric form +!!!!!!!!! + + +!!!! U component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*us(i,j,k) + ddy(i,j,k) = vs(i,j,k)*us(i,j,k) + ddz(i,j,k) = ws(i,j,k)*us(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2x(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! V component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*vs(i,j,k) + ddy(i,j,k) = vs(i,j,k)*vs(i,j,k) + ddz(i,j,k) = ws(i,j,k)*vs(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2y(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! W component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*ws(i,j,k) + ddy(i,j,k) = vs(i,j,k)*ws(i,j,k) + ddz(i,j,k) = ws(i,j,k)*ws(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2z(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! Compute the second term in the skew symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Uk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Uk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Uk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After btran in U computations' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product evaluations' + + call ftran_wrap(nis,nlx,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After forward transforms' + + nlx = nlx/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlx computation' + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Vk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Vk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Vk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After b trans in V compute' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product eval. in V' + + call ftran_wrap(nis,nly,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After forward trans in V' + + nly = nly/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nly computation' + +!!!!!!!!!!!!!! +!! Compute W products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Wk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Wk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Wk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(nis,nlz,ns1,ns2,ns3,fns1,fns2,fns3) + + nlz = nlz/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlz computation' + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Form the complex skew-symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!$ + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlx(i,j,k) = 0.5*(nlx(i,j,k) + nlu2x(i,j,k)) + nly(i,j,k) = 0.5*(nly(i,j,k) + nlu2y(i,j,k)) + nlz(i,j,k) = 0.5*(nlz(i,j,k) + nlu2z(i,j,k)) + enddo + enddo + enddo + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!! Form non-linear term for the scalar +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + deallocate(ddx) + deallocate(ddy) + deallocate(ddz) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(nis) + + +!!PAR!! if (iscalar.eq.0) then + + deallocate(us) + deallocate(vs) + deallocate(ws) +!!PAR!! nlmf = 0.0_WP + +!!PAR!! else + +!!PAR!! allocate(ddx(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddy(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddz(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(nis(ns1sc,ns2sc,ns3sc)) + +!!PAR!! allocate(ddxk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddyk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddzk(fns1sc,fns2sc,fns3sc)) + +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! ddxk(i,j,k) = ii*kxsc(i)*Zk(i,j,k) +!!PAR!! ddyk(i,j,k) = ii*kysc(j)*Zk(i,j,k) +!!PAR!! ddzk(i,j,k) = ii*kzsc(k)*Zk(i,j,k) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +!!PAR!! ddx = 0.0_WP +!!PAR!! ddy = 0.0_WP +!!PAR!! ddz = 0.0_WP + +!!PAR!! call btran_wrap(ddxk,ddx,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddyk,ddy,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddzk,ddz,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + +!!PAR!! deallocate(ddxk) +!!PAR!! deallocate(ddyk) +!!PAR!! deallocate(ddzk) + +!!PAR!! allocate(uss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(vss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(wss(ns1sc,ns2sc,ns3sc)) +!!PAR!! uss = 0.0 +!!PAR!! vss = 0.0 +!!PAR!! wss = 0.0 + +!!PAR!! if (ns1sc.gt.ns1) then +!!PAR!! call discretisation2(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else if (ns1sc.lt.ns1) then +!!PAR!! call discretisation3(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else +!!PAR!! uss = us +!!PAR!! vss = vs +!!PAR!! wss = ws +!!PAR!! end if + +!!PAR!! deallocate(us) +!!PAR!! deallocate(vs) +!!PAR!! deallocate(ws) + +!!PAR!! do k = 1,ns3sc +!!PAR!! do j = 1,ns2sc +!!PAR!! do i = 1,ns1sc +!!PAR!! nis(i,j,k) = uss(i,j,k)*(ddx(i,j,k)+cx) + & +!!PAR!! & vss(i,j,k)*(ddy(i,j,k)+cy) +& +!!PAR!! & wss(i,j,k)*(ddz(i,j,k)+cz) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! deallocate(uss) +!!PAR!! deallocate(vss) +!!PAR!! deallocate(wss) +!!PAR!! deallocate(ddx) +!!PAR!! deallocate(ddy) +!!PAR!! deallocate(ddz) + +!!PAR!! call ftran_wrap(nis,nlmf,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! nlmf = nlmf/real((ns1sc**3.0),WP) + +!!PAR!! deallocate(nis) + + +!!PAR!! endif + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Dealias the non-linear term + + call dealias + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! LES MODEL + +if (iles.ne.0) then +! if (iles.eq.1) call smagmodel + if (iles.eq.2) call dynsmagmodel +! if (iles.eq.8) call SISM +! if (iles.eq.12) call dynsmagmodel2 +! if (iles.eq.13) call dynsmagmodel3 +endif +if (ilessc.ne.0) then +! if (ilessc.eq.1) call smagmodelsca +! if (ilessc.eq.2) call dynsmagmodelsca +! if (ilessc.eq.3) call dynsmagmodelscanew +! if (ilessc.eq.4) call dynsmagmodelscacut +! if (ilessc.eq.5) call dynsmagmodelscanewcut +! if (ilessc.eq.6) call dynsfmodelscacut +! if (ilessc.eq.7) call dynsfmodelscanewcut +! if (ilessc.eq.8) call dynsigmamodelscacut +! if (ilessc.eq.9) call dynsigmamodelscanewcut +! if (ilessc.eq.12) call dyndd2modelscacut +! if (ilessc.eq.13) call dyndd4modelscacut +! if (ilessc.eq.14) call dynddsmagmodelscanewcut +! if (ilessc.eq.15) call dynsflpmodelscacut +! if (ilessc.eq.16) call ssmodelscacut +! if (ilessc.eq.17) call dynsmagtestmodelscacut +endif + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +!!!!!!!!!! +!! Form the pressure term and add it to the nonlinear term +!!!!!!!!!! + +!! SEMBLE NE PAS DONNER DIV(U)=0. ??? +!! +!! do k = 1,fns3 +!! do j = 1,fns2 +!! do i = 1,fns1 +!! +!! kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 +!! if (sqrt(kk).gt.kmin) then +!! knl = kx(i)*nlx(i,j,k) + ky(j)*nly(i,j,k) +& +!! & kz(k)*nlz(i,j,k) +!! nlx(i,j,k) = kx(i)*knl/kk - nlx(i,j,k) +!! nly(i,j,k) = ky(j)*knl/kk - nly(i,j,k) +!! nlz(i,j,k) = kz(k)*knl/kk - nlz(i,j,k) +!! nlmf(i,j,k) = -nlmf(i,j,k) +!! else +!! nlx(i,j,k) = 0.0_WP +!! nly(i,j,k) = 0.0_WP +!! nlz(i,j,k) = 0.0_WP +!! nlmf(i,j,k) = 0.0_WP +!!!!!!!!!!!!!!!INSTEAD + nlx = -nlx + nly = -nly + nlz = -nlz +!!PAR!! nlmf = -nlmf +!! endif +!! enddo +!! enddo +!! enddo + + +end subroutine non_linear + + +subroutine get_timestep + + use solver + use parallel + use data + + real(WP) :: max_s, max_sg + character(len=str_long) :: sim_name + + integer :: ierr,nn + + max_s = 0.0_WP + max_sg = 0.0_WP + + call parser_read('Simulation name', sim_name) + if (trim(sim_name).ne.'Test case') call u_compute !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + + max_s = maxval(abs(U) +abs(V)+abs(W)) + + + call MPI_ALLREDUCE(max_s,max_sg,1,MPI_REAL_WP,MPI_MAX,& + &MPI_COMM_WORLD,ierr) + + call parser_read('fixed time step',dt) + + if (dt.eq.0) then + if (max_sg.gt.0.0_WP) then + nn = nx +!!PAR!! if(iscalar.ne.0) nn = max(nx,nxsc) + dt = courant/max_sg*(L/nn) + else + print *,' SOMETHING WRONG IN TIME_STEP', rank, max_sg,max_s,nx + stop + endif + endif + + +!!$ print *,' MAX_TIME ', dt + +end subroutine get_timestep + + +subroutine dealias + + use solver + use parallel + use precision + + implicit none + + real(WP) :: kk + integer :: i,j,k + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + + kk = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) + ! kk = sqrt(kk) +! if ((abs(kz(k)).gt.kmax).or.(abs(ky(j)).gt.kmax).or.(abs(kx(i)).gt.kmax)) then +! if (kk.gt.kmax) then + if (kk.gt.kcut) then + nlx(i,j,k) = 0.0_WP + nly(i,j,k) = 0.0_WP + nlz(i,j,k) = 0.0_WP + endif + enddo + enddo + enddo +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = sqrt(kxsc(i)**2.0_WP + kysc(j)**2.0_WP + kzsc(k)**2.0_WP) +!!PAR!! if (kk.gt.kcutsc) then +!!PAR!! nlmf(i,j,k) = 0.0_WP +!!PAR!! endif +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +end subroutine dealias + +subroutine fourier_write + use solver + +! call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + +end subroutine fourier_write + + diff --git a/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav b/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav new file mode 100755 index 000000000..f910ac3f4 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav @@ -0,0 +1,963 @@ +module solver + + use precision + + implicit none + + real(WP), dimension(:), allocatable :: kx + real(WP), dimension(:), allocatable :: ky + real(WP), dimension(:), allocatable :: kz + + real(WP), dimension(:), allocatable :: kxsc + real(WP), dimension(:), allocatable :: kysc + real(WP), dimension(:), allocatable :: kzsc + + integer :: deal + real(WP) :: dk,kmax,kcut + real(WP) :: kmaxsc,kcutsc + + real(WP) :: mu_solver, diff_solver + real(WP) :: courant + + integer :: iforce,iscalar,iles,ilessc,ydir,ipost + + + complex(WP), dimension(:,:,:), allocatable :: Uk + complex(WP), dimension(:,:,:), allocatable :: Vk + complex(WP), dimension(:,:,:), allocatable :: Wk + complex(WP), dimension(:,:,:), allocatable :: Zk + + complex(WP), dimension(:,:,:),pointer :: Udummy + complex(WP), dimension(:,:,:),pointer :: Vdummy + complex(WP), dimension(:,:,:),pointer :: Wdummy + complex(WP), dimension(:,:,:),pointer :: Zdummy + + complex(WP), dimension(:,:,:), allocatable :: nlx + complex(WP), dimension(:,:,:), allocatable :: nly + complex(WP), dimension(:,:,:), allocatable :: nlz + complex(WP), dimension(:,:,:), allocatable :: nlmf + + complex(WP), dimension(:,:,:), allocatable :: nlu2x + complex(WP), dimension(:,:,:), allocatable :: nlu2y + complex(WP), dimension(:,:,:), allocatable :: nlu2z + + + + logical, parameter :: flg_inplace = .false. + complex(WP), parameter :: ii = (0.0_WP,1.0_WP) + real(WP), parameter :: kmin = 1e-06_WP + + real(WP) :: dt,sim_time + + integer :: impose + real(WP) :: cx,cy,cz + +end module solver + + +subroutine solver_init + + use parallel + use data + use solver + use transform + + implicit none + + integer :: i,j,k,il,jl,kl,gg(3),itype + real(WP) :: pi + real(WP) :: umax,vmax,wmax + + + allocate(kx(fns1)) + allocate(ky(fns2)) + allocate(kz(fns3)) + +!!PAR!! allocate(kxsc(fns1sc)) +!!PAR!! allocate(kysc(fns2sc)) +!!PAR!! allocate(kzsc(fns3sc)) + + pi = acos(-1.0_WP) + dk = 2.0_WP*pi/L + + do i = fnxs,fnxe + il = i -fnxs+1 + kx(il) = real((i-1),WP)*dk + enddo +!!PAR!! do i = fnxssc,fnxesc +!!PAR!! il = i -fnxssc+1 +!!PAR!! kxsc(il) = real((i-1),WP)*dk +!!PAR!! enddo + + do j = fnys,fnye + jl = j - fnys +1 + ky(jl) = real((j-1),WP)*dk + if (j.gt.nk) ky(jl) = -real(nx+1-j,WP)*dk + enddo +!!PAR!! do j = fnyssc,fnyesc +!!PAR!! jl = j - fnyssc +1 +!!PAR!! kysc(jl) = real((j-1),WP)*dk +!!PAR!! if (j.gt.nksc) kysc(jl) = -real(nxsc+1-j,WP)*dk +!!PAR!! enddo + + do k = fnzs,fnze + kl = k -fnzs+1 + kz(kl) = real((k-1),WP)*dk + if (k.gt.nk) kz(kl) = -real(nx+1-k,WP)*dk + enddo +!!PAR!! do k = fnzssc,fnzesc +!!PAR!! kl = k -fnzssc+1 +!!PAR!! kzsc(kl) = real((k-1),WP)*dk +!!PAR!! if (k.gt.nksc) kzsc(kl) = -real(nxsc+1-k,WP)*dk +!!PAR!! enddo + + +! print *,'First checkpoint',rank + + + allocate(Uk(fns1,fns2,fns3)) + allocate(Vk(fns1,fns2,fns3)) + allocate(Wk(fns1,fns2,fns3)) +!!PAR!! allocate(Zk(fns1sc,fns2sc,fns3sc)) + + allocate(Udummy(fns1,fns2,fns3)) + allocate(Vdummy(fns1,fns2,fns3)) + allocate(Wdummy(fns1,fns2,fns3)) +!!PAR!! allocate(Zdummy(fns1sc,fns2sc,fns3sc)) + + + + call ftran_wrap(U,Uk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(V,Vk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(W,Wk,ns1,ns2,ns3,fns1,fns2,fns3) +!!PAR!! call ftran_wrap(SC,Zk,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + + + Uk = Uk/real(nx**3.0,WP) + Vk = Vk/real(nx**3.0,WP) + Wk = Wk/real(nx**3.0,WP) +!!PAR!! Zk = Zk/real(nxsc**3.0,WP) + + call parallel_max(maxval(abs(Uk)),umax) + call parallel_max(maxval(abs(Vk)),vmax) + call parallel_max(maxval(abs(Wk)),wmax) + + if (rank.eq.0) then + print *,' Maximum of U,V,W after trans',umax,vmax,wmax + endif + + + +!!$ call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + + allocate(nlx(fns1,fns2,fns3)) + allocate(nly(fns1,fns2,fns3)) + allocate(nlz(fns1,fns2,fns3)) +!!PAR!! allocate(nlmf(fns1sc,fns2sc,fns3sc)) + allocate(nlu2x(fns1,fns2,fns3)) + allocate(nlu2y(fns1,fns2,fns3)) + allocate(nlu2z(fns1,fns2,fns3)) + +!!$ +!!$ call parallel_max(maxval(abs(Uk)),umax) +!!$ call parallel_max(maxval(abs(Vk)),vmax) +!!$ call parallel_max(maxval(abs(Wk)),wmax) + +!!$ if (rank.eq.0) then +!!$ print *,' Maximum U,V,W in solver',umax,vmax,wmax +!!$ endif +!!$ +!!$ if (umax.eq.maxval(abs(Uk))) then +!!$ print *,' Maximum in rank', rank +!!$ print *,' location ', maxloc(abs(Uk)) +!!$ gg = maxloc(abs(Uk)) +!!$ print *,' max value for conformation', Uk(gg(1),gg(2),gg(3)) +!!$ endif +!!$ +!!$ if (wmax.eq.maxval(abs(Wk))) then +!!$ print *,' Maximum in rank W', rank +!!$ print *,' location W', maxloc(abs(Wk)) +!!$ gg = maxloc(abs(Wk)) +!!$ print *,' max value for W conformation', Wk(gg(1),gg(2),gg(3)) +!!$ endif + + sim_time = 0.0_WP + + call parser_read('Dealiasing',deal,0) + + kmax = sqrt(3.0_WP)*kx(nx/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) +!!PAR!! kmaxsc = sqrt(3.0_WP)*kxsc(nxsc/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) + if (deal.eq.1) then + kcut = 2.0_WP/3.0_WP*kmax +!!PAR!! kcutsc = 2.0_WP/3.0_WP*kmaxsc + else + kcut = 10000.0_WP +!!PAR!! kcutsc = 10000.0_WP + endif + + mu_solver = mu + diff_solver = diff + + call parser_read('LES model',iles,0) + call parser_read('LES scalar model',ilessc,0) + call parser_read('y inhomogeneity',ydir,0) + + call parser_read('Postprocessing',ipost,0) + + call parser_read('Forcing',iforce,0) + if (iforce.eq.1) call forcing_init + + call parser_read('Courant number', courant,0.5_WP) + +!!!! Determine if it is required to solver the scalar equation +!!!! If running from scratch with forcing, dont solver scalar equation + + call parser_read('Simulation type', itype) + call parser_read('Compute scalar', iscalar) + if (iscalar.eq.0) then + if (rank.eq.0) print *,'Not solving scalar transport equation .....' + endif + + call parser_read('Imposing mean gradient',impose,0) + if (impose.eq.1) then + call parser_read('X-gradient',cx,0.0_WP) + call parser_read('Y-gradient',cy,0.0_WP) + call parser_read('Z-gradient',cz,0.0_WP) + else + cx = 0.0_WP + cy = 0.0_WP + cz = 0.0_WP + endif + + spfilename = 'spectrum_solver.init' + spfilename2 = 'spectrum_solver.init.z' + call get_dns_numbers(0) + + print*,'test U init solver', U(1,1,1), V(1,1,1),W(1,1,1) + +end subroutine solver_init + + + +subroutine solver_step + + use solver + use parallel + use data + + implicit none + + complex(WP), dimension(:,:,:), allocatable :: Pressk + real(WP), dimension(:,:,:), allocatable :: tab + character(len=str_long) :: sim_name + real(WP) :: Ufz, Vfz, Wfz + + integer :: i,j,k,ierr + + real(WP) :: kk,h, divumax + + + allocate(Pressk(fns1,fns2,fns3)) + allocate(tab(ns1,ns2,ns3)) + + +!!$ if (rank.eq.0) print *,' Viscosity', mu_solver +!!!! GEL DU CHAMP DE VITESSE POUR LES TEST !!!! +call parser_read('Simulation name', sim_name) +if (trim(sim_name).eq.'Test case') then + call parser_read('Frozen U', Ufz) + call parser_read('Frozen V', Vfz) + call parser_read('Frozen W', Wfz) + U = Ufz + V = Vfz + W = Wfz +endif + + call get_timestep + sim_time = sim_time +dt + +!!!!!!!!!!!! +!!! Second-order RK scheme +!!!!!!!!!!! + h = dt/2.0_WP + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + Udummy(i,j,k) = Uk(i,j,k) + Vdummy(i,j,k) = Vk(i,j,k) + Wdummy(i,j,k) = Wk(i,j,k) + enddo + enddo + enddo +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! Zdummy(i,j,k) = Zk(i,j,k) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + + call non_linear + +! if (iforce.eq.1) call force_compute +!!!!!! Step 1 for RK scheme + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Uk(i,j,k) + h*nlx(i,j,k))/exp(mu_solver*kk*h) + Vk(i,j,k) = (Vk(i,j,k) + h*nly(i,j,k))/exp(mu_solver*kk*h) + Wk(i,j,k) = (Wk(i,j,k) + h*nlz(i,j,k))/exp(mu_solver*kk*h) + enddo + enddo + enddo +!!PAR!! if (iscalar.ne.0) then +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = kxsc(i)**2.0 + kysc(j)**2.0 + kzsc(k)**2.0 +!!PAR!! Zk(i,j,k) = (Zk(i,j,k) + h*nlmf(i,j,k))/exp(diff_solver*kk*h) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! end if + + +!!$ +!!$!!!!!!! Step 2 for RK scheme +!!$ + call non_linear + if (iforce.eq.1) call force_compute + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Udummy(i,j,k) + dt*nlx(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Vk(i,j,k) = (Vdummy(i,j,k) + dt*nly(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Wk(i,j,k) = (Wdummy(i,j,k) + dt*nlz(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + enddo + enddo + enddo +!!PAR!! if (iscalar.ne.0) then +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = kxsc(i)**2.0 + kysc(j)**2.0 + kzsc(k)**2.0 +!!PAR!! Zk(i,j,k) = (Zdummy(i,j,k) + dt*nlmf(i,j,k)*exp(diff_solver*kk*h))/exp(diff_solver*kk*dt) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! end if + + ! Projection + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + if(kk.gt.0.0_WP) then + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) )/kk + end if + Uk(i,j,k) = Uk(i,j,k) - ii*kx(i)*Pressk(i,j,k) + Vk(i,j,k) = Vk(i,j,k) - ii*ky(j)*Pressk(i,j,k) + Wk(i,j,k) = Wk(i,j,k) - ii*kz(k)*Pressk(i,j,k) + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) ) + end do + end do + end do +! call btran_wrap(Pressk,tab,ns1,ns2,ns3,fns1,fns2,fns3) +! call parallel_max(maxval(abs(tab)),divumax) +! if (rank.eq.0) print*,'divergence max = ', divumax +! call parallel_max(maxval(abs(Uk)),divumax) +! if (rank.eq.0) print*,'abs(Uk) max = ', divumax + +!!PAR!! - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + if (nproc.ne.1) then + if (rank.eq.0) print*,'NOT AVAILABLE IN PARALLEL' + STOP + else + +!!PAR!! 1. on remet les vitesses dans l'espace physique + if (trim(sim_name).ne.'Test case') call u_compute !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + +!!PAR!! 2. appelle du transport particulaire + call x_advec + call y_advec + call z_advec + + end if +!!PAR!! - FIN - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + + + deallocate(Pressk) + deallocate(tab) + + +end subroutine solver_step + +subroutine non_linear + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(:,:,:),allocatable :: ddx,ddy,ddz,nis + real(WP), dimension(:,:,:),allocatable :: us,vs,ws + real(WP), dimension(:,:,:),allocatable :: uss,vss,wss + complex(WP), dimension(:,:,:),allocatable :: ddxk,ddyk,ddzk + ! LES + + complex(WP) :: knl + real(WP) :: kk + + integer :: i,j,k + real(WP) :: umax,vmax,wmax + + integer :: sizemess, tag, ierr, status(MPI_STATUS_SIZE) + integer :: yeloc, ysloc, yelocsc, yslocsc, rank2send1, rank2send2, fs1, fe1, fs2, fe2, fnysrank, fnyerank, cptrank + + + + allocate(ddx(ns1,ns2,ns3)) + allocate(ddy(ns1,ns2,ns3)) + allocate(ddz(ns1,ns2,ns3)) + allocate(nis(ns1,ns2,ns3)) + + allocate(ddxk(fns1,fns2,fns3)) + allocate(ddyk(fns1,fns2,fns3)) + allocate(ddzk(fns1,fns2,fns3)) + + + allocate(us(ns1,ns2,ns3)) + allocate(vs(ns1,ns2,ns3)) + allocate(ws(ns1,ns2,ns3)) + +!!!!!!!!!!! +!! Convert velocity to spatial coordinates +!!!!!!!!!! + + call btran_wrap(Uk,us,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,vs,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,ws,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ call parallel_max(maxval(abs(us)),umax) +!!$ call parallel_max(maxval(abs(vs)),vmax) +!!$ call parallel_max(maxval(abs(ws)),wmax) +!!$ +!!$! if (rank.eq.0) write(*,'(A10,3(E12.5,3X))') ' MAX VAL', umax,vmax,wmax + + +!!$ if (rank.eq.0) print *,' After velocity conversion' + + +!!!!!!!!!! +!! Form the first term in the skew-symmetric form +!!!!!!!!! + + +!!!! U component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*us(i,j,k) + ddy(i,j,k) = vs(i,j,k)*us(i,j,k) + ddz(i,j,k) = ws(i,j,k)*us(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2x(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! V component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*vs(i,j,k) + ddy(i,j,k) = vs(i,j,k)*vs(i,j,k) + ddz(i,j,k) = ws(i,j,k)*vs(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2y(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! W component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*ws(i,j,k) + ddy(i,j,k) = vs(i,j,k)*ws(i,j,k) + ddz(i,j,k) = ws(i,j,k)*ws(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2z(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! Compute the second term in the skew symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Uk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Uk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Uk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After btran in U computations' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product evaluations' + + call ftran_wrap(nis,nlx,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After forward transforms' + + nlx = nlx/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlx computation' + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Vk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Vk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Vk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After b trans in V compute' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product eval. in V' + + call ftran_wrap(nis,nly,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After nly computation' + +!!!!!!!!!!!!!! +!! Compute W products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Wk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Wk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Wk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(nis,nlz,ns1,ns2,ns3,fns1,fns2,fns3) + + nlz = nlz/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlz computation' + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Form the complex skew-symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!$ + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlx(i,j,k) = 0.5*(nlx(i,j,k) + nlu2x(i,j,k)) + nly(i,j,k) = 0.5*(nly(i,j,k) + nlu2y(i,j,k)) + nlz(i,j,k) = 0.5*(nlz(i,j,k) + nlu2z(i,j,k)) + enddo + enddo + enddo + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!! Form non-linear term for the scalar +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + deallocate(ddx) + deallocate(ddy) + deallocate(ddz) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(nis) + + +!!PAR!! if (iscalar.eq.0) then + + deallocate(us) + deallocate(vs) + deallocate(ws) +!!PAR!! nlmf = 0.0_WP + +!!PAR!! else + +!!PAR!! allocate(ddx(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddy(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddz(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(nis(ns1sc,ns2sc,ns3sc)) + +!!PAR!! allocate(ddxk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddyk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddzk(fns1sc,fns2sc,fns3sc)) + +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! ddxk(i,j,k) = ii*kxsc(i)*Zk(i,j,k) +!!PAR!! ddyk(i,j,k) = ii*kysc(j)*Zk(i,j,k) +!!PAR!! ddzk(i,j,k) = ii*kzsc(k)*Zk(i,j,k) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +!!PAR!! ddx = 0.0_WP +!!PAR!! ddy = 0.0_WP +!!PAR!! ddz = 0.0_WP + +!!PAR!! call btran_wrap(ddxk,ddx,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddyk,ddy,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddzk,ddz,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + +!!PAR!! deallocate(ddxk) +!!PAR!! deallocate(ddyk) +!!PAR!! deallocate(ddzk) + +!!PAR!! allocate(uss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(vss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(wss(ns1sc,ns2sc,ns3sc)) +!!PAR!! uss = 0.0 +!!PAR!! vss = 0.0 +!!PAR!! wss = 0.0 + +!!PAR!! if (ns1sc.gt.ns1) then +!!PAR!! call discretisation2(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else if (ns1sc.lt.ns1) then +!!PAR!! call discretisation3(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else +!!PAR!! uss = us +!!PAR!! vss = vs +!!PAR!! wss = ws +!!PAR!! end if + +!!PAR!! deallocate(us) +!!PAR!! deallocate(vs) +!!PAR!! deallocate(ws) + +!!PAR!! do k = 1,ns3sc +!!PAR!! do j = 1,ns2sc +!!PAR!! do i = 1,ns1sc +!!PAR!! nis(i,j,k) = uss(i,j,k)*(ddx(i,j,k)+cx) + & +!!PAR!! & vss(i,j,k)*(ddy(i,j,k)+cy) +& +!!PAR!! & wss(i,j,k)*(ddz(i,j,k)+cz) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! deallocate(uss) +!!PAR!! deallocate(vss) +!!PAR!! deallocate(wss) +!!PAR!! deallocate(ddx) +!!PAR!! deallocate(ddy) +!!PAR!! deallocate(ddz) + +!!PAR!! call ftran_wrap(nis,nlmf,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! nlmf = nlmf/real((ns1sc**3.0),WP) + +!!PAR!! deallocate(nis) + + +!!PAR!! endif + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Dealias the non-linear term + + call dealias + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! LES MODEL + +if (iles.ne.0) then +! if (iles.eq.1) call smagmodel + if (iles.eq.2) call dynsmagmodel +! if (iles.eq.8) call SISM +! if (iles.eq.12) call dynsmagmodel2 +! if (iles.eq.13) call dynsmagmodel3 +endif +if (ilessc.ne.0) then +! if (ilessc.eq.1) call smagmodelsca +! if (ilessc.eq.2) call dynsmagmodelsca +! if (ilessc.eq.3) call dynsmagmodelscanew +! if (ilessc.eq.4) call dynsmagmodelscacut +! if (ilessc.eq.5) call dynsmagmodelscanewcut +! if (ilessc.eq.6) call dynsfmodelscacut +! if (ilessc.eq.7) call dynsfmodelscanewcut +! if (ilessc.eq.8) call dynsigmamodelscacut +! if (ilessc.eq.9) call dynsigmamodelscanewcut +! if (ilessc.eq.12) call dyndd2modelscacut +! if (ilessc.eq.13) call dyndd4modelscacut +! if (ilessc.eq.14) call dynddsmagmodelscanewcut +! if (ilessc.eq.15) call dynsflpmodelscacut +! if (ilessc.eq.16) call ssmodelscacut +! if (ilessc.eq.17) call dynsmagtestmodelscacut +endif + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +!!!!!!!!!! +!! Form the pressure term and add it to the nonlinear term +!!!!!!!!!! + +!! SEMBLE NE PAS DONNER DIV(U)=0. ??? +!! +!! do k = 1,fns3 +!! do j = 1,fns2 +!! do i = 1,fns1 +!! +!! kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 +!! if (sqrt(kk).gt.kmin) then +!! knl = kx(i)*nlx(i,j,k) + ky(j)*nly(i,j,k) +& +!! & kz(k)*nlz(i,j,k) +!! nlx(i,j,k) = kx(i)*knl/kk - nlx(i,j,k) +!! nly(i,j,k) = ky(j)*knl/kk - nly(i,j,k) +!! nlz(i,j,k) = kz(k)*knl/kk - nlz(i,j,k) +!! nlmf(i,j,k) = -nlmf(i,j,k) +!! else +!! nlx(i,j,k) = 0.0_WP +!! nly(i,j,k) = 0.0_WP +!! nlz(i,j,k) = 0.0_WP +!! nlmf(i,j,k) = 0.0_WP +!!!!!!!!!!!!!!!INSTEAD + nlx = -nlx + nly = -nly + nlz = -nlz +!!PAR!! nlmf = -nlmf +!! endif +!! enddo +!! enddo +!! enddo + + +end subroutine non_linear + + +subroutine get_timestep + + use solver + use parallel + use data + + real(WP) :: max_s, max_sg + character(len=str_long) :: sim_name + + integer :: ierr,nn + + max_s = 0.0_WP + max_sg = 0.0_WP + + call parser_read('Simulation name', sim_name) + if (trim(sim_name).ne.'Test case') call u_compute !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + + max_s = maxval(abs(U) +abs(V)+abs(W)) + + + call MPI_ALLREDUCE(max_s,max_sg,1,MPI_REAL_WP,MPI_MAX,& + &MPI_COMM_WORLD,ierr) + + call parser_read('fixed time step',dt) + + if (dt.eq.0) then + if (max_sg.gt.0.0_WP) then + nn = nx +!!PAR!! if(iscalar.ne.0) nn = max(nx,nxsc) + dt = courant/max_sg*(L/nn) + else + print *,' SOMETHING WRONG IN TIME_STEP', rank, max_sg,max_s,nx + stop + endif + endif + + +!!$ print *,' MAX_TIME ', dt + +end subroutine get_timestep + + +subroutine dealias + + use solver + use parallel + use precision + + implicit none + + real(WP) :: kk + integer :: i,j,k + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + + kk = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) + ! kk = sqrt(kk) +! if ((abs(kz(k)).gt.kmax).or.(abs(ky(j)).gt.kmax).or.(abs(kx(i)).gt.kmax)) then +! if (kk.gt.kmax) then + if (kk.gt.kcut) then + nlx(i,j,k) = 0.0_WP + nly(i,j,k) = 0.0_WP + nlz(i,j,k) = 0.0_WP + endif + enddo + enddo + enddo +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = sqrt(kxsc(i)**2.0_WP + kysc(j)**2.0_WP + kzsc(k)**2.0_WP) +!!PAR!! if (kk.gt.kcutsc) then +!!PAR!! nlmf(i,j,k) = 0.0_WP +!!PAR!! endif +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +end subroutine dealias + +subroutine fourier_write + use solver + +! call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + +end subroutine fourier_write + + diff --git a/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav2 b/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav2 new file mode 100755 index 000000000..e1a55aeb2 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/solver.f90_sav2 @@ -0,0 +1,987 @@ +module solver + + use precision + + implicit none + + real(WP), dimension(:), allocatable :: kx + real(WP), dimension(:), allocatable :: ky + real(WP), dimension(:), allocatable :: kz + + real(WP), dimension(:), allocatable :: kxsc + real(WP), dimension(:), allocatable :: kysc + real(WP), dimension(:), allocatable :: kzsc + + integer :: deal + real(WP) :: dk,kmax,kcut + real(WP) :: kmaxsc,kcutsc + + real(WP) :: mu_solver, diff_solver + real(WP) :: courant + + integer :: iforce,iscalar,iles,ilessc,ydir,ipost + + + complex(WP), dimension(:,:,:), allocatable :: Uk + complex(WP), dimension(:,:,:), allocatable :: Vk + complex(WP), dimension(:,:,:), allocatable :: Wk + complex(WP), dimension(:,:,:), allocatable :: Zk + + complex(WP), dimension(:,:,:),pointer :: Udummy + complex(WP), dimension(:,:,:),pointer :: Vdummy + complex(WP), dimension(:,:,:),pointer :: Wdummy + complex(WP), dimension(:,:,:),pointer :: Zdummy + + complex(WP), dimension(:,:,:), allocatable :: nlx + complex(WP), dimension(:,:,:), allocatable :: nly + complex(WP), dimension(:,:,:), allocatable :: nlz + complex(WP), dimension(:,:,:), allocatable :: nlmf + + complex(WP), dimension(:,:,:), allocatable :: nlu2x + complex(WP), dimension(:,:,:), allocatable :: nlu2y + complex(WP), dimension(:,:,:), allocatable :: nlu2z + + + + logical, parameter :: flg_inplace = .false. + complex(WP), parameter :: ii = (0.0_WP,1.0_WP) + real(WP), parameter :: kmin = 1e-06_WP + + real(WP) :: dt,sim_time + + integer :: impose + real(WP) :: cx,cy,cz + +end module solver + + +subroutine solver_init + + use parallel + use data + use solver + use transform + + implicit none + + integer :: i,j,k,il,jl,kl,gg(3),itype + real(WP) :: pi + real(WP) :: umax,vmax,wmax + + if (rank.eq.0) print*,'init : test1' + + allocate(kx(fns1)) + allocate(ky(fns2)) + allocate(kz(fns3)) + +!!PAR!! allocate(kxsc(fns1sc)) +!!PAR!! allocate(kysc(fns2sc)) +!!PAR!! allocate(kzsc(fns3sc)) + + pi = acos(-1.0_WP) + dk = 2.0_WP*pi/L + + do i = fnxs,fnxe + il = i -fnxs+1 + kx(il) = real((i-1),WP)*dk + enddo +!!PAR!! do i = fnxssc,fnxesc +!!PAR!! il = i -fnxssc+1 +!!PAR!! kxsc(il) = real((i-1),WP)*dk +!!PAR!! enddo + + do j = fnys,fnye + jl = j - fnys +1 + ky(jl) = real((j-1),WP)*dk + if (j.gt.nk) ky(jl) = -real(nx+1-j,WP)*dk + enddo +!!PAR!! do j = fnyssc,fnyesc +!!PAR!! jl = j - fnyssc +1 +!!PAR!! kysc(jl) = real((j-1),WP)*dk +!!PAR!! if (j.gt.nksc) kysc(jl) = -real(nxsc+1-j,WP)*dk +!!PAR!! enddo + + do k = fnzs,fnze + kl = k -fnzs+1 + kz(kl) = real((k-1),WP)*dk + if (k.gt.nk) kz(kl) = -real(nx+1-k,WP)*dk + enddo +!!PAR!! do k = fnzssc,fnzesc +!!PAR!! kl = k -fnzssc+1 +!!PAR!! kzsc(kl) = real((k-1),WP)*dk +!!PAR!! if (k.gt.nksc) kzsc(kl) = -real(nxsc+1-k,WP)*dk +!!PAR!! enddo + + +! print *,'First checkpoint',rank + + + allocate(Uk(fns1,fns2,fns3)) + allocate(Vk(fns1,fns2,fns3)) + allocate(Wk(fns1,fns2,fns3)) +!!PAR!! allocate(Zk(fns1sc,fns2sc,fns3sc)) + + allocate(Udummy(fns1,fns2,fns3)) + allocate(Vdummy(fns1,fns2,fns3)) + allocate(Wdummy(fns1,fns2,fns3)) +!!PAR!! allocate(Zdummy(fns1sc,fns2sc,fns3sc)) + + + if (rank.eq.0) print*,'init : test2' + + call ftran_wrap(U,Uk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(V,Vk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(W,Wk,ns1,ns2,ns3,fns1,fns2,fns3) +!!PAR!! call ftran_wrap(SC,Zk,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + + + Uk = Uk/real(nx**3.0,WP) + Vk = Vk/real(nx**3.0,WP) + Wk = Wk/real(nx**3.0,WP) +!!PAR!! Zk = Zk/real(nxsc**3.0,WP) + + call parallel_max(maxval(abs(Uk)),umax) + call parallel_max(maxval(abs(Vk)),vmax) + call parallel_max(maxval(abs(Wk)),wmax) + + if (rank.eq.0) then + print *,' Maximum of U,V,W after trans',umax,vmax,wmax + endif + + + +!!$ call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + + allocate(nlx(fns1,fns2,fns3)) + allocate(nly(fns1,fns2,fns3)) + allocate(nlz(fns1,fns2,fns3)) +!!PAR!! allocate(nlmf(fns1sc,fns2sc,fns3sc)) + allocate(nlu2x(fns1,fns2,fns3)) + allocate(nlu2y(fns1,fns2,fns3)) + allocate(nlu2z(fns1,fns2,fns3)) + +!!$ +!!$ call parallel_max(maxval(abs(Uk)),umax) +!!$ call parallel_max(maxval(abs(Vk)),vmax) +!!$ call parallel_max(maxval(abs(Wk)),wmax) + +!!$ if (rank.eq.0) then +!!$ print *,' Maximum U,V,W in solver',umax,vmax,wmax +!!$ endif +!!$ +!!$ if (umax.eq.maxval(abs(Uk))) then +!!$ print *,' Maximum in rank', rank +!!$ print *,' location ', maxloc(abs(Uk)) +!!$ gg = maxloc(abs(Uk)) +!!$ print *,' max value for conformation', Uk(gg(1),gg(2),gg(3)) +!!$ endif +!!$ +!!$ if (wmax.eq.maxval(abs(Wk))) then +!!$ print *,' Maximum in rank W', rank +!!$ print *,' location W', maxloc(abs(Wk)) +!!$ gg = maxloc(abs(Wk)) +!!$ print *,' max value for W conformation', Wk(gg(1),gg(2),gg(3)) +!!$ endif + + sim_time = 0.0_WP + + call parser_read('Dealiasing',deal,0) + + kmax = sqrt(3.0_WP)*kx(nx/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) +!!PAR!! kmaxsc = sqrt(3.0_WP)*kxsc(nxsc/2+1) !sqrt(2.0_WP)*real(nx,WP)/3.0_WP !sqrt(3.0_WP)*real((nx/2+1),WP) + if (deal.eq.1) then + kcut = 2.0_WP/3.0_WP*kmax +!!PAR!! kcutsc = 2.0_WP/3.0_WP*kmaxsc + else + kcut = 10000.0_WP +!!PAR!! kcutsc = 10000.0_WP + endif + + if (rank.eq.0) print*,'init : test3' + + mu_solver = mu + diff_solver = diff + + call parser_read('LES model',iles,0) + call parser_read('LES scalar model',ilessc,0) + call parser_read('y inhomogeneity',ydir,0) + + call parser_read('Postprocessing',ipost,0) + + call parser_read('Forcing',iforce,0) + if (iforce.eq.1) call forcing_init + + call parser_read('Courant number', courant,0.5_WP) + +!!!! Determine if it is required to solver the scalar equation +!!!! If running from scratch with forcing, dont solver scalar equation + + call parser_read('Simulation type', itype) + call parser_read('Compute scalar', iscalar) + if (iscalar.eq.0) then + if (rank.eq.0) print *,'Not solving scalar transport equation .....' + endif + + call parser_read('Imposing mean gradient',impose,0) + if (impose.eq.1) then + call parser_read('X-gradient',cx,0.0_WP) + call parser_read('Y-gradient',cy,0.0_WP) + call parser_read('Z-gradient',cz,0.0_WP) + else + cx = 0.0_WP + cy = 0.0_WP + cz = 0.0_WP + endif + + spfilename = 'spectrum_solver.init' + spfilename2 = 'spectrum_solver.init.z' + call get_dns_numbers(0) + + if (rank.eq.0) print*,'init : test4' + + print*,'test U init solver', U(1,1,1), V(1,1,1),W(1,1,1) + +end subroutine solver_init + + + +subroutine solver_step + + use solver + use parallel + use data + + implicit none + + complex(WP), dimension(:,:,:), allocatable :: Pressk + real(WP), dimension(:,:,:), allocatable :: tab + character(len=str_long) :: sim_name + real(WP) :: Ufz, Vfz, Wfz + + integer :: i,j,k,ierr + + real(WP) :: kk,h, divumax + + + if (rank.eq.0) print*,'test1' + print*,'test U solver 0', U(1,1,1), V(1,1,1),W(1,1,1) + + + allocate(Pressk(fns1,fns2,fns3)) + allocate(tab(ns1,ns2,ns3)) + + +!!$ if (rank.eq.0) print *,' Viscosity', mu_solver +!!!! GEL DU CHAMP DE VITESSE POUR LES TEST !!!! +call parser_read('Simulation name', sim_name) +if (trim(sim_name).eq.'Test case') then + call parser_read('Frozen U', Ufz) + call parser_read('Frozen V', Vfz) + call parser_read('Frozen W', Wfz) + U = Ufz + V = Vfz + W = Wfz + print*,'test U solver 1', U(1,1,1), V(1,1,1),W(1,1,1) +endif + + call get_timestep + sim_time = sim_time +dt + +!!!!!!!!!!!! +!!! Second-order RK scheme +!!!!!!!!!!! + h = dt/2.0_WP + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + Udummy(i,j,k) = Uk(i,j,k) + Vdummy(i,j,k) = Vk(i,j,k) + Wdummy(i,j,k) = Wk(i,j,k) + enddo + enddo + enddo +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! Zdummy(i,j,k) = Zk(i,j,k) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + + if (rank.eq.0) print*,'test2' + + call non_linear + + if (rank.eq.0) print*,'test3' +! if (iforce.eq.1) call force_compute +!!!!!! Step 1 for RK scheme + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Uk(i,j,k) + h*nlx(i,j,k))/exp(mu_solver*kk*h) + Vk(i,j,k) = (Vk(i,j,k) + h*nly(i,j,k))/exp(mu_solver*kk*h) + Wk(i,j,k) = (Wk(i,j,k) + h*nlz(i,j,k))/exp(mu_solver*kk*h) + enddo + enddo + enddo +!!PAR!! if (iscalar.ne.0) then +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = kxsc(i)**2.0 + kysc(j)**2.0 + kzsc(k)**2.0 +!!PAR!! Zk(i,j,k) = (Zk(i,j,k) + h*nlmf(i,j,k))/exp(diff_solver*kk*h) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! end if + + +!!$ +!!$!!!!!!! Step 2 for RK scheme +!!$ + call non_linear + if (iforce.eq.1) call force_compute + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + Uk(i,j,k) = (Udummy(i,j,k) + dt*nlx(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Vk(i,j,k) = (Vdummy(i,j,k) + dt*nly(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + Wk(i,j,k) = (Wdummy(i,j,k) + dt*nlz(i,j,k)*exp(mu_solver*kk*h))/exp(mu_solver*kk*dt) + enddo + enddo + enddo +!!PAR!! if (iscalar.ne.0) then +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = kxsc(i)**2.0 + kysc(j)**2.0 + kzsc(k)**2.0 +!!PAR!! Zk(i,j,k) = (Zdummy(i,j,k) + dt*nlmf(i,j,k)*exp(diff_solver*kk*h))/exp(diff_solver*kk*dt) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! end if + + ! Projection + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 + if(kk.gt.0.0_WP) then + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) )/kk + end if + Uk(i,j,k) = Uk(i,j,k) - ii*kx(i)*Pressk(i,j,k) + Vk(i,j,k) = Vk(i,j,k) - ii*ky(j)*Pressk(i,j,k) + Wk(i,j,k) = Wk(i,j,k) - ii*kz(k)*Pressk(i,j,k) + Pressk(i,j,k) = - ( ii*kx(i)*Uk(i,j,k) + ii*ky(j)*Vk(i,j,k) + ii*kz(k)*Wk(i,j,k) ) + end do + end do + end do +! call btran_wrap(Pressk,tab,ns1,ns2,ns3,fns1,fns2,fns3) +! call parallel_max(maxval(abs(tab)),divumax) +! if (rank.eq.0) print*,'divergence max = ', divumax +! call parallel_max(maxval(abs(Uk)),divumax) +! if (rank.eq.0) print*,'abs(Uk) max = ', divumax + +!!PAR!! - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + if (nproc.ne.1) then + if (rank.eq.0) print*,'NOT AVAILABLE IN PARALLEL' + STOP + else + +!!PAR!! 1. on remet les vitesses dans l'espace physique + print*,'test U solver 2', U(1,1,1), V(1,1,1),W(1,1,1) + if (trim(sim_name).ne.'Test case') call u_compute !!!! GEL DU CHAMP DE VITESSE POUR LES TESTS !!!! + + print*,'test U solver 3', U(1,1,1), V(1,1,1),W(1,1,1) + +!!PAR!! 2. appelle du transport particulaire + call x_advec + print*,'x advec done' + call y_advec + print*,'y advec done' + call z_advec + print*,'z advec done' +! call z_advec + + end if +!!PAR!! - FIN - INTERFACAGE AVEC LA METHODE PARTICULAIRE + + + + deallocate(Pressk) + deallocate(tab) + + +end subroutine solver_step + +subroutine non_linear + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(:,:,:),allocatable :: ddx,ddy,ddz,nis + real(WP), dimension(:,:,:),allocatable :: us,vs,ws + real(WP), dimension(:,:,:),allocatable :: uss,vss,wss + complex(WP), dimension(:,:,:),allocatable :: ddxk,ddyk,ddzk + ! LES + + complex(WP) :: knl + real(WP) :: kk + + integer :: i,j,k + real(WP) :: umax,vmax,wmax + + integer :: sizemess, tag, ierr, status(MPI_STATUS_SIZE) + integer :: yeloc, ysloc, yelocsc, yslocsc, rank2send1, rank2send2, fs1, fe1, fs2, fe2, fnysrank, fnyerank, cptrank + + + + allocate(ddx(ns1,ns2,ns3)) + allocate(ddy(ns1,ns2,ns3)) + allocate(ddz(ns1,ns2,ns3)) + allocate(nis(ns1,ns2,ns3)) + + allocate(ddxk(fns1,fns2,fns3)) + allocate(ddyk(fns1,fns2,fns3)) + allocate(ddzk(fns1,fns2,fns3)) + + + allocate(us(ns1,ns2,ns3)) + allocate(vs(ns1,ns2,ns3)) + allocate(ws(ns1,ns2,ns3)) + +!!!!!!!!!!! +!! Convert velocity to spatial coordinates +!!!!!!!!!! + + call btran_wrap(Uk,us,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,vs,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,ws,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ call parallel_max(maxval(abs(us)),umax) +!!$ call parallel_max(maxval(abs(vs)),vmax) +!!$ call parallel_max(maxval(abs(ws)),wmax) +!!$ +!!$! if (rank.eq.0) write(*,'(A10,3(E12.5,3X))') ' MAX VAL', umax,vmax,wmax + + +!!$ if (rank.eq.0) print *,' After velocity conversion' + + +!!!!!!!!!! +!! Form the first term in the skew-symmetric form +!!!!!!!!! + + +!!!! U component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*us(i,j,k) + ddy(i,j,k) = vs(i,j,k)*us(i,j,k) + ddz(i,j,k) = ws(i,j,k)*us(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2x(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! V component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*vs(i,j,k) + ddy(i,j,k) = vs(i,j,k)*vs(i,j,k) + ddz(i,j,k) = ws(i,j,k)*vs(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2y(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + +!!!! W component + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + ddx(i,j,k) = us(i,j,k)*ws(i,j,k) + ddy(i,j,k) = vs(i,j,k)*ws(i,j,k) + ddz(i,j,k) = ws(i,j,k)*ws(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(ddx,ddxk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddy,ddyk,ns1,ns2,ns3,fns1,fns2,fns3) + call ftran_wrap(ddz,ddzk,ns1,ns2,ns3,fns1,fns2,fns3) + + ddxk = ddxk/real(ns1**3.0,WP) + ddyk = ddyk/real(ns1**3.0,WP) + ddzk = ddzk/real(ns1**3.0,WP) + + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlu2z(i,j,k) = ii*(kx(i)*ddxk(i,j,k) + & + &ky(j)*ddyk(i,j,k) + kz(k)*ddzk(i,j,k)) + enddo + enddo + enddo + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! Compute the second term in the skew symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Uk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Uk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Uk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After btran in U computations' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product evaluations' + + call ftran_wrap(nis,nlx,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After forward transforms' + + nlx = nlx/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlx computation' + +!!!!!!!!!!!!!! +!! Compute U products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Vk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Vk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Vk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After b trans in V compute' + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + +!!$ if (rank.eq.0) print *,' After product eval. in V' + + call ftran_wrap(nis,nly,ns1,ns2,ns3,fns1,fns2,fns3) + +!!$ if (rank.eq.0) print *,' After forward trans in V' + + nly = nly/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nly computation' + +!!!!!!!!!!!!!! +!! Compute W products +!!!!!!!!!!!!!! + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + ddxk(i,j,k) = ii*kx(i)*Wk(i,j,k) + ddyk(i,j,k) = ii*ky(j)*Wk(i,j,k) + ddzk(i,j,k) = ii*kz(k)*Wk(i,j,k) + enddo + enddo + enddo + + ddx = 0.0_WP + ddy = 0.0_WP + ddz = 0.0_WP + + call btran_wrap(ddxk,ddx,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddyk,ddy,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(ddzk,ddz,ns1,ns2,ns3,fns1,fns2,fns3) + + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + nis(i,j,k) = us(i,j,k)*ddx(i,j,k) + & + & vs(i,j,k)*ddy(i,j,k) +& + & ws(i,j,k)*ddz(i,j,k) + enddo + enddo + enddo + + call ftran_wrap(nis,nlz,ns1,ns2,ns3,fns1,fns2,fns3) + + nlz = nlz/real((ns1**3.0),WP) + +!!$ if (rank.eq.0) print *,' After nlz computation' + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Form the complex skew-symmetric form +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!$ + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + nlx(i,j,k) = 0.5*(nlx(i,j,k) + nlu2x(i,j,k)) + nly(i,j,k) = 0.5*(nly(i,j,k) + nlu2y(i,j,k)) + nlz(i,j,k) = 0.5*(nlz(i,j,k) + nlu2z(i,j,k)) + enddo + enddo + enddo + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!! Form non-linear term for the scalar +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + deallocate(ddx) + deallocate(ddy) + deallocate(ddz) + deallocate(ddxk) + deallocate(ddyk) + deallocate(ddzk) + deallocate(nis) + + +!!PAR!! if (iscalar.eq.0) then + + deallocate(us) + deallocate(vs) + deallocate(ws) +!!PAR!! nlmf = 0.0_WP + +!!PAR!! else + +!!PAR!! allocate(ddx(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddy(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(ddz(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(nis(ns1sc,ns2sc,ns3sc)) + +!!PAR!! allocate(ddxk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddyk(fns1sc,fns2sc,fns3sc)) +!!PAR!! allocate(ddzk(fns1sc,fns2sc,fns3sc)) + +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! ddxk(i,j,k) = ii*kxsc(i)*Zk(i,j,k) +!!PAR!! ddyk(i,j,k) = ii*kysc(j)*Zk(i,j,k) +!!PAR!! ddzk(i,j,k) = ii*kzsc(k)*Zk(i,j,k) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +!!PAR!! ddx = 0.0_WP +!!PAR!! ddy = 0.0_WP +!!PAR!! ddz = 0.0_WP + +!!PAR!! call btran_wrap(ddxk,ddx,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddyk,ddy,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! call btran_wrap(ddzk,ddz,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + +!!PAR!! deallocate(ddxk) +!!PAR!! deallocate(ddyk) +!!PAR!! deallocate(ddzk) + +!!PAR!! allocate(uss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(vss(ns1sc,ns2sc,ns3sc)) +!!PAR!! allocate(wss(ns1sc,ns2sc,ns3sc)) +!!PAR!! uss = 0.0 +!!PAR!! vss = 0.0 +!!PAR!! wss = 0.0 + +!!PAR!! if (ns1sc.gt.ns1) then +!!PAR!! call discretisation2(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation2(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else if (ns1sc.lt.ns1) then +!!PAR!! call discretisation3(us,uss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(vs,vss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! call discretisation3(ws,wss,ns1,ns2,ns3,ns1sc,ns2sc,ns3sc) +!!PAR!! else +!!PAR!! uss = us +!!PAR!! vss = vs +!!PAR!! wss = ws +!!PAR!! end if + +!!PAR!! deallocate(us) +!!PAR!! deallocate(vs) +!!PAR!! deallocate(ws) + +!!PAR!! do k = 1,ns3sc +!!PAR!! do j = 1,ns2sc +!!PAR!! do i = 1,ns1sc +!!PAR!! nis(i,j,k) = uss(i,j,k)*(ddx(i,j,k)+cx) + & +!!PAR!! & vss(i,j,k)*(ddy(i,j,k)+cy) +& +!!PAR!! & wss(i,j,k)*(ddz(i,j,k)+cz) +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! deallocate(uss) +!!PAR!! deallocate(vss) +!!PAR!! deallocate(wss) +!!PAR!! deallocate(ddx) +!!PAR!! deallocate(ddy) +!!PAR!! deallocate(ddz) + +!!PAR!! call ftran_wrap(nis,nlmf,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) +!!PAR!! nlmf = nlmf/real((ns1sc**3.0),WP) + +!!PAR!! deallocate(nis) + + +!!PAR!! endif + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! Dealias the non-linear term + + call dealias + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!! LES MODEL + +if (iles.ne.0) then +! if (iles.eq.1) call smagmodel +! if (iles.eq.2) call dynsmagmodel +! if (iles.eq.8) call SISM +! if (iles.eq.12) call dynsmagmodel2 +! if (iles.eq.13) call dynsmagmodel3 +endif +if (ilessc.ne.0) then +! if (ilessc.eq.1) call smagmodelsca +! if (ilessc.eq.2) call dynsmagmodelsca +! if (ilessc.eq.3) call dynsmagmodelscanew +! if (ilessc.eq.4) call dynsmagmodelscacut +! if (ilessc.eq.5) call dynsmagmodelscanewcut +! if (ilessc.eq.6) call dynsfmodelscacut +! if (ilessc.eq.7) call dynsfmodelscanewcut +! if (ilessc.eq.8) call dynsigmamodelscacut +! if (ilessc.eq.9) call dynsigmamodelscanewcut +! if (ilessc.eq.12) call dyndd2modelscacut +! if (ilessc.eq.13) call dyndd4modelscacut +! if (ilessc.eq.14) call dynddsmagmodelscanewcut +! if (ilessc.eq.15) call dynsflpmodelscacut +! if (ilessc.eq.16) call ssmodelscacut +! if (ilessc.eq.17) call dynsmagtestmodelscacut +endif + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +!!!!!!!!!! +!! Form the pressure term and add it to the nonlinear term +!!!!!!!!!! + +!! SEMBLE NE PAS DONNER DIV(U)=0. ??? +!! +!! do k = 1,fns3 +!! do j = 1,fns2 +!! do i = 1,fns1 +!! +!! kk = kx(i)**2.0 + ky(j)**2.0 + kz(k)**2.0 +!! if (sqrt(kk).gt.kmin) then +!! knl = kx(i)*nlx(i,j,k) + ky(j)*nly(i,j,k) +& +!! & kz(k)*nlz(i,j,k) +!! nlx(i,j,k) = kx(i)*knl/kk - nlx(i,j,k) +!! nly(i,j,k) = ky(j)*knl/kk - nly(i,j,k) +!! nlz(i,j,k) = kz(k)*knl/kk - nlz(i,j,k) +!! nlmf(i,j,k) = -nlmf(i,j,k) +!! else +!! nlx(i,j,k) = 0.0_WP +!! nly(i,j,k) = 0.0_WP +!! nlz(i,j,k) = 0.0_WP +!! nlmf(i,j,k) = 0.0_WP +!!!!!!!!!!!!!!!INSTEAD + nlx = -nlx + nly = -nly + nlz = -nlz +!!PAR!! nlmf = -nlmf +!! endif +!! enddo +!! enddo +!! enddo + + +end subroutine non_linear + + +subroutine get_timestep + + use solver + use parallel + use data + + real(WP) :: max_s, max_sg + + integer :: ierr,nn + + max_s = 0.0_WP + max_sg = 0.0_WP + +!!!! GEL DU CHAMP DE VITESSE POUR LES TEST !!!! call u_compute + print*,'test U get_timestep 1', U(1,1,1), V(1,1,1),W(1,1,1) + + max_s = maxval(abs(U) +abs(V)+abs(W)) + + + call MPI_ALLREDUCE(max_s,max_sg,1,MPI_REAL_WP,MPI_MAX,& + &MPI_COMM_WORLD,ierr) + + call parser_read('fixed time step',dt) + + if (dt.eq.0) then + if (max_sg.gt.0.0_WP) then + nn = nx +!!PAR!! if(iscalar.ne.0) nn = max(nx,nxsc) + dt = courant/max_sg*(L/nn) + else + print *,' SOMETHING WRONG IN TIME_STEP', rank, max_sg,max_s,nx + stop + endif + endif + + +!!$ print *,' MAX_TIME ', dt + +end subroutine get_timestep + + +subroutine dealias + + use solver + use parallel + use precision + + implicit none + + real(WP) :: kk + integer :: i,j,k + + do k = 1,fns3 + do j = 1,fns2 + do i = 1,fns1 + + kk = sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) + ! kk = sqrt(kk) +! if ((abs(kz(k)).gt.kmax).or.(abs(ky(j)).gt.kmax).or.(abs(kx(i)).gt.kmax)) then +! if (kk.gt.kmax) then + if (kk.gt.kcut) then + nlx(i,j,k) = 0.0_WP + nly(i,j,k) = 0.0_WP + nlz(i,j,k) = 0.0_WP + endif + enddo + enddo + enddo +!!PAR!! do k = 1,fns3sc +!!PAR!! do j = 1,fns2sc +!!PAR!! do i = 1,fns1sc +!!PAR!! kk = sqrt(kxsc(i)**2.0_WP + kysc(j)**2.0_WP + kzsc(k)**2.0_WP) +!!PAR!! if (kk.gt.kcutsc) then +!!PAR!! nlmf(i,j,k) = 0.0_WP +!!PAR!! endif +!!PAR!! enddo +!!PAR!! enddo +!!PAR!! enddo + +end subroutine dealias + +subroutine fourier_write + use solver + +! call data_write_fourier(Uk,Vk,Wk,fns1,fns2,fns3) + +end subroutine fourier_write + + diff --git a/CodesEnVrac/Remesh/FFTPAR/string.f90 b/CodesEnVrac/Remesh/FFTPAR/string.f90 new file mode 100755 index 000000000..1964ca2b9 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/string.f90 @@ -0,0 +1,7 @@ +module string + implicit none + integer, parameter :: str_short = 8 + integer, parameter :: str_medium = 64 + integer, parameter :: str_long = 4096 +end module string + diff --git a/CodesEnVrac/Remesh/FFTPAR/tg_init.f90 b/CodesEnVrac/Remesh/FFTPAR/tg_init.f90 new file mode 100755 index 000000000..462520e79 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/tg_init.f90 @@ -0,0 +1,48 @@ +subroutine tg_init + + use parallel + use data + + + implicit none + + integer :: i,j,k,tgdim + real(WP) :: dx,per,acos,yj,zk,xi,factor + + + call parser_read('Length of domain',L) + call parser_read('Number of points', nx) + call parser_read('TG dimensions',tgdim,1) + + + dx = L/real(nx-1,WP) + per = 0.5*L/acos(-1.0) + + if (tgdim.eq.1) then + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + yj = real(j+nys-1,WP)*dx + zk = real(k+nzs-1,WP)*dx + U(i,j,k) = 0.0_WP + V(i,j,k) = cos(yj/per)*sin(zk/per) + W(i,j,k) = -sin(yj/per)*cos(zk/per) + enddo + enddo + enddo + else + do k = 1,ns3 + do j = 1,ns2 + do i = 1,ns1 + xi = real(i+nxs-1,WP)*dx + yj = real(j+nys-1,WP)*dx + zk = real(k+nzs-1,WP)*dx + U(i,j,k) = sin(xi)*cos(yj)*cos(zk) + V(i,j,k) = -cos(xi)*sin(yj)*cos(zk) + W(i,j,k) = 0.0 + enddo + enddo + enddo + endif + +end subroutine tg_init diff --git a/CodesEnVrac/Remesh/FFTPAR/tools.f90 b/CodesEnVrac/Remesh/FFTPAR/tools.f90 new file mode 100755 index 000000000..81435626c --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/tools.f90 @@ -0,0 +1,668 @@ +subroutine dns_stats + + use solver + use parallel + use data + + implicit none + + real(WP), dimension(2,nx+1) :: S1,S2,S + real(WP), dimension(ns1,ns2,ns3) :: tab,tab1 + real(WP), dimension(:,:,:), allocatable :: SCO, SCO2 + real(WP),dimension(ns1sc,ns2sc,ns3sc) :: tabsc + complex(WP),dimension(fns1,fns2,fns3) :: tabf +! real(WP),dimension(ns1,ns2,ns3) :: tabx,taby,tabz +! complex(WP),dimension(fns1,fns2,fns3) :: tabfx,tabfy,tabfz + real(WP) :: esum, k2sum,lambda_t,Re_lambda,uturb,divumax + real(WP) :: buf,grms,drms,lambda,buf1 + + integer :: k,i,j,ierr,ik,nxo,nxoz + real(WP) :: kk,umax,vmax,wmax,cos,pi,kc,eps,e_spec,zmax,zstat2,zstat,zstat2o,zstato + + S = 0.0_WP + S1 = 0.0_WP + S2 = 0.0_WP + call u_compute + + pi = acos(-1.0_WP) +! dk = 2.0_WP*pi/L +! kc = pi*nx/L +! eps = kc/1000000_WP +! +! do k = 1,fns3 +! do j = 1,fns2 +! do i = 1,fns1 +! kk= sqrt(kx(i)**2.0_WP + ky(j)**2.0_WP + kz(k)**2.0_WP) +! ik = 1+idint(kk/dk+0.5_WP) +! if (kk.gt.eps.and.kk.le.kc) then +! e_spec = (real(Uk(i,j,k)*conjg(Uk(i,j,k))) + & +! & real(Vk(i,j,k)*conjg(Vk(i,j,k))) +& +! & real(Wk(i,j,k)*conjg(Wk(i,j,k)))) +! S1(2,ik) = S1(2,ik) + e_spec +! S2(2,ik) = S2(2,ik) + 2*mu*kk**2.0_WP*e_spec +! endif +! enddo +! enddo +! enddo +! do i = 1,nx+1 +! S1(1,i) = real(i-1,WP)*dk +! S2(1,i) = real(i-1,WP)*dk +! enddo +! S = S1 +! +! call MPI_ALLREDUCE(S1(2,:),S(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& +! &MPI_COMM_WORLD,ierr) +! +! S1 = S +! +! call MPI_ALLREDUCE(S2(2,:),S(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& +! &MPI_COMM_WORLD,ierr) +! +! S2 = S +! +! esum = 0.0_WP +! k2sum = 0.0_WP +! do k = 1,nx+1 +! kk = S(1,k) +! esum = esum + S1(2,k) +! k2sum = k2sum + S2(2,k) +! enddo +! lambda_t = sqrt(5*esum/k2sum) +!-----urms + tab=U**2+V**2+W**2 + buf=0. + do k=1,ns3 + do j=1,ns2 + do i=1,ns1 + buf=buf+tab(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,grms,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) +! print*,"U rms =",grms/(ns1**3.) +!-----<dudx^2>+<dvdy^2>+<dwdz^2> + buf=0. + tab=0. + tabf=0. + do k=1,fns3 + do j=1,fns2 + tabf(:,j,k) = ii*kx(:)*Uk(:,j,k) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + do k=1,ns3 + do j=1,ns2 + do i=1,ns1 + buf=buf+tab(i,j,k)**2. + enddo + enddo + enddo + tab=0. + tabf=0. + do k=1,fns3 + do i=1,fns1 + tabf(i,:,k) = ii*ky(:)*Vk(i,:,k) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + do k=1,ns3 + do j=1,ns2 + do i=1,ns1 + buf=buf+tab(i,j,k)**2. + enddo + enddo + enddo + tab=0. + tabf=0. + do j=1,fns2 + do i=1,fns1 + tabf(i,j,:) = ii*kz(:)*Wk(i,j,:) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + do k=1,ns3 + do j=1,ns2 + do i=1,ns1 + buf=buf+tab(i,j,k)**2. + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,drms,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) +!---- +!---divergence +! -- divergences +!- velocity + tab1=0. + tab=0. + tabf=0. + do k=1,fns3 + do j=1,fns2 + tabf(:,j,k) = ii*kx(:)*Uk(:,j,k) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + tab1 = tab + tab=0. + tabf=0. + do k=1,fns3 + do i=1,fns1 + tabf(i,:,k) = ii*ky(:)*Vk(i,:,k) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + tab1 = tab1 + tab + tab=0. + tabf=0. + do j=1,fns2 + do i=1,fns1 + tabf(i,j,:) = ii*kz(:)*Wk(i,j,:) + enddo + enddo + call btran_wrap(tabf,tab,ns1,ns2,ns3,fns1,fns2,fns3) + tab1 = tab1 + tab + call parallel_max(maxval(abs(tab1)),divumax) +!---- + lambda = sqrt(grms/drms) + uturb = sqrt(grms/(3.*real(nx**3,WP))) + Re_lambda = uturb*lambda/mu_solver + + call parallel_max(maxval(abs(U)),umax) + call parallel_max(maxval(abs(V)),vmax) + call parallel_max(maxval(abs(W)),wmax) + call parallel_max(maxval(abs(SC)),zmax) + tabsc=SC**2 + buf=0. + buf1=0. + do k=1,ns3sc + do j=1,ns2sc + do i=1,ns1sc + buf=buf+tabsc(i,j,k) + buf1=buf1+SC(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,zstat2,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(buf1,zstat,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + zstat=zstat/(real(nxsc**3,WP)) + zstat2=zstat2/(real(nxsc**3,WP)) + zstat2 = (zstat2 - zstat**2.)**(0.5) + + call parser_read('Nx filter output',nxo,0) + if (nxo.lt.ns1sc.and.nxo.ne.0) then + nxoz = nxo / nproc + allocate(SCO(nxo,nxo,nxoz)) + allocate(SCO2(nxo,nxo,nxoz)) + call discretisation3(SC,SCO,ns1sc,ns2sc,ns3sc,nxo,nxo,nxoz) + SCO2=SCO**2.0 + buf=0. + buf1=0. + do k=1,nxoz + do j=1,nxo + do i=1,nxo + buf=buf+SCO2(i,j,k) + buf1=buf1+SCO(i,j,k) + enddo + enddo + enddo + call MPI_ALLREDUCE(buf,zstat2o,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + call MPI_ALLREDUCE(buf1,zstato,1,MPI_REAL_WP,MPI_SUM, & + MPI_COMM_WORLD,ierr) + zstato=zstato/(real(nxo**3,WP)) + zstat2o=zstat2o/(real(nxo**3,WP)) + zstat2o = (zstat2o - zstato**2.)**(0.5) + deallocate(SCO) + deallocate(SCO2) + end if + + if (rank.eq.0) then +! print*,grms,drms,lambda,uturb,mu_solver + write(*,'(A10,8(E12.5,2X))') 'STEP ', sim_time,Re_lambda,uturb,umax,divumax,zmax,zstat2,zstat2o + endif + + + +end subroutine dns_stats + +subroutine u_compute + + use solver + use data + use parallel + + implicit none + + real(WP) :: Uloc(ns1,ns2,ns3) + real(WP) :: Vloc(ns1,ns2,ns3) + real(WP) :: Wloc(ns1,ns2,ns3) + + call btran_wrap(Uk,Uloc,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,Vloc,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,Wloc,ns1,ns2,ns3,fns1,fns2,fns3) + + U = Uloc + V = Vloc + W = Wloc + +end subroutine u_compute + +subroutine uz_compute + + use solver + use data + use parallel + + implicit none + + real(WP) :: Uloc(ns1,ns2,ns3) + real(WP) :: Vloc(ns1,ns2,ns3) + real(WP) :: Wloc(ns1,ns2,ns3) + real(WP) :: SCloc(ns1sc,ns2sc,ns3sc) + + call btran_wrap(Uk,Uloc,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Vk,Vloc,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Wk,Wloc,ns1,ns2,ns3,fns1,fns2,fns3) + call btran_wrap(Zk,SCloc,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc) + + U = Uloc + V = Vloc + W = Wloc + SC = SCloc + +end subroutine uz_compute + + +subroutine get_spectrum(Bdummy,nx1,nx2,nx3,fnx1,fnx2,fnx3,L,Sg,Sg1) + + use transform + use precision + use parallel + + implicit none +! include 'fftw3.f' + + integer :: nx1,nx2,nx3 + integer :: fnx1,fnx2,fnx3 + integer :: fn1zs,fn1ze,fn1ys,fn1ye,fn1xs,fn1xe + real(WP), dimension(2,nx1+1) :: S, Sg, Sg1 + real(WP), dimension(nx1,nx2,nx3) :: Bdummy + real(WP) :: ke,kd,ks,dk,ksk0ratio,kc,kcksratio,kk,kx,ky,kz,kk2 + + + real(WP), dimension(:,:,:), pointer :: Rbuf + + real(WP), dimension(:,:,:), pointer :: in + complex(WP), dimension(:,:,:), pointer :: out + + integer :: ierr + integer :: i,j,k,ik,iunit,gg(3) + integer :: il,jl,kl,nkk + complex(WP) :: ii=(0.0_WP,1.0_WP) + real(WP) :: rand,pi,eps,L,gmax + + integer(KIND=8) :: plan_3d + + real(WP), dimension(nx1+1) :: nnodes + real(WP) :: node_density + + + + + allocate(Rbuf(fnx1,fnx2,fnx3)) + allocate(A(nx1,nx2,nx3)) + allocate(B(fnx1,fnx2,fnx3)) + allocate(C(fnx1,fnx2,fnx3)) + allocate(D(fnx1,fnx3,fnx2)) + + + do k = 1,nx3 + do j = 1,nx2 + do i = 1,nx1 + A(i,j,k) = Bdummy(i,j,k) + enddo + enddo + enddo + + call forward_transform(nx1,nx2,nx3,fnx1,fnx2,fnx3) + + do k = 1,fnx3 + do j = 1,fnx2 + do i = 1,fnx1 + B(i,j,k) = B(i,j,k)/real(nx1**3.0,WP) + Rbuf(i,j,k) = sqrt(real(B(i,j,k)*conjg(B(i,j,k)),WP)) + enddo + enddo + enddo + + + + + Sg = 0.0_WP + Sg1 = 0.0_WP + nnodes = 0.0_WP + + ! Create pi + pi = acos(-1.0_WP) + + ! ================= + ! Velocity Spectrum + + ! Spectrum computation + + dk = 2.0_WP*pi/L + kc = pi*nx1/L + eps=kc/1000000.0_WP + + nkk = nx1/2+1 + fn1zs = 1 + fn1ze = fnx3 + fn1ys = 1 + (rank)*fnx2 + fn1ye = (rank+1)*fnx2 + fn1xs = 1 + fn1xe = nkk + + do k = fn1zs,fn1ze + do j = fn1ys,fn1ye + do i = fn1xs,fn1xe + il = i-fn1xs+1 + jl = j-fn1ys+1 + kl = k-fn1zs+1 + ! Wavenumbers + kx=real(i-1,WP)*dk +! if (i.gt.(nkk)) kx=-real(nx1-i+1,WP)*dk + ky=real(j-1,WP)*dk + if (j.gt.nkk) ky=-real(nx1-j+1,WP)*dk + kz=real(k-1,WP)*dk + if (k.gt.nkk) kz=-real(nx1-k+1,WP)*dk + kk=sqrt(kx**2+ky**2+kz**2) + ! Spectrum + ik=1+idint(kk/dk+0.5_WP) +!!$ nnodes(ik) = nnodes(ik) + 1.0_WP + if ((kk.gt.eps).and.(kk.le.kc)) then +!!$ if (i.gt.1) then + Sg(2,ik)=Sg(2,ik)+(Rbuf(il,jl,kl)**2) + Sg1(2,ik) = Sg1(2,ik) + kk**2.0_WP*(Rbuf(il,jl,kl)**2) +!!$ else +!!$ S(2,ik)=S(2,ik)+0.5_WP*(Rbuf(il,jl,kl)**2)/dk +!!$ endif + end if + end do + end do + end do + + + do ik=1,nx1+1 + Sg(1,ik)=real(dk*(ik-1),WP) + Sg1(1,ik)=real(dk*(ik-1),WP) + end do + + + + deallocate(Rbuf) + + + deallocate(A) + deallocate(B) + deallocate(C) + deallocate(D) + + +end subroutine get_spectrum + +subroutine get_dns_numbers(iinfo) + + use parallel + use data + implicit none + + real(WP) :: pi + real(WP) :: ke,mu_cin,dx + real(WP) :: kcin,epsi,l11,lt,re_turb,tau_epsi,l_k,tau_k + + real(WP) :: keta, L_large,dk,eta,dissipation,tke,Rlambda + real(WP), dimension(:,:), pointer :: S1,S2,S3,Sg + real(WP), dimension(:,:), pointer :: S11,S21,S31,Sg1 + + + + integer :: i, iunit, ierr, iinfo + + + + + + allocate(S1(2,nx+1),S2(2,nx+1),S3(2,nx+1),Sg(2,nx+1)) + allocate(S11(2,nx+1),S21(2,nx+1),S31(2,nx+1),Sg1(2,nx+1)) + + Sg = 0.0_WP + + S1 = 0.0_WP + S2 = 0.0_WP + S3 = 0.0_WP + + + call get_spectrum(V,ns1,ns2,ns3,fns1,fns2,fns3,L,S1,S11) + call get_spectrum(U,ns1,ns2,ns3,fns1,fns2,fns3,L,S2,S21) + call get_spectrum(W,ns1,ns2,ns3,fns1,fns2,fns3,L,S3,S31) + + Sg(1,:) = S1(1,:) + Sg(1,:) = S11(1,:) + + S1 = S1 + S2 + S3 + S11 = S11 + S21 + S31 + + call MPI_ALLREDUCE(S1(2,:),Sg(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + call MPI_ALLREDUCE(S11(2,:),Sg1(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + if (rank.eq.0) then + iunit = iopen() + open(iunit,file=trim(adjustl(spfilename)),form='formatted') + + do i = 1,nx+1 + if ((Sg(1,i).ne.0.0_WP).and.(Sg(2,i).ne.0.0_WP)) then + write(11,*) Sg(1,i), Sg(2,i) + endif + enddo + close(iclose(iunit)) + endif + + call parser_read('Kmax eta', keta) + + + + pi = acos(-1.0_WP) + dx = L/real(nx,WP) + tke = 0.0_WP + dissipation = 0.0_WP + + do i = 1,nx+1 + tke = tke + Sg(2,i) + dissipation = dissipation + 2*mu*Sg1(2,i) + enddo + + Ut = sqrt(tke/1.5_WP) + eta = (2.0_WP*keta)/real(nx,WP) + re_turb = tke**2.0/(dissipation*mu) + Rlambda = sqrt(20.0_WP/3.0_WP*re_turb) + + lt = eta*(3.0_WP/20.0_WP*Rlambda*Rlambda)**(3.0/4.0) + L11 = lt*0.43 + + + ke = 1.3_WP/L11 + dk = 2.0_WP*pi/L + + tau_epsi = tke/dissipation + tau_k = sqrt(mu/dissipation) + + + + if (rank.eq.0.and.iinfo.eq.1) then + + write(*,*) + write(*,*) ' ======================================== ' + write(*,*)' Debugging turbulent values ' + write(*,*)' ---------------------------------------- ' + if (trim(spectrum).eq.'PP') then + write(*,*)' -Spectrum type ----------> Passot-Pouquet' + else if (trim(spectrum).eq.'VKP') then + write(*,*)' -Spectrum type ----------> Von Karman-Pao' + end if + write(*,*)' Viscosity ' + write(*,*)' mu ------->', mu + write(*,*)' -Turbulent Reynolds ' + write(*,*)' Re_t --------> ', re_turb + write(*,*)' -Turbulent kinetic energy ' + write(*,*)' k -----------> ', tke + write(*,*)' -Turbulent dissipation rate ' + write(*,*)' epsilon -----> ', dissipation + write(*,*)' -Size of the biggest eddy ' + write(*,*)' l_t ---------> ', lt + write(*,*)' C1 ----------> ', L/lt + write(*,*)' -Eddy turn over time ' + write(*,*)' tau ---------> ', tau_epsi + write(*,*)' -Kolmogorov scale ' + write(*,*)' l_k ---------> ', eta + write(*,*)' C2 ----------> ', eta/dx + write(*,*)' -Kolmogorov time scale ' + write(*,*)' tau_k -------> ', tau_k + write(*,*)' -Reynolds lambda ' + write(*,*)' Re_lambda ---> ', Rlambda + if (trim(spectrum).eq.'PP') then + write(*,*)' -Integral length scale ' + write(*,*)' Lii --------> ', l11 + write(*,*)' -Turbulent Reynolds based on Lii ' + write(*,*)' Re_Lii -----> ', Ut*l11/mu + end if + write(*,*)' ======================================== ' + + endif + + deallocate(S1,S2,S3,Sg) + deallocate(S11,S21,S31,Sg1) + allocate(S3(2,nxsc+1),Sg(2,nxsc+1)) + allocate(S31(2,nxsc+1),Sg1(2,nxsc+1)) + S3 = 0.0 + S31 = 0.0 + call get_spectrum(SC,ns1sc,ns2sc,ns3sc,fns1sc,fns2sc,fns3sc,L,S3,S31) + Sg(1,:) = S3(1,:) + Sg(1,:) = S31(1,:) + call MPI_ALLREDUCE(S3(2,:),Sg(2,:),nxsc+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + call MPI_ALLREDUCE(S31(2,:),Sg1(2,:),nxsc+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + + if (rank.eq.0) then + iunit = iopen() + open(iunit,file=trim(adjustl(spfilename2)),form='formatted') + + do i = 1,nxsc+1 + if ((Sg(1,i).ne.0.0_WP).and.(Sg(2,i).ne.0.0_WP)) then + write(11,*) Sg(1,i), Sg(2,i) + endif + enddo + close(iclose(iunit)) + endif + deallocate(S3,Sg) + deallocate(S31,Sg1) + + +end subroutine get_dns_numbers + + +subroutine tg_stats + + use solver + use parallel + use data + + implicit none + + real(WP) :: umax,vmax,wmax,nmax + real(WP),dimension(2,nx+1) :: S1,S + real(WP) :: esum, k2sum,lambda_t,Re_lambda,uturb + + integer :: k,ierr + real(WP) :: kk + + + + S = 0.0_WP + S1 = 0.0_WP + + call u_compute + call get_spectrum(U,ns1,ns2,ns3,L,S1) + S = S1 + call get_spectrum(V,ns1,ns2,ns3,L,S1) + S = S + S1 + call get_spectrum(W,ns1,ns2,ns3,L,S1) + S = S + S1 + + S(1,:) = S1(1,:) + S1 = S + + call MPI_ALLREDUCE(S1(2,:),S(2,:),nx+1,MPI_REAL_WP,MPI_SUM,& + &MPI_COMM_WORLD,ierr) + + esum = 0.0_WP + k2sum = 0.0_WP + do k = 1,nx+1 + kk = S1(1,k) + esum = esum + S(2,k) + k2sum = k2sum + S(2,k)*S1(1,k)**2.0 + enddo + lambda_t = sqrt(5*esum/k2sum) + uturb = sqrt(2.0_WP/3.0_Wp*esum) + if (mu.gt.0.0_WP) then + Re_lambda = lambda_t*uturb/mu + else + Re_lambda = 0.0_WP + endif + + + call parallel_max(maxval(abs(U)),umax) + call parallel_max(maxval(abs(V)),vmax) + call parallel_max(maxval(abs(W)),wmax) + + if (rank.eq.0) then + write(*,'(A7,4(E12.5,3X),2E15.8)') 'STEP ', sim_time, umax, vmax,wmax,k2sum,esum + endif + + + +end subroutine tg_stats + + +real(WP) function spec(ka,kb,ke) + + use precision + + implicit none + real(WP) :: e,dk,ka,kb,ke,integ,k + integer :: i,n + + n = 1000 + + dk = (kb-ka)/real(n,WP) + + integ = 0.0_WP + k = ka + do i =1,n + k = k + dk + integ = integ + (k/ke)**4.0_WP*exp(-2.0_WP*(k/ke)**2.0_WP)*dk + enddo + spec = integ/(kb-ka) + +end function spec + + + diff --git a/CodesEnVrac/Remesh/FFTPAR/transforms.f90 b/CodesEnVrac/Remesh/FFTPAR/transforms.f90 new file mode 100755 index 000000000..3c2d56b1a --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/transforms.f90 @@ -0,0 +1,329 @@ +module transform + + use precision + use parallel + implicit none + include 'fftw3.f' + + real(WP), dimension(:,:,:), pointer :: A !_real (ns1,ns2,ns3) + complex(WP), dimension(:,:,:), pointer :: B !_complex (fns1,fns2,fns3) + complex(WP), dimension(:,:,:), pointer :: C !_dummy (fns1,fns2,fns3) + complex(WP), dimension(:,:,:), pointer :: D !_dummy (fns1,fns3,fns2) +end module transform + + +subroutine forward_transform(n1,n2,n3,fn1,fn2,fn3) + + use transform + implicit none + + integer :: nsize(2),idim,istride,idist,ostride,odist + integer :: idim2,istride2,idist2,ostride2,odist2 + integer :: inem(3),onem(3),howmany + integer :: n1,n2,n3,fn1,fn2,fn3 + integer(KIND=8) :: plan_mf1,plan_mf2 + + + integer, parameter :: NULL = 0 + + integer :: nsize1 + + idim = 2 + nsize(1) = n1 + nsize(2) = n2 + inem(1) = n1 + inem(2) = n2 + inem(3) = n3 + istride = 1 + idist = n1*n2 + + onem(1) = fn1 + onem(2) = fn3 + onem(3) = fn2 + ostride = 1 + odist = fn1*fn3 + + call dfftw_plan_many_dft_r2c(plan_mf1,idim,nsize,n3,A,inem,istride,idist,D,onem,ostride,odist,FFTW_ESTIMATE) + call dfftw_execute_dft_r2c(plan_mf1,A,D) + call dfftw_destroy_plan(plan_mf1) + + call transpose_forward(n1,n2,n3,fn1,fn2,fn3) !(D,B) + + idim2 = 1 + nsize1 = fn3 + howmany = fn1*fn2 + + inem(1) = fn1 + inem(2) = fn2 + inem(3) = fn3 + istride2 = fn1*fn2 + idist2 = 1 + + onem(1) = fn1 + onem(2) = fn2 + onem(3) = fn3 + ostride2 = fn1*fn2 + odist2 = 1 + + call dfftw_plan_many_dft(plan_mf2,idim2,nsize1,howmany,B,inem,istride2,idist2,B,onem,ostride2,& + &odist2,FFTW_FORWARD,FFTW_ESTIMATE) + call dfftw_execute_dft(plan_mf2,B,B) + call dfftw_destroy_plan(plan_mf2) + +end subroutine forward_transform + + +subroutine backward_transform(n1,n2,n3,fn1,fn2,fn3) + + use transform + implicit none + integer :: k,j,i + integer :: nsize(2),idim,istride,idist,ostride,odist + integer :: idim2,istride2,idist2,ostride2,odist2 + integer :: inem(3),onem(3),howmany,nsize1 + integer :: n1,n2,n3,fn1,fn2,fn3 + integer(KIND=8) :: plan_mb1,plan_mb2 + + + idim2 = 1 + nsize1 = fn3 + howmany = fn1*fn2 + + inem(1) = fn1 + inem(2) = fn2 + inem(3) = fn3 + istride2 = fn1*fn2 + idist2 = 1 + + onem(1) = fn1 + onem(2) = fn2 + onem(3) = fn3 + ostride2 = fn1*fn2 + odist2 = 1 + + call dfftw_plan_many_dft(plan_mb1,idim2,nsize1,howmany,B,inem,istride2,idist2,B,onem,ostride2,& + &odist2,FFTW_BACKWARD,FFTW_ESTIMATE) + call dfftw_execute_dft(plan_mb1,B,B) + call dfftw_destroy_plan(plan_mb1) + + call transpose_backward(n1,n2,n3,fn1,fn2,fn3) !(B,D) + + idim = 2 + nsize(1) = n1 + nsize(2) = n2 + inem(1) = n1 + inem(2) = n2 + inem(3) = n3 + istride = 1 + idist = n1*n2 + + onem(1) = fn1 + onem(2) = fn3 + onem(3) = fn2 + ostride = 1 + odist = fn1*fn3 + + call dfftw_plan_many_dft_c2r(plan_mb2,idim,nsize,fn2,D,onem,ostride,odist,A,inem,istride,idist,FFTW_ESTIMATE) + call dfftw_execute_dft_c2r(plan_mb2,D,A) + call dfftw_destroy_plan(plan_mb2) + +end subroutine backward_transform + + + +subroutine transpose_forward(n1,n2,n3,fn1,fn2,fn3) + + + + use transform + implicit none + + integer :: n1,n2,n3,fn1,fn2,fn3 + integer :: scount,ierr,i,k,ki,jstart,jend,j + + if (nproc.gt.1) then + + scount = fn1*fn2*fn2 + + + do i = 1,nproc + do k = 1,fn2 + ki = (i-1)*fn2 + k + jstart = (i-1)*fn2 + 1 + jend = i*fn2 + + C(1:fn1,1:fn2,ki) = D(1:fn1,jstart:jend,k) + enddo + enddo + + + call MPI_ALLTOALL(C,scount,MPI_COMPLEX_WP,B,scount,MPI_COMPLEX_WP,MPI_COMM_WORLD,ierr) + else + do k = 1,fn3 + do j = 1,fn2 + do i = 1,fn1 + B(i,j,k) = D(i,j,k) + enddo + enddo + enddo + endif +end subroutine transpose_forward + +subroutine transpose_backward(n1,n2,n3,fn1,fn2,fn3) + + + + use transform + implicit none + + integer :: n1,n2,n3,fn1,fn2,fn3 + integer :: scount,ierr,i,k,ki,jstart,jend,j + + if (nproc.gt.1) then + + scount = fn1*fn2*fn2 + + + call MPI_ALLTOALL(B,scount,MPI_COMPLEX_WP,C,scount,MPI_COMPLEX_WP,MPI_COMM_WORLD,ierr) + + + do i = 1,nproc + do k = 1,fn2 + ki = (i-1)*fn2 + k + jstart = (i-1)*fn2 + 1 + jend = i*fn2 + D(1:fn1,jstart:jend,k) = C(1:fn1,1:fn2,ki) + enddo + enddo + else + do k = 1,fn3 + do j = 1,fn2 + do i = 1,fn1 + D(i,j,k) = B(i,j,k) + enddo + enddo + enddo + endif + +end subroutine transpose_backward + + + + + + + + + + +subroutine transform_init + + use transform + + + + implicit none + + integer :: nsize(2),idim,istride,idist,ostride,odist + integer :: idim2,istride2,idist2,ostride2,odist2 + integer :: inem(3),onem(3),howmany + integer, parameter :: NULL = 0 + + integer :: nsize1 + + +! print *,' PLANS', plan_mf1,plan_mf2,plan_mb1,plan_mb2 + + +end subroutine transform_init + + +subroutine ftran_wrap(in,out,n1,n2,n3,fn1,fn2,fn3) + + use transform + use precision + implicit none + + integer :: n1,n2,n3,fn1,fn2,fn3 + real(WP) :: in(n1,n2,n3) + complex(WP) :: out(fn1,fn2,fn3) + integer :: i,j,k + + allocate(A(n1,n2,n3)) + allocate(B(fn1,fn2,fn3)) + allocate(C(fn1,fn2,fn3)) + allocate(D(fn1,fn3,fn2)) + + + do k = 1,n3 + do j = 1,n2 + do i = 1,n1 + A(i,j,k) = in(i,j,k) + enddo + enddo + enddo + + call forward_transform(n1,n2,n3,fn1,fn2,fn3) + + do k = 1,fn3 + do j = 1,fn2 + do i = 1,fn1 + out(i,j,k) = B(i,j,k) + enddo + enddo + enddo + deallocate(A) + deallocate(B) + deallocate(C) + deallocate(D) + + +end subroutine ftran_wrap + +subroutine btran_wrap(in,out,n1,n2,n3,fn1,fn2,fn3) + + use transform + use precision + + implicit none + + integer :: n1,n2,n3,fn1,fn2,fn3 + real(WP) :: out(n1,n2,n3) + complex(WP) :: in(fn1,fn2,fn3) + + + integer :: i,j,k + + + allocate(A(n1,n2,n3)) + allocate(B(fn1,fn2,fn3)) + allocate(C(fn1,fn2,fn3)) + allocate(D(fn1,fn3,fn2)) + + + do k = 1,fn3 + do j = 1,fn2 + do i = 1,fn1 + B(i,j,k) = in(i,j,k) + enddo + enddo + enddo + + + call backward_transform(n1,n2,n3,fn1,fn2,fn3) + + do k = 1,n3 + do j = 1,n2 + do i = 1,n1 + out(i,j,k) = A(i,j,k) + enddo + enddo + enddo + + deallocate(A) + deallocate(B) + deallocate(C) + deallocate(D) + + +end subroutine btran_wrap diff --git a/CodesEnVrac/Remesh/FFTPAR/x_advec.f90 b/CodesEnVrac/Remesh/FFTPAR/x_advec.f90 new file mode 100755 index 000000000..279369680 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/x_advec.f90 @@ -0,0 +1,296 @@ +module x_advec_m + + use solver + use data + + implicit none + + integer :: npart, ntag_total, npg + real(WP) :: xmin, ymin, zmin, xmax, ymax, zmax + integer, dimension(:), allocatable :: itype + real(WP), dimension(:), allocatable :: up + real(WP), dimension(:), allocatable :: up_aux + real(WP), dimension(:), allocatable :: xp + real(WP), dimension(:), allocatable :: xp0 + real(WP), dimension(:), allocatable :: xp_aux + real(WP), dimension(:), allocatable :: vx + real(WP), dimension(:), allocatable :: vx_aux + + real(WP) :: circlim + +end module x_advec_m + + + +subroutine x_advec_init + + use x_advec_m + + implicit none + + npg = nxsc !100000 + + allocate(up(npg)) + allocate(up_aux(npg)) + allocate(xp(npg)) !!-> code original npg = 256 mais ca marche pas + allocate(xp0(npg)) + allocate(xp_aux(npg)) + allocate(vx(npg)) + allocate(vx_aux(npg)) + allocate(itype(npg)) + + up = 0.0 + up_aux = 0.0 + xp = 0.0 + xp0 = 0.0 + xp_aux = 0.0 + vx = 0.0 + vx_aux = 0.0 + + itype = 0 + + npart = 0 + ntag_total = 0 + + xmin = 0. + ymin = 0. + zmin = 0. + xmax = L + ymax = L + zmax = L + + circlim = 10**(-5) + +end subroutine x_advec_init + + + +subroutine x_advec + + use x_advec_m + + implicit none + + real(WP) :: cfl, dx, yy, zz + integer :: i,j,k,np,n, jr, kr + + + dx = L/nxsc + cfl = dt/dx + + print*,"dt =",dt + + npart = 0 + ntag_total = 0 + + do k=1,nxsc + zz=xmin+float(k-1)*dx + do j=1,nxsc + np=0 + yy=xmin+float(j-1)*dx + do i=1,nxsc + if (abs(SC(i,j,k)).gt.circlim) then + np=np+1 + up(np)=SC(i,j,k) + xp(np)=xmin+float(i-1)*dx + up_aux(np)=SC(i,j,k) + xp_aux(np)=xmin+float(i-1)*dx + end if + end do + if (np.ne.0) then + call velox_x(np,j,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + end do + call velox_x(np,j,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + end do + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + end do + jr=j + kr=k + call remeshx(np,jr,kr) + npart=npart+np + end if + end do + end do + + print*, 'NPART, NTAG ', npart,ntag_total + +end subroutine x_advec + + + +subroutine velox_x(np,j,k) + + use x_advec_m + + implicit none + + integer :: np, j, k, i, nx3, ny3, nz3, jp1, jp2, kp1, kp2, ip1, ip2 + real(WP) :: dx3, dy3, dz3, dxinv, yy, zz, x0, y0, z0, dx2 + real(WP) :: yy1, yy2, zz1, zz2, b1, b2, c1, c2, a1, a2 + real(WP) :: x, xx1, xx2 + + do i=1,np + vx(i)=0. + end do + + nx3=nx + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + x0=xmin + y0=ymin + z0=zmin + + dx2 = L/nxsc + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2 = 1.0 - yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2 = 1.0 - zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + do i = 1,np + + x = xp(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 + + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + + a1 = xx2 + a2 = xx1 + + vx(i)= vx(i) + U(ip1,jp1,kp1)*a1*b1*c1 + vx(i)= vx(i) + U(ip2,jp1,kp1)*a2*b1*c1 + vx(i)= vx(i) + U(ip1,jp2,kp1)*a1*b2*c1 + vx(i)= vx(i) + U(ip2,jp2,kp1)*a2*b2*c1 + vx(i)= vx(i) + U(ip1,jp1,kp2)*a1*b1*c2 + vx(i)= vx(i) + U(ip2,jp1,kp2)*a2*b1*c2 + vx(i)= vx(i) + U(ip1,jp2,kp2)*a1*b2*c2 + vx(i)= vx(i) + U(ip2,jp2,kp2)*a2*b2*c2 + + end do + +end subroutine velox_x + +subroutine remeshx(np1,jj,kk) + + use x_advec_m + + implicit none + + integer :: np1, jj, kk + integer :: i, nx2, n, ip0, ip1, ip2, k, j + real(WP) :: dxinv, dx2, x0, g1, x, xx0, xx1, xx2, a0, a1, a2 + + nx2 = nxsc + dx2 = L/nx2 + + dxinv=1./dx2 + + do i=1,nx2 + SC(i,jj,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up_aux(n) + x = xp_aux(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(ip0,jj,kk) = SC(ip0,jj,kk) + g1*a0 + SC(ip1,jj,kk) = SC(ip1,jj,kk) + g1*a1 + SC(ip2,jj,kk) = SC(ip2,jj,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(ip0,jj,kk) = SC(ip0,jj,kk) + g1*a0 + SC(ip1,jj,kk) = SC(ip1,jj,kk) + g1*a1 + SC(ip2,jj,kk) = SC(ip2,jj,kk) + g1*a2 + + end if + end do + +!!! go to 222 !! -> ca veut dire quoi goto ? +!!! do k=3,nx2-2 +!!! do j=1,nx2 +!!! do i=1,nx2 +!!! if (SC(i,j,k).gt.1.2) then +!!! print*,'BOUM', i,j,k,SC(i,j,k) +!!! goto 222 +!!! end if +!!! end do +!!! end do +!!! end do + +end subroutine remeshx diff --git a/CodesEnVrac/Remesh/FFTPAR/y_advec.f90 b/CodesEnVrac/Remesh/FFTPAR/y_advec.f90 new file mode 100755 index 000000000..b5d20fb72 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/y_advec.f90 @@ -0,0 +1,221 @@ +subroutine y_advec + + use x_advec_m + + implicit none + + real(WP) :: cfl, dx, yy, zz + integer :: i,j,k,np,n, ir, kr + + + dx = L/nxsc + cfl = dt/dx + + do k=1,nxsc + zz=xmin+float(k-1)*dx + do i=1,nxsc + np=0 + yy=xmin+float(i-1)*dx + do j=1,nxsc + if (abs(SC(i,j,k)).gt.circlim) then + np=np+1 +! up(np)=SC(i,j,k) + xp(np)=xmin+float(j-1)*dx + up_aux(np)=SC(i,j,k) + xp_aux(np)=xmin+float(j-1)*dx + endif + enddo + if (np.ne.0) then + call velox_y(np,i,k) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_y(np,i,k) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + kr=k + call remeshy(np,ir,kr) + endif + enddo + enddo + +end subroutine y_advec + + + +subroutine velox_y(np,j,k) + + use x_advec_m + + implicit none + + integer :: np, j, k, i, nx3, ny3, nz3, jp1, jp2, kp1, kp2, ip1, ip2 + real(WP) :: dx3, dy3, dz3, dxinv, yy, zz, x0, y0, z0, dx2 + real(WP) :: yy1, yy2, zz1, zz2, b1, b2, c1, c2, a1, a2 + real(WP) :: x, xx1, xx2 + + do i=1,np + vx(i)=0. + end do + + nx3=nx + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + x0=xmin + y0=ymin + z0=zmin + + dx2 = L/nxsc + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2 = 1.0 - yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2 = 1.0 - zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + do i = 1,np + + x = xp(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 + + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + + a1 = xx2 + a2 = xx1 + + vx(i)= vx(i) + V(jp1,ip1,kp1)*a1*b1*c1 + vx(i)= vx(i) + V(jp1,ip2,kp1)*a2*b1*c1 + vx(i)= vx(i) + V(jp2,ip1,kp1)*a1*b2*c1 + vx(i)= vx(i) + V(jp2,ip2,kp1)*a2*b2*c1 + vx(i)= vx(i) + V(jp1,ip1,kp2)*a1*b1*c2 + vx(i)= vx(i) + V(jp1,ip2,kp2)*a2*b1*c2 + vx(i)= vx(i) + V(jp2,ip1,kp2)*a1*b2*c2 + vx(i)= vx(i) + V(jp2,ip2,kp2)*a2*b2*c2 + + end do + +end subroutine velox_y + +subroutine remeshy(np1,jj,kk) + + use x_advec_m + + implicit none + + integer :: np1, jj, kk + integer :: i, nx2, n, ip0, ip1, ip2, k, j + real(WP) :: dxinv, dx2, x0, g1, x, xx0, xx1, xx2, a0, a1, a2 + + nx2 = nxsc + dx2 = L/nx2 + + dxinv=1./dx2 + + do i=1,nx2 + SC(jj,i,kk)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up_aux(n) + x = xp_aux(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(jj,ip0,kk) = SC(jj,ip0,kk) + g1*a0 + SC(jj,ip1,kk) = SC(jj,ip1,kk) + g1*a1 + SC(jj,ip2,kk) = SC(jj,ip2,kk) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(jj,ip0,kk) = SC(jj,ip0,kk) + g1*a0 + SC(jj,ip1,kk) = SC(jj,ip1,kk) + g1*a1 + SC(jj,ip2,kk) = SC(jj,ip2,kk) + g1*a2 + + end if + end do + +!!! go to 222 !! -> ca veut dire quoi goto ? +!!! do k=3,nx2-2 +!!! do j=1,nx2 +!!! do i=1,nx2 +!!! if (SC(i,j,k).gt.1.2) then +!!! print*,'BOUM', i,j,k,SC(i,j,k) +!!! goto 222 +!!! end if +!!! end do +!!! end do +!!! end do + +end subroutine remeshy diff --git a/CodesEnVrac/Remesh/FFTPAR/z_advec.f90 b/CodesEnVrac/Remesh/FFTPAR/z_advec.f90 new file mode 100755 index 000000000..583721781 --- /dev/null +++ b/CodesEnVrac/Remesh/FFTPAR/z_advec.f90 @@ -0,0 +1,221 @@ +subroutine z_advec + + use x_advec_m + + implicit none + + real(WP) :: cfl, dx, yy, zz + integer :: i,j,k,np,n, ir, jr + + + dx = L/nxsc + cfl = dt/dx + + do j=1,nxsc + zz=xmin+float(k-1)*dx + do i=1,nxsc + np=0 + yy=xmin+float(i-1)*dx + do k=1,nxsc + if (abs(SC(i,j,k)).gt.circlim) then + np=np+1 +! up(np)=SC(i,j,k) + xp(np)=xmin+float(k-1)*dx + up_aux(np)=SC(i,j,k) + xp_aux(np)=xmin+float(k-1)*dx + endif + enddo + if (np.ne.0) then + call velox_z(np,i,j) + do n=1,np + xp0(n)=xp(n) + xp(n)=xp(n)+0.5*dt*vx(n) + if (xp(n).gt.xmax) xp(n)=xp(n)-xmax+xmin + if (xp(n).lt.xmin) xp(n)=xp(n)+xmax-xmin + enddo + call velox_z(np,i,j) + do n=1,np + xp_aux(n)=xp0(n) + vx_aux(n)=vx(n) + itype(n)=1 + enddo + do n=1,np + xp_aux(n)=xp_aux(n)+dt*vx_aux(n) + if (xp_aux(n).gt.xmax) xp_aux(n)=xp_aux(n)-xmax+xmin + if (xp_aux(n).lt.xmin) xp_aux(n)=xp_aux(n)+xmax-xmin + enddo + ir=i + jr=j + call remeshz(np,ir,jr) + endif + enddo + enddo + +end subroutine z_advec + + + +subroutine velox_z(np,j,k) + + use x_advec_m + + implicit none + + integer :: np, j, k, i, nx3, ny3, nz3, jp1, jp2, kp1, kp2, ip1, ip2 + real(WP) :: dx3, dy3, dz3, dxinv, yy, zz, x0, y0, z0, dx2 + real(WP) :: yy1, yy2, zz1, zz2, b1, b2, c1, c2, a1, a2 + real(WP) :: x, xx1, xx2 + + do i=1,np + vx(i)=0. + end do + + nx3=nx + ny3=nx3 + nz3=nx3 + dx3=xmax/float(nx3) + dy3=dx3 + dz3=dx3 + + dxinv=1./dx3 + + x0=xmin + y0=ymin + z0=zmin + + dx2 = L/nxsc + + yy=+float(j-1)*dx2 + zz=+float(k-1)*dx2 + + jp1 = int((yy)/dx3) + jp2 = jp1 + 1 + kp1 = int((zz)/dx3) + kp2 = kp1 + 1 + yy1 = (yy-float(jp1)*dx3)/dx3 + yy2 = 1.0 - yy1 + zz1 = (zz-float(kp1)*dx3)/dx3 + zz2 = 1.0 - zz1 + b1=yy2 + b2=yy1 + c1=zz2 + c2=zz1 + + jp1=mod(jp1+nx3,nx3) +1 + jp2=mod(jp2+nx3,nx3) +1 + kp1=mod(kp1+nx3,nx3) +1 + kp2=mod(kp2+nx3,nx3) +1 + + do i = 1,np + + x = xp(i) + + ip1 = int((x-x0)*dxinv) + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx3-x0)*dxinv + xx2=1-xx1 + + ip1=mod(ip1+nx3,nx3) +1 + ip2=mod(ip2+nx3,nx3) +1 + + a1 = xx2 + a2 = xx1 + + vx(i)= vx(i) + W(jp1,kp1,ip1)*a1*b1*c1 + vx(i)= vx(i) + W(jp1,kp1,ip2)*a2*b1*c1 + vx(i)= vx(i) + W(jp2,kp1,ip1)*a1*b2*c1 + vx(i)= vx(i) + W(jp2,kp1,ip2)*a2*b2*c1 + vx(i)= vx(i) + W(jp1,kp2,ip1)*a1*b1*c2 + vx(i)= vx(i) + W(jp1,kp2,ip2)*a2*b1*c2 + vx(i)= vx(i) + W(jp2,kp2,ip1)*a1*b2*c2 + vx(i)= vx(i) + W(jp2,kp2,ip2)*a2*b2*c2 + + end do + +end subroutine velox_z + +subroutine remeshz(np1,jj,kk) + + use x_advec_m + + implicit none + + integer :: np1, jj, kk + integer :: i, nx2, n, ip0, ip1, ip2, k, j + real(WP) :: dxinv, dx2, x0, g1, x, xx0, xx1, xx2, a0, a1, a2 + + nx2 = nxsc + dx2 = L/nx2 + + dxinv=1./dx2 + + do i=1,nx2 + SC(jj,kk,i)=0. + enddo + + x0=xmin + + do n = 1,np1 + g1 = up_aux(n) + x = xp_aux(n) + + if (itype(n).eq.0) then + ip1 = int((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(jj,kk,ip0) = SC(jj,kk,ip0) + g1*a0 + SC(jj,kk,ip1) = SC(jj,kk,ip1) + g1*a1 + SC(jj,kk,ip2) = SC(jj,kk,ip2) + g1*a2 + + else + + ip1 = nint((x-x0)*dxinv) + ip0 = ip1 - 1 + ip2 = ip1 + 1 + + xx1 = (x - float(ip1)*dx2-x0)*dxinv + xx0=xx1+1 + xx2=1-xx1 + + ip1=mod(ip1+nx2,nx2) +1 + ip0=mod(ip0+nx2,nx2) +1 + ip2=mod(ip2+nx2,nx2) +1 + + a0=-0.5*xx1*xx2 + a1=1.-xx1**2 + a2=0.5*xx0*xx1 + + SC(jj,kk,ip0) = SC(jj,kk,ip0) + g1*a0 + SC(jj,kk,ip1) = SC(jj,kk,ip1) + g1*a1 + SC(jj,kk,ip2) = SC(jj,kk,ip2) + g1*a2 + + end if + end do + +!!! go to 222 !! -> ca veut dire quoi goto ? +!!! do k=3,nx2-2 +!!! do j=1,nx2 +!!! do i=1,nx2 +!!! if (SC(i,j,k).gt.1.2) then +!!! print*,'BOUM', i,j,k,SC(i,j,k) +!!! goto 222 +!!! end if +!!! end do +!!! end do +!!! end do + +end subroutine remeshz diff --git a/CodesEnVrac/Remesh/README b/CodesEnVrac/Remesh/README new file mode 100644 index 000000000..778b7641b --- /dev/null +++ b/CodesEnVrac/Remesh/README @@ -0,0 +1,10 @@ +Codes d'Adrien: + +-Advection 2D (formules de remaillage consistantes) +split_2d + + +-Advection 3D (formules consistantes) +split_3d_rapide + + diff --git a/Docs/Devel/CodingRules.org b/CodingRules.org similarity index 100% rename from Docs/Devel/CodingRules.org rename to CodingRules.org diff --git a/Docs/Devel/HowToGrid5000.org b/DevelDocs/HowToGrid5000.org similarity index 100% rename from Docs/Devel/HowToGrid5000.org rename to DevelDocs/HowToGrid5000.org diff --git a/Docs/Devel/ParmesCD.pdf b/DevelDocs/ParmesCD.pdf similarity index 100% rename from Docs/Devel/ParmesCD.pdf rename to DevelDocs/ParmesCD.pdf diff --git a/Docs/Devel/about_data_management_on_GPU.tex b/DevelDocs/about_data_management_on_GPU.tex similarity index 100% rename from Docs/Devel/about_data_management_on_GPU.tex rename to DevelDocs/about_data_management_on_GPU.tex diff --git a/Examples/Attic/NavierStokes3d.py b/Examples/Attic/NavierStokes3d.py new file mode 100755 index 000000000..1531b49ed --- /dev/null +++ b/Examples/Attic/NavierStokes3d.py @@ -0,0 +1,188 @@ +#!/usr/bin/python +import parmepy as pp +import parmepy.f2py +import numpy as np +import mpi4py.MPI as MPI +import math as m + +PARMES_REAL = pp.constants.PARMES_REAL +ORDER = pp.constants.ORDER + +#from numpy import linalg as LA + +pi = m.pi + +# Import scales and fftw solvers +ppfft = parmepy.f2py.fftw2py +scales = parmepy.f2py.scales2py + +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +# ----------- A 3d problem ----------- +print " ========= Start test for Navier-Stokes 3D =========" + +# Physical Domain description +Lx = Ly = Lz = 2 * pi +myDomain3d = pp.Box(dimension=3, length=[Lx, Ly, Lz], origin=[0., 0., 0.]) +resolution3d = np.asarray((65, 65, 65)) +ncells = resolution3d - 1 +hx = Lx / ncells[0] +hy = Ly / ncells[1] +hz = Lz / ncells[2] + +## Obstacle +lambd = np.array([0, 1, 10 ** 8], dtype=PARMES_REAL, order=ORDER) +sphere = pp.Obstacle(myDomain3d, name='sphere', zlayer=0.1, + radius=0.1, center=[0.5, 0.5, 0.5], + orientation='West', porousLayer=0.05) + +## Post +outputFilePrefix = './res/NS_' +outputModulo = 1 + +# Simulation parameters +timeStep = 1e-8 +finalTime = timeStep#1.0 + +# Fields declaration + +# 1 - Poisson/diffusion solvers initialisation. +# See poisson3d.py for a working example. +# poisson = pp.Poisson(vorticity,velocity) +# +localres, localoffset = ppfft.init_fftw_solver(resolution3d, + myDomain3d.length) + +print "FFT solver local resolution/offset: ", localres, localoffset + +##topofft = poisson.getTopology() + + +def computeVel(x, y, z): + vx = 2. / np.sqrt(3) * np.sin(2. * pi / 3.) * np.sin(x) \ + * np.cos(y) * np.cos(z) + vy = 2. / np.sqrt(3) * np.sin(-2. * pi / 3.) * np.cos(x) \ + * np.sin(y) * np.cos(z) + vz = 0. + return vx, vy, vz + + +def computeVort(x, y, z): + wx = - np.cos(x) * np.sin(y) * np.sin(z) + wy = - np.sin(x) * np.cos(y) * np.sin(z) + wz = 2. * np.sin(x) * np.sin(y) * np.cos(z) + return wx, wy, wz + + +velocity = pp.AnalyticalField(domain=myDomain3d, formula=computeVel, + name='Velocity', vector=True) +vorticity = pp.AnalyticalField(domain=myDomain3d, formula=computeVort, + name='Vorticity', vector=True) + +############ REF ############## +x = np.arange(localoffset[0], localres[0] + localoffset[0], + dtype='float64') * hx +y = np.arange(localoffset[1], localres[1] + localoffset[1], + dtype='float64') * hy +z = np.arange(localoffset[2], localres[2] + localoffset[2], + dtype='float64') * hz + +cden = 4 * pi ** 2 * (Ly ** 2 * Lz ** 2 + Lx ** 2 * Lz ** 2 + + Lx ** 2 * Ly ** 2) / (Lx ** 2 * Ly ** 2 * Lz ** 2) +cx = 2 * pi / Lx +cy = 2 * pi / Ly +cz = 2 * pi / Lz + +# Initialize vorticity (This init should be improved or done if C or Fortran) +## for k in range(localres[2]): +## for j in range(localres[1]): +## for i in range(localres[0]): +## omega_x[i, j, k] = cden * (m.sin(cx * x[i]) * +## m.sin(cy * y[j]) * m.cos(cz * z[k])) +## omega_y[i, j, k] = cden * (m.cos(cx * x[i]) * +## m.sin(cy * y[j]) * m.sin(cz * z[k])) +## omega_z[i, j, k] = cden * (m.cos(cx * x[i]) * +## m.cos(cy * y[j]) * m.sin(cz * z[k])) +## ref_x[i, j, k] = -cy * (m.cos(cx * x[i]) * m.sin(cy * y[j]) +## * m.sin(cz * z[k])) - \ +## cz * (m.cos(cx * x[i]) * m.sin(cy * y[j]) * m.cos(cz * z[k])) + +## ref_y[i, j, k] = -cz * (m.sin(cx * x[i]) * m.sin(cy * y[j]) +## * m.sin(cz * z[k])) + \ +## cx * (m.sin(cx * x[i]) * m.cos(cy * y[j]) * m.sin(cz * z[k])) + +## ref_z[i, j, k] = -cx * (m.sin(cx * x[i]) * m.sin(cy * y[j]) +## * m.sin(cz * z[k])) - \ +## cy * (m.sin(cx * x[i]) * m.cos(cy * y[j]) * m.cos(cz * z[k])) + + +# 2 - Advection solver initialisation. See testScales for a working example. +# Based on scales JB solver +# Warning : fields input for scales should be of size (ncells), not localres. +nbProcs = MPI.COMM_WORLD.Get_size() +topodims = [1, 1, nbProcs] # fits with fftw topology + +scalesres, scalesoffset, stab_coeff = \ + scales.init_advection_solver(ncells, myDomain3d.length, + topodims, order='p_O2') + +##topofft = poisson.getTopology() +##,ghost=2 +topofft = pp.CartesianTopology(domain=myDomain3d, + resolution=resolution3d, dim=3) + +# 3 - Stretching +stretch = pp.Stretching(vorticity, velocity) + +# 4 - Penalization +sphere.discretize(topofft) +sphereD = sphere.discreteObstacle[0] +penal = pp.Penalization(velocity, vorticity, sphereD, lambd) + +# Define the problem to solve +navierStokes = pp.Problem(topofft, [penal, stretch]) + +printer = pp.Printer(fields=[vorticity, velocity], frequency=outputModulo, + outputPrefix=outputFilePrefix) + +navierStokes.setSolver(finalTime, timeStep, solver_type='basic', io=printer) + +## Problem => ParticularSover = basic.initialize() +navierStokes.initSolver() + +omega_x = vorticity.discreteField[0][0] +omega_y = vorticity.discreteField[0][1] +omega_z = vorticity.discreteField[0][2] +vx = velocity.discreteField[0][0] +vy = velocity.discreteField[0][1] +vz = velocity.discreteField[0][2] + + +## end of init ## +# Mind that scales works on arrays of size resolution - 1 +# --> pointers to subarrays of velocity/vorticity +#somega_x = np.zeros((localcells), dtype='float64', order='Fortran') +# solve advection +omega_x = scales.solve_advection(timeStep, vx, vy, vz, omega_x) +omega_y = scales.solve_advection(timeStep, vx, vy, vz, omega_y) +omega_z = scales.solve_advection(timeStep, vx, vy, vz, omega_z) + +# solve stretching +navierStokes.solve() + +print 'vorticity', vorticity.discreteField[0][0] , vorticity.discreteField[0][1] , vorticity.discreteField[0][2] + +# solve diffusion + +nudt = 0.0001 +omega_x, omega_y, omega_z = \ + ppfft.solve_diffusion_3d(nudt, vx, vy, vz, omega_x, omega_y, omega_z) + +# solve poisson +vx, vy, vz = ppfft.solve_poisson_3d(omega_x, omega_y, omega_z, vx, vy, vz) + +## end of time loop ## + +# Clean memory buffers +ppfft.clean_fftw_solver(myDomain3d.dimension) diff --git a/Examples/Attic/NavierStokes3d_RMI.py b/Examples/Attic/NavierStokes3d_RMI.py new file mode 100755 index 000000000..e01b076e2 --- /dev/null +++ b/Examples/Attic/NavierStokes3d_RMI.py @@ -0,0 +1,219 @@ +#!/usr/bin/python +#import sys +#sys.path.insert(0,'/scratch/mimeau/install-parmes3/') +import time +import parmepy as pp +from parmepy.f2py import fftw2py +import mpi4py.MPI as MPI +import math as m +from parmepy.constants import np, PARMES_REAL, ORDER +from parmepy.operator.advection import Advection +from parmepy.operator.density import DensityVisco +from parmepy.operator.stretching import Stretching +from parmepy.operator.diffusion import Diffusion +from parmepy.operator.poisson import Poisson +from parmepy.operator.multiphase import Baroclinic +from parmepy.operator.penalization import Penalization +from parmepy.operator.redistribute import Redistribute +from parmepy.problem.navier_stokes import NSProblem +from parmepy.problem.simulation import Simulation +from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy +from parmepy.operator.monitors.reprojection_criterion import Reprojection_criterion +from parmepy.operator.monitors.printer import Printer +from parmepy.dataloader import DataLoader + +#from numpy import linalg as LA + +pi = m.pi + +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +## ----------- A 3d problem ----------- +print " ========= Start test for Navier-Stokes 3D (Taylor Green benchmark)=========" + +## Opening/reading input data file +data = DataLoader('inputData.dat') + +# Parameters +dim = 3 +nbElem = [data.resX, data.resY, data.resZ] +nbElemFilter = [data.resFilterX, data.resFilterY, data.resFilterZ] +densityVal = [data.rho, data.rho2] +viscoVal = [data.visco, data.visco2] + +t0 = time.time() + +## Domain +box = pp.Box(dim, length=[data.Lx, data.Ly, data.Lz], + origin=[data.Ox, data.Oy, data.Oz]) + +## Fields declaration +def computeVel(x, y, z): +#--------Richtmyer Meshkov------------ + vx = data.uinf + vy = 0. + vz = 0. + return vx, vy, vz + +def computeVort(x, y, z): +#--------Richtmyer Meshkov------------ + wx = 0. + wy = 0. + wz = (data.uinf * 2.0 * pi / data.Ly) * \ + m.sin(2.0 * pi * y / data.Ly) + return wx, wy, wz + +def computeDensity(x, y, z): +#--------Richtmyer Meshkov------------ + perturb = 0.2 * np.sin(2.0 * pi * y / 5.9333) + d = (3.0 + perturb + 0.5 - x)/(2.0 * 0.5) + c = 1.0 + if d > 0. and d < 1.0 : + c = 0.5 +# c = m.exp(-(-m.log10(0.)) * m.fabs(d)^8.0) + elif d >= 1.0 : + c = 0. + rho = densityVal[0] + (densityVal[1] - densityVal[0]) * c + return rho + +def computeVisco(x, y, z): +#--------Richtmyer Meshkov------------ + perturb = 0.2 * np.sin(2.0 * pi * y / 5.9333) + d = (3.0 + perturb + 0.5 - x)/(2.0 * 0.5) + c = 1.0 + if d > 0. and d < 1.0 : + c = 0.5 +# c = m.exp(-(-m.log10(0.)) * m.fabs(d)^8.0) + elif d >= 1.0 : + c = 0. + nu = viscoVal[0] + (viscoVal[1] - viscoVal[0]) * c + return nu + +## Fields +velo = pp.Field(domain=box, formula=computeVel, + name='Velocity', isVector=True) +vorti = pp.Field(domain=box, formula=computeVort, + name='Vorticity', isVector=True) +rho = pp.Field(domain=box, formula=computeDensity, + name='Density', isVector=False) +visco = pp.Field(domain=box, formula=computeVisco, + name='Viscosity', isVector=False) + +## Operators +advecVort = Advection(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=data.methodAdv + ) + +stretch = Stretching(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=data.methodStretch, + propertyOp=data.propStretch + ) + +diffusion = Diffusion(vorti, + resolution=nbElem, + method='fftw', + viscosity=data.visco + ) + +baroclinic = Baroclinic(velo, vorti, rho, visco, + resolutions={velo: nbElem, + vorti: nbElem, + rho: nbElem, + visco: nbElem}, + method=data.methodBaro + ) + +advecScalar = Advection(velo, rho, + resolutions={velo: nbElem, + rho: nbElem}, + method=data.methodAdvSc + ) + +density = DensityVisco(rho, visco, + resolutions={rho: nbElem, + visco: nbElem}, + method='', + densityVal = densityVal, + viscoVal = viscoVal + ) + +poisson = Poisson(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method='fftw', + projection=data.vortProj, + multires=data.multires, + filterSize=box.length / \ + (np.asarray(nbElemFilter, + dtype=PARMES_REAL) - 1) + ) + +## Diagnostics related to the problem +energy = Energy_enstrophy(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + viscosity=data.visco, + frequency=data.outModuloEnergies, + prefix='./res/Energies_test.dat') + +#reproj = Reprojection_criterion(velo, vorti, +# resolutions={velo: nbElem, +# vorti: nbElem}, +# method='FD_order4', +# frequency=1, +# prefix='../res/Reproj.dat') + +printer = Printer(fields=[rho], + frequency=data.outModuloPrinter, + prefix=data.outputPrinter, + ext='.vtk' + ) + +distrAdvStr = Redistribute([vorti, velo], advecVort, stretch) +distrStrDiff = Redistribute([vorti], stretch, diffusion) +distrDiffBaro = Redistribute([vorti], diffusion, baroclinic) +distrBaroPoiss = Redistribute([vorti], baroclinic, poisson) +distrDensBaro = Redistribute([rho, visco], density, baroclinic) + +## Definition of simulation parameters +simu = Simulation(tinit=0.0, tend=data.finalTime, timeStep=data.timeStep, iterMax=1000000) + +## Define the problem to solve +#pb = NSProblem([advecVort, stretch, diffusion, baroclinic, advecScalar, density, poisson], +pb = NSProblem(operators=[advecVort, distrAdvStr, stretch, distrStrDiff, diffusion, + distrDiffBaro, baroclinic, distrBaroPoiss, advecScalar, + density, poisson, distrDensBaro], +#pb = NSProblem(operators=[advecVort, distrAdvStr, stretch, distrStrDiff, diffusion, +# advecScalar, density, poisson], + simulation=simu, + monitors=[energy], + dumpFreq=int(data.dumpfreq), name=data.dumpfile) +## Setting solver to Problem +pb.setUp() + +## Restarting Problem from dumped field values +if data.restart : + pb.restart(data.dumpfile) + +t1 = time.time() + +## Solve problem +#poisson.apply(simu) +timings = pb.solve() + +tf = time.time() + +print "\n" +print "Total time : ", tf - t0, "sec (CPU)" +print "Init time : ", t1 - t0, "sec (CPU)" +print "Solving time : ", tf - t1, "sec (CPU)" + +## end of time loop ## + +# Clean memory buffers +fftw2py.clean_fftw_solver(box.dimension) diff --git a/Examples/Attic/NavierStokes3d_penal.py b/Examples/Attic/NavierStokes3d_penal.py new file mode 100755 index 000000000..f21e2a167 --- /dev/null +++ b/Examples/Attic/NavierStokes3d_penal.py @@ -0,0 +1,285 @@ +#!/usr/bin/python +import time +import parmepy as pp +import parmepy.f2py +import numpy as np +import mpi4py.MPI as MPI +import math as m +from parmepy.constants import PARMES_REAL, ORDER +from parmepy.domain.obstacle.obstacle_3D import Obstacle3D +from parmepy.operator.advection import Advection +from parmepy.operator.stretching import Stretching +from parmepy.operator.poisson import Poisson +from parmepy.operator.diffusion import Diffusion +from parmepy.operator.penalization import Penalization +from parmepy.operator.redistribute import Redistribute +from parmepy.problem.navier_stokes import NSProblem +from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy +from parmepy.operator.monitors.printer import Printer +from parmepy.operator.monitors.compute_forces import Compute_forces + +#from numpy import linalg as LA + +pi = m.pi + +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +## ----------- A 3d problem ----------- +print " ========= Start test for penalized Navier-Stokes 3D =========" + +## Opening/reading input data file +inputData = open("input.dat", "r") + +Ox = np.float64(inputData.readline().rstrip('\n\r')) +Oy = np.float64(inputData.readline().rstrip('\n\r')) +Oz = np.float64(inputData.readline().rstrip('\n\r')) +Lx = np.float64(inputData.readline().rstrip('\n\r')) +Ly = np.float64(inputData.readline().rstrip('\n\r')) +Lz = np.float64(inputData.readline().rstrip('\n\r')) +resX = np.uint32(inputData.readline().rstrip('\n\r')) +resY = np.uint32(inputData.readline().rstrip('\n\r')) +resZ = np.uint32(inputData.readline().rstrip('\n\r')) +timeStep = np.float64(inputData.readline().rstrip('\n\r')) +finalTime = np.float64(inputData.readline().rstrip('\n\r')) +outModuloPrinter = np.uint32(inputData.readline().rstrip('\n\r')) +outputPrinter = inputData.readline().rstrip('\n\r') +outModuloForces = np.uint32(inputData.readline().rstrip('\n\r')) +outputForces = inputData.readline().rstrip('\n\r') +outModuloEnergies = np.uint32(inputData.readline().rstrip('\n\r')) +outputEnergies = inputData.readline().rstrip('\n\r') +visco = np.float64(inputData.readline().rstrip('\n\r')) +vortProj = np.uint32(inputData.readline().rstrip('\n\r')) +methodAdv = inputData.readline().rstrip('\n\r') +methodStretch = inputData.readline().rstrip('\n\r') +methodPenal = inputData.readline().rstrip('\n\r') +methodForces = inputData.readline().rstrip('\n\r') +uinf = np.float64(inputData.readline().rstrip('\n\r')) +obstName = inputData.readline().rstrip('\n\r') +lambdFluid = np.float64(inputData.readline().rstrip('\n\r')) +lambdPorous = np.float64(inputData.readline().rstrip('\n\r')) +lambdSolid = np.float64(inputData.readline().rstrip('\n\r')) +obstRadius = np.float64(inputData.readline().rstrip('\n\r')) +obstOx = np.float64(inputData.readline().rstrip('\n\r')) +obstOy = np.float64(inputData.readline().rstrip('\n\r')) +obstOz = np.float64(inputData.readline().rstrip('\n\r')) +obstOrientation = inputData.readline().rstrip('\n\r') +thicknPorous = np.float64(inputData.readline().rstrip('\n\r')) +thicknZbound = np.float64(inputData.readline().rstrip('\n\r')) + +inputData.close() + +# Parameters +dim = 3 +nbElem = [resX, resY, resZ] + +t0 = time.time() + +## Domain +box = pp.Box(dim, length=[1., 1., 1.], origin=[0., 0., 0.]) + +## Obstacle +lambd = np.array([lambdSolid, lambdPorous], + dtype=PARMES_REAL, order=ORDER) +sphere = Obstacle3D(box, + center=[obstOx, obstOy, obstOz], + zlayer=thicknZbound, + porousLayerThickn=thicknPorous, + porousLayerConfig='', + obstacleName=obstName, + radius=obstRadius) + +## Fields declaration +def computeVel(x, y, z): +# vx = 2. / np.sqrt(3) * np.sin(2. * pi / 3.) * np.sin(x) \ +# * np.cos(y) * np.cos(z) +# vy = 2. / np.sqrt(3) * np.sin(-2. * pi / 3.) * np.cos(x) \ +# * np.sin(y) * np.cos(z) +# vz = 0. +#----------- flow past sphere ---------- + vx = 0. + module = (x - obstOx) ** 2 + (y - obstOy) ** 2 + (z - obstOz) ** 2 + if (module >= obstRadius ** 2): + vx = uinf * (1 - (obstRadius ** 2 / module)) + vy = 0. + vz = 0. +# # --------Taylor Green------------ +# vx = np.sin(x) * np.cos(y) * np.cos(z) +# vy = - np.cos(x) * np.sin(y) * np.cos(z) +# vz = 0. +#----------------- +# vx = 0. +# vy = 0. +# vz = 0. + return vx, vy, vz + + +def computeVort(x, y, z): +# wx = - np.cos(x) * np.sin(y) * np.sin(z) +# wy = - np.sin(x) * np.cos(y) * np.sin(z) +# wz = 2. * np.sin(x) * np.sin(y) * np.cos(z) +#----------- flow past sphere ---------- + wx = 0. + wy = 0. + wz = 0. +# module = (x - obstOx) ** 2 + (y - obstOy) ** 2 + (z - obstOz) ** 2 +# if (module >= obstRadius ** 2): +# wy = (2.0 * uinf * obstRadius ** 2 * (z - obstOz)) / module ** 2 +# wz = -(2.0 * uinf * obstRadius ** 2 * (y - obstOy)) / module ** 2 +# # --------Taylor Green------------ +# wx = - np.cos(x) * np.sin(y) * np.sin(z) +# wy = - np.sin(x) * np.cos(y) * np.sin(z) +# wz = 2. * np.sin(x) * np.sin(y) * np.cos(z) +#----------------- +# xc = 6./2. +# yc = 6./2. +# zc = 6./6. +# R = 1.5 +# sigma = R / 3. +# Gamma = 0.0075 +# dist = m.sqrt((x-xc)**2 + (y-yc)**2) +# s2 = (z - zc)**2 + (dist - R)**2 +# wx = 0. +# wy = 0. +# wz = 0. +# if (dist != 0.): +# cosTheta = (x-xc) / dist +# sinTheta = (y-yc) / dist +# wTheta = Gamma / (pi * sigma**2) * m.exp(-(s2 / sigma**2)) +# wx = - wTheta * sinTheta +# wy = wTheta * cosTheta +# wz = 0. + return wx, wy, wz + +def computeVortNorm(x, y, z): + norm = 0. +#---------------- +# xc = 6./2. +# yc = 6./2. +# zc = 6./6. +# R = 1.5 +# sigma = R / 3. +# Gamma = 0.0075 +# dist = m.sqrt((x-xc)**2 + (y-yc)**2) +# s2 = (z - zc)**2 + (dist - R)**2 +# norm = 0. +# if (dist != 0.): +# cosTheta = (x-xc) / dist +# sinTheta = (y-yc) / dist +# wTheta = Gamma / (pi * sigma**2) * m.exp(-(s2 / sigma**2)) +# wx = - wTheta * sinTheta +# wy = wTheta * cosTheta +# wz = 0. +# norm = np.sqrt(wx ** 2 + wy ** 2 + wz ** 2) + return norm + +#def computeDensity(x, y, z): +# if (x>=0): +# rho = 1000. +# else : +# rho = 1. +# return rho + + +## Fields +velo = pp.Field(domain=box, formula=computeVel, + name='Velocity', isVector=True) +vorti = pp.Field(domain=box, formula=computeVort, + name='Vorticity', isVector=True) +#vortNorm = pp.Field(domain=box, formula=computeVortNorm, +# name='VortNorm', isVector=False) +#density = pp.Field(domain=box, formula=computeDensity, +# name='Density', isVector=False) + +## Operators +advec = Advection(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=methodAdv + ) + +stretch = Stretching(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=methodStretch, + propertyOp='divConservation' + ) + +diffusion = Diffusion(vorti, + resolution=nbElem, + method='fftw', + viscosity=visco + ) + +poisson = Poisson(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method='fftw', + projection=False + ) + +penal = Penalization(velo, vorti, sphere, lambd, + resolutions={velo: nbElem, + vorti: nbElem}, + method=methodPenal, + with_curl=True + ) + +## Diagnostics related to the problem +forces = Compute_forces(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + penal=penal, + boxMin=[Ox + Lx / 10., Oy + Ly / 10., Oz + Lz / 10.], + boxMax=[Lx - Lx / 10., Ly - Ly / 10., Lz - Lz / 10.], + Reynolds=uinf * obstRadius/ visco, + method=methodForces, + frequency=outModuloForces, + outputPrefix=outputForces) + +energy = Energy_enstrophy(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + viscosity=visco, + frequency=outModuloEnergies, + outputPrefix=outputEnergies) + +printer = Printer(fields=[vorti, velo], + resolutions={velo: nbElem, + vorti: nbElem}, + frequency=outModuloPrinter, + outputPrefix=outputPrinter) + +distrAdvStr = Redistribute([vorti, velo], advec, stretch) +distrStrPoiss = Redistribute([vorti, velo], stretch, poisson) +distrPoissPen = Redistribute([vorti, velo], poisson, penal) +distrPenAdv = Redistribute([vorti, velo], penal, advec) + +## Define the problem to solve +#pb = NSProblem([advec, distrAdvPen, penal, distrPenAdv], +# monitors=[energy, printer]) +pb = NSProblem([advec, distrAdvStr, stretch, distrStrPoiss, + diffusion, poisson, distrPoissPen, penal, distrPenAdv], + monitors=[energy, printer]) + +## Setting solver to Problem +pb.setUp(finalTime, timeStep) + +t1 = time.time() + +## Solve problem +penal.apply(0., timeStep, 0) +distrPenAdv.apply(0., timeStep, 0) +timings = pb.solve() + +tf = time.time() + +print "\n" +print "Total time : ", tf - t0, "sec (CPU)" +print "Init time : ", t1 - t0, "sec (CPU)" +print "Solving time : ", tf - t1, "sec (CPU)" + +## end of time loop ## + +# Clean memory buffers +fftw2py.clean_fftw_solver(box.dimension) diff --git a/Examples/Attic/NavierStokes3d_sphere.py b/Examples/Attic/NavierStokes3d_sphere.py new file mode 100755 index 000000000..ca7ca59e8 --- /dev/null +++ b/Examples/Attic/NavierStokes3d_sphere.py @@ -0,0 +1,278 @@ +#!/usr/bin/python +import parmepy as pp +import parmepy.f2py +import numpy as np +import mpi4py.MPI as MPI +import math as m +from parmepy.obstacle.obstacle import Obstacle +from parmepy.operator.advec_scales import Advec_scales +from parmepy.operator.stretching import Stretching +from parmepy.operator.poisson import Poisson +from parmepy.operator.diffusion import Diffusion +from parmepy.operator.penalization import Penalization +from parmepy.tools.timer import Timer +from parmepy.tools.printer import Printer +from parmepy.tools.compute_forces import Compute_forces +from parmepy.tools.energy_enstrophy import Energy_enstrophy + +PARMES_REAL = pp.constants.PARMES_REAL +ORDER = pp.constants.ORDER + +#from numpy import linalg as LA + +pi = m.pi + +## Import scales and fftw solvers +ppfft = parmepy.f2py.fftw2py +scales = parmepy.f2py.scales2py + +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +## ----------- A 3d problem ----------- +print " ========= Start test for Navier-Stokes 3D =========" + +## Opening/reading input data file +inputData = open("input.dat", "r") + +Ox = np.float64(inputData.readline().rstrip('\n\r')) +Oy = np.float64(inputData.readline().rstrip('\n\r')) +Oz = np.float64(inputData.readline().rstrip('\n\r')) +Lx = np.float64(inputData.readline().rstrip('\n\r')) +Ly = np.float64(inputData.readline().rstrip('\n\r')) +Lz = np.float64(inputData.readline().rstrip('\n\r')) +resX = np.uint32(inputData.readline().rstrip('\n\r')) +resY = np.uint32(inputData.readline().rstrip('\n\r')) +resZ = np.uint32(inputData.readline().rstrip('\n\r')) +timeStep = np.float64(inputData.readline().rstrip('\n\r')) +finalTime = np.float64(inputData.readline().rstrip('\n\r')) +outModuloPrinter = np.uint32(inputData.readline().rstrip('\n\r')) +outputPrinter = inputData.readline().rstrip('\n\r') +outModuloForces = np.uint32(inputData.readline().rstrip('\n\r')) +outputForces = inputData.readline().rstrip('\n\r') +outModuloEnergies = np.uint32(inputData.readline().rstrip('\n\r')) +outputEnergies = inputData.readline().rstrip('\n\r') +nbGhosts = np.uint32(inputData.readline().rstrip('\n\r')) +visco = np.float64(inputData.readline().rstrip('\n\r')) +uinf = np.float64(inputData.readline().rstrip('\n\r')) +obstName = inputData.readline().rstrip('\n\r') +lambdFluid = np.float64(inputData.readline().rstrip('\n\r')) +lambdPorous = np.float64(inputData.readline().rstrip('\n\r')) +lambdSolid = np.float64(inputData.readline().rstrip('\n\r')) +obstRadius = np.float64(inputData.readline().rstrip('\n\r')) +obstOx = np.float64(inputData.readline().rstrip('\n\r')) +obstOy = np.float64(inputData.readline().rstrip('\n\r')) +obstOz = np.float64(inputData.readline().rstrip('\n\r')) +obstOrientation = inputData.readline().rstrip('\n\r') +thicknPorous = np.float64(inputData.readline().rstrip('\n\r')) +thicknZbound = np.float64(inputData.readline().rstrip('\n\r')) + +inputData.close() + +## Physical Domain description +myDomain3d = pp.Box(dimension=3, length=[Lx, Ly, Lz], origin=[Ox, Oy, Oz]) +resolution3d = np.asarray((resX, resY, resZ)) +ncells = resolution3d - 1 +hx = Lx / ncells[0] +hy = Ly / ncells[1] +hz = Lz / ncells[2] + +## Obstacle +lambd = np.array([lambdSolid, lambdPorous], + dtype=PARMES_REAL, order=ORDER) +sphere = Obstacle(myDomain3d, + name=obstName, + zlayer=thicknZbound, + radius=obstRadius, + center=[obstOx, obstOy, obstOz], + orientation=obstOrientation, + porousLayer=thicknPorous) + +### Post +#outputFilePrefix = './res/NS_' +#outputModulo = 50 + +### Simulation parameters +#timeStep = 1.#1e-1 +#finalTime = 10000.#20.*timeStep + + +## Topologies definitions +# 1---- FFT topology + diffusion/poisson solvers initialization ----------- +localres, localoffset = ppfft.init_fftw_solver(resolution3d, + myDomain3d.length) +print "FFT solver local resolution/offset: ", localres, localoffset +##topofft = poisson.getTopology() + +# ---- Cartesian topology ----- +topoCart = pp.Cartesian(domain=myDomain3d, + dim=3, + globalMeshResolution=resolution3d, + ghosts=[nbGhosts,nbGhosts,nbGhosts]) + +# ---- JB's topology ---------- +nbProcs = MPI.COMM_WORLD.Get_size() +topodims = [1, 1, nbProcs] # fits with fftw topology + + +## Fields declaration +def computeVel(x, y, z): +# vx = 2. / np.sqrt(3) * np.sin(2. * pi / 3.) * np.sin(x) \ +# * np.cos(y) * np.cos(z) +# vy = 2. / np.sqrt(3) * np.sin(-2. * pi / 3.) * np.cos(x) \ +# * np.sin(y) * np.cos(z) +# vz = 0. +#------------------ + vx = 0. + module = (x-obstOx)**2 + (y-obstOy)**2 + (z-obstOz)**2 + if (module >= obstRadius**2): + vx = uinf * (1-(obstRadius**2/module)) + vy = 0. + vz = 0. +#----------------- +# vx = 0. +# vy = 0. +# vz = 0. + return vx, vy, vz + + +def computeVort(x, y, z): +# wx = - np.cos(x) * np.sin(y) * np.sin(z) +# wy = - np.sin(x) * np.cos(y) * np.sin(z) +# wz = 2. * np.sin(x) * np.sin(y) * np.cos(z) +#----------------- + wx = 0. + wy = 0. + wz = 0. +#----------------- +# xc = 6./2. +# yc = 6./2. +# zc = 6./6. +# R = 1.5 +# sigma = R / 3. +# Gamma = 0.0075 +# dist = m.sqrt((x-xc)**2 + (y-yc)**2) +# s2 = (z - zc)**2 + (dist - R)**2 +# wx = 0. +# wy = 0. +# wz = 0. +# if (dist != 0.): +# cosTheta = (x-xc) / dist +# sinTheta = (y-yc) / dist +# wTheta = Gamma / (pi * sigma**2) * m.exp(-(s2 / sigma**2)) +# wx = - wTheta * sinTheta +# wy = wTheta * cosTheta +# wz = 0. + return wx, wy, wz + +def computeVortNorm(x, y, z): + norm = 0. +#---------------- +# xc = 6./2. +# yc = 6./2. +# zc = 6./6. +# R = 1.5 +# sigma = R / 3. +# Gamma = 0.0075 +# dist = m.sqrt((x-xc)**2 + (y-yc)**2) +# s2 = (z - zc)**2 + (dist - R)**2 +# norm = 0. +# if (dist != 0.): +# cosTheta = (x-xc) / dist +# sinTheta = (y-yc) / dist +# wTheta = Gamma / (pi * sigma**2) * m.exp(-(s2 / sigma**2)) +# wx = - wTheta * sinTheta +# wy = wTheta * cosTheta +# wz = 0. +# norm = np.sqrt(wx ** 2 + wy ** 2 + wz ** 2) + return norm + +#def computeDensity(x, y, z): +# if (x>=0): +# rho = 1000. +# else : +# rho = 1. +# return rho + +velocity = pp.AnalyticalField(domain=myDomain3d, formula=computeVel, + name='Velocity', vector=True) +vorticity = pp.AnalyticalField(domain=myDomain3d, formula=computeVort, + name='Vorticity', vector=True) +vortNorm = pp.AnalyticalField(domain=myDomain3d, formula=computeVortNorm, + name='VortNorm', vector=False) +#density = pp.AnalyticalField(domain=myDomain3d, formula=computeDensity, +# name='Density', vector=False) + + + +## 2 - Advection solver initialization. See testScales for a working example. +# Based on scales JB solver +# Warning : fields input for scales should be of size (ncells), not localres. + +scalesres, scalesoffset, stab_coeff = \ + scales.init_advection_solver(ncells, myDomain3d.length, + topodims, order='p_O2') + +print 'advection stability coeff', stab_coeff +advecVort = Advec_scales(stab_coeff, velocity, vorticity, vortNorm) +#advecDensity = Advec_scales(stab_coeff, velocity, density) + +# ----> Change TOPO from Scales to Cartesian + +## 3 - Stretching +stretch = Stretching(velocity, vorticity) + +# ----> Change TOPO from Cartesian to FFT + +## 4 - Diffusion +diffusion = Diffusion(velocity, vorticity, viscosity=visco) + +## 4 - Poisson +poisson = Poisson(velocity, vorticity) + +# ----> Change TOPO from FFT to Cartesian + +## 6 - Penalization +penal = Penalization(velocity, vorticity, sphere, lambd) + +# ----> Change TOPO from Cartesian to Scales + +## Define the problem to solve +navierStokes = pp.Problem(topoCart, [advecVort, stretch, diffusion, poisson, penal]) +#navierStokes = pp.Problem(topoCart, [advecVort, stretch, poisson]) + +## Set solver and Define the diagnostics related to the problem +printer = Printer(fields=[vorticity, velocity, vortNorm], frequency=outModuloPrinter, + outputPrefix=outputPrinter) + +#forces = Compute_forces(velocity=velocity, vorticity=vorticity, +# topology=topoCart, +# obstacle=sphere, +# boxMin=[Ox + Lx / 10., Oy + Ly / 10., Oz + Lz / 10.], +# boxMax=[Lx - Lx / 10., Ly - Ly / 10., Lz - Lz / 10.], +# Reynolds=uinf * obstRadius/ visco, +# frequency=outModuloForces, +# outputPrefix=outputForces) + +energy = Energy_enstrophy(velocity=velocity, vorticity=vorticity, + topology=topoCart, + frequency=outModuloEnergies, + outputPrefix=outputEnergies) + +navierStokes.addDiagnostics([energy]) + +navierStokes.setSolver(finalTime, timeStep, solver_type='basic', io=printer) + +## Initialize problem +navierStokes.initSolver() + +penal.apply(0., timeStep) +#poisson.apply(0., timeStep) + +## Solve problem +navierStokes.solve() + +## End of time loop ## + +## Clean memory buffers +ppfft.clean_fftw_solver(myDomain3d.dimension) diff --git a/Examples/Attic/NavierStokes3d_vortRing.py b/Examples/Attic/NavierStokes3d_vortRing.py new file mode 100755 index 000000000..c609bf47d --- /dev/null +++ b/Examples/Attic/NavierStokes3d_vortRing.py @@ -0,0 +1,233 @@ +#!/usr/bin/python +#import sys +#sys.path.insert(0,'/scratch/mimeau/install-parmes3/') +import time +import parmepy as pp +from parmepy.f2py import fftw2py +import numpy as np +import mpi4py.MPI as MPI +import math as m +from parmepy.constants import PARMES_REAL, ORDER +from parmepy.operator.advection import Advection +from parmepy.operator.stretching import Stretching +from parmepy.operator.poisson import Poisson +from parmepy.operator.diffusion import Diffusion +from parmepy.operator.penalization import Penalization +from parmepy.operator.redistribute import Redistribute +from parmepy.problem.navier_stokes import NSProblem +from parmepy.problem.simulation import Simulation +from parmepy.operator.monitors.energy_enstrophy import Energy_enstrophy +from parmepy.operator.monitors.reprojection_criterion import Reprojection_criterion +from parmepy.operator.monitors.printer import Printer +from parmepy.dataloader import DataLoader + + +#from numpy import linalg as LA + +pi = m.pi + +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +## ----------- A 3d problem ----------- +print " ========= Start test for Navier-Stokes 3D (Taylor Green benchmark)=========" + +## Opening/reading input data file +data = DataLoader('inputData_TG.dat') + +#inputData = open("input.dat", "r") + +#Ox = np.float64(inputData.readline().rstrip('\n\r')) +#Oy = np.float64(inputData.readline().rstrip('\n\r')) +#Oz = np.float64(inputData.readline().rstrip('\n\r')) +#Lx = np.float64(inputData.readline().rstrip('\n\r')) +#Ly = np.float64(inputData.readline().rstrip('\n\r')) +#Lz = np.float64(inputData.readline().rstrip('\n\r')) +#resX = np.uint32(inputData.readline().rstrip('\n\r')) +#resY = np.uint32(inputData.readline().rstrip('\n\r')) +#resZ = np.uint32(inputData.readline().rstrip('\n\r')) +#dt = np.float64(inputData.readline().rstrip('\n\r')) +#finalTime = np.float64(inputData.readline().rstrip('\n\r')) +#restart = np.uint32(inputData.readline().rstrip('\n\r')) +#dumpfreq = np.uint32(inputData.readline().rstrip('\n\r')) +#dumpfile = inputData.readline().rstrip('\n\r') +#outModuloPrinter = np.uint32(inputData.readline().rstrip('\n\r')) +#outputPrinter = inputData.readline().rstrip('\n\r') +#outModuloForces = np.uint32(inputData.readline().rstrip('\n\r')) +#outputForces = inputData.readline().rstrip('\n\r') +#outModuloEnergies = np.uint32(inputData.readline().rstrip('\n\r')) +#outputEnergies = inputData.readline().rstrip('\n\r') +#visco = np.float64(inputData.readline().rstrip('\n\r')) +#vortProj = np.uint32(inputData.readline().rstrip('\n\r')) +#methodAdv = inputData.readline().rstrip('\n\r') +#methodStretch = inputData.readline().rstrip('\n\r') +#multires = np.uint32(inputData.readline().rstrip('\n\r')) +#resFilterX = np.uint32(inputData.readline().rstrip('\n\r')) +#resFilterY = np.uint32(inputData.readline().rstrip('\n\r')) +#resFilterZ = np.uint32(inputData.readline().rstrip('\n\r')) + +#inputData.close() + +# Parameters +dim = 3 +nbElem = [data.resX, data.resY, data.resZ] +nbElemFilter = [data.resFilterX, data.resFilterY, data.resFilterZ] + +t0 = time.time() + +## Domain +box = pp.Box(dim, length=[2.0 * pi, 2.0 * pi, 2.0 * pi], + origin=[data.Ox, data.Oy, data.Oz]) + +## Fields declaration +def computeVel(x, y, z): +# # --------Vorticity ring---------- +# vx = 0. +# vy = 0. +# vz = 0. +# # --------Taylor Green------------ + vx = np.sin(x) * np.cos(y) * np.cos(z) + vy = - np.cos(x) * np.sin(y) * np.cos(z) + vz = 0. + return vx, vy, vz + +def computeVort(x, y, z): + # --------Vorticity ring---------- +# xc = 6. / 2. +# yc = 6. / 2. +# zc = 6. / 6. +# R = 1.5 +# sigma = R / 3. +# Gamma = 0.75 +# dist = m.sqrt((x - xc) ** 2 + (y - yc) ** 2) +# s2 = (z - zc) ** 2 + (dist - R) ** 2 +# wx = 0. +# wy = 0. +# wz = 0. +# if (dist != 0.): +# cosTheta = (x - xc) / dist +# sinTheta = (y - yc) / dist +# wTheta = Gamma / (pi * sigma ** 2) * m.exp(-(s2 / sigma ** 2)) +# wx = - wTheta * sinTheta +# wy = wTheta * cosTheta +# wz = 0. +# # --------Taylor Green------------ + wx = - np.cos(x) * np.sin(y) * np.sin(z) + wy = - np.sin(x) * np.cos(y) * np.sin(z) + wz = 2. * np.sin(x) * np.sin(y) * np.cos(z) + return wx, wy, wz + +def computeVortNorm(x, y, z): + xc = 6. / 2. + yc = 6. / 2. + zc = 6. / 6. + R = 1.5 + sigma = R / 3. + Gamma = 7.5 + dist = m.sqrt((x - xc) ** 2 + (y - yc) ** 2) + s2 = (z - zc) ** 2 + (dist - R) ** 2 + norm = 0. + if (dist != 0.): + cosTheta = (x - xc) / dist + sinTheta = (y - yc) / dist + wTheta = Gamma / (pi * sigma ** 2) * m.exp(-(s2 / sigma ** 2)) + wx = - wTheta * sinTheta + wy = wTheta * cosTheta + wz = 0. + norm = np.sqrt(wx ** 2 + wy ** 2 + wz ** 2) + return norm + +## Fields +velo = pp.Field(domain=box, formula=computeVel, + name='Velocity', isVector=True) +vorti = pp.Field(domain=box, formula=computeVort, + name='Vorticity', isVector=True) +#vortNorm = pp.Field(domain=box, formula=computeVortNorm, +# name='VortNorm', isVector=False) + +## Operators +advec = Advection(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=data.methodAdv + ) + +stretch = Stretching(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method=data.methodStretch, + propertyOp=data.propStretch, + ) + +diffusion = Diffusion(vorti, + resolution=nbElem, + method='fftw', + viscosity=data.visco + ) + +poisson = Poisson(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method='fftw', + projection=data.vortProj, + multires=data.multires, + filterSize=box.length / \ + (np.asarray(nbElemFilter, + dtype=PARMES_REAL) - 1) + ) + +## Diagnostics related to the problem +energy = Energy_enstrophy(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + viscosity=data.visco, + frequency=data.outModuloEnergies, + prefix=data.outputEnergies) + +reproj = Reprojection_criterion(velo, vorti, + resolutions={velo: nbElem, + vorti: nbElem}, + method='FD_order4', + frequency=1, + prefix='./Reproj.dat') + +printer = Printer(fields=[vorti, velo], + frequency=data.outModuloPrinter, + prefix=data.outputPrinter, + ext='.vtk') + +distrAdvStr = Redistribute([vorti, velo], advec, stretch) +distrStrPoiss = Redistribute([vorti, velo], stretch, poisson) + +## Definition of simulation parameters +simu = Simulation(tinit=0.0, tend=data.finalTime, timeStep=data.timeStep, iterMax=1000000) + +## Define the problem to solve +#pb = NSProblem([diffusion, poisson], +pb = NSProblem(operators=[advec, distrAdvStr, stretch, distrStrPoiss, diffusion, poisson], + simulation=simu, monitors=[printer, energy, reproj], + dumpFreq=int(data.dumpfreq), name=data.dumpfile) +## Setting solver to Problem +pb.setUp() + +## Restarting Problem from dumped field values +if data.restart : + pb.restart(data.dumpfile) + +t1 = time.time() + +## Solve problem +#poisson.apply(simu) +timings = pb.solve() + +tf = time.time() + +print "\n" +print "Total time : ", tf - t0, "sec (CPU)" +print "Init time : ", t1 - t0, "sec (CPU)" +print "Solving time : ", tf - t1, "sec (CPU)" + +## end of time loop ## + +# Clean memory buffers +fftw2py.clean_fftw_solver(box.dimension) diff --git a/Examples/Attic/driver3D.py b/Examples/Attic/driver3D.py new file mode 100755 index 000000000..48b642abb --- /dev/null +++ b/Examples/Attic/driver3D.py @@ -0,0 +1,61 @@ +import parmepy as pp +import numpy as np +import mpi4py.MPI as MPI +import math +import parmepy.f2py + +pi = math.pi +ppfft = parmepy.f2py.fftw2py + +# Start MPI and get informations +rank = MPI.COMM_WORLD.Get_rank() +print "Mpi process number ", rank + +# Physical Domain description (geometry and boundary conditions) +myDomain = pp.Box(dimension=3,length=[1.,1.,1.],origin=[0.,-0.5,-0.5]) + +# Continuous fields declaration +scalar = pp.ContinuousField(domain=myDomain,name="scalar3D") +velocity = pp.ContinuousField(domain=myDomain,name="velocity3D") +vorticity = pp.ContinuousField(domain=myDomain,name="vorticity3D") + +# Build operators/problems +poisson = pp.Poisson(vorticity,velocity) + +# Set and initialize a solving method for this problem +poisson.setSolvingMethod("fftw-cpu") +# Set one (or more) global resolution. +globalResolution = [65,65,65] +poisson.initialize_solver(globalResolution) # ---> call localRes,localOffset = ppfft.init_poisson_solver(globalResolution,myDomain.length) +# this will create a topology, a local discretisation for vel and vort and will allocate memory for those fields + +# initialize data +vorticity.discretize(topoFFT) + +# Solve ... + +poisson.solve() ## call velx,vely,velz = ppfft.solve_poisson_3d(omx,omy,omz) + + + + + +# Build some mpi topologies on the current domain + +#topo3D = pp.CartesianTopology(domain=myDomain,resolution=globalResolution,dim=3) + +#resol2D = [1, 12, 12] +#topo2D = pp.CartesianTopology(domain=myDomain,resolution=resol2D,dims=[1,2]) +# Discretize a field on these topologies +#scalar.discretize(topo3D) +#scalD,idScalD = scalar.discretize(topo2D) + +#print scalar + +#print scalD + +#velocity.discretize(topo3D) + +## scalarD.tofile("toto") + +## print velo diff --git a/Examples/Attic/gaussianSheared.cl b/Examples/Attic/gaussianSheared.cl new file mode 100644 index 000000000..c2c1b25c5 --- /dev/null +++ b/Examples/Attic/gaussianSheared.cl @@ -0,0 +1,36 @@ +__kernel void initScalar(__global float* scalar, + float4 minPos, + float4 size) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint i; + float r; + float2 pos; + for(i=gidX; i<WIDTH; i+=WGN) + { + pos = (float2)(i*size.x + minPos.x, gidY*size.y + minPos.x); + r = length(pos); + scalar[i+gidY*(WIDTH)] = ((r<1.0f) ? pown(1.0f - r*r,6) : 0.0f); + } +} + + +__kernel void initVelocity(__global float* veloX,__global float* veloY, + float4 minPos, + float4 size) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint i; + float v,r; + float2 pos; + for(i=gidX; i<WIDTH; i+=WGN) + { + pos = (float2)(i*size.x + minPos.x, gidY*size.y + minPos.x); + r = length(pos); + v = pos.y*cos(3.0f*M_PI_2_F*r); + veloX[i+gidY*(WIDTH)] = -v; // = Vx(x,y) + veloY[i+gidY*(WIDTH)] = v;// = Vy(y,x) = -Vx(x,y) + } +} diff --git a/Examples/Attic/gaussianSheared.py b/Examples/Attic/gaussianSheared.py new file mode 100644 index 000000000..095e304a0 --- /dev/null +++ b/Examples/Attic/gaussianSheared.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +import math + + +def vitesse(x): + r = math.sqrt(x[0] * x[0] + x[1] * x[1]) + c = math.cos(3 * math.pi * r / 2.) + return [-c * x[1], c * x[0]] + + +def scalaire(x): + r = math.sqrt(x[0] * x[0] + x[1] * x[1]) + if r < 1: + return (1. - r * r) ** 6 + else: + return 0. + + +def run(): + dim = 2 + nb = 256 + boxLength = [2., 2.] + boxMin = [-1., -1.] + nbElem = [nb, nb] + + timeStep = 0.02 + finalTime = 2*timeStep + outputFilePrefix = './res/gaussianSheared_results_' + outputModulo = 1 + + t0 = time.time() + + t0 = time.time() + + ## Domain + box = pp.Box(dim, length=boxLength, origin=boxMin) + + ## Fields + scal = pp.ContinuousField(domain=box, name='Scalar') + velo = pp.ContinuousField(domain=box, name='Velocity', vector=True) + #scal = pp.AnalyticalField(domain=box, formula=scalaire, name='Scalar') + #velo = pp.AnalyticalField(domain=box, formula=vitesse, name='Velocity', vector=True) + + ## Operators + advec = pp.Transport(velo, scal) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=nbElem, dim=dim) + + ##Problem + pb = pp.Problem(topo3D, [advec]) + + ## Setting solver to Problem + pb.setSolver(finalTime, timeStep, 'gpu', + src=['./gaussianSheared.cl'], + io=pp.Printer(fields=[scal, velo], frequency=outputModulo, outputPrefix=outputFilePrefix)) + pb.initSolver() + + t1 = time.time() + + ## Solve problem + pb.solve() + + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Attic/input.dat b/Examples/Attic/input.dat new file mode 100644 index 000000000..a7812513c --- /dev/null +++ b/Examples/Attic/input.dat @@ -0,0 +1,42 @@ +0.0 +0.0 +0.0 +6.28318531 +6.28318531 +6.28318531 +257 +257 +257 +0.01 +10.0 +1 +4000000 +./res/restart +8000000 +./res/TG_ +1 +./res/NocaForces.dat +1 +./res/Energies_256_noproj_nomultires.dat +0.000625 +0 +scales_p_M6 +FD_order4 RK3 +0 +129 +129 +129 +FD_order4 +FD_order4 +1.0 +sphere +0. +10. +10E8 +0.1 +0.3 +0.5 +0.5 +West +0. +0.001 diff --git a/Examples/Attic/inputData.dat b/Examples/Attic/inputData.dat new file mode 100644 index 000000000..fd60ee84a --- /dev/null +++ b/Examples/Attic/inputData.dat @@ -0,0 +1,54 @@ +#--------- DOMAIN ----------- +Origin X = 0.0 +Origin Y = 0.0 +Origin Z = 0.0 +Lenght X = 9.3 +Lenght Y = 9.3 +Lenght Z = 9.3 +Resolution X (nbs points) = 33 +Resolution Y (nbs points) = 33 +Resolution Z (nbs points) = 33 +#---------- TIME ------------ +Time Step = 0.01 +Final Time = 10.0 +Restart = 0 +#-------- OUTPUTS ----------- +Frequency of Saving = 4000000 +File to restart = ../res/restart +Frequency of Visualisation = 8000000 +Output file for visualisation = ../res/TG_ +Frequency of Forces output = 1 +Output file for Forces = ../res/NocaForces.dat +Frequency of Energy output = 1 +Output file for Energy = ../res/Energies_test.dat +#--------- FLOW ------------- +Upstream velocity = 1.0 +Density = 784.6 +Viscosity = 0.000316 +Dens2 = 1880 +Visco2 = 0.0000142 +#------- NUM METHODS -------- +Advection Method = scales_p_M6 +Scalar Advec Method = scales_p_M6 +Stretching Method = FD_order4 RK3 +Stretching Property = massConservation +Baro Method = FD_order4 +Penalisation Method = FD_order4 +Forces Method = FD_order4 +#----- PROJ & MULTIRES ------ +Vorticity projection = 0 +Multi resolution = 0 +Resolution Filter X = 129 +Resolution Filter Y = 129 +Resolution Filter Z = 129 +#------ PENALIZATION -------- +Name of Obstacle = sphere +Lambda Fluid = 0. +Lambda Porous = 10. +Lambda Solid = 10E8 +Obstacle Radius = 0.1 +Obstacle origin in X = 0.3 +Obstacle origin in Y = 0.5 +Obstacle origin in Z = 0.5 +Thickness of Porous layer = 0. +Size of Bound in Z direction = 0.001 diff --git a/Examples/Attic/inputData_TG.dat b/Examples/Attic/inputData_TG.dat new file mode 100644 index 000000000..f36df6a2e --- /dev/null +++ b/Examples/Attic/inputData_TG.dat @@ -0,0 +1,34 @@ +#--------- DOMAIN ----------- +Origin X = 0.0 +Origin Y = 0.0 +Origin Z = 0.0 +Lenght X = 6.28318531 +Lenght Y = 6.28318531 +Lenght Z = 6.28318531 +Resolution X (nbs points) = 33 +Resolution Y (nbs points) = 33 +Resolution Z (nbs points) = 33 +#---------- TIME ------------ +Time Step = 0.01 +Final Time = 10.0 +Restart = 0 +#-------- OUTPUTS ----------- +Frequency of Saving = 4000000 +File to restart = ../res/restart +Frequency of Visualisation = 8000000 +Output file for visualisation = ../res/TG_ +Frequency of Energy output = 1 +Output file for Energy = ../res/Energies_test.dat +#--------- FLOW ------------- +Upstream velocity = 1.0 +Viscosity = 0.000625 +#------- NUM METHODS -------- +Advection Method = scales_p_M6 +Stretching Method = FD_order4 RK3 +Stretching Property = divConservation +#----- PROJ & MULTIRES ------ +Vorticity projection = 1 +Multi resolution = 0 +Resolution Filter X = 129 +Resolution Filter Y = 129 +Resolution Filter Z = 129 diff --git a/Examples/Attic/mainED.py b/Examples/Attic/mainED.py new file mode 100755 index 000000000..21e3fcdf5 --- /dev/null +++ b/Examples/Attic/mainED.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +from math import * + + +def vitesse(x, y, z): + vx = 1. + x + vy = - x * y + vz = x * y * z + 10. + return vx, vy, vz + +def vorticite(x, y, z): + wx = x * y + wy = y * z + wz = - y + return wx, wy, wz + +def scalaire(x, y, z): + if x < 0.5 and y < 0.5 and z < 0.5: + return 1. + else: + return 0. + + +def run(): + # Parameters + nb = 32 + timeStep = 0.02 + finalTime = 1. + outputFilePrefix = './res/Stretching_' + outputModulo = 1 + + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Fields + #scal = pp.ContinuousField(domain=box, name='Scalar') + #velo = pp.ContinuousField(domain=box, name='Velocity', vector=True) + #vorti = pp.ContinuousField(domain=box, name='Vorticity', vector=True) + #scal = pp.AnalyticalField(domain=box, name='Scalar') + velo = pp.AnalyticalField(domain=box, formula=vitesse, name='Velocity', vector=True) + vorti = pp.AnalyticalField(domain=box, formula=vorticite, name='Vorticity', vector=True) + + ## Operators + #advec = pp.Transport(velo, scal) + stretch = pp.Stretching(velo,vorti) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3) + + ##Problem + #pb = pp.Problem(topo3D, [advec,stretch]) + pb = pp.Problem(topo3D, [stretch]) + + ## Setting solver to Problem + ## Problem => ParticularSover = basic.init() + pb.setSolver(finalTime, timeStep, solver_type='basic', + io=pp.Printer(fields=[vorti, velo], frequency=outputModulo, outputPrefix=outputFilePrefix)) + ## Problem => ParticularSover = basic.initialize() + pb.initSolver() + + t1 = time.time() + + ## Solve problem + pb.solve() + + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Attic/main_Rotating_2D.py b/Examples/Attic/main_Rotating_2D.py new file mode 100644 index 000000000..20b9b6e30 --- /dev/null +++ b/Examples/Attic/main_Rotating_2D.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +import time +import new_ParMePy as pp +import math + + +def vitesse(x): + return [- x[1] * 2 * math.acos(-1), x[0] * 2 * math.acos(-1)] + + +def scalaire(x): + rr = math.sqrt(x[0] * x[0] + (x[1] - 0.5) * (x[1] - 0.5)) + if rr < 0.25: + return (1. - rr * rr / 0.0625) ** 4 + else: + return 0. + + +def run(): + dim = 2 + nb = 1024 + boxLength = [2., 2.] + boxMin = [-1., -1.] + nbElem = [nb, nb] + + timeStep = 0.07 + FinalTime = 1. + outputFilePrefix = './res/RK2_' + outputModulo = 1 + + t0 = time.time() + + box = pp.Domain.Box(dimension=dim, + length=boxLength, + minPosition=boxMin) + velo = pp.Variable.AnalyticalVariable(domain=box, + dimension=dim, + formula=vitesse) + scal = pp.Variable.AnalyticalVariable(domain=box, + dimension=1, + formula=scalaire, scalar=True) + advec = pp.Operator.Advection(velo, scal) + cTspPb = pp.Problem.ContinuousTransportProblem(advection=advec) + + cTspPb.discretize(dSpec=[nbElem]) + + InterpolationMethod = pp.Utils.Linear(grid=box.discreteDomain, gvalues=velo.discreteVariable) + RemeshingMethod = pp.Utils.M6Prime(grid=box.discreteDomain, gvalues=scal.discreteVariable) + ODESolver = pp.Utils.RK2(InterpolationMethod, box.discreteDomain.applyConditions) + ## cpu + #solver = pp.Utils.ParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod) + ## gpu + #solver = pp.GPUParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu') + solver = pp.GPUParticularSolver_GLRender(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu', dt=timeStep) + cTspPb.setSolver(solver) + cTspPb.setPrinter(pp.Utils.Printer(frequency=outputModulo, outputPrefix=outputFilePrefix, problem=cTspPb)) + + t1 = time.time() + + cTspPb.solve(T=FinalTime, dt=timeStep) + + tf = time.time() + + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Attic/main_Rotating_2D_GH.py b/Examples/Attic/main_Rotating_2D_GH.py new file mode 100644 index 000000000..7b8801bdc --- /dev/null +++ b/Examples/Attic/main_Rotating_2D_GH.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +import time +import new_ParMePy as pp +import math + + +# def vitesse(x): +# return [-math.sin(x[0] * math.pi) ** 2 * math.sin(x[1] * math.pi * 2), +# math.sin(x[1] * math.pi) ** 2 * math.sin(x[0] * math.pi * 2)] +# #vx(i)=-sin(pix)*sin(pix)*sin(pi2y)*amodul +# #vy(i)=+sin(pi2x)*sin(piy)*sin(piy)*amodul + + +# def scalaire(x): +# rr = math.sqrt((x[0] - 0.5) ** 2 + (x[1] - 0.75) ** 2) +# if rr < 0.15: +# return 1. +# else: +# return 0. + + +def run(): + dim = 2 + nb = 1024 + boxLength = [1., 1.] + boxMin = [0., 0.] + nbElem = [nb, nb] + + timeStep = 0.07 + period = 10. + FinalTime = period + outputFilePrefix = './res/RK2_' + outputModulo = 1 + + t0 = time.time() + + box = pp.Domain.Box(dimension=dim, + length=boxLength, + minPosition=boxMin) + velo = pp.Variable.AnalyticalVariable(domain=box, + dimension=dim, name="Velocity" + ) + scal = pp.Variable.AnalyticalVariable(domain=box, + dimension=1, + scalar=True, name="Scalar" + ) + advec = pp.Operator.Advection(velo, scal) + cTspPb = pp.Problem.ContinuousTransportProblem(advection=advec) + cTspPb.addOperator(pp.Operator.VelocityOp(velo, period=period), 0) + + cTspPb.discretize(dSpec=[nbElem]) + + InterpolationMethod = pp.Utils.Linear(grid=box.discreteDomain, gvalues=velo.discreteVariable) + RemeshingMethod = pp.Utils.M6Prime(grid=box.discreteDomain, gvalues=scal.discreteVariable) + ODESolver = pp.Utils.RK2(InterpolationMethod, box.discreteDomain.applyConditions) + ## cpu + #solver = pp.Utils.ParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod) + ## gpu + #solver = pp.GPUParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu') + solver = pp.GPUParticularSolver_GLRender(cTspPb, + ODESolver, InterpolationMethod, RemeshingMethod, + device_type='gpu', dt=timeStep, + src='./examples/main_Rotating_2D_GH_kernels.cl', + endTime=FinalTime + ) + cTspPb.setSolver(solver) + cTspPb.setPrinter(pp.Utils.Printer(frequency=outputModulo, outputPrefix=outputFilePrefix, problem=cTspPb)) + + t1 = time.time() + + cTspPb.solve(T=FinalTime, dt=timeStep) + + tf = time.time() + + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Attic/main_Rotating_2D_GH_kernels.cl b/Examples/Attic/main_Rotating_2D_GH_kernels.cl new file mode 100644 index 000000000..6232abf62 --- /dev/null +++ b/Examples/Attic/main_Rotating_2D_GH_kernels.cl @@ -0,0 +1,51 @@ + +__kernel void initScalar(__global float* values, + __private const float t, + __private const float4 min, + __private const uint4 nb, + __private const float4 size) +{ + __private uint ind,ix,iy; + __private float px,py,s; + + ix = get_global_id(0); + iy = get_global_id(1); + + px = min.x + (float)(ix)*size.x; + py = min.y + (float)(iy)*size.y; + + if (sqrt((px-0.5f)*(px-0.5f) + (py-0.75f)*(py-0.75f)) < 0.15f) + s = 1.0f; + else + s = 0.0f; + // Write + ind = iy + ix*nb.y; + values[ind] = s; +} + +// velocity field +__kernel void velocity(__global float* gvelo, + __private const float t, + __private const float period, + __private const float4 min, + __private const uint4 nb, + __private const float4 size + ) +{ + __private uint ix,iy, ind; + __private float px,py,vx,vy; + + ix = get_global_id(0); + iy = get_global_id(1); + + px = min.x + (float)(ix)*size.x; //2flop + py = min.y + (float)(iy)*size.y; //2flop + + vx = -sin(px*M_PI_F)*sin(px*M_PI_F)*sin(2.0f*py*M_PI_F)*cos(t*M_PI_F/period); // 14flop + vy = sin(py*M_PI_F)*sin(py*M_PI_F)*sin(2.0f*px*M_PI_F)*cos(t*M_PI_F/period); // 14flop + + ind = iy + ix*nb.y; + gvelo[ind] = vx; + ind = nb.x*nb.y + ix + iy*nb.x; + gvelo[ind] = vy; +} diff --git a/Examples/Attic/main_Rotating_3D_GH.py b/Examples/Attic/main_Rotating_3D_GH.py new file mode 100644 index 000000000..731d99cd6 --- /dev/null +++ b/Examples/Attic/main_Rotating_3D_GH.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +import time +import new_ParMePy as pp +import math + + +def run(): + dim = 3 + nb = 160 + boxLength = [1., 1., 1.] + boxMin = [0., 0., 0.] + nbElem = [nb, nb, nb] + + timeStep = 0.07 + period = 3. + FinalTime = period + outputFilePrefix = './res/RK2_' + outputModulo = 1 + + t0 = time.time() + + box = pp.Domain.Box(dimension=dim, + length=boxLength, + minPosition=boxMin) + velo = pp.Variable.AnalyticalVariable(domain=box, + dimension=dim, name="Velocity" + ) + scal = pp.Variable.AnalyticalVariable(domain=box, + dimension=1, + scalar=True, name="Scalar" + ) + advec = pp.Operator.Advection(velo, scal) + cTspPb = pp.Problem.ContinuousTransportProblem(advection=advec) + cTspPb.addOperator(pp.Operator.VelocityOp(velo, period=period), 0) + + cTspPb.discretize(dSpec=[nbElem]) + + InterpolationMethod = pp.Utils.Linear(grid=box.discreteDomain, gvalues=velo.discreteVariable) + RemeshingMethod = pp.Utils.M6Prime(grid=box.discreteDomain, gvalues=scal.discreteVariable) + ODESolver = pp.Utils.RK2(InterpolationMethod, box.discreteDomain.applyConditions) + ## cpu + #solver = pp.Utils.ParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod) + ## gpu + #solver = pp.GPUParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu') + solver = pp.GPUParticularSolver_GLRender(cTspPb, + ODESolver, InterpolationMethod, RemeshingMethod, + device_type='gpu', dt=timeStep, + src='./examples/main_Rotating_3D_GH_kernels.cl' + ) + cTspPb.setSolver(solver) + cTspPb.setPrinter(pp.Utils.Printer(frequency=outputModulo, outputPrefix=outputFilePrefix, problem=cTspPb)) + + t1 = time.time() + + cTspPb.solve(T=FinalTime, dt=timeStep) + + tf = time.time() + + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Attic/main_Rotating_3D_GH_kernels.cl b/Examples/Attic/main_Rotating_3D_GH_kernels.cl new file mode 100644 index 000000000..60446e284 --- /dev/null +++ b/Examples/Attic/main_Rotating_3D_GH_kernels.cl @@ -0,0 +1,58 @@ + +__kernel void initScalar(__global float* values, + __private const float t, + __private const float4 min, + __private const uint4 nb, + __private const float4 size) +{ + __private uint ind,ix,iy,iz; + __private float px,py,pz,s; + + ix = get_global_id(0); + iy = get_global_id(1); + iz = get_global_id(2); + + px = min.x + (float)(ix)*size.x; + py = min.y + (float)(iy)*size.y; + pz = min.z + (float)(iz)*size.z; + + if (sqrt((px-0.35f)*(px-0.35f) + (py-0.35f)*(py-0.35f) + (pz-0.35f)*(pz-0.35f)) < 0.15f) + s = 1.0f; + else + s = 0.0f; + // Write + ind = iz + iy*nb.z + ix*nb.y*nb.z; + values[ind] = s; +} + +// velocity field +__kernel void velocity(__global float* gvelo, + __private const float t, + __private const float period, + __private const float4 min, + __private const uint4 nb, + __private const float4 size + ) +{ + __private uint ix,iy, iz, ind; + __private float px,py, pz,vx,vy,vz; + + ix = get_global_id(0); + iy = get_global_id(1); + iz = get_global_id(2); + + px = min.x + (float)(ix)*size.x; + py = min.y + (float)(iy)*size.y; + pz = min.z + (float)(iz)*size.z; + + vx = 2.0f * sin(px*M_PI_F)*sin(px*M_PI_F)*sin(2.0f*py*M_PI_F)*sin(2.0f*pz*M_PI_F)*cos(t*M_PI_F/period); + vy = -sin(2.0f*px*M_PI_F)*sin(py*M_PI_F)*sin(py*M_PI_F)*sin(2.0f*pz*M_PI_F)*cos(t*M_PI_F/period); + vz = -sin(2.0f*px*M_PI_F)*sin(pz*M_PI_F)*sin(pz*M_PI_F)*sin(2.0f*py*M_PI_F)*cos(t*M_PI_F/period); + + ind = iz + iy*nb.z + ix*nb.y*nb.z; + gvelo[ind] = vx; + ind = (nb.x*nb.y*nb.z) + iz + ix*nb.z + iy*nb.x*nb.z; + gvelo[ind] = vy; + ind = (nb.x*nb.y*nb.z)*2 + iy + ix*nb.y + iz*nb.x*nb.y; + gvelo[ind] = vz; +} diff --git a/Examples/Attic/main_Shear_2D.py b/Examples/Attic/main_Shear_2D.py new file mode 100644 index 000000000..dd1ac45cf --- /dev/null +++ b/Examples/Attic/main_Shear_2D.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +import math + + +def vitesse(x): + r = math.sqrt(x[0] * x[0] + x[1] * x[1]) + c = math.cos(3 * math.pi * r / 2.) + return [-c * x[1], c * x[0]] + + +def scalaire(x): + r = math.sqrt(x[0] * x[0] + x[1] * x[1]) + if r < 1: + return (1. - r * r) ** 6 + else: + return 0. + + +def run(): + dim = 2 + nb = 128 + boxLength = [2., 2.] + boxMin = [-1., -1.] + nbElem = [nb, nb] + + timeStep = 0.02 + FinalTime = 1. + outputFilePrefix = './res/RK2_' + outputModulo = 1 + + t0 = time.time() + + box = pp.Domain.Box(dimension=dim, + length=boxLength, + minPosition=boxMin) + velo = pp.Variable.AnalyticalVariable(domain=box, + dimension=dim, + formula=vitesse) + scal = pp.Variable.AnalyticalVariable(domain=box, + dimension=1, + formula=scalaire, scalar=True) + advec = pp.Operator.Advection(velo, scal) + cTspPb = pp.Problem.ContinuousTransportProblem(advection=advec) + + cTspPb.discretize(dSpec=[nbElem]) + + InterpolationMethod = pp.Utils.Linear(grid=box.discreteDomain, gvalues=velo.discreteVariable) + RemeshingMethod = pp.Utils.M6Prime(grid=box.discreteDomain, gvalues=scal.discreteVariable) + ODESolver = pp.Utils.RK2(InterpolationMethod, box.discreteDomain.applyConditions) + ## cpu + #solver = pp.Utils.ParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod) + ## gpu + #solver = pp.GPUParticularSolver(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu') + solver = pp.GPUParticularSolver_GLRender(cTspPb, ODESolver, InterpolationMethod, RemeshingMethod, device_type='gpu', dt=timeStep) + cTspPb.setSolver(solver) + cTspPb.setPrinter(pp.Utils.Printer(frequency=outputModulo, outputPrefix=outputFilePrefix, problem=cTspPb)) + + t1 = time.time() + + cTspPb.solve(T=FinalTime, dt=timeStep) + + tf = time.time() + + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/Examples/Froggy/MPI_HelloWorld.py b/Examples/Froggy/MPI_HelloWorld.py new file mode 100644 index 000000000..132730df7 --- /dev/null +++ b/Examples/Froggy/MPI_HelloWorld.py @@ -0,0 +1,9 @@ +import mpi4py.MPI as mpi +comm = mpi.COMM_WORLD +rank = comm.Get_rank() +size = comm.Get_size() +name = mpi.Get_processor_name() + +print (str(name) + ' :: Rank:' + str(rank) + ' (Total='+ str(size) + ')') + + diff --git a/Examples/Froggy/launcher.sh b/Examples/Froggy/launcher.sh new file mode 100755 index 000000000..4027391f5 --- /dev/null +++ b/Examples/Froggy/launcher.sh @@ -0,0 +1,8 @@ +#!/bin/bash +## Oarscript demo launcher + +# Basic demo +oarsub -l/nodes=2/core=3,walltime=00:30:00 --project parmes -n TEST_BASIC -S ./oarscript_basic.sh + +# GPU demo (no need of GPU nodes for the HelloWorld, otherwise it requires the oarsub option: -t gpu) +oarsub -l/nodes=2/core=3,walltime=00:30:00 --project parmes -n TEST_GPU -S ./oarscript_gpu.sh \ No newline at end of file diff --git a/Examples/Froggy/oarscript_basic.sh b/Examples/Froggy/oarscript_basic.sh new file mode 100755 index 000000000..946e351c1 --- /dev/null +++ b/Examples/Froggy/oarscript_basic.sh @@ -0,0 +1,23 @@ +#!/bin/bash +#OAR -n JOBNAME + +# Source the Froggy environment file +source /home/$USER/Code/Parmes/Froggy_Env.sh + +# Export the prefix for our custom mpirun +export MPIPREFIX="/home/perignon/install-gnu-4.8" + +# Set a current directory variable +# Each job is associated with a scratch dir : /scratch/$USER/oar.$OAR_JOB_ID. This directory is erased at the job end. +# A manual directory in the scratch is not erased: /scratch/$USER/toto +CURRENT_DIR="/home/$USER/Code/Examples/Froggy_Tools/" +cd $CURRENT_DIR + +# Compute the proper core number for the OAR_NODE_FILE. +# It results in a run on all cores requested in the oarsub command. +nbcores=`cat $OAR_NODE_FILE|wc -l` + +# The mpirun command. +# OAR_NODE_FILE is given as a openmpi machinefile. +# One must forward the 3 environment variables : PATH, PYTHONPATH and LD_LIBRARY_PATH +mpirun --machinefile $OAR_NODE_FILE --prefix $MPIPREFIX -x PYTHONPATH -x PATH -x LD_LIBRARY_PATH -np $nbcores python $CURRENT_DIR'MPI_HelloWorld.py' diff --git a/Examples/Froggy/oarscript_gpu.sh b/Examples/Froggy/oarscript_gpu.sh new file mode 100755 index 000000000..3241dce7c --- /dev/null +++ b/Examples/Froggy/oarscript_gpu.sh @@ -0,0 +1,26 @@ +#!/bin/bash +#OAR -n JOBNAME + +# Source the Froggy environment file +source /home/jmetancelin/Code/Parmes/Froggy_Env.sh + +# Export the prefix for our custom mpirun +export MPIPREFIX="/home/perignon/install-gnu-4.8" + +# Set a current directory variable +CURRENT_DIR="/home/$USER/Code/Examples/Froggy_Tools/" +cd $CURRENT_DIR + +# Compute the mpi_rankfile on the allocated nodes. +# It places 2 processes on each node since each node has 2 GPU. The processes are located on the 1st slot of each socket. +# The OAR_NODE_FILE is parsed to the mpi_rankfile file +# example of a mpi_rankfile line : rank 0=keplernodes2 slot=0:0 -> Place the 1st rank on the 1st core of the 1st socket of the node keplernodes2 +nbcorespernode=2 +awk -v i=0 -v n=$nbcorespernode 'x[$0]<n { x[$0]++; print "rank " i "=" $0 " slot=" (i++)%n }' $OAR_NODE_FILE > $CURRENT_DIR'mpi_rankfile_'$OAR_JOB_ID +# The number of cores is collected for the mpi_rankfile +nbcores=`cat $CURRENT_DIR'mpi_rankfile' | wc -l` + +# The mpirun command. +# It uses the mpi_rankfile just created above. The prefix of the mpirun command is given. +# One must forward the 3 environment variables : PATH, PYTHONPATH and LD_LIBRARY_PATH +mpirun --rankfile $CURRENT_DIR'mpi_rankfile_'$OAR_JOB_ID --prefix $MPIPREFIX -x PYTHONPATH -x PATH -x LD_LIBRARY_PATH -np $nbcores python $CURRENT_DIR'MPI_HelloWorld.py' diff --git a/Examples/Tools/plot_2D.gp b/Examples/Tools/plot_2D.gp new file mode 100644 index 000000000..b59d58d6a --- /dev/null +++ b/Examples/Tools/plot_2D.gp @@ -0,0 +1,8 @@ +## Script Gnuplot d'animation 2D de résultats de new_ParMePy +f=50 +i=0 +while (i<=f) { + sp sprintf("res/RK2_results_%05d.dat",i) u 3:4:7:7 pt 7 ps 0.25 palette t sprintf("%05d",i) + i=i+1 + pause 0.1 +} \ No newline at end of file diff --git a/Examples/Tools/plot_3D.gp b/Examples/Tools/plot_3D.gp new file mode 100644 index 000000000..661d20ce1 --- /dev/null +++ b/Examples/Tools/plot_3D.gp @@ -0,0 +1,8 @@ +## Script Gnuplot d'animation 3D de résultats de new_ParMePy +f=50 +i=0 +while (i<=f) { + sp sprintf("res/RK2_results_%05d.dat",i) u 4:5:6:10 pt 7 ps 0.25 palette t sprintf("%05d",i) + i=i+1 + pause 0.1 +} \ No newline at end of file diff --git a/Examples/Tools/print_volume_2D.gp b/Examples/Tools/print_volume_2D.gp new file mode 100644 index 000000000..a8dd09cef --- /dev/null +++ b/Examples/Tools/print_volume_2D.gp @@ -0,0 +1,19 @@ +reset +set auto + +vol_theo = pi*0.15*0.15 + +set title "Volume en fonction du temps" +set xl 'temps' +set yl 'volume' +set ytics nomirror +set y2l 'erreur relative' +set y2tics +set key outside bottom center maxrows 1 box height 1 +set yr [0:*] + +p'volume.dat' u ($0*0.07):1 w lp t 'volume' axes x1y1,\ + (vol_theo) t'volume théorique' axes x1y1, \ + 'volume.dat' u ($0*0.07):(abs($1-vol_theo)/vol_theo) t 'erreur' w lp axes x1y2 + +l'loop.gp' \ No newline at end of file diff --git a/Examples/Tools/print_volume_3D.gp b/Examples/Tools/print_volume_3D.gp new file mode 100644 index 000000000..f7baf84c6 --- /dev/null +++ b/Examples/Tools/print_volume_3D.gp @@ -0,0 +1,19 @@ +reset +set auto + +vol_theo = 4.0*pi*0.15*0.15*0.15/3.0 + +set title "Volume en fonction du temps" +set xl 'temps' +set yl 'volume' +set ytics nomirror +set y2l 'erreur relative' +set y2tics +set key outside bottom center maxrows 1 box height 1 +set yr [0:*] + +p'volume.dat' u ($0*0.07):1 w lp t 'volume' axes x1y1,\ + (vol_theo) t'volume théorique' axes x1y1, \ + 'volume.dat' u ($0*0.07):(abs($1-vol_theo)/vol_theo) t 'erreur' w lp axes x1y2 + +l'loop.gp' \ No newline at end of file diff --git a/HySoP/CMake/CMakeListsForTests.cmake b/HySoP/CMake/CMakeListsForTests.cmake new file mode 100644 index 000000000..bdb9e0596 --- /dev/null +++ b/HySoP/CMake/CMakeListsForTests.cmake @@ -0,0 +1,26 @@ +# -*- cmake -*- +# This is the test cmake configuration +# built from @CMAKE_SOURCE_DIR@/cmake/CMakeListsForTests.cmake.in + +# scan the list of test executables +foreach(_EXE ${_EXE_LIST_${_CURRENT_TEST_DIRECTORY}}) + + message(STATUS "Adding test suite ${_CURRENT_TEST_DIRECTORY}/${_EXE}") + + # Create an executable for the current test + add_executable(${_EXE} ${${_EXE}_FSOURCES}) + + # Add a dependency between current test and the main library target + add_dependencies(${_EXE} ${PROJECT_LIBRARY_NAME}) + # link current target test with the same lib as for main project lib + target_link_libraries(${_EXE} ${PROJECT_LIBRARY_NAME}) + target_link_libraries(${_EXE} ${LIBS}) + + # add test for ctest + add_test(${_EXE} ${_EXE}) + + set_tests_properties(${_EXE} PROPERTIES FAIL_REGULAR_EXPRESSION "FAILURE;Exception;failed;ERROR") + message("ADD MPI TESTS ...") + add_test(NAME mpi_${_EXE} COMMAND mpirun -np 4 ${_EXE}) + +endforeach(_EXE ${_EXE_LIST_${_CURRENT_TEST_DIRECTORY}}) diff --git a/HySoP/CMake/InstallPackage.cmake b/HySoP/CMake/InstallPackage.cmake new file mode 100644 index 000000000..a594a0b3d --- /dev/null +++ b/HySoP/CMake/InstallPackage.cmake @@ -0,0 +1,62 @@ +#=========================================================== +# Macro to install parmes package +# +# F. Pérignon, LJK-CNRS, april 2011 +# +#=========================================================== + +macro(install_package) + + if(ARGV2) + set(_HEADERS ${ARGV2}) + endif() + + # Offer the user the choice of overriding the installation directories + set(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") + set(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") + set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + set(INSTALL_DATA_DIR share CACHE PATH "Installation directory for data files") + + # Make relative paths absolute (needed later on) + foreach(p LIB BIN INCLUDE DATA) + set(var INSTALL_${p}_DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() + endforeach() + + # The library + install(TARGETS ${ARGV1} + EXPORT ${ARGV0}LibraryDepends + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" # static libs + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib # shared libs + PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT dev + ) + + # The headers and modules + if(_HEADERS) + install(FILES ${_HEADERS} DESTINATION "${INSTALL_INCLUDE_DIR}") + endif() + install(DIRECTORY ${CMAKE_BINARY_DIR}/Modules DESTINATION "${INSTALL_INCLUDE_DIR}") + + export(TARGETS ${ARGV1} FILE "${PROJECT_BINARY_DIR}/InstallFiles/${ARGV0}LibraryDepends.cmake") + + # Install the export set for use with the install-tree + install(EXPORT ${ARGV0}LibraryDepends DESTINATION + "${INSTALL_DATA_DIR}/CMake" COMPONENT dev) + + set(${ARGV0}_INCLUDE_DIRS "${INSTALL_INCLUDE_DIR}") + set(${ARGV0}_LIB_DIR "${INSTALL_LIB_DIR}") + set(${ARGV0}_CMAKE_DIR "${INSTALL_DATA_DIR}/CMake") + + display(${ARGV0}_CMAKE_DIR) + configure_file(${CMAKE_SOURCE_DIR}/${ARGV0}Config.cmake.in + "${PROJECT_BINARY_DIR}/InstallFiles/${ARGV0}Config.cmake") + configure_file(${CMAKE_SOURCE_DIR}/${ARGV0}ConfigVersion.cmake.in + "${PROJECT_BINARY_DIR}/InstallFiles/${ARGV0}ConfigVersion.cmake" @ONLY) + install(FILES + "${PROJECT_BINARY_DIR}/InstallFiles/${ARGV0}Config.cmake" + "${PROJECT_BINARY_DIR}/InstallFiles/${ARGV0}ConfigVersion.cmake" + DESTINATION "${${ARGV0}_CMAKE_DIR}" COMPONENT dev) + +endmacro() diff --git a/HySoP/CMake/TestFortranAcceptsFlag.cmake b/HySoP/CMake/TestFortranAcceptsFlag.cmake new file mode 100644 index 000000000..73f3b1a1d --- /dev/null +++ b/HySoP/CMake/TestFortranAcceptsFlag.cmake @@ -0,0 +1,38 @@ +# - Test Fortran compiler for a flag +# Check if the Fortran compiler accepts a flag +# +# Macro CHECK_Fortran_ACCEPTS_FLAG(FLAGS VARIABLE) - +# checks if the function exists +# FLAGS - the flags to try +# VARIABLE - variable to store the result +# +# F. Pérignon - LJK/CNRS - March 2011 +# From Kitware TestCXXAcceptsFlag.cmake +# + +MACRO(CHECK_Fortran_ACCEPTS_FLAG FLAGS VARIABLE) + IF(NOT DEFINED ${VARIABLE}) + MESSAGE(STATUS "Checking to see if Fortran compiler accepts flag ${FLAGS}") + FILE(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/Dummy.f + "program TESTFortran + implicit none + print *, 'Hello' + end program ") + TRY_COMPILE(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/Dummy.f + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${FLAGS} + OUTPUT_VARIABLE OUTPUT) + IF(${VARIABLE}) + MESSAGE(STATUS "Checking to see if Fortran compiler accepts flag ${FLAGS} - yes") + FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the Fortran compiler accepts the flag ${FLAGS} passed with " + "the following output:\n${OUTPUT}\n\n") + ELSE(${VARIABLE}) + MESSAGE(STATUS "Checking to see if Fortran compiler accepts flag ${FLAGS} - no") + FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the Fortran compiler accepts the flag ${FLAGS} failed with " + "the following output:\n${OUTPUT}\n\n") + ENDIF(${VARIABLE}) + ENDIF(NOT DEFINED ${VARIABLE}) +ENDMACRO(CHECK_Fortran_ACCEPTS_FLAG) diff --git a/HySoP/FroggyHowTo.org b/HySoP/FroggyHowTo.org new file mode 100644 index 000000000..c4941c154 --- /dev/null +++ b/HySoP/FroggyHowTo.org @@ -0,0 +1,14 @@ +* To use parmespy on Froggy ... +source /applis/site/env.bash +module load gcc/4.8.1_gcc-4.4.6 +module load cmake/2.8.11.2_gcc-4.4.6 +. /home/perignon/MyPython/bin/activate +export PATH=/home/perignon/install-gnu-4.8/bin/:${PATH} +export LD_LIBRARY_PATH=/home/perignon/install-gnu-4.8/lib/:/applis/site/stow/gcc_4.4.6/gcc_4.8.1/lib64:${LD_LIBRARY_PATH} +export PYTHONPATH=/home/perignon/MyPython/lib/python2.7/site-packages:/home/perignon/install-gnu-4.8/lib/python2.7/site-packages +export CC=mpicc CXX=mpic++ FC=mpif90 +unset LDFLAGS +unset CFLAGS +cmake path-to-Parmes -Dfftw_DIR=/home/perignon/install-gnu-4.8/ +make install -j 8 +export PYTHONPATH=/home/YOURLOGIN/.local/lib/python2.7/site-packages diff --git a/HySoP/Froggy_BuildEnv.sh b/HySoP/Froggy_BuildEnv.sh new file mode 100644 index 000000000..5b98a27bf --- /dev/null +++ b/HySoP/Froggy_BuildEnv.sh @@ -0,0 +1,16 @@ +## Source this file to get a clean working environment on Froggy +## It uses the binaries and libraries from /home/perignon +source /applis/site/env.bash +module load gcc/4.8.1_gcc-4.4.6 +module load cmake/2.8.11.2_gcc-4.4.6 +. /home/perignon/MyPython/bin/activate +export PATH=/home/perignon/install-gnu-4.8/bin/:${PATH} +export LD_LIBRARY_PATH=/home/perignon/install-gnu-4.8/lib/:/applis/site/stow/gcc_4.4.6/gcc_4.8.1/lib64:${LD_LIBRARY_PATH} +export PYTHONPATH=~/.local/lib/python2.7/site-packages:/home/perignon/MyPython/lib/python2.7/site-packages:/home/perignon/install-gnu-4.8/lib/python2.7/site-packages +export CC=mpicc CXX=mpic++ FC=mpif90 +unset LDFLAGS +unset CFLAGS + +## Build parmes helping cmake to find FFTW headers: +# cmake path-to-Parmes -Dfftw_DIR=/home/perignon/install-gnu-4.8/ +# make install -j 8 diff --git a/HySoP/Froggy_Env.sh b/HySoP/Froggy_Env.sh new file mode 100644 index 000000000..dc374f6c5 --- /dev/null +++ b/HySoP/Froggy_Env.sh @@ -0,0 +1,8 @@ +## Source this file to get a clean working environment on Froggy for running parmes +## It uses the binaries and libraries from /home/perignon +source /applis/site/env.bash +module load gcc/4.8.1_gcc-4.4.6 +. /home/perignon/MyPython/bin/activate +export PATH=/home/perignon/install-gnu-4.8/bin/:${PATH} +export LD_LIBRARY_PATH=/home/perignon/install-gnu-4.8/lib/:/applis/site/stow/gcc_4.4.6/gcc_4.8.1/lib64:${LD_LIBRARY_PATH} +export PYTHONPATH=~/.local/lib/python2.7/site-packages:/home/perignon/MyPython/lib/python2.7/site-packages:/home/perignon/install-gnu-4.8/lib/python2.7/site-packages diff --git a/HySoP/Global_tests/README b/HySoP/Global_tests/README new file mode 100644 index 000000000..20dd663df --- /dev/null +++ b/HySoP/Global_tests/README @@ -0,0 +1,3 @@ +This directory contains py files used to test global functionnalities (a specific operator, a method ...) +and to check performances and memory usage. + diff --git a/HySoP/Global_tests/testPerfAndMemForFD_and_div.py b/HySoP/Global_tests/testPerfAndMemForFD_and_div.py new file mode 100644 index 000000000..f104f5512 --- /dev/null +++ b/HySoP/Global_tests/testPerfAndMemForFD_and_div.py @@ -0,0 +1,305 @@ +#!/usr/bin/python + +""" +Test memory and performances for finite differences operations. + +""" + +import parmepy as pp +import parmepy.tools.numpywrappers as npw +import math as m +from parmepy.fields.continuous import Field +from parmepy.mpi.topology import Cartesian +from parmepy.operator.stretching import Stretching + + +## ----------- A 3d problem ----------- +print " ========= Start Finite Differences tests =========" +dim = 3 +pi = m.pi +sin = m.sin +cos = m.cos +## Domain +box = pp.Box(dim, length=[2.0 * pi, 2.0 * pi, 2.0 * pi]) + +## Global resolution +nb = 65 +nbElem = [nb] * dim + + +## Function to compute velocity +def computeVel(x, y, z): + vx = sin(x) * cos(y) * cos(z) + vy = - cos(x) * sin(y) * cos(z) + vz = 0. + return vx, vy, vz + + +## Function to compute vorticity +def computeVort(x, y, z): + wx = - cos(x) * sin(y) * sin(z) + wy = - sin(x) * cos(y) * sin(z) + wz = 2. * sin(x) * sin(y) * cos(z) + return wx, wy, wz + +## Fields +velo = Field(domain=box, formula=computeVel, + name='Velocity', isVector=True) +vorti = Field(domain=box, formula=computeVort, + name='VorticityC', isVector=True) + +## A topology with ghosts +NBGHOSTS = 2 +ghosts = npw.ones((box.dimension)) * NBGHOSTS +topo = Cartesian(box, box.dimension, nbElem, + ghosts=ghosts) + +## local coordinates +coords = topo.mesh.coords +## Fields discretization +velo.discretize(topo) +vorti.discretize(topo) +velo.initialize() +vorti.initialize() + +## alias to discrete fields components +w = vorti.discreteFields.values()[0].data +v = velo.discreteFields.values()[0].data + +from parmepy.mpi import MPI +from parmepy.numerics.finite_differences import FD_C_4 + +## FD scheme creation and init +fd_scheme = FD_C_4((topo.mesh.space_step)) +fd_scheme.computeIndices(topo.mesh.iCompute) + +import numpy as np +#### Timings for finite differences schemes + +iter = 10 +# Allocation of work vector to store results +result = npw.zeros_like(w[0]) + +## Add raw_input to check memory with htop +print 'press any key to start tests' +raw_input() + +########### Test 1 : finite diff. direct call ########### + +#### First method ##### +print 'start ...' +time = MPI.Wtime() +for i in xrange(iter): + fd_scheme.compute(w[0], 0, result) +print 'FD compute method time ', MPI.Wtime() - time +raw_input() +print 'start ... ' +#### Second method ##### +time = MPI.Wtime() +for i in xrange(iter): + fd_scheme.compute_and_add(w[0], 0, result) +print 'FD compute_and_add method time ', MPI.Wtime() - time + +del result +iter = 1 + +# +# Res : first method is faster and cost less in memory +# + +########### Test 2 : 'FD, with accumulation of the result ########### + +result = [npw.zeros_like(w[0]) for i in xrange(2)] + +## fd results are accumulated into result[0] + +raw_input() +print 'start' +#### First method #### +## Needs at least two workspaces and one is used for the final result. +time = MPI.Wtime() +for i in xrange(iter): + #for cdir in xrange(3): + fd_scheme.compute(w[0], 0, result[0]) + fd_scheme.compute(w[1], 0, result[1]) + np.add(result[0], result[1], result[0]) + fd_scheme.compute(w[2], 0, result[1]) + np.add(result[0], result[1], result[0]) +print 'Accumulate/FD Compute meth time ', MPI.Wtime() - time + +raw_input() +print 'start ...' +result2 = npw.zeros_like(w[0]) +#### Second method #### +## Needs only one workspace, used for the final result. +time = MPI.Wtime() +for i in xrange(iter): + #for cdir in xrange(3): + fd_scheme.compute(w[0], 0, result2) + fd_scheme.compute_and_add(w[1], 0, result2) + fd_scheme.compute_and_add(w[2], 0, result2) +print 'Accumulate/FD Compute_and_add meth time ', MPI.Wtime() - time + +print 'Computation ok? ', np.allclose(result[0], result2) +del result +del result2 + +# +# Res : first method is faster and cost less in memory +# + +########### Test 3 : 'real' case +# corresponding more or less to divV computation ########### +# Needs an intermediate workspace to compute w.v +raw_input() +print 'start ...' +work = [npw.zeros_like(w[0]) for i in xrange(3)] +raw_input() + +## fd results are accumulated into result[0] + +#### First method #### +## Needs at least three workspaces and one is used for the final result. +time = MPI.Wtime() +for i in xrange(iter): + #for cdir in xrange(3): + work[2][...] = v[0] * w[0] + fd_scheme.compute(work[2], 0, work[0]) + work[2][...] = v[0] * w[1] + fd_scheme.compute(work[2], 0, work[1]) + np.add(work[0], work[1], work[0]) + work[2][...] = v[0] * w[2] + fd_scheme.compute(work[2], 0, work[1]) + np.add(work[0], work[1], work[0]) +print 'Div/FD Compute meth time ', MPI.Wtime() - time +time = MPI.Wtime() +for i in xrange(iter): + #for cdir in xrange(3): + work[2][...] = v[0] * w[0] + fd_scheme.compute(work[2], 0, work[0]) + work[2][...] = v[0] * w[1] + fd_scheme.compute(work[2], 0, work[1]) + work[0][...] += work[1] + work[2][...] = v[0] * w[2] + fd_scheme.compute(work[2], 0, work[1]) + work[0][...] += work[1] +print 'Div/FD Compute meth time (bis) ', MPI.Wtime() - time + +#### Second method #### +## Needs only two workspace, used for the final result. +raw_input() +print 'start ...' +work2 = [npw.zeros_like(w[0]) for i in xrange(2)] +raw_input() + +print 'pre id ...', id(work2[1]) +time = MPI.Wtime() +for i in xrange(iter): + #for cdir in xrange(3): + work2[1][...] = v[0] * w[0] + print 'post id ...', id(work2[1]) + fd_scheme.compute(work2[1], 0, work2[0]) + work2[1][...] = v[0] * w[1] + fd_scheme.compute_and_add(work2[1], 0, work2[0]) + work2[1][...] = v[0] * w[2] + fd_scheme.compute_and_add(work2[1], 0, work2[0]) +print 'Div/FD Compute_and_add meth time ', MPI.Wtime() - time + +print 'Computation ok? ', np.allclose(work[0], work2[0]) + +del work +del work2 +# +# Res : first method is faster and cost less in memory +# (but it's almost the same) +# + +########### Test 4 : 'real' case +# corresponding more or less to divT computation ########### +# Needs an intermediate workspace to compute w.v + +raw_input() +print 'start ...' +work = [npw.zeros_like(w[0]) for i in xrange(5)] +raw_input() + +## fd results are accumulated into work[0:2] + +#### First method #### +## Needs at least five workspaces and three are used for the final result. +# work[i] = divV(w vi) +time = MPI.Wtime() +for i in xrange(iter): + # Compute first component of divT ... + work[2] = v[0] * w[0] + fd_scheme.compute(work[2], 0, work[0]) + work[2] = v[0] * w[1] + fd_scheme.compute(work[2], 0, work[1]) + np.add(work[0], work[1], work[0]) + work[2] = v[0] * w[2] + fd_scheme.compute(work[2], 0, work[1]) + np.add(work[0], work[1], work[0]) + # Second component ... work[0] can not be used anymore + work[3] = v[0] * w[0] + fd_scheme.compute(work[3], 0, work[1]) + work[3] = v[0] * w[1] + fd_scheme.compute(work[3], 0, work[2]) + np.add(work[1], work[2], work[1]) + work[3] = v[0] * w[2] + fd_scheme.compute(work[3], 0, work[2]) + np.add(work[1], work[2], work[1]) + # Last component ... work[0] and work[1] can not be used anymore + work[4] = v[0] * w[0] + fd_scheme.compute(work[4], 0, work[2]) + work[4] = v[0] * w[1] + fd_scheme.compute(work[4], 0, work[3]) + np.add(work[2], work[3], work[2]) + work[4] = v[0] * w[2] + fd_scheme.compute(work[4], 0, work[3]) + np.add(work[2], work[3], work[2]) + +print 'DivT/FD Compute meth time ', MPI.Wtime() - time +#### Second method #### +## Needs only 4 workspaces, used for the final result. +raw_input() +print 'start ...' +work2 = [npw.zeros_like(w[0]) for i in xrange(4)] +time = MPI.Wtime() +for i in xrange(iter): + # Compute first component of divT ... + work2[3] = v[0] * w[0] + fd_scheme.compute(work2[3], 0, work2[0]) + work2[3] = v[0] * w[1] + fd_scheme.compute_and_add(work2[3], 0, work2[0]) + work2[3] = v[0] * w[2] + fd_scheme.compute_and_add(work2[3], 0, work2[0]) + # Second component ... work2[0] can not be used anymore + work2[3] = v[0] * w[0] + fd_scheme.compute(work2[3], 0, work2[1]) + work2[3] = v[0] * w[1] + fd_scheme.compute_and_add(work2[3], 0, work2[1]) + work2[3] = v[0] * w[2] + fd_scheme.compute_and_add(work2[3], 0, work2[1]) + # Last component ... work2[0] and work2[1] can not be used anymore + work2[3] = v[0] * w[0] + fd_scheme.compute(work2[3], 0, work2[2]) + work2[3] = v[0] * w[1] + fd_scheme.compute_and_add(work2[3], 0, work2[2]) + work2[3] = v[0] * w[2] + fd_scheme.compute_and_add(work2[3], 0, work2[2]) + +print 'DivT/FD Compute_and_add meth time ', MPI.Wtime() - time + +ind = topo.mesh.iCompute +for i in xrange(3): + print 'Computation ok? ', np.allclose(work[i][ind], work2[i][ind]) +# +# Res : first method is faster and cost less in memory +# (but it's almost the same) +# + + +## Conclusion (if res > 200 **)-> it seems that first method, although it needs +# more initial workspaces, is always faster and cheaper +# concerning memory (because of hidden tmp alloc) +# BUT for smaller resolutions, second method may be more efficient ... diff --git a/HySoP/HySoPConfig.cmake.in b/HySoP/ParmesConfig.cmake.in similarity index 100% rename from HySoP/HySoPConfig.cmake.in rename to HySoP/ParmesConfig.cmake.in diff --git a/HySoP/HySoPConfigVersion.cmake.in b/HySoP/ParmesConfigVersion.cmake.in similarity index 100% rename from HySoP/HySoPConfigVersion.cmake.in rename to HySoP/ParmesConfigVersion.cmake.in diff --git a/HySoP/ParmesToSinglePrecision.patch b/HySoP/ParmesToSinglePrecision.patch new file mode 100644 index 000000000..5e644fe4e --- /dev/null +++ b/HySoP/ParmesToSinglePrecision.patch @@ -0,0 +1,947 @@ +diff --git parmepy/constants.py parmepy/constants.py +index 3672059..3022c21 100644 +--- parmepy/constants.py ++++ parmepy/constants.py +@@ -18,13 +18,13 @@ else: + + PI = math.pi + # Set default type for real and integer numbers +-PARMES_REAL = np.float64 ++PARMES_REAL = np.float32 + # type for array indices + PARMES_INDEX = np.uint32 + # type for integers +-PARMES_INTEGER = np.int64 ++PARMES_INTEGER = np.int32 + # float type for MPI messages +-PARMES_MPI_REAL = MPI.DOUBLE ++PARMES_MPI_REAL = MPI.REAL + ## default array layout (fortran or C convention) + ORDER = 'F' + # to check array ordering with : +diff --git parmepy/f2py/fftw2py.f90 parmepy/f2py/fftw2py.f90 +index 8645a9f..718eb19 100755 +--- parmepy/f2py/fftw2py.f90 ++++ parmepy/f2py/fftw2py.f90 +@@ -5,7 +5,7 @@ + module fftw2py + + use client_data +- use parmesparam ++ use parmesparam_sp + !> 2d case + use fft2d + !> 3d case +@@ -81,7 +81,7 @@ contains + subroutine solve_poisson_2d(omega,velocity_x,velocity_y) + real(pk),dimension(:,:),intent(in):: omega + real(pk),dimension(size(omega,1),size(omega,2)),intent(out) :: velocity_x,velocity_y +- real(pk) :: start ++ real(8) :: start + !f2py intent(in,out) :: velocity_x,velocity_y + start = MPI_WTime() + +@@ -117,7 +117,7 @@ contains + real(pk),dimension(:,:,:),intent(in):: omega_x,omega_y,omega_z + real(pk),dimension(size(omega_x,1),size(omega_y,2),size(omega_z,3)),intent(out) :: velocity_x,velocity_y,velocity_z + integer, dimension(3), intent(in) :: ghosts_vort, ghosts_velo +- real(pk) :: start ++ real(8) :: start + !f2py intent(in,out) :: velocity_x,velocity_y,velocity_z + start = MPI_WTime() + call r2c_3d(omega_x,omega_y,omega_z, ghosts_vort) +diff --git parmepy/f2py/scales2py.f90 parmepy/f2py/scales2py.f90 +index ab5b440..d56112e 100755 +--- parmepy/f2py/scales2py.f90 ++++ parmepy/f2py/scales2py.f90 +@@ -6,7 +6,7 @@ use advec, only : advec_init,advec_step,advec_step_Inter_basic,advec_step_Inter_ + use advec_vect, only : advec_step_Vect,advec_step_Inter_basic_Vect + use interpolation_velo, only : interpol_init + use mpi +-use parmesparam ++use parmesparam_sp + + + implicit none +@@ -93,7 +93,7 @@ contains + real(pk), dimension(size(vx,1),size(vx,2),size(vx,3)), intent(inout) :: scal + !f2py real(pk) intent(in,out), depend(size(vx,1)) :: scal + +- real(pk) :: t0 ++ real(8) :: t0 + + t0 = MPI_Wtime() + call advec_step(dt,vx,vy,vz,scal) +diff --git setup.py.in setup.py.in +index f771350..22fd086 100644 +--- setup.py.in ++++ setup.py.in +@@ -71,8 +71,8 @@ if(enable_fortran is "ON"): + fortran_src.append(fortran_dir+'fftw2py.f90') + fftwdir = '@FFTWLIB@' + fftwdir = os.path.split(fftwdir)[0] +- parmeslib.append('fftw3') +- parmeslib.append('fftw3_mpi') ++ parmeslib.append('fftw3f') ++ parmeslib.append('fftw3f_mpi') + parmes_libdir.append(fftwdir) + else: + packages.append('parmepy.fakef2py') +diff --git src/client_data.f90 src/client_data.f90 +index 46b5268..77178d9 100755 +--- src/client_data.f90 ++++ src/client_data.f90 +@@ -1,14 +1,14 @@ + !> Some global parameters and variables + module client_data + +- use MPI, only : MPI_DOUBLE_PRECISION ++ use MPI, only : MPI_REAL + use, intrinsic :: iso_c_binding ! required for fftw + implicit none + + !> kind for real variables (simple or double precision) +- integer, parameter :: mk = kind(1.0d0) ! double precision ++ integer, parameter :: mk = kind(1.0) ! single precision + !> kind for real variables in mpi routines +- integer, parameter :: mpi_mk = MPI_DOUBLE_PRECISION ++ integer, parameter :: mpi_mk = MPI_REAL + !> Problem dimension (model, required for ppm to work properly) + integer, parameter :: dime = 2 + !> Real dimension +@@ -26,7 +26,7 @@ module client_data + !> to activate (or not) screen output + logical,parameter :: verbose = .True. + !> i (sqrt(-1) ...) +- complex(C_DOUBLE_COMPLEX), parameter :: Icmplx = cmplx(0._mk,1._mk, kind=mk) ++ complex(C_FLOAT_COMPLEX), parameter :: Icmplx = cmplx(0._mk,1._mk, kind=mk) + !> tolerance used to compute error + real(mk), parameter :: tolerance = 1e-12 + +diff --git src/fftw/Poisson.f90 src/fftw/Poisson.f90 +index 78b355c..8804e3d 100755 +--- src/fftw/Poisson.f90 ++++ src/fftw/Poisson.f90 +@@ -53,7 +53,7 @@ contains + real(mk),dimension(:,:,:),intent(in) :: omega_x,omega_y,omega_z + real(mk),dimension(:,:,:),intent(inout) :: velocity_x,velocity_y,velocity_z + integer, dimension(3), intent(in) :: ghosts_w, ghosts_v +- real(mk) :: start ++ real(8) :: start + !! Compute fftw forward transform + !! Omega is used to initialize the fftw buffer for input field. + +@@ -74,7 +74,7 @@ contains + + real(mk),dimension(:,:,:),intent(in) :: omega_x,omega_y,omega_z + real(mk),dimension(:,:,:),intent(inout) :: velocity_x,velocity_y,velocity_z +- real(mk) :: start ++ real(8) :: start + !! Compute fftw forward transform + !! Omega is used to initialize the fftw buffer for input field. + +diff --git src/fftw/fft2d.f90 src/fftw/fft2d.f90 +index c56412f..7edbfd3 100755 +--- src/fftw/fft2d.f90 ++++ src/fftw/fft2d.f90 +@@ -36,15 +36,15 @@ module fft2d + type(C_PTR) :: cbuffer2 + !! Note Franck : check if local declarations of datain/out works and improve perfs. + !> Field (complex values) for fftw input +- complex(C_DOUBLE_COMPLEX), pointer :: datain1(:,:),datain2(:,:) ++ complex(C_FLOAT_COMPLEX), pointer :: datain1(:,:),datain2(:,:) + !> Field (real values) for fftw input +- real(C_DOUBLE), pointer :: rdatain1(:,:) ++ real(C_FLOAT), pointer :: rdatain1(:,:) + !> Field (complex values) for fftw (forward) output +- complex(C_DOUBLE_COMPLEX), pointer :: dataout1(:,:) ++ complex(C_FLOAT_COMPLEX), pointer :: dataout1(:,:) + !> Field (real values) for fftw output +- real(C_DOUBLE), pointer :: rdatain2(:,:) ++ real(C_FLOAT), pointer :: rdatain2(:,:) + !> Field (complex values) for fftw (forward) output +- complex(C_DOUBLE_COMPLEX), pointer :: dataout2(:,:) ++ complex(C_FLOAT_COMPLEX), pointer :: dataout2(:,:) + !> GLOBAL number of points in each direction + integer(C_INTPTR_T),pointer :: fft_resolution(:) + !> LOCAL resolution +@@ -52,13 +52,13 @@ module fft2d + !> Offset in the direction of distribution + integer(c_INTPTR_T),dimension(2) :: local_offset + !> wave numbers for fft in x direction +- real(C_DOUBLE), pointer :: kx(:) ++ real(C_FLOAT), pointer :: kx(:) + !> wave numbers for fft in y direction +- real(C_DOUBLE), pointer :: ky(:) ++ real(C_FLOAT), pointer :: ky(:) + !> log file for fftw + character(len=20),parameter :: filename ="parmesfftw.log" + !> normalization factor +- real(C_DOUBLE) :: normFFT ++ real(C_FLOAT) :: normFFT + !> true if all the allocation stuff for global variables has been done. + logical :: is2DUpToDate = .false. + +@@ -81,7 +81,7 @@ contains + if(is2DUpToDate) return + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + + if(rank==0) open(unit=21,file=filename,form="formatted") + +@@ -90,27 +90,27 @@ contains + fft_resolution = resolution-1 + + ! compute "optimal" size (according to fftw) for local date (warning : dimension reversal) +- alloc_local = fftw_mpi_local_size_2d_transposed(fft_resolution(c_Y),fft_resolution(c_X),main_comm,& ++ alloc_local = fftwf_mpi_local_size_2d_transposed(fft_resolution(c_Y),fft_resolution(c_X),main_comm,& + local_resolution(c_Y),local_offset(c_Y),local_resolution(c_X),local_offset(c_X)); + + ! allocate local buffer (used to save datain/dataout1 ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) + ! link datain and dataout1 to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, datain1, [fft_resolution(c_X),local_resolution(c_Y)]) + call c_f_pointer(cbuffer1, dataout1, [fft_resolution(c_Y),local_resolution(c_X)]) + + ! second buffer used for backward transform. Used to copy dataout1 into dataout2 (input for backward transform and filter) + ! and to save (in-place) the transform of the second component of the velocity +- cbuffer2 = fftw_alloc_complex(alloc_local) ++ cbuffer2 = fftwf_alloc_complex(alloc_local) + call c_f_pointer(cbuffer2, datain2, [fft_resolution(c_X),local_resolution(c_Y)]) + call c_f_pointer(cbuffer2, dataout2, [fft_resolution(c_Y),local_resolution(c_X)]) + + ! create MPI plan for in-place forward/backward DFT (note dimension reversal) +- plan_forward1 = fftw_mpi_plan_dft_2d(fft_resolution(c_Y), fft_resolution(c_X),datain1,dataout1,& ++ plan_forward1 = fftwf_mpi_plan_dft_2d(fft_resolution(c_Y), fft_resolution(c_X),datain1,dataout1,& + main_comm,FFTW_FORWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_dft_2d(fft_resolution(c_Y),fft_resolution(c_X),dataout1,datain1,& ++ plan_backward1 = fftwf_mpi_plan_dft_2d(fft_resolution(c_Y),fft_resolution(c_X),dataout1,datain1,& + main_comm,FFTW_BACKWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_backward2 = fftw_mpi_plan_dft_2d(fft_resolution(c_Y),fft_resolution(c_X),dataout2,datain2,& ++ plan_backward2 = fftwf_mpi_plan_dft_2d(fft_resolution(c_Y),fft_resolution(c_X),dataout2,datain2,& + main_comm,FFTW_BACKWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + + call computeKxC(lengths(c_X)) +@@ -139,7 +139,7 @@ contains + end do + + ! compute transform (as many times as desired) +- call fftw_mpi_execute_dft(plan_forward1, datain1, dataout1) ++ call fftwf_mpi_execute_dft(plan_forward1, datain1, dataout1) + + !!$ do i = 1, fft_resolution(c_Y) + !!$ write(*,'(a,i5,a,16f10.4)') 'out[',rank,'] ', dataout1(i,1:local_resolution(c_X)) +@@ -147,8 +147,8 @@ contains + !!$ + call filter_poisson_2d() + +- call fftw_mpi_execute_dft(plan_backward1, dataout1, datain1) +- call fftw_mpi_execute_dft(plan_backward2,dataout2,datain2) ++ call fftwf_mpi_execute_dft(plan_backward1, dataout1, datain1) ++ call fftwf_mpi_execute_dft(plan_backward2,dataout2,datain2) + do j = 1, local_resolution(c_Y) + do i = 1, fft_resolution(c_X) + velocity_x(i,j) = datain1(i,j)*normFFT +@@ -183,7 +183,7 @@ contains + if(is2DUpToDate) return + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + + if(rank==0) open(unit=21,file=filename,form="formatted") + +@@ -191,11 +191,11 @@ contains + fft_resolution(:) = resolution(:)-1 + halfLength = fft_resolution(c_X)/2+1 + ! allocate local buffer (used to save datain/dataout1 ==> in-place transform!!) +- alloc_local = fftw_mpi_local_size_2d_transposed(fft_resolution(c_Y),halfLength,main_comm,local_resolution(c_Y),& ++ alloc_local = fftwf_mpi_local_size_2d_transposed(fft_resolution(c_Y),halfLength,main_comm,local_resolution(c_Y),& + local_offset(c_Y),local_resolution(c_X),local_offset(c_X)); + + ! allocate local buffer (used to save datain/dataout1 ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) + + ! link rdatain1 and dataout1 to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, rdatain1, [2*halfLength,local_resolution(c_Y)]) +@@ -203,17 +203,17 @@ contains + + ! second buffer used for backward transform. Used to copy dataout1 into dataout2 (input for backward transform and filter) + ! and to save (in-place) the transform of the second component of the velocity +- cbuffer2 = fftw_alloc_complex(alloc_local) ++ cbuffer2 = fftwf_alloc_complex(alloc_local) + + call c_f_pointer(cbuffer2, rdatain2, [2*halfLength,local_resolution(c_Y)]) + call c_f_pointer(cbuffer2, dataout2, [fft_resolution(c_Y),local_resolution(c_X)]) + + ! create MPI plans for in-place forward/backward DFT (note dimension reversal) +- plan_forward1 = fftw_mpi_plan_dft_r2c_2d(fft_resolution(c_Y), fft_resolution(c_X), rdatain1, dataout1, & ++ plan_forward1 = fftwf_mpi_plan_dft_r2c_2d(fft_resolution(c_Y), fft_resolution(c_X), rdatain1, dataout1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & ++ plan_backward1 = fftwf_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_backward2 = fftw_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & ++ plan_backward2 = fftwf_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + + call computeKx(lengths(c_X)) +@@ -248,7 +248,7 @@ contains + !!$ end do + !!$ + ! compute transform (as many times as desired) +- call fftw_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) ++ call fftwf_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) + + !!$ do i = 1, fft_resolution(c_Y) + !!$ write(*,'(a,i5,a,16f10.4)') 'aaaa[',rank,'] ', dataout1(i,1:local_resolution(c_X)) +@@ -261,8 +261,8 @@ contains + real(mk),dimension(:,:),intent(inout) :: velocity_x,velocity_y + integer(C_INTPTR_T) :: i, j + +- call fftw_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) +- call fftw_mpi_execute_dft_c2r(plan_backward2,dataout2,rdatain2) ++ call fftwf_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) ++ call fftwf_mpi_execute_dft_c2r(plan_backward2,dataout2,rdatain2) + do j = 1, local_resolution(c_Y) + do i = 1, fft_resolution(c_X) + velocity_x(i,j) = rdatain1(i,j)*normFFT +@@ -288,7 +288,7 @@ contains + real(mk),dimension(:,:),intent(inout) :: omega + integer(C_INTPTR_T) :: i, j + +- call fftw_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) ++ call fftwf_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) + do j = 1, local_resolution(c_Y) + do i = 1, fft_resolution(c_X) + omega(i,j) = rdatain1(i,j)*normFFT +@@ -390,7 +390,7 @@ contains + subroutine filter_poisson_2d() + + integer(C_INTPTR_T) :: i, j +- complex(C_DOUBLE_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: coeff + if(local_offset(c_X)==0) then + if(local_offset(c_Y) == 0) then + dataout1(1,1) = 0.0 +@@ -437,9 +437,9 @@ contains + + subroutine filter_diffusion_2d(nudt) + +- real(C_DOUBLE), intent(in) :: nudt ++ real(C_FLOAT), intent(in) :: nudt + integer(C_INTPTR_T) :: i, j +- complex(C_DOUBLE_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: coeff + + do i = 1,local_resolution(c_X) + do j = 1, fft_resolution(c_Y) +@@ -452,20 +452,20 @@ contains + + !> Clean fftw context (free memory, plans ...) + subroutine cleanFFTW_2d() +- call fftw_destroy_plan(plan_forward1) +- call fftw_destroy_plan(plan_backward1) +- !call fftw_destroy_plan(plan_forward2) +- !call fftw_destroy_plan(plan_backward2) +- call fftw_free(cbuffer1) +- call fftw_free(cbuffer2) +- call fftw_mpi_cleanup() ++ call fftwf_destroy_plan(plan_forward1) ++ call fftwf_destroy_plan(plan_backward1) ++ !call fftwf_destroy_plan(plan_forward2) ++ !call fftwf_destroy_plan(plan_backward2) ++ call fftwf_free(cbuffer1) ++ call fftwf_free(cbuffer2) ++ call fftwf_mpi_cleanup() + deallocate(fft_resolution) + if(rank==0) close(21) + end subroutine cleanFFTW_2d + + subroutine fft2d_diagnostics(nbelem) + integer(C_INTPTR_T), intent(in) :: nbelem +- complex(C_DOUBLE_COMPLEX) :: memoryAllocated ++ complex(C_FLOAT_COMPLEX) :: memoryAllocated + memoryAllocated = real(nbelem*sizeof(memoryAllocated),mk)*1e-6 + write(*,'(a,i5,a,i12,f10.2)') '[',rank,'] size of each buffer (elements / memory in MB):', & + nbelem, memoryAllocated +@@ -499,10 +499,10 @@ contains + integer(C_INTPTR_T), dimension(2) :: n + + !> Field (real values) for fftw input +- real(C_DOUBLE), pointer :: rdatain1Many(:,:,:) ++ real(C_FLOAT), pointer :: rdatain1Many(:,:,:) + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + howmany = 1 + if(rank==0) open(unit=21,file=filename,form="formatted") + +@@ -514,12 +514,12 @@ contains + n(1) = fft_resolution(2) + n(2) = halfLength + ! allocate local buffer (used to save datain/dataout1 ==> in-place transform!!) +- alloc_local = fftw_mpi_local_size_many_transposed(2,n,howmany,FFTW_MPI_DEFAULT_BLOCK,& ++ alloc_local = fftwf_mpi_local_size_many_transposed(2,n,howmany,FFTW_MPI_DEFAULT_BLOCK,& + FFTW_MPI_DEFAULT_BLOCK,main_comm,local_resolution(c_Y),& + local_offset(c_Y),local_resolution(c_X),local_offset(c_X)); + + ! allocate local buffer (used to save datain/dataout1 ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) + + ! link rdatain1 and dataout1 to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, rdatain1Many, [howmany,2*halfLength,local_resolution(c_Y)]) +@@ -527,17 +527,17 @@ contains + + ! second buffer used for backward transform. Used to copy dataout1 into dataout2 (input for backward transform and filter) + ! and to save (in-place) the transform of the second component of the velocity +- cbuffer2 = fftw_alloc_complex(alloc_local) ++ cbuffer2 = fftwf_alloc_complex(alloc_local) + + call c_f_pointer(cbuffer2, rdatain1Many, [howmany,2*halfLength,local_resolution(c_Y)]) + call c_f_pointer(cbuffer2, dataout2, [fft_resolution(c_Y),local_resolution(c_X)]) + + ! create MPI plans for in-place forward/backward DFT (note dimension reversal) +- plan_forward1 = fftw_mpi_plan_dft_r2c_2d(fft_resolution(c_Y), fft_resolution(c_X), rdatain1Many, dataout1, & ++ plan_forward1 = fftwf_mpi_plan_dft_r2c_2d(fft_resolution(c_Y), fft_resolution(c_X), rdatain1Many, dataout1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & ++ plan_backward1 = fftwf_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_backward2 = fftw_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & ++ plan_backward2 = fftwf_mpi_plan_dft_c2r_2d(fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + + call computeKx(lengths(c_X)) +diff --git src/fftw/fft3d.f90 src/fftw/fft3d.f90 +index 1b06457..a857855 100755 +--- src/fftw/fft3d.f90 ++++ src/fftw/fft3d.f90 +@@ -40,15 +40,15 @@ module fft3d + type(C_PTR) :: cbuffer3 + !! Note Franck : check if local declarations of datain/out works and improve perfs. + !> Field (complex values) for fftw input +- complex(C_DOUBLE_COMPLEX), pointer :: datain1(:,:,:)=>NULL(), datain2(:,:,:)=>NULL(), datain3(:,:,:)=>NULL() ++ complex(C_FLOAT_COMPLEX), pointer :: datain1(:,:,:)=>NULL(), datain2(:,:,:)=>NULL(), datain3(:,:,:)=>NULL() + !> Field (real values) for fftw input (these are only pointers to the cbuffers) +- real(C_DOUBLE), pointer :: rdatain1(:,:,:)=>NULL() ,rdatain2(:,:,:)=>NULL() ,rdatain3(:,:,:)=>NULL() ++ real(C_FLOAT), pointer :: rdatain1(:,:,:)=>NULL() ,rdatain2(:,:,:)=>NULL() ,rdatain3(:,:,:)=>NULL() + !> Field (real values) for fftw input in the fftw-many case +- real(C_DOUBLE), pointer :: rdatain_many(:,:,:,:)=>NULL() ++ real(C_FLOAT), pointer :: rdatain_many(:,:,:,:)=>NULL() + !> Field (complex values) for fftw (forward) output +- complex(C_DOUBLE_COMPLEX), pointer :: dataout1(:,:,:)=>NULL() ,dataout2(:,:,:)=>NULL() ,dataout3(:,:,:)=>NULL() ++ complex(C_FLOAT_COMPLEX), pointer :: dataout1(:,:,:)=>NULL() ,dataout2(:,:,:)=>NULL() ,dataout3(:,:,:)=>NULL() + !> Field (complex values) for fftw (forward) output in the fftw-many case +- complex(C_DOUBLE_COMPLEX), pointer :: dataout_many(:,:,:,:)=>NULL() ++ complex(C_FLOAT_COMPLEX), pointer :: dataout_many(:,:,:,:)=>NULL() + !> GLOBAL number of points in each direction on which fft is applied (--> corresponds to "real" resolution - 1) + integer(C_INTPTR_T),pointer :: fft_resolution(:)=>NULL() + !> LOCAL number of points for fft +@@ -56,15 +56,15 @@ module fft3d + !> Offset in the direction of distribution + integer(c_INTPTR_T),dimension(3) :: local_offset + !> wave numbers for fft in x direction +- real(C_DOUBLE), pointer :: kx(:) ++ real(C_FLOAT), pointer :: kx(:) + !> wave numbers for fft in y direction +- real(C_DOUBLE), pointer :: ky(:) ++ real(C_FLOAT), pointer :: ky(:) + !> wave numbers for fft in z direction +- real(C_DOUBLE), pointer :: kz(:) ++ real(C_FLOAT), pointer :: kz(:) + !> log file for fftw + character(len=20),parameter :: filename ="parmesfftw.log" + !> normalization factor +- real(C_DOUBLE) :: normFFT ++ real(C_FLOAT) :: normFFT + !> true if we use fftw-many routines + logical :: manycase + !> true if all the allocation stuff for global variables has been done. +@@ -89,7 +89,7 @@ contains + if(is3DUpToDate) return + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + + if(rank==0) open(unit=21,file=filename,form="formatted") + +@@ -98,7 +98,7 @@ contains + fft_resolution(:) = resolution(:)-1 + + ! compute "optimal" size (according to fftw) for local data (warning : dimension reversal) +- alloc_local = fftw_mpi_local_size_3d_transposed(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),main_comm,& ++ alloc_local = fftwf_mpi_local_size_3d_transposed(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),main_comm,& + local_resolution(c_Z),local_offset(c_Z),local_resolution(c_Y),local_offset(c_Y)); + + ! Set a default value for c_X components. +@@ -106,35 +106,35 @@ contains + local_resolution(c_X) = fft_resolution(c_X) + + ! allocate local buffer (used to save datain/dataout ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) + ! link datain and dataout to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, datain1, [fft_resolution(c_X),fft_resolution(c_Y),local_resolution(c_Z)]) + call c_f_pointer(cbuffer1, dataout1, [fft_resolution(c_X),fft_resolution(c_Z),local_resolution(c_Y)]) + + ! second buffer used for backward transform. Used to copy dataout into dataout2 (input for backward transform and filter) + ! and to save (in-place) the transform of the second component of the velocity +- cbuffer2 = fftw_alloc_complex(alloc_local) ++ cbuffer2 = fftwf_alloc_complex(alloc_local) + call c_f_pointer(cbuffer2, datain2, [fft_resolution(c_X),fft_resolution(c_Y),local_resolution(c_Z)]) + call c_f_pointer(cbuffer2, dataout2, [fft_resolution(c_X),fft_resolution(c_Z),local_resolution(c_Y)]) + + ! second buffer used for backward transform. Used to copy dataout into dataout2 (input for backward transform and filter) + ! and to save (in-place) the transform of the second component of the velocity +- cbuffer3 = fftw_alloc_complex(alloc_local) ++ cbuffer3 = fftwf_alloc_complex(alloc_local) + call c_f_pointer(cbuffer3, datain3, [fft_resolution(c_X),fft_resolution(c_Y),local_resolution(c_Z)]) + call c_f_pointer(cbuffer3, dataout3, [fft_resolution(c_X),fft_resolution(c_Z),local_resolution(c_Y)]) + + ! create MPI plan for in-place forward/backward DFT (note dimension reversal) +- plan_forward1 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain1,dataout1,& ++ plan_forward1 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain1,dataout1,& + main_comm,FFTW_FORWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout1,datain1,& ++ plan_backward1 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout1,datain1,& + main_comm,FFTW_BACKWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_forward2 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain2,dataout2,& ++ plan_forward2 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain2,dataout2,& + main_comm,FFTW_FORWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward2 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout2,datain2,& ++ plan_backward2 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout2,datain2,& + main_comm,FFTW_BACKWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_forward3 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain3,dataout3,& ++ plan_forward3 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z), fft_resolution(c_Y), fft_resolution(c_X),datain3,dataout3,& + main_comm,FFTW_FORWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward3 = fftw_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout3,datain3,& ++ plan_backward3 = fftwf_mpi_plan_dft_3d(fft_resolution(c_Z),fft_resolution(c_Y),fft_resolution(c_X),dataout3,datain3,& + main_comm,FFTW_BACKWARD,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + + call computeKx(lengths(c_X)) +@@ -173,17 +173,17 @@ contains + end do + end do + ! compute transform (as many times as desired) +- call fftw_mpi_execute_dft(plan_forward1, datain1, dataout1) +- call fftw_mpi_execute_dft(plan_forward2, datain2, dataout2) +- call fftw_mpi_execute_dft(plan_forward3, datain3, dataout3) ++ call fftwf_mpi_execute_dft(plan_forward1, datain1, dataout1) ++ call fftwf_mpi_execute_dft(plan_forward2, datain2, dataout2) ++ call fftwf_mpi_execute_dft(plan_forward3, datain3, dataout3) + + ! apply poisson filter + call filter_poisson_3d() + + ! inverse transform to retrieve velocity +- call fftw_mpi_execute_dft(plan_backward1, dataout1,datain1) +- call fftw_mpi_execute_dft(plan_backward2,dataout2,datain2) +- call fftw_mpi_execute_dft(plan_backward3,dataout3,datain3) ++ call fftwf_mpi_execute_dft(plan_backward1, dataout1,datain1) ++ call fftwf_mpi_execute_dft(plan_backward2,dataout2,datain2) ++ call fftwf_mpi_execute_dft(plan_backward3,dataout3,datain3) + do k =1, local_resolution(c_Z) + do j = 1, fft_resolution(c_Y) + do i = 1, fft_resolution(c_X) +@@ -213,7 +213,7 @@ contains + if(is3DUpToDate) return + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + + if(rank==0) open(unit=21,file=filename,form="formatted") + allocate(fft_resolution(3)) +@@ -221,7 +221,7 @@ contains + halfLength = fft_resolution(c_X)/2+1 + + ! compute "optimal" size (according to fftw) for local data (warning : dimension reversal) +- alloc_local = fftw_mpi_local_size_3d_transposed(fft_resolution(c_Z),fft_resolution(c_Y),halfLength,& ++ alloc_local = fftwf_mpi_local_size_3d_transposed(fft_resolution(c_Z),fft_resolution(c_Y),halfLength,& + main_comm,local_resolution(c_Z),local_offset(c_Z),local_resolution(c_Y),local_offset(c_Y)); + + ! init c_X part. This is required to compute kx with the same function in 2d and 3d cases. +@@ -229,9 +229,9 @@ contains + local_resolution(c_X) = halfLength + + ! allocate local buffer (used to save datain/dataout ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) +- cbuffer2 = fftw_alloc_complex(alloc_local) +- cbuffer3 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) ++ cbuffer2 = fftwf_alloc_complex(alloc_local) ++ cbuffer3 = fftwf_alloc_complex(alloc_local) + + ! link rdatain and dataout to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, rdatain1, [2*halfLength,fft_resolution(c_Y),local_resolution(c_Z)]) +@@ -246,17 +246,17 @@ contains + rdatain3 = 0.0 + + ! create MPI plans for in-place forward/backward DFT (note dimension reversal) +- plan_forward1 = fftw_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain1, dataout1, & ++ plan_forward1 = fftwf_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain1, dataout1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & ++ plan_backward1 = fftwf_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout1, rdatain1, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_forward2 = fftw_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain2, dataout2, & ++ plan_forward2 = fftwf_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain2, dataout2, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward2 = fftw_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & ++ plan_backward2 = fftwf_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout2, rdatain2, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) +- plan_forward3 = fftw_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain3, dataout3, & ++ plan_forward3 = fftwf_mpi_plan_dft_r2c_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), rdatain3, dataout3, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward3 = fftw_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout3, rdatain3, & ++ plan_backward3 = fftwf_mpi_plan_dft_c2r_3d(fft_resolution(c_Z),fft_resolution(c_Y), fft_resolution(c_X), dataout3, rdatain3, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + + call computeKx(lengths(c_X)) +@@ -279,7 +279,7 @@ contains + + real(mk),dimension(:,:,:),intent(in) :: omega_x,omega_y,omega_z + integer, dimension(3), intent(in) :: ghosts +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k, ig, jg, kg + + ! ig, jg, kg are used to take into account +@@ -301,9 +301,9 @@ contains + + ! compute transforms for each component + start = MPI_WTIME() +- call fftw_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) +- call fftw_mpi_execute_dft_r2c(plan_forward2, rdatain2, dataout2) +- call fftw_mpi_execute_dft_r2c(plan_forward3, rdatain3, dataout3) ++ call fftwf_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) ++ call fftwf_mpi_execute_dft_r2c(plan_forward2, rdatain2, dataout2) ++ call fftwf_mpi_execute_dft_r2c(plan_forward3, rdatain3, dataout3) + !!print *, "r2c time = ", MPI_WTIME() - start + + end subroutine r2c_3d +@@ -316,12 +316,12 @@ contains + subroutine c2r_3d(velocity_x,velocity_y,velocity_z, ghosts) + real(mk),dimension(:,:,:),intent(inout) :: velocity_x,velocity_y,velocity_z + integer, dimension(3), intent(in) :: ghosts +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k, ig, jg, kg + start = MPI_WTIME() +- call fftw_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) +- call fftw_mpi_execute_dft_c2r(plan_backward2,dataout2,rdatain2) +- call fftw_mpi_execute_dft_c2r(plan_backward3,dataout3,rdatain3) ++ call fftwf_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) ++ call fftwf_mpi_execute_dft_c2r(plan_backward2,dataout2,rdatain2) ++ call fftwf_mpi_execute_dft_c2r(plan_backward3,dataout3,rdatain3) + !! print *, "c2r time : ", MPI_WTIME() -start + ! copy back to velocity and normalisation + do k =1, local_resolution(c_Z) +@@ -346,7 +346,7 @@ contains + + real(mk),dimension(:,:,:),intent(in) :: omega + integer, dimension(3), intent(in) :: ghosts +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k, ig, jg, kg + + ! ig, jg, kg are used to take into account +@@ -366,7 +366,7 @@ contains + + ! compute transforms for each component + start = MPI_WTIME() +- call fftw_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) ++ call fftwf_mpi_execute_dft_r2c(plan_forward1, rdatain1, dataout1) + !!print *, "r2c time = ", MPI_WTIME() - start + + end subroutine r2c_scalar_3d +@@ -377,10 +377,10 @@ contains + subroutine c2r_scalar_3d(omega, ghosts) + real(mk),dimension(:,:,:),intent(inout) :: omega + integer, dimension(3), intent(in) :: ghosts +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k, ig, jg, kg + start = MPI_WTIME() +- call fftw_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) ++ call fftwf_mpi_execute_dft_c2r(plan_backward1,dataout1,rdatain1) + !! print *, "c2r time : ", MPI_WTIME() -start + ! copy back to velocity and normalisation + do k =1, local_resolution(c_Z) +@@ -412,7 +412,7 @@ contains + integer(C_INTPTR_T),dimension(3) :: n + + ! init fftw mpi context +- call fftw_mpi_init() ++ call fftwf_mpi_init() + blocksize = FFTW_MPI_DEFAULT_BLOCK + if(rank==0) open(unit=21,file=filename,form="formatted") + allocate(fft_resolution(3)) +@@ -423,7 +423,7 @@ contains + n(3) = halfLength + howmany = 3 + ! compute "optimal" size (according to fftw) for local data (warning : dimension reversal) +- alloc_local = fftw_mpi_local_size_many_transposed(3,n,howmany,blocksize,blocksize,& ++ alloc_local = fftwf_mpi_local_size_many_transposed(3,n,howmany,blocksize,blocksize,& + main_comm,local_resolution(c_Z),local_offset(c_Z),local_resolution(c_Y),local_offset(c_Y)); + + ! init c_X part. This is required to compute kx with the same function in 2d and 3d cases. +@@ -431,7 +431,7 @@ contains + local_resolution(c_X) = halfLength + + ! allocate local buffer (used to save datain/dataout ==> in-place transform!!) +- cbuffer1 = fftw_alloc_complex(alloc_local) ++ cbuffer1 = fftwf_alloc_complex(alloc_local) + + ! link rdatain and dataout to cbuffer, setting the right dimensions for each + call c_f_pointer(cbuffer1, rdatain_many, [howmany,2*halfLength,fft_resolution(c_Y),local_resolution(c_Z)]) +@@ -440,9 +440,9 @@ contains + ! create MPI plans for in-place forward/backward DFT (note dimension reversal) + n(3) = fft_resolution(c_X) + +- plan_forward1 = fftw_mpi_plan_many_dft_r2c(3,n,howmany,blocksize,blocksize, rdatain_many, dataout_many, & ++ plan_forward1 = fftwf_mpi_plan_many_dft_r2c(3,n,howmany,blocksize,blocksize, rdatain_many, dataout_many, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_OUT)) +- plan_backward1 = fftw_mpi_plan_many_dft_c2r(3,n,howmany,blocksize,blocksize, dataout_many, rdatain_many, & ++ plan_backward1 = fftwf_mpi_plan_many_dft_c2r(3,n,howmany,blocksize,blocksize, dataout_many, rdatain_many, & + main_comm,ior(FFTW_MEASURE,FFTW_MPI_TRANSPOSED_IN)) + call computeKx(lengths(c_X)) + call computeKy(lengths(c_Y)) +@@ -464,7 +464,7 @@ contains + subroutine r2c_3d_many(omega_x,omega_y,omega_z) + + real(mk),dimension(:,:,:),intent(in) :: omega_x,omega_y,omega_z +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k + + ! init +@@ -480,7 +480,7 @@ contains + + ! compute transform (as many times as desired) + start = MPI_WTIME() +- call fftw_mpi_execute_dft_r2c(plan_forward1, rdatain_many, dataout_many) ++ call fftwf_mpi_execute_dft_r2c(plan_forward1, rdatain_many, dataout_many) + !! print *, "r2c time = ", MPI_WTIME() - start + + end subroutine r2c_3d_many +@@ -491,11 +491,11 @@ contains + !! @param[in,out] velocity_z 3d scalar field, z-component of the output vector field + subroutine c2r_3d_many(velocity_x,velocity_y,velocity_z) + real(mk),dimension(:,:,:),intent(inout) :: velocity_x,velocity_y,velocity_z +- real(mk) :: start ++ real(8) :: start + integer(C_INTPTR_T) :: i,j,k + + start = MPI_WTIME() +- call fftw_mpi_execute_dft_c2r(plan_backward1,dataout_many,rdatain_many) ++ call fftwf_mpi_execute_dft_c2r(plan_backward1,dataout_many,rdatain_many) + !! print *, "c2r time : ", MPI_WTIME() -start + do k =1, local_resolution(c_Z) + do j = 1, fft_resolution(c_Y) +@@ -536,7 +536,7 @@ contains + !> Computation of frequencies coeff, over distributed direction(s) + !> @param lengths size of the domain + subroutine computeKy(length) +- real(C_DOUBLE), intent(in) :: length ++ real(C_FLOAT), intent(in) :: length + + !! Local loops indices + integer(C_INTPTR_T) :: i +@@ -589,8 +589,8 @@ contains + subroutine filter_poisson_3d() + + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2 + + ! Set first coeff (check for "all freq = 0" case) + if(local_offset(c_Y) == 0) then +@@ -648,10 +648,10 @@ contains + !! @param[in] nudt \f$ \nu\times dt\f$, diffusion coefficient times current time step + subroutine filter_curl_diffusion_3d(nudt) + +- real(C_DOUBLE), intent(in) :: nudt ++ real(C_FLOAT), intent(in) :: nudt + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2 + + !! mind the transpose -> index inversion between y and z + do j = 1,local_resolution(c_Y) +@@ -674,9 +674,9 @@ contains + !! @param[in] nudt \f$ \nu\times dt\f$, diffusion coefficient times current time step + subroutine filter_diffusion_3d(nudt) + +- real(C_DOUBLE), intent(in) :: nudt ++ real(C_FLOAT), intent(in) :: nudt + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: coeff + + !! mind the transpose -> index inversion between y and z + do j = 1,local_resolution(c_Y) +@@ -697,8 +697,8 @@ contains + subroutine filter_curl_3d() + + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2 + + !! mind the transpose -> index inversion between y and z + do j = 1,local_resolution(c_Y) +@@ -721,8 +721,8 @@ contains + subroutine filter_projection_om_3d() + + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2,buffer3 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2,buffer3 + + ! Set first coeff (check for "all freq = 0" case) + if(local_offset(c_Y) == 0) then +@@ -783,9 +783,9 @@ contains + !! @param[in] dxf, dyf, dzf: grid filter size = domainLength/(CoarseRes-1) + subroutine filter_multires_om_3d(dxf, dyf, dzf) + +- real(C_DOUBLE), intent(in) :: dxf, dyf, dzf ++ real(C_FLOAT), intent(in) :: dxf, dyf, dzf + integer(C_INTPTR_T) :: i,j,k +- real(C_DOUBLE) :: kxc, kyc, kzc ++ real(C_FLOAT) :: kxc, kyc, kzc + + kxc = pi / dxf + kyc = pi / dyf +@@ -810,7 +810,7 @@ contains + !! pressure from velocity in the Fourier space + subroutine filter_pressure_3d() + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: coeff + + ! Set first coeff (check for "all freq = 0" case) + if(local_offset(c_Y) == 0) then +@@ -851,8 +851,8 @@ contains + subroutine filter_poisson_3d_many() + + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2 + + ! Set first coeff (check for "all freq = 0" case) + if(local_offset(c_Y) == 0) then +@@ -908,10 +908,10 @@ contains + !! @param[in] nudt \f$ \nu\times dt\f$, diffusion coefficient times current time step + subroutine filter_diffusion_3d_many(nudt) + +- real(C_DOUBLE), intent(in) :: nudt ++ real(C_FLOAT), intent(in) :: nudt + integer(C_INTPTR_T) :: i,j,k +- complex(C_DOUBLE_COMPLEX) :: coeff +- complex(C_DOUBLE_COMPLEX) :: buffer1,buffer2 ++ complex(C_FLOAT_COMPLEX) :: coeff ++ complex(C_FLOAT_COMPLEX) :: buffer1,buffer2 + + !! mind the transpose -> index inversion between y and z + do j = 1,local_resolution(c_Y) +@@ -931,18 +931,18 @@ contains + + !> Clean fftw context (free memory, plans ...) + subroutine cleanFFTW_3d() +- call fftw_destroy_plan(plan_forward1) +- call fftw_destroy_plan(plan_backward1) ++ call fftwf_destroy_plan(plan_forward1) ++ call fftwf_destroy_plan(plan_backward1) + if(.not.manycase) then +- call fftw_destroy_plan(plan_forward2) +- call fftw_destroy_plan(plan_backward2) +- call fftw_destroy_plan(plan_forward3) +- call fftw_destroy_plan(plan_backward3) +- call fftw_free(cbuffer2) +- call fftw_free(cbuffer3) ++ call fftwf_destroy_plan(plan_forward2) ++ call fftwf_destroy_plan(plan_backward2) ++ call fftwf_destroy_plan(plan_forward3) ++ call fftwf_destroy_plan(plan_backward3) ++ call fftwf_free(cbuffer2) ++ call fftwf_free(cbuffer3) + endif +- call fftw_free(cbuffer1) +- call fftw_mpi_cleanup() ++ call fftwf_free(cbuffer1) ++ call fftwf_mpi_cleanup() + deallocate(fft_resolution) + deallocate(kx,ky,kz) + if(rank==0) close(21) +@@ -953,7 +953,7 @@ contains + integer(C_INTPTR_T), intent(in) :: nbelem + ! number of buffers used for fftw + integer, optional,intent(in) :: howmany +- complex(C_DOUBLE_COMPLEX) :: memoryAllocated ++ complex(C_FLOAT_COMPLEX) :: memoryAllocated + + integer :: nbFields + if(present(howmany)) then +diff --git src/main/main.f90 src/main/main.f90 +index 38cc6a5..0fc8f5f 100755 +--- src/main/main.f90 ++++ src/main/main.f90 +@@ -9,7 +9,7 @@ use vectorcalculus + implicit none + + integer :: info +-real(mk) :: start, end ++real(8) :: start, end + + !complex(mk), dimension(resolution(1),resolution(2)) :: omega,velocity_x,velocity_y + call MPI_Init(info) +@@ -116,7 +116,8 @@ contains + real(mk),dimension(3) :: lengths,step + integer, dimension(3) :: ghosts_v, ghosts_w + integer(C_INTPTR_T),dimension(3) :: nfft,offset +- real(mk) :: error,start ++ real(mk) :: error ++ real(8) :: start + logical :: ok + + if (rank==0) print *, " ======= Test 3D Poisson (r2c) solver for resolution ", resolution +diff --git src/scalesInterface/precision_tools.f90 src/scalesInterface/precision_tools.f90 +index 5dacf3f..4ae1a6a 100644 +--- src/scalesInterface/precision_tools.f90 ++++ src/scalesInterface/precision_tools.f90 +@@ -20,15 +20,15 @@ + !------------------------------------------------------------------------------ + + MODULE precision_tools +- use mpi, only: MPI_DOUBLE_PRECISION ++ use mpi, only: MPI_REAL + implicit None + + !> Floats precision + INTEGER, PARAMETER :: SP = kind(1.0) + INTEGER, PARAMETER :: DP = kind(1.0d0) +- INTEGER, PARAMETER :: WP = DP ++ INTEGER, PARAMETER :: WP = SP + !> the MPI type for REAL exchanges in simple or double precision +- INTEGER, parameter :: MPI_REAL_WP = MPI_DOUBLE_PRECISION ++ INTEGER, parameter :: MPI_REAL_WP = MPI_REAL + REAL(WP), PRIVATE :: sample_real_at_WP + REAL(WP), PARAMETER :: MAX_REAL_WP = HUGE(sample_real_at_WP) + INTEGER, PRIVATE :: sample_int diff --git a/HySoP/hysop/domain/obstacle/__init__.py b/HySoP/hysop/domain/obstacle/__init__.py new file mode 100644 index 000000000..be5911bbc --- /dev/null +++ b/HySoP/hysop/domain/obstacle/__init__.py @@ -0,0 +1,57 @@ +## @package parmepy.domain.obstacle +# Obstacles description (geometry). +# +# +# An 'obstacle' is the description of a sub-domain +# of the main physical domain with one or more user-defined +# functions of the space coordinates (at least). +# +# What for? \n +# Mainly to provide some 'index sets' to penalization operator.\n +# For a given obstacle, and a given discrete field, we must be able to call: +# \code +# cond = obstacle.discretize(topo) +# field[cond] = 1.9 +# \endcode +# This example means that the field (discretized on topology topo) +# will be set to 1.9 everywhere inside the obstacle. +# +# +# Obviouslvy the index sets will depend on the discretization +# of the domain (the underlying topology indeed). +# So each obstacle handles a dictionnary of boolean arrays. The keys +# of the dictionnaries are the topologies and the values some boolean arrays +# which values are true on and inside the object and false outside. +# \code +# obstacle.ind[topo] = someBooleanArray +# \endcode +# Each component of the dictionnary is created using the method 'discretize': +# \code +# # Create the boolean array that represents the obstacle for topology topo: +# someBooleanArray = obstacle.discretize(topo) +# # So for a field already discretized on topo, we may call +# field[someBooleanArray] +# \endcode +# +# A more complete example : initialize a scalar field with one inside a sphere +# and zero everywhere else. +# +# \code +# Lx = Ly = Lz = 2 +# dom = pp.Box(dimension=3, length=[Lx, Ly, Lz], origin=[-1., -1., -1.]) +# # Definition of a sphere in the middle of the domain +# sphere = Sphere(dom, position=[0., 0., 0.], radius=0.5) +# # A topology +# topo = Cartesian(dom, 3, [33, 33, 33]) +# # A scalar field on the domain : +# scal = pp.Field(domain=dom, name='Scalar') +# # Discretization on topo: +# scal_discr = scal.discretize(topo) +# # scal set to 1. inside the obstacle: +# condition = sphere.discretize(topo) +# scal.discreteFields[topo][condition] = 1. +# # equivalent to +# scal_discr[condition] = 1. +# # to set a value everywhere except in the sphere +# scal_discr[not condition] = 8. +# \endcode diff --git a/HySoP/hysop/domain/obstacle/controlBox.py b/HySoP/hysop/domain/obstacle/controlBox.py new file mode 100644 index 000000000..9e5c7cc24 --- /dev/null +++ b/HySoP/hysop/domain/obstacle/controlBox.py @@ -0,0 +1,296 @@ +""" +@file controlBox.py +Define a sub-domain with a box-liked shape. +""" +from parmepy.domain.obstacle.obstacle import Obstacle +from parmepy.domain.obstacle.planes import SubSpace, SubPlane +from parmepy.mpi.mesh import SubMesh +import numpy as np +import parmepy.tools.numpywrappers as npw + + +class ControlBox(Obstacle): + """ + Build a sub-domain, box-shaped + ==> define set of indices inside this domain (ind member) + and set of indices belonging to surfaces of this domain (slices members). + Useful to define control volume to perform integration. + See for example parmepy.operator.monitor.forces + """ + + def __init__(self, origin, lengths, **kwds): + """ + Build the volume of control + @param origin : coordinates of the lowest point in the sub-domain + @param lengths : lengths of box sides. + """ + super(ControlBox, self).__init__(**kwds) + + ## Lowest point of the box + self.origin = npw.realarray(origin) + ## Box's sides dimension + self.lengths = npw.realarray(lengths) + ## Dictionnary of local meshes, such that + ## mesh[topo] is the restriction of topo.mesh + ## to the current control box. + self.mesh = {} + self.upper = None + self.lower = None + self.upperS = None + self.lowerS = None + self.slices = {} + self.indReduced = {} + self._boxCreated = False + ## Check if the defined box contains points + ## for a given topology. self.isEmpty[topo] = False + ## if some grid points are inside the box on + ## the current processor for topo discretization. + self.isEmpty = {} + ## Dict of local coordinates for a given topology + self.coords = {} + ## Global resolution of the obstacle (plane, sub space ...) + ## At the time, it's computed only for subspaces, by calling + ## globalResolution method. + self.gRes = None + ## Global index in the original topology of the 'lowest' point + ## of the obstacle. Only for subspaces. + self.gstart = None + + def createVolumeAndSides(self, spaceStep): + """ + @param[in] array of size self._dim, space step size in each direction + This value will be used to compute a tolerance and detect + points inside the box. + """ + # Build Half-spaces indices list in all directions + normalUp = np.identity(self._dim) + normalDown = np.identity(self._dim) * -1. + pointsUp = npw.zeros((self._dim, self._dim)) + # Control box will be used for integration, so we remove the + # last point in the grid. + boxlengths = self.lengths - spaceStep + tol = spaceStep * 0.5 + + for i in xrange(self._dim): + pointsUp[:, i] = self.origin + pointsUp.flat[::self._dim + 1] += self.lengths + # -- Control volume : union of two halfspaces -- + if self.upper is None: + self.upper = [SubSpace(domain=self.domain, normal=normalUp[:, i], + point=pointsUp[:, i], + lengths=boxlengths, + epsilon=tol[i]) + for i in xrange(self._dim)] + if self.lower is None: + self.lower = [SubSpace(domain=self.domain, normal=normalDown[:, i], + point=self.origin, lengths=boxlengths, + epsilon=tol[i]) + for i in xrange(self._dim)] + + # Create objects to describe the sides of the box + if self.upperS is None: + self.upperS = [SubPlane(domain=self.domain, normal=normalUp[:, i], + point=pointsUp[:, i], + lengths=boxlengths, + epsilon=tol[i]) + for i in xrange(self._dim)] + + if self.lowerS is None: + self.lowerS = [SubPlane(domain=self.domain, normal=normalDown[:, i], + point=self.origin, lengths=boxlengths, + epsilon=tol[i]) + for i in xrange(self._dim)] + self._boxCreated = True + + def discretize(self, topo): + """ + Discretize the box volume and its surfaces. + @param topo : the topology that described the discretization. + """ + # Check if already done. If so, this function has no effect. + if topo not in self.ind.keys(): + spaceStep = topo.mesh.space_step + # -- Control volume : union of two halfspaces -- + if not self._boxCreated: + self.createVolumeAndSides(spaceStep) + + # Discretize all volume and surfaces of + # the box for topo + for i in xrange(self._dim): + self.lower[i].discretize(topo) + self.upper[i].discretize(topo) + self.lowerS[i].discretize(topo) + self.upperS[i].discretize(topo) + + # 1 -- Compute list of indices inside the box, + # for topo --> ind[topo] + self.ind[topo] = [] + + self.ind[topo].append(np.logical_and(self.upper[0].ind[topo][0], + self.lower[0].ind[topo][0])) + for i in xrange(1, self._dim): + cond = np.logical_and(self.upper[i].ind[topo][0], + self.lower[i].ind[topo][0]) + self.ind[topo][0] = np.logical_and(self.ind[topo][0], cond) + + ind = np.where(self.ind[topo][0]) + + # 2 -- Convert ind[topo] (array of bool) to slices + # which may be more convenient for computations + # --> slices[topo] + # + mesh[topo], a parmepy.mpi.SubMesh, useful + # to get local coordinates and so on + if ind[0].size == 0: + self.slices[topo] = [slice(0, 0) for i in xrange(self._dim)] + self.mesh[topo] = None + self.isEmpty[topo] = True + else: + self.isEmpty[topo] = False + ic = topo.mesh.iCompute + lstart = [ind[i].min() if ind[i].size > 0 else None + for i in xrange(self._dim)] + lstart = npw.integerarray([max(lstart[i], ic[i].start) + for i in xrange(self._dim)]) + end = [ind[i].max() for i in xrange(self._dim)] + end = npw.integerarray([min(end[i], ic[i].stop - 1) + for i in xrange(self._dim)]) + # slice(start,end) --> end not included, so +1 + end += 1 + resol = end - lstart + 2 * topo.ghosts + gstart = lstart + topo.mesh.global_start - topo.ghosts + self.mesh[topo] = SubMesh(topo, gstart, resol) + self.slices[topo] = [slice(lstart[i], end[i]) + for i in xrange(self._dim)] + coords = [] + for i in xrange(self._dim): + cc = topo.mesh.coords[i].flat[self.slices[topo][i]] + coords.append(cc) + coords = tuple(coords) + self.coords[topo] = np.ix_(*coords) + + # --> self.ind[topo][0] components are True + # for points inside the volume + # --> self.slices[topo] represent the same thing + # but using slices of numpy arrays. + # Usage (vd being a numpy array discretized + # on the whole domain, cb a control box): + # # Set values to all points inside the control box + # vd[cb.ind[topo][0]] = ... + # # Get a sub-array of vd representing the control box + # # and use it + # result[...] = vd[cb.slices] + ... + # The important difference between slices and ind is: + # 1 - vd[ind] returns a 1D array whatever vd shape is. + # 2 - vd[slices] return an array of the same dim as vd, + # with shape given by slices. + + return self.ind[topo] + + def sub(self, obstacle, topo): + """ + Remove all points corresponding to the input obstacle from + the current control box + """ + if topo not in self.ind.keys(): + obstacle.discretize(topo) + self.discretize(topo) + self.indReduced[topo] = [] + # Warning : obstacle may have several layers + cond = obstacle.ind[topo][0] + for i in xrange(1, len(obstacle.ind[topo])): + cond = npw.asarray(np.logical_or(cond, obstacle.ind[topo][i])) + cond = np.logical_not(cond) + self.indReduced[topo].append(np.logical_and(self.ind[topo][0], + cond)) + return self.indReduced[topo][-1] + + def integrate_on_proc(self, field, topo, useSlice=True, component=0): + """ + integrate field on the box + """ + if useSlice: + cond = self.slices[topo] + else: + iC = topo.mesh.iCompute + cond = self.ind[topo][0][iC] + dvol = npw.prod(topo.mesh.space_step) + result = npw.sum(field.discretize(topo)[component][cond]) + result *= dvol + return result + + def integrate(self, field, topo, useSlice=True, + component=0, root=0, mpiall=True): + res = self.integrate_on_proc(field, topo, useSlice, component) + if mpiall: + return topo.comm.allreduce(res) + else: + return topo.comm.reduce(res, root=root) + + def integrateOnSurface(self, field, topo, normalDir=0, up=True, + useSlice=True, component=0, root=0, mpiall=True): + """ + integrate field on top (if up is True) or down surface + normal to a direction + """ + res = self.integrateOnSurf_proc(field, topo, normalDir, up, useSlice, + component) + if mpiall: + return topo.comm.allreduce(res) + else: + return topo.comm.reduce(res, root=root) + + def integrateOnSurf_proc(self, field, topo, normalDir=0, + up=True, useSlice=True, component=0): + """ + integrate field on top and down surfaces normal to a direction + """ + if up: + surf = self.upperS[normalDir] + else: + surf = self.lowerS[normalDir] + if useSlice: + cond = surf.slices[topo] + else: + iC = topo.mesh.iCompute + cond = surf.ind[topo][0][iC] + dirs = np.logical_not(np.arange(self._dim) == normalDir) + dS = npw.prod(topo.mesh.space_step[dirs]) + result = npw.sum(field.discretize(topo)[component][cond]) + result *= dS + return result + + def globalResolution(self, parent_topo): + """ + Compute 'global resolution' of the subplane + """ + # We create a false topology, with only one proc + # to get the global resolution for the plane. + # This could also be done with local computation + # sum but that would need a lot of communications. + if parent_topo.rank == 0: + color = 0 + else: + color = 1 + subcomm = parent_topo.comm.Split(color) + dimension = self.domain.dimension + tmp = None + if parent_topo.rank == 0: + resolution = parent_topo.globalMeshResolution + ghosts = parent_topo.ghosts + topo = self.domain.getOrCreateTopology(3, resolution, + ghosts=ghosts, comm=subcomm) + self.discretize(topo) + sl = self.slices[topo] + self.gRes = [sl[i].stop - sl[i].start for i in xrange(dimension)] + self.gstart = [sl[i].start for i in xrange(dimension)] + # if the topology has been created just to + # get the global resolution, we can remove it + if topo.isNew: + self.domain.remove(topo) + self.slices.pop(topo) + self.ind.pop(topo) + tmp = self.gRes + self.gstart + tmp = parent_topo.comm.bcast(tmp) + self.gRes = tmp[:dimension] + self.gstart = tmp[dimension:] + return self.gRes diff --git a/HySoP/hysop/domain/obstacle/disk.py b/HySoP/hysop/domain/obstacle/disk.py new file mode 100644 index 000000000..f57cbcc92 --- /dev/null +++ b/HySoP/hysop/domain/obstacle/disk.py @@ -0,0 +1,64 @@ +""" +@file disk.py +Rigid disk (2D) +""" +from parmepy.domain.obstacle.sphere import Sphere, HemiSphere +import numpy as np +import parmepy.tools.numpywrappers as npw + + +class Disk(Sphere): + """ + Disk in a 2D domain. + """ + + def __init__(self, **kwds): + """ + Description of a disk in a domain. + @param domain : the physical domain that contains the sphere. + @param position : position of the center + @param radius : sphere radius, default = 1 + @param porousLayers : a list of thicknesses + for successive porous layers + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. + @param vd : velocity of the disk (considered as a rigid body), + default = 0. + """ + super(Disk, self).__init__(**kwds) + assert self.domain.dimension == 2 + + def dist(x, y, R): + return npw.asarray(np.sqrt((x - self.position[0]) ** 2 + + (y - self.position[1]) ** 2) - R) + self.chi = [dist] + + +class HalfDisk(HemiSphere): + """ + Half disk in a 2D domain. + """ + def __init__(self, **kwds): + """ + Constructor for the semi-disk. + @param domain : the physical domain that contains the sphere. + @param position : position of the center + @param radius : sphere radius, default = 1 + (if box ...) + @param vd : velocity of the disk (considered as a rigid body), + default = 0. + """ + super(HalfDisk, self).__init__(**kwds) + assert self.domain.dimension == 2 + + def dist(x, y, R): + """ + """ + return npw.asarray(np.sqrt((x - self.position[0]) ** 2 + + (y - self.position[1]) ** 2) - R) + self.chi = [dist] + + def LeftBox(x, y): + return x - self.position[0] + + self.LeftBox = LeftBox diff --git a/HySoP/hysop/domain/obstacle/obstacle.py b/HySoP/hysop/domain/obstacle/obstacle.py new file mode 100644 index 000000000..c052ed7aa --- /dev/null +++ b/HySoP/hysop/domain/obstacle/obstacle.py @@ -0,0 +1,96 @@ +"""@file obstacle.py + +General interface to define a new geometry +inside a domain (sphere, control box ...) +""" +import numpy as np + + +class Obstacle(object): + """Ddescription of a physical obstacle. + An obstacle is the geometrical description of + a physical sub-domain. + """ + def __init__(self, domain, formula=None, vd=0.0): + """ Constructor + @param domain : the domain that contains this obstacle. + @param formula : a list of functions that describe + the geometry of the obstacle. + @param vd : velocity of the obstacle (considered as a rigid body), + default = 0. + """ + ## Domain. + self.domain = domain + from parmepy.domain.box import Box + assert isinstance(domain, Box),\ + 'Obstacle only implemented for box-like domains' + ## Obstacle dimension. + self._dim = domain.dimension + ## A function that describe the geometry of the obstacle. + ## see parmepy.domain.obstacle. + self.chi = [] + if formula is not None: + if isinstance(formula, list): + for func in formula: + self.chi.append = np.vectorize(func) + else: + self.chi = [np.vectorize(formula)] + ## A dictionnary of lists of indices ... + ## ind[topo][i] represents the set of points of the domain + ## discretized with topo that are in the area defined with chi[i]. + self.ind = {} + ## Velocity of the center of mass of the obstacle + ## (considered as a rigid body) + self.vd = vd + ## Check if some grid points are present inside the current object + ## for the current mpi proc. If not, isEmpty[topo] = True. + self.isEmpty = {} + + + def discretize(self, topo): + """ + For a given topology, computes the list of points in the domain + that belongs to the obstacle. + Add a new index into self.indices. + @param topo : topology specification for discretization + @return an array of bool such that array[i,j,k] = True if + point(i,j,k) is in the obstacle. + + Note FP : there are two ways to 'save' which points are + in the obstacle : either we set a test function and + fill a boolean numpy array (case A) or we compute domain.dimension + lists of indice (B). + - case A : indices[topo] is a numpy array of the same + size as topo.mesh. + +++ : very fast to compute, very fast to apply + --- : needs more memory (size of bool * topo.mesh.size) + - case B : indices[topo] is a tupple of lists, like (ix, iy, iz). + A point inside the obstacle is thus given + by the indices ix[i], iy[i], iz[i] + +++ : needs less memory + --- : very slow to compute/apply compared to case A + Default choice = case A + \todo : provide a way for user to choose between case A and B. + Note FP 2: maybe that would be better to save indices in + operator (penalization) and not in obstacle, to save memory? + """ + # first check if we have already compute indices for + # this topology + if topo not in self.ind[0].keys(): + # for each indicator function + self.ind[topo] = [] + for func in self.chi: + # current function position + i = self.chi.index(func) + # apply indicator function on local mesh for the required topo + self.ind[topo].append(self.chi[i](*topo.mesh.coords) <= 0) + + return self.ind[topo] + + def _isempty(self, topo): + ilist = np.where(self.ind[topo]) + if ilist[0].size == 0: + self.isEmpty[topo] = True + else: + self.isEmpty[topo] = False + diff --git a/HySoP/hysop/domain/obstacle/planes.py b/HySoP/hysop/domain/obstacle/planes.py new file mode 100644 index 000000000..9d86e4553 --- /dev/null +++ b/HySoP/hysop/domain/obstacle/planes.py @@ -0,0 +1,359 @@ +""" +@file planes.py +Plate-like sub-domains at boundaries, normal +to a given direction. +""" +from parmepy.domain.obstacle.obstacle import Obstacle +import numpy as np +import parmepy.tools.numpywrappers as npw + + +class HalfSpace(Obstacle): + """ + Divide domain into two sub-spaces, on each side of a plane + defined by its normal and a point. + Indices of this.ind describe the half-space below the plane, + 'normal' being the outward normal of the plane. + """ + + def __init__(self, normal, point, epsilon=1e-2, **kwds): + """ + Half space define by the points of the domain on one side + of a plane. + @param domain : the physical domain that contains the plane + @param normal : outward normal + @param point : coordinates of a point of the plane. + @param epsilon : tolerance + """ + super(HalfSpace, self).__init__(**kwds) + assert epsilon > 0.0, 'Tolerance value must be positive' + ## Tolerance used to considered that points at the boundary are + ## in the subspace. Good choice may be grid space_step / 2. + self.epsilon = epsilon + ## Direction of the normal to the plate (0:x, 1:y, 2:z)) + ## normal is the 'outer' normal of the 'in' subspace. + self.normal = npw.integerarray(normal) + self.point = point + self.origin = npw.realarray(point) + + def Outside(*coords): + return sum([(coords[i] - self.point[i]) * self.normal[i] + for i in xrange(self.domain.dimension)]) + + ## Test function for half-space. + ## Positive value if outside subdomain else negative + self.chi = [Outside] + self.slices = {} + ## Global resolution of the obstacle (plane, sub space ...) + ## At the time, it's computed only for subspaces, by calling + ## globalResolution method. + self.gRes = None + ## Global index in the original topology of the 'lowest' point + ## of the obstacle. Only for subspaces. + self.gstart = None + + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + + if topo not in self.ind.keys(): + self.ind[topo] = [] + # apply indicator function on topo local mesh + cond = npw.asarray(self.chi[0](*topo.mesh.coords) <= self.epsilon) + self.ind[topo].append(cond) + self._isempty(topo) + return self.ind[topo] + + def __str__(self): + s = 'Plane normal to vector' + str(self.normal) + s += ' going through point ' + str(self.point) + return s + + +class Plane(HalfSpace): + """ + A plane in the domain, defined by its normal and a point. + Indices of plane.ind describe the points belonging to the plane. + """ + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + + if topo not in self.ind.keys(): + self.ind[topo] = [] + # apply indicator function on topo local mesh + cond = npw.abs(self.chi[0](*topo.mesh.coords)) < self.epsilon + self.ind[topo].append(cond) + self._isempty(topo) + + # assert that the plane is a real surface, i.e. + # only one value for coords[normalDir]. + # The expr is a bit tricky but it works ... + ndir = np.where(self.normal != 0)[0][0] + assert assertSubPlane(ndir, self.ind[topo][0], *topo.mesh.coords),\ + 'Your plane is not a surface but a volume.\ + Please reduce epsilon value.' + + return self.ind[topo] + + +class SubSpace(HalfSpace): + """ + Define a rectangular space in a plane normal to one + coord. axis and the subspace below this suface. + 'Below' = direction opposite to the outward normal of the plane + (input param) + """ + def __init__(self, lengths, **kwds): + """ + @param domain : the physical domain that contains the space + @param normal : outward normal + @param point : coordinates of a point of the plane. + @param lengths : lengths of the subplane + @param epsilon : tolerance + @param vd : velocity of the obstacle (considered as a rigid body), + default = 0. + """ + super(SubSpace, self).__init__(**kwds) + + def dist(cdir, val, *coords): + return coords[cdir] - val + + self.dist = dist + self.max = self.origin + npw.realarray(lengths) + self.lengths = npw.realarray(lengths) + ndir = np.where(self.normal != 0)[0][0] + if self.normal[ndir] > 0: + self.max[ndir] = self.origin[ndir] + elif self.normal[ndir] < 0: + self.max[ndir] = self.domain.max[ndir] + # Only implemented for planes orthogonal to coord. axes + assert len(self.normal[self.normal == 0]) == self.domain.dimension - 1 + self.coords = {} + + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + condMax = [0] * self.domain.dimension + condMin = [0] * self.domain.dimension + if topo not in self.ind.keys(): + self.ind[topo] = [] + # apply indicator function on topo local mesh + coords = topo.mesh.coords + cond = npw.asarray(self.chi[0](*coords) < self.epsilon) + indices = np.where(self.normal == 0)[0] + + for i in indices: + condMax[i] = self.dist(i, self.max[i], *coords) < self.epsilon + condMin[i] = self.dist(i, self.origin[i], *coords) > - self.epsilon + condMin[i] = np.logical_and(condMax[i], condMin[i]) + cond = npw.asarray(np.logical_and(cond, condMin[i])) + + self.ind[topo].append(cond) + self._isempty(topo) + return self.ind[topo] + + +class SubPlane(SubSpace): + """ + Define a rectangular surf in a plane normal to one + coord. axis. + """ + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + dim = self.domain.dimension + condMax = [0] * dim + condMin = [0] * dim + if topo not in self.ind.keys(): + self.ind[topo] = [] + # apply indicator function on topo local mesh + coords = topo.mesh.coords + cond = npw.abs(self.chi[0](*coords)) < self.epsilon + indices = np.where(self.normal == 0)[0] + for i in indices: + condMax[i] = self.dist(i, self.max[i], *coords) < self.epsilon + condMin[i] = self.dist(i, self.origin[i], *coords) > -self.epsilon + condMin[i] = np.logical_and(condMax[i], condMin[i]) + cond = npw.asarray(np.logical_and(cond, condMin[i])) + + self.ind[topo].append(cond) + ilist = np.where(cond) + if ilist[0].size == 0: + self.slices[topo] = [slice(0, 0) for i in xrange(dim)] + self.isEmpty[topo] = True + else: + self.isEmpty[topo] = False + start = [ilist[i].min() for i in xrange(dim)] + # Ghost points must not be included into surf. points + ic = topo.mesh.iCompute + start = [max(start[i], ic[i].start) for i in xrange(dim)] + end = [ilist[i].max() for i in xrange(dim)] + end = npw.integerarray([min(end[i], ic[i].stop - 1) + for i in xrange(dim)]) + end += 1 + ndir = np.where(self.normal != 0)[0][0] + end[ndir] = start[ndir] + 1 + self.slices[topo] = [slice(start[i], end[i]) + for i in xrange(dim)] + assert assertSubPlane(ndir, cond, *topo.mesh.coords),\ + 'Your plane is not a surface but a volume.\ + Please reduce epsilon value.' + subcoords = [] + # !! Warning : slices will be used for integration, + # so the last point in each dir is not included. + # Same thing for coords. + for i in xrange(dim): + subcoords.append(coords[i].flat[self.slices[topo][i]]) + subcoords = tuple(subcoords) + self.coords[topo] = np.ix_(*subcoords) + return self.ind[topo] + + def globalResolution(self, parent_topo): + """ + Compute 'global resolution' of the subplane + """ + # We create a false topology, with only one proc + # to get the global resolution for the plane. + # This could also be done with local computation + # sum but that would need a lot of communications. + if parent_topo.rank == 0: + color = 0 + else: + color = 1 + subcomm = parent_topo.comm.Split(color) + dimension = self.domain.dimension + tmp = None + if parent_topo.rank == 0: + resolution = parent_topo.globalMeshResolution + ghosts = parent_topo.ghosts + topo = self.domain.getOrCreateTopology(3, resolution, + ghosts=ghosts, comm=subcomm) + self.discretize(topo) + sl = self.slices[topo] + self.gRes = [sl[i].stop - sl[i].start for i in xrange(dimension)] + self.gstart = [sl[i].start for i in xrange(dimension)] + # if the topology has been created just to + # get the global resolution, we can remove it + if topo.isNew: + self.domain.remove(topo) + self.slices.pop(topo) + self.ind.pop(topo) + tmp = self.gRes + self.gstart + tmp = parent_topo.comm.bcast(tmp) + self.gRes = tmp[:dimension] + self.gstart = tmp[dimension:] + return self.gRes + + +class PlaneBoundaries(Obstacle): + """ + Defines top and down (meaning for min and max value in + a given direction) planes at boundaries. + All points in the spaces above the top plane and below the down plane + will be included in the PlaneBoundaries list of indices. + Thickness of the top/down areas is given as an input param. + Example for z dir: + \f$ \{x,y,z\} \ for \ z_{max} - \epsilon \leq z \leq z_{max} + \epsilon + \ or \ z_{min} - \epsilon \leq z \leq z_{min}\f$ + """ + + def __init__(self, normal_dir, thickness=0.1, **kwds): + """ + Description of a sphere in a domain. + @param domain : the physical domain that contains the sphere. + @param thickness : thickness of boundary areas + @param vd : velocity of obstacle (considered as a rigid body), + default = 0. + """ + super(PlaneBoundaries, self).__init__(**kwds) + assert thickness > 0.0, 'Plate thickness must be positive' + ## Thickness/2 + self.thickness = thickness + ## Direction of the normal to the plate (0:x, 1:y, 2:z)) + normalUp = np.zeros((self.domain.dimension)) + normalUp[normal_dir] = -1 + pointUp = npw.zeros((self.domain.dimension)) + pointUp[normal_dir] = self.domain.max[normal_dir] - thickness + self.upper = HalfSpace(domain=self.domain, normal=normalUp, point=pointUp, + epsilon=1e-3) + normalDown = np.zeros((self.domain.dimension)) + normalDown[normal_dir] = 1 + pointDown = npw.zeros((self.domain.dimension)) + pointDown[normal_dir] = self.domain.origin[normal_dir] + thickness + self.lower = HalfSpace(domain=self.domain, normal=normalDown, + point=pointDown, epsilon=1e-3) + + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + + self.lower.discretize(topo) + self.upper.discretize(topo) + if topo not in self.ind.keys(): + # Warning FP : ind[topo] must be a list to be coherent + # with sphere definition, where porous layers are allowed. + # todo if required : add porous layers for planes. + self.ind[topo] = [] + self.ind[topo].append(np.logical_or(self.upper.ind[topo][0], + self.lower.ind[topo][0])) + self._isempty(topo) + return self.ind[topo] + + +def assertSubPlane(ndir, ind, *coords): + dim = len(coords) + if dim == 2: + return assertline(ndir, ind, *coords) + elif dim == 3: + return assertsurface(ndir, ind, *coords) + + +def assertsurface(nd, ind, *coords): + + dim = len(coords) + shape = np.zeros(dim, dtype=np.int32) + shape[:] = [coords[i].shape[i] for i in xrange(dim)] + cshape = coords[nd].shape + if nd == 0: + return max([a.max() - a.min() + for a in [coords[nd][ind[:, i, j]] + for i in xrange(shape[1]) + for j in xrange(shape[2]) + if coords[nd][ind[:, i, j]].size + > 0]] + [0]) == 0. + elif nd == 1: + return max([a.max() - a.min() + for a in [coords[nd][ind[i, :, j].reshape(cshape)] + for i in xrange(shape[0]) + for j in xrange(shape[2]) + if coords[nd][ind[i, :, j].reshape(cshape)].size + > 0]] + [0]) == 0. + + else: + return max([a.max() - a.min() + for a in [coords[nd][ind[i, j, :].reshape(cshape)] + for i in xrange(shape[0]) + for j in xrange(shape[1]) + if coords[nd][ind[i, j, :].reshape(cshape)].size + > 0]] + [0]) == 0. + + +def assertline(nd, ind, *coords): + + dim = len(coords) + shape = np.zeros(dim, dtype=np.int32) + shape[:] = [coords[i].shape[i] for i in xrange(dim)] + cshape = coords[nd].shape + if nd == 0: + return max([a.max() - a.min() + for a in [coords[nd][ind[:, i]] + for i in xrange(shape[1]) + if coords[nd][ind[:, i]].size + > 0]] + [0]) == 0. + elif nd == 1: + return max([a.max() - a.min() + for a in [coords[nd][ind[i, :].reshape(cshape)] + for i in xrange(shape[0]) + if coords[nd][ind[i, :].reshape(cshape)].size + > 0]] + [0]) == 0. diff --git a/HySoP/hysop/domain/obstacle/sphere.py b/HySoP/hysop/domain/obstacle/sphere.py new file mode 100644 index 000000000..1bb0d62c7 --- /dev/null +++ b/HySoP/hysop/domain/obstacle/sphere.py @@ -0,0 +1,132 @@ +""" +@file sphere.py +Spherical or hemispherical sub-domain. +""" +from parmepy.domain.obstacle.obstacle import Obstacle +import numpy as np +import parmepy.tools.numpywrappers as npw + + +class Sphere(Obstacle): + """ + Spherical domain. + """ + + def __init__(self, position, radius=1.0, porousLayers=None, **kwds): + """ + Description of a sphere in a domain. + @param domain : the physical domain that contains the sphere. + @param position : position of the center + @param radius : sphere radius, default = 1 + @param porousLayers : a list of thicknesses + for successive porous layers + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. + @param vd : velocity of the sphere (considered as a rigid body), + default = 0. + """ + super(Sphere, self).__init__(**kwds) + + ## Radius of the sphere + self.radius = radius + ## Center position + self.position = np.asarray(position) + + def dist(x, y, z, R): + """ + """ + return npw.asarray(np.sqrt((x - self.position[0]) ** 2 + + (y - self.position[1]) ** 2 + + (z - self.position[2]) ** 2) - R) + + self.chi = [dist] + ## List of thicknesses for porous layers + if porousLayers is None: + porousLayers = [] + self.layers = porousLayers + + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + + if topo not in self.ind.keys(): + currentRadius = self.radius + self.ind[topo] = [] + # First, internal sphere + args = (currentRadius,) + self.ind[topo].append(self.chi[0](*(topo.mesh.coords + args)) <= 0) + # Then each layer from inside to outside + # for each indicator function + for thickness in self.layers: + # apply indicator function on topo local mesh + args = (currentRadius,) + condA = self.chi[0](*(topo.mesh.coords + args)) > 0 + args = (currentRadius + thickness,) + condB = self.chi[0](*(topo.mesh.coords + args)) <= 0 + self.ind[topo].append(np.logical_and(condA, condB)) + # update current radius + currentRadius = currentRadius + thickness + self._isempty(topo) + return self.ind[topo] + + def __str__(self): + """ToString method""" + s = self.__class__.__name__ + ' of radius ' + str(self.radius) + s += ' and center position ' + str(self.position) + return s + + +class HemiSphere(Sphere): + """ + HemiSpherical domain. + Area defined by the intersection of a sphere and the volume where + x < xs for xs == x position of the center of the sphere. + """ + def __init__(self, **kwds): + """ + Description of a sphere in a domain. + @param domain : the physical domain that contains the sphere. + @param position : position of the center + @param radius : sphere radius, default = 1 + @param porousLayers : a list of thicknesses + for successive porous layers + radius is the inside sphere radius and thicknesses are given from + inside layer to outside one. + @param vd : velocity of the sphere (considered as a rigid body), + default = 0. + """ + super(HemiSphere, self).__init__(**kwds) + + def LeftBox(x, y, z): + return x - self.position[0] + self.LeftBox = LeftBox + + def discretize(self, topo): + # first check if we have already compute indices for + # this topology + if topo not in self.ind.keys(): + currentRadius = self.radius + self.ind[topo] = [] + # check if we are in the left half-box + cond0 = self.LeftBox(*(topo.mesh.coords)) <= 0 + # First, internal sphere + args = (currentRadius,) + condA = self.chi[0](*(topo.mesh.coords + args)) <= 0 + self.ind[topo].append(np.logical_and(condA, cond0)) + # Then each layer from inside to outside + # for each indicator function + for thickness in self.layers: + # apply indicator function on topo local mesh + args = (currentRadius,) + condA = self.chi[0](*(topo.mesh.coords + args)) > 0 + args = (currentRadius + thickness,) + condB = self.chi[0](*(topo.mesh.coords + args)) <= 0 + np.logical_and(condA, condB, condA) + np.logical_and(condA, cond0, condA) + condA = npw.asarray(condA) + self.ind[topo].append(condA) + # update current radius + currentRadius = currentRadius + thickness + self._isempty(topo) + + return self.ind[topo] diff --git a/HySoP/hysop/domain/tests/test_obstacle.py b/HySoP/hysop/domain/tests/test_obstacle.py new file mode 100644 index 000000000..75b274f74 --- /dev/null +++ b/HySoP/hysop/domain/tests/test_obstacle.py @@ -0,0 +1,267 @@ +""" +Testing parmepy.domain.obstacle.Obstacle +""" +import parmepy as pp +from parmepy.fields.continuous import Field +from parmepy.mpi.topology import Cartesian +from parmepy.domain.obstacle.sphere import Sphere, HemiSphere +from parmepy.domain.obstacle.disk import Disk, HalfDisk +from parmepy.domain.obstacle.planes import HalfSpace, Plane, SubSpace,\ + SubPlane, PlaneBoundaries +from parmepy.domain.obstacle.controlBox import ControlBox +import numpy as np +from parmepy.constants import CHECK_F_CONT + + +nb = 129 +Lx = Ly = Lz = 2 +dom = pp.Box(dimension=3, length=[Lx, Ly, Lz], origin=[-1., -1., -1.]) +dom2D = pp.Box(dimension=2, length=[Lx, Ly], origin=[-1., -1.]) +resol3D = [nb, nb, nb] +resol2D = [nb, nb] +scal = Field(domain=dom) +scal2D = Field(domain=dom2D) +topo = Cartesian(dom, 3, resol3D) +topo2D = Cartesian(dom2D, 2, resol2D) +coords = topo.mesh.coords +coords2D = topo2D.mesh.coords +scald = scal.discretize(topo).data[0] +scald2D = scal2D.discretize(topo2D).data[0] +h3d = topo.mesh.space_step +h2d = topo2D.mesh.space_step +dvol = np.prod(h3d) +ds = np.prod(h2d) +import math +pi = math.pi +tol = 1e-6 +lengths = np.asarray([20 * h3d[0], 22 * h3d[1], 31 * h3d[2]]) +rlengths = lengths + h3d +rlengths2d = lengths[:2] + h2d +scald[:] = 1. +scald2D[:] = 1. + + +def testSphere(): + scald[:] = 1. + rad = 0.3 + sphere = Sphere(domain=dom, position=[0., 0., 0.], + radius=rad, porousLayers=[0.13]) + + sphere.discretize(topo) + ind = sphere.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([-0.2, 0, 0.2]) + assert ind[ix, iy, iz] + (ix, iy, iz) = topo.mesh.indices([0.5, 0.1, 0.2]) + assert not ind[ix, iy, iz] + + +def testHemiSphere(): + scald[:] = 1. + rad = 0.3 + sphere = HemiSphere(domain=dom, position=[0., 0., 0.], + radius=rad, porousLayers=[0.13]) + + sphere.discretize(topo) + ind = sphere.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([-0.3, 0., 0.]) + assert ind[ix, iy, iz] + (ix, iy, iz) = topo.mesh.indices([0.3, 0., 0.]) + assert not ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testDisk(): + scald2D[:] = 1. + rad = 0.3 + sphere = Disk(domain=dom2D, position=[0., 0.], + radius=rad, porousLayers=[0.13]) + + sphere.discretize(topo2D) + ind = sphere.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.2, 0.]) + assert ind[ix, iy] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testHalfDisk(): + scald2D[:] = 1. + rad = 0.3 + sphere = HalfDisk(domain=dom2D, position=[0., 0.], + radius=rad, porousLayers=[0.13]) + + sphere.discretize(topo2D) + ind = sphere.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.2, 0.]) + assert ind[ix, iy] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testHalfSpace2D(): + hsp = HalfSpace(domain=dom2D, normal=[1, 1], point=[0., 0.]) + hsp.discretize(topo2D) + ind = hsp.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.8, 0.5]) + assert ind[ix, iy] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testHalfSpace3D(): + hsp = HalfSpace(domain=dom, normal=[1, 1, 1], point=[0., 0., 0.]) + hsp.discretize(topo) + ind = hsp.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([-0.8, 0.5, -0.5]) + assert ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testPlane2D(): + plane = Plane(domain=dom2D, normal=[1, 1], point=[0., 0.]) + plane.discretize(topo2D) + ind = plane.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.5, 0.5]) + assert ind[ix, iy] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testPlane3D(): + plane = Plane(domain=dom, normal=[1, 1, 1], point=[0., 0., 0.]) + plane.discretize(topo) + ind = plane.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([-0.3, 0.5, -0.2]) + assert ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testSubSpace2D(): + ssp = SubSpace(domain=dom2D, normal=[1, 0.], point=[0., 0.], lengths=lengths[:2]) + ssp.discretize(topo2D) + ind = ssp.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.5, 0.2]) + assert ind[ix, iy] + + +def testSubSpace3D(): + ssp = SubSpace(domain=dom, normal=[0, 1, 0], point=[0., 0., 0.], lengths=lengths) + ssp.discretize(topo) + ind = ssp.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([0.3, -0.1, 0.2]) + assert ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testSubPlane2D(): + ssp = SubPlane(domain=dom2D, normal=[1, 0], point=[0., 0.], lengths=lengths[:2]) + ssp.discretize(topo2D) + ind = ssp.ind[topo2D][0] + ll = np.sum(scald2D[ind]) * h2d[1] + rll = rlengths2d[1] + assert abs(ll - rll) < tol + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testSubPlane3D(): + ssp = SubPlane(domain=dom, normal=[0, 1, 0], point=[0., 0., 0.], lengths=lengths) + ssp.discretize(topo) + ind = ssp.ind[topo][0] + surf = np.sum(scald[ind]) * ds + rsurf = rlengths[0] * rlengths[2] + assert abs(surf - rsurf) < tol + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testPlaneBC2D(): + bc = PlaneBoundaries(domain=dom2D, normal_dir=1, thickness=0.2) + bc.discretize(topo2D) + ind = bc.ind[topo2D][0] + (ix, iy) = topo2D.mesh.indices([-0.5, - Ly * 0.5]) + assert ind[ix, iy] + (ix, iy) = topo2D.mesh.indices([-0.5, Ly * 0.5 - 2 * h2d[1]]) + assert ind[ix, iy] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testPlaneBC3D(): + bc = PlaneBoundaries(domain=dom, normal_dir=1, thickness=0.2) + bc.discretize(topo) + ind = bc.ind[topo][0] + (ix, iy, iz) = topo.mesh.indices([-0.5, -Ly * 0.5, 0.3]) + assert ind[ix, iy, iz] + (ix, iy, iz) = topo.mesh.indices([-0.5, Ly * 0.5 - 2 * h2d[1], 0.3]) + assert ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + + +def testControlBox2D(): + lx = 10 * h3d[0] + ly = 22 * h3d[1] + + cb = ControlBox(domain=dom2D, origin=[-0.5, -0.5], lengths=[lx, ly]) + cb.discretize(topo2D) + surf = cb.integrate(scal2D, topo2D) + rsurf = lx * ly + assert abs(surf - rsurf) < tol + assert cb.ind[topo2D][0].flags.f_contiguous is CHECK_F_CONT + + +def testControlBox3D(): + ll = np.asarray([0] * 3) + ll[0] = 10 * h3d[0] + ll[1] = 22 * h3d[1] + ll[2] = 51 * h3d[2] + + cb = ControlBox(domain=dom, origin=[0.5, -0.5, -0.5], lengths=ll) + cb.discretize(topo) + vol = cb.integrate(scal, topo) + rvol = np.prod(ll) + assert abs(rvol - vol) < tol + + vol = cb.integrate(scal, topo, useSlice=False) + assert abs(rvol - vol) < tol + ind = np.asarray([0, 1, 2]) + for i in xrange(3): + surfUp = cb.integrateOnSurface(scal, topo, normalDir=i, up=True) + surfDown = cb.integrateOnSurface(scal, topo, normalDir=i, up=False) + j = np.where(ind != i) + sref = np.prod(ll[j]) + assert abs(surfUp - sref) < tol + assert abs(surfDown - sref) < tol + + assert cb.ind[topo][0].flags.f_contiguous is CHECK_F_CONT + + +def testControlBoxSphere(): + lx = 1.5 + ly = 1.5 + lz = 1.5 + rad = 0.2 + cb = ControlBox(domain=dom, origin=[-0.75, -0.75, -0.75], lengths=[lx, ly, lz]) + layer = 2 * h3d[0] + sphere = Sphere(domain=dom, position=[0., 0., 0.], + radius=rad, porousLayers=[layer]) + cb.sub(sphere, topo) + ind = cb.indReduced[topo][0] + (ix, iy, iz) = topo.mesh.indices([0.1, 0.0, 0.]) + assert not ind[ix, iy, iz] + (ix, iy, iz) = topo.mesh.indices([0.3, 0.0, 0.]) + assert ind[ix, iy, iz] + assert ind.flags.f_contiguous is CHECK_F_CONT + +# This may be useful to run mpi tests +#if __name__ == "__main__": + ## TODO : add tests for distributed obstacles. + ## testHemiSphere() + ## testDisk() + ## testHalfDisk() + ## testHalfSpace2D() + ## testHalfSpace3D() + ## testPlane2D() + ## testPlane3D() + ## testSubSpace2D() + ## testSubSpace3D() + ## testSubPlane2D() + ## testSubPlane3D() + ## testPlaneBC2D() + ## testPlaneBC3D() + ## testControlBox2D() + ## testControlBox3D() + ## testControlBoxSphere() diff --git a/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_2d.cl b/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_2d.cl new file mode 100644 index 000000000..10a605498 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_2d.cl @@ -0,0 +1,83 @@ +/** + * @file advection_and_remeshing_vector_2d.cl + * Advection and remeshing kernel for 2D vector advection. + */ + +/** + * Performs advection and then remeshing of the particles' vector. + * A work-group is handling a 1D problem. Thus, gidY and gidZ are constants among work-items of a work-group. + * Each work-item computes NB_I/WI_NB particles positions. To avoid concurrent witings, in case of strong velocity gradients, work-items computes contiguous particles. + * Particle are computed through OpenCL vector types of lenght 2, 4 or 8. + * Scalar results are stored in a local buffer as a cache and then copied to global memory buffer. + * + * @param gvelo Velocity field + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param dt Time step + * @param min_position Domain lower coordinate + * @param dx Space step + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>WI_NB</code> corresponds to the work-item number. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @see parmepy.gpu.tools.parse_file + */ +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pvec_X, + __global const float* pvec_Y, + __global float* gvec_X, + __global float* gvec_Y, + float dt,float min_position, float dx) +{ + uint gidX = get_global_id(0); /* OpenCL work-itme global index (X) */ + uint gidY = get_global_id(1); /* OpenCL work-itme global index (Y) */ + uint gidZ = get_global_id(2); /* OpenCL work-itme global index (Z) */ + float invdx = 1.0/dx; /* Space step inverse */ + uint i; /* Particle index in 1D problem */ + float__N__ p, /* Particle position */ + pv_X, pv_Y, /* Particle vector */ + v; /* Particle velocity */ + uint line_index = gidY*NB_I+ gidZ*NB_I*NB_II; /* Current 1D problem index */ + + __local float gvec_X_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Y_loc[NB_I]; /* Local buffer for result */ + __local float gvelo_loc[NB_I]; /* Velocity cache */ + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Read velocity */ + v = vload__N__((i+line_index)/__N__, gvelo); + /* Fill velocity cache */ + gvelo_loc[noBC_id(i+__NN__)] = v.s__NN__; + /* Initialize result buffer */ + gvec_X_loc[noBC_id(i+__NN__)] = 0.0; + gvec_Y_loc[noBC_id(i+__NN__)] = 0.0; + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*PART_NB_PER_WI; i<(gidX + 1)*PART_NB_PER_WI; i+=__N__) + { + /* Read Particle scalar */ + pv_X = vload__N__((i + line_index)/__N__, pvec_X); + pv_Y = vload__N__((i + line_index)/__N__, pvec_Y); + /* Compute particle position */ + p = advection(i, dt, dx, invdx, gvelo_loc); + /* Remesh particle */ + remesh(i, dx, invdx, pv_X, pv_Y, p, gvec_X_loc, gvec_Y_loc); + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Store result */ + vstore__N__((float__N__)(gvec_X_loc[noBC_id(i+__NN__)], + ), (i + line_index)/__N__, gvec_X); + vstore__N__((float__N__)(gvec_Y_loc[noBC_id(i+__NN__)], + ), (i + line_index)/__N__, gvec_Y); + } +} diff --git a/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_3d.cl b/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_3d.cl new file mode 100644 index 000000000..abbdbe006 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/kernels/advection_and_remeshing_vector_3d.cl @@ -0,0 +1,90 @@ +/** + * @file advection_and_remeshing_vector_3d.cl + * Advection and remeshing kernel for 3D vector advection. + */ + +/** + * Performs advection and then remeshing of the particles' vector. + * A work-group is handling a 1D problem. Thus, gidY and gidZ are constants among work-items of a work-group. + * Each work-item computes NB_I/WI_NB particles positions. To avoid concurrent witings, in case of strong velocity gradients, work-items computes contiguous particles. + * Particle are computed through OpenCL vector types of lenght 2, 4 or 8. + * Scalar results are stored in a local buffer as a cache and then copied to global memory buffer. + * + * @param gvelo Velocity field + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param dt Time step + * @param min_position Domain lower coordinate + * @param dx Space step + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>WI_NB</code> corresponds to the work-item number. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @see parmepy.gpu.tools.parse_file + */ +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pvec_X, + __global const float* pvec_Y, + __global const float* pvec_Z, + __global float* gvec_X, + __global float* gvec_Y, + __global float* gvec_Z, + float dt,float min_position, float dx) +{ + uint gidX = get_global_id(0); /* OpenCL work-itme global index (X) */ + uint gidY = get_global_id(1); /* OpenCL work-itme global index (Y) */ + uint gidZ = get_global_id(2); /* OpenCL work-itme global index (Z) */ + float invdx = 1.0/dx; /* Space step inverse */ + uint i; /* Particle index in 1D problem */ + float__N__ p, /* Particle position */ + pv_X, pv_Y, pv_Z, /* Particle vector */ + v; /* Particle velocity */ + uint line_index = gidY*NB_I+ gidZ*NB_I*NB_II; /* Current 1D problem index */ + + __local float gvec_X_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Y_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Z_loc[NB_I]; /* Local buffer for result */ + __local float gvelo_loc[NB_I]; /* Velocity cache */ + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Read velocity */ + v = vload__N__((i+line_index)/__N__, gvelo); + /* Fill velocity cache */ + gvelo_loc[noBC_id(i+__NN__)] = v.s__NN__; + /* Initialize result buffer */ + gvec_X_loc[noBC_id(i+__NN__)] = 0.0; + gvec_Y_loc[noBC_id(i+__NN__)] = 0.0; + gvec_Z_loc[noBC_id(i+__NN__)] = 0.0; + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*PART_NB_PER_WI; i<(gidX + 1)*PART_NB_PER_WI; i+=__N__) + { + /* Read Particle scalar */ + pv_X = vload__N__((i + line_index)/__N__, pvec_X); + pv_Y = vload__N__((i + line_index)/__N__, pvec_Y); + pv_Z = vload__N__((i + line_index)/__N__, pvec_Z); + /* Compute particle position */ + p = advection(i, dt, dx, invdx, gvelo_loc); + /* Remesh particle */ + remesh(i, dx, invdx, pv_X, pv_Y, pv_Z, p, gvec_X_loc, gvec_Y_loc, gvec_Z_loc); + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Store result */ + vstore__N__((float__N__)(gvec_X_loc[noBC_id(i+__NN__)], + ), (i + line_index)/__N__, gvec_X); + vstore__N__((float__N__)(gvec_Y_loc[noBC_id(i+__NN__)], + ), (i + line_index)/__N__, gvec_Y); + vstore__N__((float__N__)(gvec_Z_loc[noBC_id(i+__NN__)], + ), (i + line_index)/__N__, gvec_Z); + } +} diff --git a/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_2d.cl b/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_2d.cl new file mode 100644 index 000000000..84cb5d360 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_2d.cl @@ -0,0 +1,76 @@ +/** + * @file remeshing_vector_2d.cl + * Remeshing kernel. + */ + +/** + * Performs remeshing of the particles' vector in 2d. + * A work-group is handling a 1D problem. Thus, gidY and gidZ are constants among work-items of a work-group. + * Each work-item computes <code>NB_I/WI_NB</code> particles positions. To avoid concurrent witings, in case of strong velocity gradients, work-items computes contiguous particles. + * Particle are computed through OpenCL vector types of lenght 2, 4 or 8. + * Scalar results are stored in a local buffer as a cache and then copied to global memory buffer. + * + * @param ppos Particle position + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param min_position Domain lower coordinate + * @param dx Space step + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>WI_NB</code> corresponds to the work-item number. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @see parmepy.gpu.tools.parse_file + */ +__kernel void remeshing_kernel(__global const float* ppos, + __global const float* pvec_X, + __global const float* pvec_Y, + __global float* gvec_X, + __global float* gvec_Y, + float min_position, float dx) +{ + uint gidX = get_global_id(0); /* OpenCL work-itme global index (X) */ + uint gidY = get_global_id(1); /* OpenCL work-itme global index (Y) */ + uint gidZ = get_global_id(2); /* OpenCL work-itme global index (Z) */ + float invdx = 1.0/dx; /* Space step inverse */ + uint i; /* Particle index in 1D problem */ + float__N__ p, /* Particle position */ + v_X, v_Y; /* Particle quantity */ + uint line_index = gidY*NB_I+ gidZ*NB_I*NB_II; /* Current 1D problem index */ + + __local float gvec_X_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Y_loc[NB_I]; /* Local buffer for result */ + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Initialize result buffer */ + gvec_X_loc[i+__NN__] = 0.0; + gvec_Y_loc[i+__NN__] = 0.0; + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*PART_NB_PER_WI; i<(gidX + 1)*PART_NB_PER_WI; i+=__N__) + { + /* Read particle position */ + p = vload__N__((i + line_index)/__N__, ppos) - (float__N__)(min_position); + /* Read particle scalar */ + v_X = vload__N__((i + line_index)/__N__, pvec_X); + v_Y = vload__N__((i + line_index)/__N__, pvec_Y); + /* Remesh particle */ + remesh(i, dx, invdx, v_X, v_Y, p, gvec_X_loc, gvec_Y_loc); + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Store result */ + vstore__N__((float__N__)(gvec_X_loc[noBC_id(i+__NN__)], + ),(i + line_index)/__N__, gvec_X); + vstore__N__((float__N__)(gvec_Y_loc[noBC_id(i+__NN__)], + ),(i + line_index)/__N__, gvec_Y); + } +} diff --git a/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_3d.cl b/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_3d.cl new file mode 100644 index 000000000..0f66a22ab --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/kernels/remeshing_vector_3d.cl @@ -0,0 +1,83 @@ +/** + * @file remeshing_vector_3d.cl + * Remeshing kernel. + */ + +/** + * Performs remeshing of the particles' vector in 3d. + * A work-group is handling a 1D problem. Thus, gidY and gidZ are constants among work-items of a work-group. + * Each work-item computes <code>NB_I/WI_NB</code> particles positions. To avoid concurrent witings, in case of strong velocity gradients, work-items computes contiguous particles. + * Particle are computed through OpenCL vector types of lenght 2, 4 or 8. + * Scalar results are stored in a local buffer as a cache and then copied to global memory buffer. + * + * @param ppos Particle position + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param min_position Domain lower coordinate + * @param dx Space step + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>WI_NB</code> corresponds to the work-item number. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @see parmepy.gpu.tools.parse_file + */ +__kernel void remeshing_kernel(__global const float* ppos, + __global const float* pvec_X, + __global const float* pvec_Y, + __global const float* pvec_Z, + __global float* gvec_X, + __global float* gvec_Y, + __global float* gvec_Z, + float min_position, float dx) +{ + uint gidX = get_global_id(0); /* OpenCL work-itme global index (X) */ + uint gidY = get_global_id(1); /* OpenCL work-itme global index (Y) */ + uint gidZ = get_global_id(2); /* OpenCL work-itme global index (Z) */ + float invdx = 1.0/dx; /* Space step inverse */ + uint i; /* Particle index in 1D problem */ + float__N__ p, /* Particle position */ + v_X, v_Y, v_Z; /* Particle quantity */ + uint line_index = gidY*NB_I+ gidZ*NB_I*NB_II; /* Current 1D problem index */ + + __local float gvec_X_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Y_loc[NB_I]; /* Local buffer for result */ + __local float gvec_Z_loc[NB_I]; /* Local buffer for result */ + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Initialize result buffer */ + gvec_X_loc[i+__NN__] = 0.0; + gvec_Y_loc[i+__NN__] = 0.0; + gvec_Z_loc[i+__NN__] = 0.0; + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*PART_NB_PER_WI; i<(gidX + 1)*PART_NB_PER_WI; i+=__N__) + { + /* Read particle position */ + p = vload__N__((i + line_index)/__N__, ppos) - (float__N__)(min_position); + /* Read particle scalar */ + v_X = vload__N__((i + line_index)/__N__, pvec_X); + v_Y = vload__N__((i + line_index)/__N__, pvec_Y); + v_Z = vload__N__((i + line_index)/__N__, pvec_Z); + /* Remesh particle */ + remesh(i, dx, invdx, v_X, v_Y, v_Z, p, gvec_X_loc, gvec_Y_loc, gvec_Z_loc); + } + + /* Synchronize work-group */ + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*__N__; i<NB_I; i+=(WI_NB*__N__)) + { + /* Store result */ + vstore__N__((float__N__)(gvec_X_loc[noBC_id(i+__NN__)], + ),(i + line_index)/__N__, gvec_X); + vstore__N__((float__N__)(gvec_Y_loc[noBC_id(i+__NN__)], + ),(i + line_index)/__N__, gvec_Y); + vstore__N__((float__N__)(gvec_Z_loc[noBC_id(i+__NN__)], + ),(i + line_index)/__N__, gvec_Z); + } +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_2d.cl b/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_2d.cl new file mode 100644 index 000000000..abb672668 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_2d.cl @@ -0,0 +1,111 @@ +/** + * @file basic_noVec_vector_2d.cl + * Remeshing function, vectorized version for 2D vector remeshing. + */ + +void remesh(uint i, float dx, float invdx, + float v_X, float v_Y, + float p, + __local float* gvec_X_loc, __local float* gvec_Y_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float v_X, float v_Y, + float p, + __local float* gvec_X_loc, __local float* gvec_Y_loc){ + float y; /* Normalized distance to nearest left grid point */ + int ind; /* Integer coordinate */ + uint index; /* Remeshing index */ + float w; + + ind = convert_int_rtn(p * invdx); + y = (p - convert_float(ind) * dx) * invdx; + + index = convert_uint((ind - REMESH_SHIFT + NB_I) % NB_I); + + w = REMESH(alpha)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(beta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(gamma)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(delta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w = REMESH(eta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(zeta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w = REMESH(theta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(iota)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w = REMESH(kappa)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(mu)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_3d.cl b/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_3d.cl new file mode 100644 index 000000000..c912769d9 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/basic_noVec_vector_3d.cl @@ -0,0 +1,121 @@ +/** + * @file basic_noVec_vector_3d.cl + * Remeshing function, vectorized version for 3D vector remeshing. + */ + +void remesh(uint i, float dx, float invdx, + float v_X, float v_Y, float v_Z, + float p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float v_X, float v_Y, float v_Z, + float p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc){ + float y; /* Normalized distance to nearest left grid point */ + int ind; /* Integer coordinate */ + uint index; /* Remeshing index */ + float w; + + ind = convert_int_rtn(p * invdx); + y = (p - convert_float(ind) * dx) * invdx; + + index = convert_uint((ind - REMESH_SHIFT + NB_I) % NB_I); + + w = REMESH(alpha)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(beta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(gamma)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(delta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w = REMESH(eta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(zeta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w = REMESH(theta)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(iota)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w = REMESH(kappa)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(mu)(y); + gvec_X_loc[noBC_id(index)] += (w * v_X); + gvec_Y_loc[noBC_id(index)] += (w * v_Y); + gvec_Z_loc[noBC_id(index)] += (w * v_Z); + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_2d.cl b/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_2d.cl new file mode 100644 index 000000000..da8d9234b --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_2d.cl @@ -0,0 +1,111 @@ +/** + * @file basic_vector_2d.cl + * Remeshing function, vectorized version for vector remeshing in 2D. + */ + +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc){ + float__N__ y; /* Normalized distance to nearest left grid point */ + int__N__ ind; /* Integer coordinate */ + uint__N__ index; /* Remeshing index */ + float w__NN__; + + ind = convert_int__N___rtn(p * invdx); + y = (p - convert_float__N__(ind) * dx) * invdx; + + index = convert_uint__N__((ind - REMESH_SHIFT + NB_I) % NB_I); + + w__NN__ = REMESH(alpha)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(beta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(gamma)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(delta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w__NN__ = REMESH(eta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(zeta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w__NN__ = REMESH(theta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(iota)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w__NN__ = REMESH(kappa)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(mu)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_3d.cl b/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_3d.cl new file mode 100644 index 000000000..ed3f4a397 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/basic_vector_3d.cl @@ -0,0 +1,121 @@ +/** + * @file basic_vector_3d.cl + * Remeshing function, vectorized version for vector remeshing in 3D. + */ + +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y, float__N__ v_Z, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y,float__N__ v_Z, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc){ + float__N__ y; /* Normalized distance to nearest left grid point */ + int__N__ ind; /* Integer coordinate */ + uint__N__ index; /* Remeshing index */ + float w__NN__; + + ind = convert_int__N___rtn(p * invdx); + y = (p - convert_float__N__(ind) * dx) * invdx; + + index = convert_uint__N__((ind - REMESH_SHIFT + NB_I) % NB_I); + + w__NN__ = REMESH(alpha)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(beta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(gamma)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(delta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w__NN__ = REMESH(eta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(zeta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w__NN__ = REMESH(theta)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(iota)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w__NN__ = REMESH(kappa)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w__NN__ = REMESH(mu)(y.s__NN__); + gvec_X_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_X.s__NN__); + gvec_Y_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Y.s__NN__); + gvec_Z_loc[noBC_id(index.s__NN__)] += (w__NN__ * v_Z.s__NN__); + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/private_vector_2d.cl b/HySoP/hysop/gpu/cl_src/remeshing/private_vector_2d.cl new file mode 100644 index 000000000..fcb1e443c --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/private_vector_2d.cl @@ -0,0 +1,112 @@ +/** + * @file private_vector_2d.cl + * Remeshing function, vectorized, private variable for 2D vector remeshing. + */ + +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * Use of a private temporary variable for remeshing weights. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc){ + float__N__ y, /* Normalized distance to nearest left grid point */ + w; /* Temporary remeshing weights */ + int__N__ ind; /* Integer coordinate */ + uint__N__ index; /* Remeshing index */ + + ind = convert_int__N___rtn(p * invdx); + y = (p - convert_float__N__(ind) * dx) * invdx; + + index = convert_uint__N__((ind - REMESH_SHIFT + NB_I) % NB_I); + + w = REMESH(alpha)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(beta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(gamma)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(delta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w = REMESH(eta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(zeta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w = REMESH(theta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(iota)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w = REMESH(kappa)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(mu)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/cl_src/remeshing/private_vector_3d.cl b/HySoP/hysop/gpu/cl_src/remeshing/private_vector_3d.cl new file mode 100644 index 000000000..dabd8e5d8 --- /dev/null +++ b/HySoP/hysop/gpu/cl_src/remeshing/private_vector_3d.cl @@ -0,0 +1,122 @@ +/** + * @file private_vector_3d.cl + * Remeshing function, vectorized, private variable for 3D vector remeshing. + */ + +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y,float__N__ v_Z, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc); + + +/** + * Remesh particles in local buffer. + * + * Remeshing formula is given a compiling time. + * Use of builtin OpenCL functions fma and mix. Computations through OpenCL vector types. + * Use of a private temporary variable for remeshing weights. + * + * @param i Particle index + * @param dx Space step + * @param invdx 1/dx + * @param s Particle scalar + * @param p Particle position + * @param gscal_loc Local buffer for result + * + * @remark <code>NB_I</code>, <code>NB_II</code>, <code>NB_III</code> : points number in directions from 1st varying index to last. + * @remark <code>__N__</code> is expanded at compilation time by vector width. + * @remark <code>__NN__</code> is expanded at compilation time by a sequence of integer for each vector component. + * @remark <code>FORMULA</code> : remeshing formula flag {<code>M4PRIME</code>, <code>M6PRIME</code>, <code>M8PRIME</code>, <code>L6STAR</code>} + * @remark <code>REMESH</code> is a function-like macro expanding to the proper remeshing formula (i.e.: <code>REMESH(alpha)</code> -> <code>alpha_l2_1</code>) + * @see parmepy.gpu.tools.parse_file + * @see parmepy.gpu.cl_src.common + */ +void remesh(uint i, float dx, float invdx, + float__N__ v_X, float__N__ v_Y,float__N__ v_Z, + float__N__ p, + __local float* gvec_X_loc, __local float* gvec_Y_loc, __local float* gvec_Z_loc){ + float__N__ y, /* Normalized distance to nearest left grid point */ + w; /* Temporary remeshing weights */ + int__N__ ind; /* Integer coordinate */ + uint__N__ index; /* Remeshing index */ + + ind = convert_int__N___rtn(p * invdx); + y = (p - convert_float__N__(ind) * dx) * invdx; + + index = convert_uint__N__((ind - REMESH_SHIFT + NB_I) % NB_I); + + w = REMESH(alpha)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(beta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(gamma)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(delta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + +#if REMESH_SHIFT > 1 + index = (index + 1) % NB_I; + w = REMESH(eta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(zeta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 2 + index = (index + 1) % NB_I; + w = REMESH(theta)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(iota)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif + +#if REMESH_SHIFT > 3 + index = (index + 1) % NB_I; + w = REMESH(kappa)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); + + index = (index + 1) % NB_I; + w = REMESH(mu)(y); + gvec_X_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_X.s__NN__; + gvec_Y_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Y.s__NN__; + gvec_Z_loc[noBC_id(index.s__NN__)] += w.s__NN__ * v_Z.s__NN__; + barrier(CLK_LOCAL_MEM_FENCE); +#endif +} diff --git a/HySoP/hysop/gpu/gpu_particle_advection_1k.py b/HySoP/hysop/gpu/gpu_particle_advection_1k.py new file mode 100644 index 000000000..fb52be095 --- /dev/null +++ b/HySoP/hysop/gpu/gpu_particle_advection_1k.py @@ -0,0 +1,237 @@ +""" +@file gpu_particle_advection_1k.py + +Discrete advection representation. +""" +from parmepy.constants import debug, PARMES_REAL +from parmepy.gpu.gpu_particle_advection import GPUParticleAdvection +from parmepy.methods_keys import TimeIntegrator, Interpolation, Remesh, \ + Support, Splitting, MultiScale +from parmepy.numerics.integrators.runge_kutta2 import RK2 +from parmepy.numerics.interpolation import Linear +from parmepy.numerics.remeshing import L2_1 +from parmepy.fields.continuous import Field +from parmepy.gpu.gpu_discrete import GPUDiscreteField +from parmepy.gpu.gpu_kernel import KernelLauncher + + +class GPUParticleAdvection1k(GPUParticleAdvection): + """ + Particle advection operator representation on GPU with a single kernel + for computing advection and remeshing. + """ + + @debug + def __init__(self, velocity, advectedFields, d, + part_position=None, part_advectedFields=None, + platform_id=None, device_id=None, + device_type=None, + method=None, + src=None, batch_nb=None, + isMultiScale=False): + """ + Create a Advection operator. + Work on a given scalar at a given velocity to produce scalar + distribution at new positions. + + @param velocity : Velocity field + @param advectedFields : Advected field (only single field is supported) + @param d : Direction to advect + @param part_position : DiscreteField to use for particle position. + @param part_advectedFields : DiscreteField to use for particle + advected fields. + @param platform_id : OpenCL platform id (default = 0). + @param device_id : OpenCL device id (default = 0). + @param device_type : OpenCL device type (default = 'gpu'). + @param method : the method to use. + @param src : User OpenCL sources. + @param batch_nb : User defined batch number for fields (computed by + default to fit the device memory). + @param isMultiScale : Flag to specify if the velocity and advected + fields are on different grids. + """ + if method is None: + method = {TimeIntegrator: RK2, + Interpolation: Linear, + Remesh: L2_1, + Support: 'gpu_1k', + Splitting: 'o2'} + GPUParticleAdvection.__init__(self, velocity, advectedFields, d, + part_position, part_advectedFields, + platform_id, device_id, + device_type, + method, src, + batch_nb, + isMultiScale=isMultiScale) + self.num_advec_and_remesh = None + + @debug + def setUp(self): + GPUParticleAdvection.setUp(self) + + def globalMemoryUsagePreview(self, v_shape, shape): + r = (self.velocity.nbComponents * v_shape.prod() + + 2 * self.advectedFields[0].nbComponents * shape.prod()) + return r * self.cl_env.prec_size + + def _buffer_allocations(self): + """ + Allocate OpenCL buffers for velocity and advected field. + And one more buffer for advected fields quantities on particles. + """ + ## Velocity. + alloc = not isinstance(self.velocity, GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, self.velocity, + self.gpu_precision, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.velocity.mem_size + + ## Transported field. + alloc = not isinstance(self.advectedFields[0], GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, + self.advectedFields[0], + self.gpu_precision, + layout=False, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.advectedFields[0].mem_size + + ## Result scalar + if self.part_advectedFields is None: + self.part_advectedFields = [ + Field(self.advectedFields[0].topology.domain, + name="Particle_AdvectedFields", + isVector=self.advectedFields[0].isVector + ).discretize(self.advectedFields[0].topology)] + alloc = not isinstance(self.part_advectedFields[0], GPUDiscreteField) + GPUDiscreteField.fromField( + self.cl_env, self.part_advectedFields[0], + self.gpu_precision, + layout=False, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.part_advectedFields[0].mem_size + + is_batch = (self.velocity.isBatch and + self.advectedFields[0].isBatch and + self.part_advectedFields[0].isBatch) + is_not_batch = (not self.velocity.isBatch and + not self.advectedFields[0].isBatch and + not self.part_advectedFields[0].isBatch) + identic_batch = True + if is_batch: + for vb, adb, padb in zip( + self.velocity.batch_nb[self.dir], + self.advectedFields[0].batch_nb[self.dir], + self.part_advectedFields[0].batch_nb[self.dir]): + identic_batch = identic_batch and (vb == adb and vb == padb) + + if not ((is_batch or is_not_batch) and + (not is_batch or (is_batch and identic_batch))): + raise RuntimeError("In operator advection on GPU, automatic " + + "batch number computations fails: (different " + + "batch number for same variables use in " + + "different advection operators). " + + "User must give an explicit and identical " + + "batch_nb parameter for all GPU advection " + + "operators") + + self.variables = [self.advectedFields[0], self.velocity, + self.part_advectedFields[0]] + self._work = self.part_advectedFields + + def _collect_kernels_cl_src(self): + """ + Compile OpenCL sources for advection and remeshing kernel. + """ + build_options = self.build_options + self._size_constants + src, is_noBC, vec, f_space = self._kernel_cfg['advec_and_remesh'] + gwi, lwi = f_space(self.resol_dir, vec) + WINb = lwi[0] + build_options += " -D FORMULA=" + self.method[Remesh].__name__.upper() + if self._isMultiScale: + build_options += " -D MS_FORMULA=" + build_options += self.method[MultiScale].__name__.upper() + if is_noBC: + build_options += " -D WITH_NOBC=1" + build_options += " -D WI_NB=" + str(WINb) + build_options += " -D PART_NB_PER_WI=" + build_options += str(self.resol_dir[0] / WINb) + build_options += self._constants[self.dir] + ## Build code + src = [s.replace('RKN', self.method[TimeIntegrator].__name__.lower()) + for s in src] + prg = self.cl_env.build_src( + src, build_options, vec, + nb_remesh_components=self.part_advectedFields[0].nbComponents) + self.num_advec_and_remesh = KernelLauncher( + prg.advection_and_remeshing, self.cl_env.queue, gwi, lwi) + + ## Local memory array for kernels + advec_nbC = self.part_advectedFields[0].nbComponents + loc_arrays = [self.v_resol_dir[0]] + loc_arrays += [self.resol_dir[0]] * (advec_nbC) + self._num_locMem, self.size_local_alloc = \ + self.cl_env.LocalMemAllocator(loc_arrays) + + def _compute_1c(self, simulation, dtCoeff, split_id, old_dir): + dt = simulation.timeStep * dtCoeff + wait_evts = self.velocity.events + \ + self.part_advectedFields[0].events + \ + self.advectedFields[0].events + evt = self.num_advec_and_remesh( + self.velocity.gpu_data[self.dir].data, + self.part_advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[0].data, + self._num_locMem[0], self._num_locMem[1], + self.gpu_precision(dt), + self.coord_min[self.dir], + self.mesh_size, self.v_mesh_size, + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def _compute_2c(self, simulation, dtCoeff, split_id, old_dir): + dt = simulation.timeStep * dtCoeff + wait_evts = self.velocity.events + \ + self.part_advectedFields[0].events + \ + self.advectedFields[0].events + evt = self.num_advec_and_remesh( + self.velocity.gpu_data[self.dir].data, + self.part_advectedFields[0].gpu_data[0].data, + self.part_advectedFields[0].gpu_data[1].data, + self.advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[1].data, + self._num_locMem[0], self._num_locMem[1], self._num_locMem[2], + self.gpu_precision(dt), + self.coord_min[self.dir], + self.mesh_size, self.v_mesh_size, + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def _compute_3c(self, simulation, dtCoeff, split_id, old_dir): + dt = simulation.timeStep * dtCoeff + wait_evts = self.velocity.events + \ + self.part_advectedFields[0].events + \ + self.advectedFields[0].events + evt = self.num_advec_and_remesh( + self.velocity.gpu_data[self.dir].data, + self.part_advectedFields[0].gpu_data[0].data, + self.part_advectedFields[0].gpu_data[1].data, + self.part_advectedFields[0].gpu_data[2].data, + self.advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[1].data, + self.advectedFields[0].gpu_data[2].data, + self._num_locMem[0], self._num_locMem[1], + self._num_locMem[2], self._num_locMem[3], + self.gpu_precision(dt), + self.coord_min[self.dir], + self.mesh_size, self.v_mesh_size, + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def finalize(self): + if self.num_advec_and_remesh.f_timer is not None: + for f_timer in self.num_advec_and_remesh.f_timer: + self.kernels_timer.addFunctionTimer(f_timer) + GPUParticleAdvection.finalize(self) diff --git a/HySoP/hysop/gpu/gpu_particle_advection_2k.py b/HySoP/hysop/gpu/gpu_particle_advection_2k.py new file mode 100644 index 000000000..85fd35b6c --- /dev/null +++ b/HySoP/hysop/gpu/gpu_particle_advection_2k.py @@ -0,0 +1,281 @@ +""" +@file gpu_particle_advection_2k.py + +Discrete advection representation. +""" +from parmepy.constants import debug, PARMES_REAL +from parmepy.gpu.gpu_particle_advection import GPUParticleAdvection +from parmepy.methods_keys import TimeIntegrator, Interpolation, Remesh, \ + Support, Splitting, MultiScale +from parmepy.numerics.integrators.runge_kutta2 import RK2 +from parmepy.numerics.interpolation import Linear +from parmepy.numerics.remeshing import L2_1 +from parmepy.fields.continuous import Field +from parmepy.gpu.gpu_discrete import GPUDiscreteField +from parmepy.gpu.gpu_kernel import KernelLauncher + + +class GPUParticleAdvection2k(GPUParticleAdvection): + """ + Particle advection operator representation on GPU. + """ + + @debug + def __init__(self, velocity, advectedFields, d, + part_position=None, part_advectedFields=None, + platform_id=None, device_id=None, + device_type=None, + method=None, + src=None, batch_nb=None, + isMultiScale=False): + """ + Create a Advection operator. + Work on a given scalar at a given velocity to produce scalar + distribution at new positions. + + @param velocity : Velocity field + @param advectedFields : Advected field (only single field is supported) + @param d : Direction to advect + @param part_position : DiscreteField to use for particle position. + @param part_advectedFields : DiscreteField to use for particle + advected fields. + @param platform_id : OpenCL platform id (default = 0). + @param device_id : OpenCL device id (default = 0). + @param device_type : OpenCL device type (default = 'gpu'). + @param method : the method to use. + @param src : User OpenCL sources. + @param batch_nb : User defined batch number for fields (computed by + default to fit the device memory). + @param isMultiScale : Flag to specify if the velocity and advected + fields are on different grids. + """ + if method is None: + method = {TimeIntegrator: RK2, + Interpolation: Linear, + Remesh: L2_1, + Support: 'gpu_2k', + Splitting: 'o2'} + GPUParticleAdvection.__init__(self, velocity, advectedFields, d, + part_position, part_advectedFields, + platform_id, device_id, + device_type, + method, src, + batch_nb, + isMultiScale=isMultiScale) + self.num_advec, self.num_remesh = None, None + + @debug + def setUp(self): + GPUParticleAdvection.setUp(self) + + def globalMemoryUsagePreview(self, v_shape, shape): + r = (self.velocity.nbComponents * v_shape.prod() + + (2 * self.advectedFields[0].nbComponents + 1) * shape.prod()) + return r * self.cl_env.prec_size + + def _buffer_allocations(self): + """ + Allocate OpenCL buffers for velocity and advected field. + And one more buffer for advected fields quantities on particles. + And a buffer for storing particle positions. + """ + ## Velocity. + alloc = not isinstance(self.velocity, GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, self.velocity, + self.gpu_precision, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.velocity.mem_size + + ## Transported field. + alloc = not isinstance(self.advectedFields[0], GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, self.advectedFields[0], + self.gpu_precision, + layout=False, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.advectedFields[0].mem_size + + ## Particle position + if self.part_position is None: + self.part_position = \ + Field(self.advectedFields[0].topology.domain, + name="Particle_Position", + isVector=False + ).discretize(self.advectedFields[0].topology) + alloc = not isinstance(self.part_position, GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, self.part_position, + self.gpu_precision, layout=False, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.part_position.mem_size + + ## Result scalar + if self.part_advectedFields is None: + self.part_advectedFields = [ + Field(self.advectedFields[0].topology.domain, + name="Particle_AdvectedFields", + isVector=self.advectedFields[0].isVector + ).discretize(self.advectedFields[0].topology)] + alloc = not isinstance(self.part_advectedFields[0], GPUDiscreteField) + GPUDiscreteField.fromField(self.cl_env, self.part_advectedFields[0], + self.gpu_precision, layout=False, + batch_nb=self.batch_nb, batch_d=self.dir) + if alloc: + self.size_global_alloc += self.part_advectedFields[0].mem_size + + is_batch = (self.velocity.isBatch and + self.advectedFields[0].isBatch and + self.part_position.isBatch and + self.part_advectedFields[0].isBatch) + is_not_batch = (not self.velocity.isBatch and + not self.advectedFields[0].isBatch and + not self.part_position.isBatch and + not self.part_advectedFields[0].isBatch) + identic_batch = True + if is_batch: + for vb, adb, pposb, padb in zip( + self.velocity.batch_nb[self.dir], + self.advectedFields[0].batch_nb[self.dir], + self.part_position.batch_nb[self.dir], + self.part_advectedFields[0].batch_nb[self.dir]): + identic_batch = identic_batch and \ + (vb == adb and vb == padb and vb == pposb) + + if not ((is_batch or is_not_batch) and + (not is_batch or (is_batch and identic_batch))): + raise RuntimeError("In operator advection on GPU, automatic " + + "batch number computations fails: (different " + + "batch number for same variables use in " + + "different advection operators). " + + "User must give an explicit and identical " + + "batch_nb parameter for all GPU advection " + + "operators") + + self.variables = [self.advectedFields[0], self.velocity, + self.part_position, self.part_advectedFields[0]] + self._work = self.part_advectedFields + [self.part_position] + + def _collect_kernels_cl_src(self): + """ + Compile OpenCL sources for advection and remeshing kernel. + """ + build_options = self.build_options + self._size_constants + src, is_noBC, vec, f_space = self._kernel_cfg['advec'] + gwi, lwi = f_space(self.resol_dir, vec) + WINb = lwi[0] + + if is_noBC: + build_options += " -D WITH_NOBC=1" + build_options += " -D WI_NB=" + str(WINb) + if self._isMultiScale: + build_options += " -D MS_FORMULA=" + build_options += self.method[MultiScale].__name__.upper() + build_options += self._constants[self.dir] + ## Build code + src = [s.replace('RKN', self.method[TimeIntegrator].__name__.lower()) + for s in src] + prg = self.cl_env.build_src( + src, + build_options, + vec, + nb_remesh_components=self.part_advectedFields[0].nbComponents) + self.num_advec = KernelLauncher( + prg.advection_kernel, self.cl_env.queue, gwi, lwi) + + ## remeshing + build_options = self.build_options + self._size_constants + src, is_noBC, vec, f_space = self._kernel_cfg['remesh'] + gwi, lwi = f_space(self.resol_dir, vec) + WINb = lwi[0] + + build_options += " -D FORMULA=" + self.method[Remesh].__name__.upper() + if is_noBC: + build_options += " -D WITH_NOBC=1" + build_options += " -D WI_NB=" + str(WINb) + build_options += " -D PART_NB_PER_WI=" + build_options += str(self.resol_dir[0] / WINb) + build_options += self._constants[self.dir] + ## Build code + prg = self.cl_env.build_src( + src, build_options, vec, + nb_remesh_components=self.part_advectedFields[0].nbComponents) + self.num_remesh = KernelLauncher( + prg.remeshing_kernel, self.cl_env.queue, gwi, lwi) + + ## Local memory array for kernels + advec_nbC = self.part_advectedFields[0].nbComponents + loc_arrays = [self.v_resol_dir[0]] + loc_arrays += [self.resol_dir[0]] * (advec_nbC) + self._num_locMem, self.size_local_alloc = \ + self.cl_env.LocalMemAllocator(loc_arrays) + + def _compute_advec(self, simulation, dtCoeff, split_id, old_dir): + dt = simulation.timeStep * dtCoeff + wait_evts = self.velocity.events+self.part_position.events + # Advection + evt = self.num_advec( + self.velocity.gpu_data[self.dir].data, + self.part_position.gpu_data[0].data, + self._num_locMem[0], + self.gpu_precision(dt), + self.coord_min[self.dir], + self.mesh_size, self.v_mesh_size, + wait_for=wait_evts) + self.part_position.events.append(evt) + + def _compute_1c(self, simulation, dtCoeff, split_id, old_dir): + self._compute_advec(simulation, dtCoeff, split_id, old_dir) + wait_evts = self.part_position.events+self.advectedFields[0].events + evt = self.num_remesh( + self.part_position.gpu_data[0].data, + self.part_advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[0].data, + self._num_locMem[1], + self.coord_min[self.dir], + self.mesh_size[self.dir], + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def _compute_2c(self, simulation, dtCoeff, split_id, old_dir): + self._compute_advec(simulation, dtCoeff, split_id, old_dir) + wait_evts = self.part_position.events+self.advectedFields[0].events + evt = self.num_remesh( + self.part_position.gpu_data[0].data, + self.part_advectedFields[0].gpu_data[0].data, + self.part_advectedFields[0].gpu_data[1].data, + self.advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[1].data, + self._num_locMem[1], + self._num_locMem[2], + self.coord_min[self.dir], + self.mesh_size[self.dir], + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def _compute_3c(self, simulation, dtCoeff, split_id, old_dir): + self._compute_advec(simulation, dtCoeff, split_id, old_dir) + wait_evts = self.part_position.events+self.advectedFields[0].events + evt = self.num_remesh( + self.part_position.gpu_data[0].data, + self.part_advectedFields[0].gpu_data[0].data, + self.part_advectedFields[0].gpu_data[1].data, + self.part_advectedFields[0].gpu_data[2].data, + self.advectedFields[0].gpu_data[0].data, + self.advectedFields[0].gpu_data[1].data, + self.advectedFields[0].gpu_data[2].data, + self._num_locMem[1], + self._num_locMem[2], + self._num_locMem[3], + self.coord_min[self.dir], + self.mesh_size[self.dir], + wait_for=wait_evts) + self.advectedFields[0].events.append(evt) + + def finalize(self): + if self.num_advec.f_timer is not None: + for f_timer in self.num_advec.f_timer: + self.kernels_timer.addFunctionTimer(f_timer) + for f_timer in self.num_remesh.f_timer: + self.kernels_timer.addFunctionTimer(f_timer) + GPUParticleAdvection.finalize(self) diff --git a/HySoP/hysop/mpi/tests/test_mesh.py b/HySoP/hysop/mpi/tests/test_mesh.py new file mode 100644 index 000000000..8f17c38e5 --- /dev/null +++ b/HySoP/hysop/mpi/tests/test_mesh.py @@ -0,0 +1,61 @@ +""" +@file parmepy.mpi.tests.test_mesh +Testing mesh. +""" +import numpy as np +from parmepy.domain.box import Box +from parmepy.mpi.topology import Cartesian + + +def test_mesh3D(): + """Periodic mesh""" + dom = Box() + resolTopo = [33, 33, 17] + topo = Cartesian(dom, 3, resolTopo) + topo.setUp() + dx = [1. / (n - 1) for n in resolTopo] + assert (topo.mesh.origin == [0. for n in resolTopo]).all() + assert (topo.mesh.end == [1. - dxx for dxx in dx]).all() + assert (topo.mesh.global_start == [0 for n in resolTopo]).all() + assert (topo.mesh.global_end == [n - 2 for n in resolTopo]).all() + assert (topo.mesh.local_start == [0 for n in resolTopo]).all() + assert (topo.mesh.local_end == [n - 2 for n in resolTopo]).all() + assert len(topo.mesh.coords) == 3 + assert topo.mesh.coords[0].shape == (resolTopo[0] - 1, 1, 1) + assert topo.mesh.coords[1].shape == (1, resolTopo[1] - 1, 1) + assert topo.mesh.coords[2].shape == (1, 1, resolTopo[2] - 1) + assert topo.mesh.coords[0][1, 0, 0] == dx[0] + assert topo.mesh.coords[1][0, 1, 0] == dx[1] + assert topo.mesh.coords[2][0, 0, 1] == dx[2] + + +def test_mesh3D_ghost(): + """Periodic mesh""" + dom = Box() + resolTopo = [33, 33, 17] + dx = [1. / (n - 1) for n in resolTopo] + ghost = np.array([2, 2, 1]) + topo = Cartesian(dom, 3, resolTopo, ghosts=ghost) + topo.setUp() + assert (topo.mesh.origin == + [0. - g * dxx for dxx, g in zip(dx, ghost)]).all() + assert (topo.mesh.end == + [1. - dxx + g * dxx for dxx, g in zip(dx, ghost)]).all() + assert (topo.mesh.global_start == + [0 for n in resolTopo]).all() + assert (topo.mesh.global_end == [n - 2 for n in resolTopo]).all() + assert (topo.mesh.local_start == [g for g in ghost]).all() + assert (topo.mesh.local_end == + [n - 2 + g for n, g in zip(resolTopo, ghost)]).all() + assert len(topo.mesh.coords) == 3 + assert topo.mesh.coords[0].shape == (resolTopo[0] - 1 + 2 * ghost[0], 1, 1) + assert topo.mesh.coords[1].shape == (1, resolTopo[1] - 1 + 2 * ghost[1], 1) + assert topo.mesh.coords[2].shape == (1, 1, resolTopo[2] - 1 + 2 * ghost[2]) + assert topo.mesh.coords[0][1, 0, 0] == (-ghost[0] + 1) * dx[0] + assert topo.mesh.coords[1][0, 1, 0] == (-ghost[1] + 1) * dx[1] + assert topo.mesh.coords[2][0, 0, 1] == (-ghost[2] + 1) * dx[2] + +# Todo : update tests for multi-proc mpi runs. +#if __name__ == '__main__': +# test_mesh3D() +# test_mesh3D_ghost() diff --git a/HySoP/hysop/operator/discrete/analytic.py b/HySoP/hysop/operator/discrete/analytic.py new file mode 100644 index 000000000..2c518f675 --- /dev/null +++ b/HySoP/hysop/operator/discrete/analytic.py @@ -0,0 +1,45 @@ +""" +@file discrete/analytic.py + +Apply user-defined formula to a set of discrete variables. +""" +from parmepy.constants import np, debug +from discrete import DiscreteOperator +from parmepy.tools.timers import timed_function + + +class Analytic_D(DiscreteOperator): + """ + Compute discrete fields values using a given analytic formula. + """ + + @debug + def __init__(self, variables, formula, doVectorize=False, method=None): + """ + @param[in,out] variables : a list of discrete variables on which + formula must be applied. + @param[in] formula : user defined formula to be applied. + @param[in] doVectorize : true if formula must be vectorized + @param method : Method used + """ + DiscreteOperator.__init__(self, variables, method) + self.output = variables + self.doVectorize = doVectorize + if self.doVectorize: + self.vformula = np.vectorize(formula) + else: + self.vformula = formula + + @debug + @timed_function + def apply(self, simulation): + """ + Initialize is always called with coords + current time. + Any extra parameters must be set using field.setExtraParameters. + """ + if simulation is None: + raise ValueError("Missing simulation value for computation.") + + for df in self.variables: + df.initialize(formula=self.vformula, doVectorize=self.doVectorize, + currentTime=simulation.time) diff --git a/HySoP/hysop/operator/monitors/__init__.py b/HySoP/hysop/operator/monitors/__init__.py new file mode 100644 index 000000000..5728a8fe9 --- /dev/null +++ b/HySoP/hysop/operator/monitors/__init__.py @@ -0,0 +1,19 @@ +## @package parmepy.operator.monitors +# Parmes tools for data and fields monitoring. +# +# import and alias so that monitors are +# available with +# from parmepy.operators.monitors import Printer, ... +import printer +Printer = printer.Printer +import compute_forces +DragAndLift = compute_forces.DragAndLift +import reprojection_criterion +Reprojection_criterion = reprojection_criterion.Reprojection_criterion +import energy_enstrophy as energy_enstrophy +Energy_enstrophy = energy_enstrophy.Energy_enstrophy + +# Set list for 'import *' +__all__ = ['DragAndLift', 'Energy_enstrophy', + 'Reprojection_criterion', 'Printer'] + diff --git a/HySoP/hysop/operator/drag_and_lift.py b/HySoP/hysop/operator/monitors/compute_forces.py similarity index 100% rename from HySoP/hysop/operator/drag_and_lift.py rename to HySoP/hysop/operator/monitors/compute_forces.py diff --git a/HySoP/hysop/operator/monitors/monitoring.py b/HySoP/hysop/operator/monitors/monitoring.py new file mode 100644 index 000000000..852c87f97 --- /dev/null +++ b/HySoP/hysop/operator/monitors/monitoring.py @@ -0,0 +1,67 @@ +""" +@file monitoring.py +Global interface for monitors. +""" +from abc import ABCMeta, abstractmethod +from parmepy.operator.continuous import Operator +from parmepy.tools.timers import Timer +import parmepy.tools.io_utils as io + + +class Monitoring(Operator): + """Abstract interface to monitoring operators.""" + + __metaclass__ = ABCMeta + + @abstractmethod + def __init__(self, io_params=None, **kwds): + """ Constructor + @param variables : list of fields to monitor. + @param topo : topo on which fields are to be monitored + @param filename output file name. Default is None ==> no output. + Full or relative path. + @param io_params : parameters (dict) to set file output. + If None, no output. Set io_params = {} if you want output, + with default parameters values. + See parmepy.tools.io_utils.Writer for details + """ + super(Monitoring, self).__init__(**kwds) + assert self.topology is not None,\ + 'A topology must be given explicitely during monitors init' + ## Object to store computational times of lower level functions + self.timer = Timer(self) + self.requirements = [] + self._isUpToDate = False + ## Output file description + self.io_params = io_params + # Output file. + if io_params is None: + self._writer = None + else: + if self.topology is not None: + self._writer = io.Writer(io_params, self.topology.comm) + + def setUp(self): + """ + Class-method required + to fit with operator base-class interface. + """ + self._isUpToDate = True + + def finalize(self): + if self._writer is not None: + self._writer.finalize() + + def discretize(self): + """ + Does nothing. + No discretization in monitors, but class-method required + to fit with operator base-class interface. + """ + pass + + def addRedistributeRequirement(self, red): + self.requirements.append(red) + + def getRedistributeRequirement(self): + return self.requirements diff --git a/HySoP/hysop/operator/monitors/printer.py b/HySoP/hysop/operator/monitors/printer.py new file mode 100644 index 000000000..cd51aee3c --- /dev/null +++ b/HySoP/hysop/operator/monitors/printer.py @@ -0,0 +1,373 @@ +""" +@file printer.py + +File output for field(s) value on a grid. +""" +from parmepy.constants import S_DIR, debug, VTK, HDF5, DATA +from parmepy.operator.monitors.monitoring import Monitoring +import parmepy.tools.numpywrappers as npw +import parmepy.tools.io_utils as io +import os +from numpy import newaxis, float64 + +try: + import evtk.hl as evtk +except ImportError as evtk_error: + evtk = None +try: + import h5py +except ImportError as h5py_error: + h5py = None +from parmepy.tools.timers import timed_function + + +class Printer(Monitoring): + """ + Print field(s) values on a given topo, in HDF5 or VTK format. + """ + def __init__(self, prefix=None, frequency=1, formattype=None, + xmfalways=False, subset=None, **kwds): + """ + Create a results printer for given fields, prefix + prefix (relative path) and an output frequency. + + @param variables : list of variables to export. + @param frequency : output rate (output every freq iteration) + @param prefix output file name. Default is None ==> no output. + Full or relative path. + @param formattype : output file format, default=vtk. + @param xmfalways : true if xmf output must be done every time + an hdf5 file is created + """ + super(Printer, self).__init__(**kwds) + + assert frequency > 0 + self.frequency = frequency + ## Default output type + if formattype is None: + self.formattype = VTK + else: + self.formattype = formattype + if self.formattype == VTK and evtk is None: + print ("You set a printer with VTK as format and evtk module ",) + print ("is not present. You must specify another format",) + print (" for output (DATA or HDF5)") + raise evtk_error + if self.formattype == HDF5 and h5py is None: + print ("You set a printer with HDF5 as format and h5py module ",) + print ("is not present. You must specify another extension",) + print (" (DATA or VTK)") + raise h5py_error + + self.input = self.variables + self.output = [] + # If no prefix is given, set it to + # the concatenation of variables'names. + if prefix is None: + prefix = io.io.defaultPath() + name = '' + for var in self.input: + name += var.name + name += '_' + prefix = os.path.join(prefix, name) + else: + if not os.path.isabs(prefix): + prefix = os.path.join(io.io.defaultPath(), prefix) + if self.topology is not None: + io.io.checkDir(prefix, 0, self.topology.comm) + self.prefix = prefix + self._xmf_data_files = [] + if self.formattype == VTK: + # filename = prefix_rk_N, rk = current process rank, + # N = counter value + self._get_filename = lambda i: self.prefix + \ + "_{0}_{1:05d}".format(self.topology.rank, i) + self.step = self._step_VTK + elif self.formattype == HDF5: + # filename = prefix_N, N = counter value + self._get_filename = lambda i: self.prefix + \ + "_{0:05d}".format(i) + '.h5' + self.step = self._step_HDF5 + if xmfalways: + self.step = self._step_HDF5_XMF + elif self.formattype == DATA: + self._get_filename = lambda i: self.prefix + \ + "_{0}_{1:05d}.dat".format(self.topology.rank, i) + self.step = self._step_DATA + self._isUpToDate = True + # count the number of calls + self._count = 0 + ## Rank of 'leader' mpi process for output + ## Forced to 0. \todo : add a param for this? + self.io_rank = 0 + + ## Set a subset of the original domain, to reduce + ## output + self.subset = subset + if self.subset is not None: + self.subset.discretize(self.topology) + self._slices = self.subset.slices[self.topology] + # Global resolution for hdf5 output + self.globalResolution = self.subset.globalResolution(self.topology) + else: + self.globalResolution = list(self.topology.globalMeshResolution - 1) + self._slices = self.topology.mesh.iCompute + self.globalResolution.reverse() + + @debug + @timed_function + def apply(self, simulation=None): + if simulation is None: + raise ValueError("Missing simulation value for monitoring.") + + if simulation.currentIteration == -1 or \ + simulation.currentIteration % self.frequency == 0: + # Transfer from GPU to CPU if required + for f in self.variables: + df = f.discreteFields[self.topology] + try: + if not df.isBatch: + # To host only if data fit in the device memory + df.toHost() + df.wait() + except AttributeError: + pass + self.step(simulation) + self._count += 1 + + def createXMFFile(self): + if self.formattype == HDF5 and self.topology.rank == self.io_rank: + # Write the xmf file driving all h5 files. + # Writing only one file + # We have a temporal list of Grid => a single xmf file + # Manual writing of the xmf file because "XDMF library very + # difficult to compile and to use" + # [Advanced HDF5 & XDMF - Groupe Calcul] + f = open(self.prefix + '.xmf', 'w') + f.write("<?xml version=\"1.0\" ?>\n") + f.write("<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\">\n") + f.write("<Xdmf Version=\"2.0\">\n") + f.write(" <Domain>\n") + f.write(" <Grid Name=\"CellTime\" GridType=\"Collection\" ") + f.write("CollectionType=\"Temporal\">\n") + for ds_names, i, t in self._xmf_data_files: + f.write(_TemporalGridXMF( + self.topology, ds_names, i, t, self._get_filename(i), + self.subset)) + f.write(" </Grid>\n") + f.write(" </Domain>\n") + f.write("</Xdmf>\n") + f.close() + + def finalize(self): + self.createXMFFile() + Monitoring.finalize(self) + + def _build_vtk_dict(self): + """Build a dictionary from fields to VTK image.""" + res = {} + + for f in self.variables: + df = f.discreteFields[self.topology] + #ind = df.topology.mesh.iCompute + for d in xrange(df.nbComponents): + if f.isVector: + name = df.name + S_DIR[d] + else: + name = df.name + if len(df.data[d].shape) == 2: + res[name] = npw.realarray(df.data[d][:, :, newaxis]) + else: + res[name] = npw.realarray(df.data[d]) + return res + + def _step_VTK(self, simu): + """ + """ + orig = [0.] * 3 + dim = self.topology.mesh.dim + orig[:dim] = [self.topology.mesh.origin[i] for i in xrange(dim)] + #orig = tuple(orig) + #ind = self.topology.mesh.local_start + ## orig = tuple([self.topology.mesh.coords[i].flatten()[ind[i]] + ## for i in xrange(self.topology.mesh.dim)]) + spacing = [0] * 3 + spacing[:dim] = [self.topology.mesh.space_step[i] for i in xrange(dim)] + evtk.imageToVTK(self._get_filename(self._count), + origin=orig, spacing=spacing, + pointData=self._build_vtk_dict()) + + def _step_HDF5(self, simu): + t = simu.time + filename = self._get_filename(self._count) + # Write the h5 file + # (force np.float64, ParaView seems to not be able to read float32) + # Writing compressed hdf5 files (gzip compression seems the best) + # In parallel, one file is written, thus filename no longe contains + # mpi rank. + # TODO: Why gzip compression not working in parallel ?? + # Remark: h5py must be build with --mpi option + if self.topology.size == 1: + f = h5py.File(filename, "w") + compression = 'gzip' + else: + f = h5py.File(filename, 'w', driver='mpio', comm=self.topology.comm) + compression = None + # It's necessary to compute the set of indices of the current subset + # in global notation + if self.subset is None: + # Note : g_start and g_end do not include ghost points. + g_start = self.topology.mesh.global_start + g_end = self.topology.mesh.global_end + 1 + sl = [slice(g_start[i], g_end[i]) + for i in xrange(self.domain.dimension)] + else: + g_start = self.subset.gstart + # convert self._slices to global position in topo + sl = self.topology.toIndexGlobal(self._slices) + # And shift using global position of the surface + sl = [slice(sl[i].start - g_start[i], sl[i].stop - g_start[i]) + for i in xrange(self.domain.dimension)] + sl.reverse() + sl = tuple(sl) + datasetNames = [] + for field in self.variables: + df = field.discreteFields[self.topology] + for d in xrange(df.nbComponents): + # creating datasets for the vector field + currentName = df.name + S_DIR[d] + datasetNames.append(currentName) + ds = f.create_dataset(currentName, + self.globalResolution, + dtype=float64, + compression=compression) + # In parallel, each proc must write in the proper part + # Of the dataset (of site global resolution) + ds[sl] = npw.realarray(df.data[d][self._slices].T) + + self._xmf_data_files.append((datasetNames, self._count, t)) + + f.close() + + def _step_HDF5_XMF(self, simu): + self._step_HDF5(simu) + self.createXMFFile() + + def _step_DATA(self, simu): + f = open(self._get_filename(self._count), 'w') + shape = self.topology.mesh.resolution + coords = self.topology.mesh.coords + pbDimension = self.domain.dimension + if pbDimension == 2: + if len(shape) == 2: + for i in xrange(shape[0] - 1): + for j in xrange(shape[1] - 1): + f.write("{0:8.12} {1:8.12} ".format( + coords[0][i, 0], coords[1][0, j])) + for field in self.variables: + df = field.discreteFields[self.topology] + if field.isVector: + f.write("{0:8.12} {1:8.12} ".format( + df[0][i, j], + df[1][i, j])) + else: + f.write("{0:8.12} ".format( + df[0][i, j])) + f.write("\n") + elif pbDimension == 3: + for i in xrange(shape[0] - 1): + for j in xrange(shape[1] - 1): + for k in xrange(shape[2] - 1): + f.write( + "{0:8.12} {1:8.12} {2:8.12} ".format( + coords[0][i, 0, 0], + coords[1][0, j, 0], + coords[2][0, 0, k])) + for field in self.variables: + df = field.discreteFields[self.topology] + if field.isVector: + f.write( + "{0:8.12} {1:8.12} " + + "{2:8.12} ".format( + df[0][i, j, k], + df[1][i, j, k], + df[2][i, j, k])) + else: + f.write("{0:8.12} ".format( + df[0][i, j, k])) + f.write("\n") + else: + for i in xrange(shape[0] - 1): + f.write("{0:8.12} ".format(coords[0][i])) + for field in self.variables: + df = field.discreteFields[self.topology] + if field.isVector: + f.write( + "{0:8.12} ".format(df[0][i])) + else: + f.write("{0:8.12} ".format(df[i])) + f.write("\n") + f.close() + + +def _listFormat(l): + """ + Format a list to the xml output. + Removes the '[]()' and replace ',' with ' ' in default str. + @param l : list to format + """ + return str(l).replace(',', ' ').replace('[', '').replace(']', '').replace( + '(', '').replace(')', '') + + +def _TemporalGridXMF(topo, datasetNames, ite, t, filename, subset=None): + g = "" + dimension = topo.mesh.dim + if dimension == 2: + topoType = "2DCORECTMesh" + geoType = "ORIGIN_DXDY" + elif dimension == 3: + topoType = "3DCORECTMesh" + geoType = "ORIGIN_DXDYDZ" + g += " <Grid Name=\"Iteration {0:03d}\"".format(ite) + g += " GridType=\"Uniform\">\n" + g += " <Time Value=\"{0}\" />\n".format(t) + g += " <Topology TopologyType=\"" + str(topoType) + "\"" + g += " NumberOfElements=\"" + if subset is not None: + resolution = subset.gRes + else: + resolution = list(topo.globalMeshResolution - 1) + resolution.reverse() + g += _listFormat(resolution) + " \"/>\n" + g += " <Geometry GeometryType=\"" + geoType + "\">\n" + g += " <DataItem Dimensions=\"" + str(dimension) + " \"" + g += " NumberType=\"Float\" Precision=\"4\" Format=\"XML\">\n" + if subset is not None: + ori = list(subset.origin) + else: + ori = list(topo.domain.origin) + ori.reverse() + g += " " + _listFormat(ori) + "\n" + g += " </DataItem>\n" + g += " <DataItem Dimensions=\"" + str(dimension) + " \"" + g += " NumberType=\"Float\" Precision=\"8\" Format=\"XML\">\n" + step = list(topo.mesh.space_step) + step.reverse() + g += " " + _listFormat(step) + "\n" + g += " </DataItem>\n" + g += " </Geometry>\n" + for name in datasetNames: + g += " <Attribute Name=\"" + g += name + "\"" + g += " AttributeType=\"Scalar\" Center=\"Node\">\n" + g += " <DataItem Dimensions=\"" + g += _listFormat(resolution) + " \"" + g += " NumberType=\"Float\" Precision=\"8\" Format=\"HDF\"" + g += " Compression=\"Raw\">\n" # + g += " " + filename.split('/')[-1] + g += ":/" + name + g += "\n </DataItem>\n" + g += " </Attribute>\n" + g += " </Grid>\n" + return g diff --git a/HySoP/hysop/operator/monitors/reader.py b/HySoP/hysop/operator/monitors/reader.py new file mode 100644 index 000000000..9241f3957 --- /dev/null +++ b/HySoP/hysop/operator/monitors/reader.py @@ -0,0 +1,141 @@ +""" +@file reader.py + +File output for field(s) value on a grid. +""" +from parmepy.constants import debug, HDF5 +from parmepy.operator.monitors.monitoring import Monitoring +import parmepy.tools.io_utils as io +import os + +try: + import h5py +except ImportError as h5py_error: + h5py = None +from parmepy.tools.timers import timed_function + + +class Reader(Monitoring): + """ + Print field(s) values on a given topo, in HDF5 or VTK format. + """ + def __init__(self, prefix, formattype=None, subset=None, names=None, + **kwds): + """ + @param variables : list of variables to read. + @param prefix input file name (without ext) + @param formattype : input file format, default=HDF5. + """ + super(Reader, self).__init__(**kwds) + ## Default output type + if formattype is None: + self.formattype = HDF5 + else: + self.formattype = formattype + if self.formattype is not HDF5: + raise ValueError("Format not allowed : only HDF5\ + readers are implemented.") + if self.formattype == HDF5 and h5py is None: + print ("You set a printer with HDF5 as format and h5py module ",) + print ("is not present. You must specify another extension",) + print (" (DATA or VTK)") + raise h5py_error + + self.input = self.variables + self.output = self.variables + if not os.path.isabs(prefix): + prefix = os.path.join(io.io.defaultPath(), prefix) + + if self.topology is not None: + io.io.checkDir(prefix, 0, self.topology.comm) + self.prefix = prefix + self._isUpToDate = True + ## Set a subset of the original domain, to reduce + ## output + self.subset = subset + if self.subset is not None: + self.subset.discretize(self.topology) + self._slices = self.subset.slices[self.topology] + # Global resolution for hdf5 output + self.globalResolution = self.subset.globalResolution(self.topology) + else: + self.globalResolution = list(self.topology.globalMeshResolution - 1) + self._slices = self.topology.mesh.iCompute + self.globalResolution.reverse() + self.step = self.readHDF5 + filename = self.prefix + '.h5' + assert os.path.isfile(filename), 'error, file does not exists' + if self.topology.size == 1: + self._file = h5py.File(filename, "r") + else: + self._file = h5py.File(filename, 'r', driver='mpio', + comm=self.topology.comm) + self._globalSlice = [] + if self.subset is None: + # Note : g_start and g_end do not include ghost points. + g_start = self.topology.mesh.global_start + g_end = self.topology.mesh.global_end + 1 + self._globalSlice = [slice(g_start[i], g_end[i]) + for i in xrange(self.domain.dimension)] + else: + g_start = self.subset.gstart + # convert self._slices to global position in topo + self._globalSlice = self.topology.toIndexGlobal(self._slices) + # And shift using global position of the surface + self._globalSlice = [slice(self._globalSlice[i].start - g_start[i], + self._globalSlice[i].stop - g_start[i]) + for i in xrange(self.domain.dimension)] + self._globalSlice.reverse() + self._globalSlice = tuple(self._globalSlice) + if names is None: + self.names = {} + names = self.dataset_names() + i = 0 + for field in self.variables: + self.names[field] = [] + for d in xrange(field.nbComponents): + self.names[field].append(names[i]) + i += 1 + else: + self.names = names + for field in self.variables: + fname = self.names[field] + self.names[field] = [v for v in self.dataset_names() + if fname in v] + # assert len(self.names[field]) == field.nbComponents + + @debug + @timed_function + def apply(self, simulation=None): + self.step() + + def dataset_names(self): + """ + Return the list of available names for datasets in + the required file. + """ + return self._file.keys() + + def readHDF5(self): + # It's necessary to compute the set of indices of the current subset + # in global notation + for field in self.variables: + df = field.discreteFields[self.topology] + for d in xrange(df.nbComponents): + # creating datasets for the vector field + #currentName = df.name + S_DIR[d] + #if not currentName in f.iterkeys(): + # raise ValueError("The required field name is \ + # not in HDF5 file.") + #Note FP : temp method --> use the first name is dataset + # as data for field. Todo : set a list of names + # to be downloaded. + currentName = self.names[field][d] + ds = self._file[currentName] + # In parallel, each proc must write in the proper part + # Of the dataset (of site global resolution) + df.data[d][self._slices] = ds[self._globalSlice].T + + def finalize(self): + Monitoring.finalize(self) + self._file.close() diff --git a/HySoP/hysop/operator/redistribute_intercomm.py b/HySoP/hysop/operator/redistribute_intercomm.py new file mode 100644 index 000000000..bb223b9e4 --- /dev/null +++ b/HySoP/hysop/operator/redistribute_intercomm.py @@ -0,0 +1,343 @@ +""" +@file redistribute_intercomm.py +Setup for data transfer/redistribution between a single parmes topology based +on different MPI communicators with null intersection (for example +by Comm_Split). One of the topology is labeled as the source and the other is +the destination. + +It relies on a Bridge_intercomm. +""" +from parmepy.constants import debug, PARMES_MPI_REAL, ORDERMPI, S_DIR, np +from parmepy import __VERBOSE__ +from parmepy.operator.continuous import Operator +from parmepy.mpi.topology import Bridge_intercomm +from parmepy.methods_keys import Support + + +class RedistributeIntercomm(Operator): + """ + Interconnection between two topologies on different sub set of MPI process. + SetUp will compute a Bridge_intercomm between a single topology. + Transfers data from topology of id_from to the id_to. + """ + @debug + def __init__(self, op_from, op_to, proc_tasks, + parent_comm, component=None, name_suffix='', **kwds): + """ + Create an operator to distribute data between two mpi topologies for a + list of variables. + + @param variables : the set of variables to be redistributed + @param topo : Parmes topology that differs across process of the + parent_comm MPI intracommunicator. + @param id_from : id of the task considered as input. + @param id_to : id of the task considered as output. + @param proc_tasks: python array specifying the task id of each of + the parent_comm MPI intracommunicator. + @param parent_comm : Parent communicator (Each process that use this + operator must be a member of the parent_comm) + @param component : Component to consider. + @remark : proc_tasks size and number of processus in parent_comm + must be equal. + """ + super(RedistributeIntercomm, self).__init__(**kwds) + vars_str = "_(" + for vv in self.variables: + vars_str += vv.name + "," + vars_str = vars_str[:-1] + ')' + if not component is None: + vars_str += S_DIR[component] + self.name += vars_str+name_suffix + assert parent_comm.Get_size() == len(proc_tasks), \ + "Parent communicator ({0})".format(parent_comm.Get_size()) + \ + " and size of the task id array " + \ + "({0}) are not equal".format(len(proc_tasks)) + self.opFrom = op_from + self.opTo = op_to + self.id_from = self.opFrom.task_id + self.id_to = self.opTo.task_id + self.parent_comm = parent_comm + self._dim = self.variables[0].domain.dimension + self.proc_tasks = proc_tasks + self.input = self.output = self.variables + self.component = component + if component is None: + # All components are considered + self._range_components = lambda v: range(v.nbComponents) + else: + # Only the given component is considered + self._range_components = lambda v: [component] + + self.bridges = {} + self.r_request = {} + self.s_request = {} + self._r_types = {} + self._s_types = {} + for v in self.variables: + self._r_types[v] = {} + self._s_types[v] = {} + self._toHost_fields = [] + self._toDevice_fields = [] + self._parent_rank = self.parent_comm.Get_rank() + self._my_rank = None + + def discretize(self): + + for v in self.variables: + if self.topology is None: + if self.proc_tasks[self._parent_rank] == self.id_from: + self.topology = self.opFrom.discreteFields[v].topology + else: + self.topology = self.opTo.discreteFields[v].topology + + self._my_rank = self.topology.comm.Get_rank() + self._dim = self.topology.domain.dimension + + for v in self.variables: + self.discreteFields[v] = v.discretize(self.topology) + + @debug + def setUp(self): + """ + Computes intersection of topologies and set the MPI intercommunicator. + """ + assert self.topology.isUpToDate, \ + """You should setup topology + before any attempt to setup a redistribute operator.""" + + # Look for an operator opertating on device. + try: + opFrom_is_device = \ + self.opFrom.method[Support].find('gpu') >= 0 + except KeyError: # op.method is a dict not containing Support in keys + opFrom_is_device = False + except IndexError: # op.method is a sting + opFrom_is_device = False + except TypeError: # op.method is None + opFrom_is_device = False + try: + opTo_is_device = \ + self.opTo.method[Support].find('gpu') >= 0 + except KeyError: # op.method is a dict not containing Support in keys + opTo_is_device = False + except IndexError: # op.method is a sting + opTo_is_device = False + except TypeError: # op.method is None + opTo_is_device = False + + if not opFrom_is_device and not opTo_is_device: + # case: opFrom(host) --bridge--> opTo(host) + self._the_apply = self._apply_host + else: + # Have on device operators + if opFrom_is_device and not opTo_is_device: + # case: opFrom(GPU) --toHost--bridge--> opTo(host) + self._the_apply = self._apply_toHost_host + elif not opFrom_is_device and opTo_is_device: + # case: opFrom(host) --bridge--toDevice--> opTo(GPU) + self._the_apply = self._apply_host_toDevice + else: + # case: opFrom(GPU) --toHost--bridge--toDevice--> opTo(host) + # Transfers are removed if variables are batched + if np.any([self.opFrom.discreteFields[v].isBatch + for v in self.variables] + + [self.opTo.discreteFields[v].isBatch + for v in self.variables]): + self._the_apply = self._host + else: + self._the_apply = self._apply_toHost_host_toDevice + + # Build bridges and toTransfer lists + self.bridge = Bridge_intercomm(self.topology, self.parent_comm, + self.id_from, self.id_to, + self.proc_tasks) + + for v in self.variables: + # toTransfer list completion + if self.proc_tasks[self._parent_rank] == self.id_from: + if opFrom_is_device: + self._toHost_fields.append(self.opFrom.discreteFields[v]) + if self.proc_tasks[self._parent_rank] == self.id_to: + if opTo_is_device: + self._toDevice_fields.append(self.opTo.discreteFields[v]) + + for v in self.variables: + dv = v.discreteFields[self.topology] + transfers = self.bridge.transfers + # Set reception + if self.proc_tasks[self._parent_rank] == self.id_to: + for from_rk in transfers.keys(): + subshape = tuple( + [transfers[from_rk][i][1] - transfers[from_rk][i][0] + for i in range(self._dim)]) + substart = tuple( + [transfers[from_rk][i][0] for i in range(self._dim)]) + self._r_types[v][from_rk] = \ + PARMES_MPI_REAL.Create_subarray(dv.data[0].shape, + subshape, + substart, + order=ORDERMPI) + self._r_types[v][from_rk].Commit() + # Set Sending + if self.proc_tasks[self._parent_rank] == self.id_from: + for to_rk in transfers.keys(): + subshape = tuple( + [transfers[to_rk][i][1] - transfers[to_rk][i][0] + for i in range(self._dim)]) + substart = tuple( + [transfers[to_rk][i][0] for i in range(self._dim)]) + self._r_types[v][to_rk] = \ + PARMES_MPI_REAL.Create_subarray(dv.data[0].shape, + subshape, + substart, + order=ORDERMPI) + self._r_types[v][to_rk].Commit() + self._isUpToDate = True + + @debug + def apply(self, simulation=None): + """ + Apply this operator to its variables. + @param simulation : object that describes the simulation + parameters (time, time step, iteration number ...), see + parmepy.problem.simulation.Simulation for details. + """ + for req in self.requirements: + req.wait() + self._the_apply(simulation) + + def _apply_toHost_host_toDevice(self, simulation=None): + if __VERBOSE__: + print ("{0} APPLY toHOST+HOST+toDEVICE".format(self._parent_rank)) + if self.proc_tasks[self._parent_rank] == self.id_from: + self._toHost() + self._wait_device() + self._host() + self._wait_host() + if self.proc_tasks[self._parent_rank] == self.id_to: + self._toDevice() + self._wait_device() + + def _apply_toHost_host(self, simulation=None): + + if __VERBOSE__: + print ("{0} APPLY toHOST+HOST".format(self._parent_rank)) + if self.proc_tasks[self._parent_rank] == self.id_from: + self._toHost() + self._wait_device() + self._host() + self._wait_host() + + def _apply_host_toDevice(self, simulation=None): + if __VERBOSE__: + print ("{0} APPLY HOST+toDEVICE".format(self._parent_rank)) + self._host() + self._wait_host() + self.parent_comm.Barrier() + if self.proc_tasks[self._parent_rank] == self.id_to: + self._toDevice() + self._wait_device() + self.parent_comm.Barrier() + + def _apply_host(self, simulation=None): + if __VERBOSE__: + print ("{0} APPLY HOST".format(self._parent_rank)) + self._host() + self._wait_host() + + def _host(self, simulation=None): + """ + Proceed with data redistribution from opFrom to opTo + """ + self.parent_comm.Barrier() + self.r_request = {} + self.s_request = {} + for v in self.variables: + dv = v.discreteFields[self.topology] + transfers = self.bridge.transfers + for d in self._range_components(v): + v_name = dv.name + S_DIR[d] + # Set reception + if self.proc_tasks[self._parent_rank] == self.id_to: + for from_rk in transfers.keys(): + self.r_request[v_name + str(from_rk)] = \ + self.bridge.inter_comm.Irecv( + [dv.data[d], 1, self._r_types[v][from_rk]], + source=from_rk, tag=from_rk) + # Set Sending + if self.proc_tasks[self._parent_rank] == self.id_from: + for to_rk in transfers.keys(): + self.s_request[v_name + str(to_rk)] = \ + self.bridge.inter_comm.Issend( + [dv.data[d], 1, self._r_types[v][to_rk]], + dest=to_rk, tag=self._my_rank) + + def _toHost(self): + """ + Proceed with data transfer of variables from device to host + """ + if __VERBOSE__: + print ("{0} APPLY toHOST".format(self._parent_rank)) + for v in self.variables: + dv = self.opFrom.discreteFields[v] + if dv in self._toHost_fields: + dv.toHost(self.component) + + def _toDevice(self): + """ + Proceed with data transfer of variables from device to host + """ + if __VERBOSE__: + print ("{0} APPLY toDEVICE".format(self._parent_rank)) + for v in self.variables: + dv = self.opTo.discreteFields[v] + if dv in self._toDevice_fields: + dv.toDevice(self.component) + + def _wait_device(self): + if __VERBOSE__: + print ("{0} WAIT OPENCL".format(self._parent_rank)) + for dv in self._toDevice_fields + self._toHost_fields: + dv.wait() + + def _wait_host(self, simulation=None): + """Wait for requests completion.""" + if __VERBOSE__: + print ("{0} WAIT MPI".format(self._parent_rank)) + for rk in self.r_request: + self.r_request[rk].Wait() + for rk in self.s_request: + self.s_request[rk].Wait() + self.parent_comm.Barrier() + self.r_request = [] + self.s_request = [] + + def test(self, rsend=None, rrecv=None): + """ + if neither rsend or rrecv is given return + True if all communication request are complete + else check for sending to rsend or + receiving from rrecv. Process ranks + should be given in local communicator. + @param rsend : variable name + S_DIR + rank + @param rrecv : variable name + S_DIR + rank + """ + if(rsend is not None or rrecv is not None): + send_res = True + recv_res = True + if rsend is not None: + send_res = self.s_request[rsend].Test() + if rrecv is not None: + recv_res = self.r_request[rrecv].Test() + res = send_res and recv_res + else: + res = True + for rk in self.r_request.keys(): + res = self.r_request[rk].Test() + if not res: + return res + for rk in self.s_request.keys(): + res = self.s_request[rk].Test() + if not res: + return res + return res diff --git a/HySoP/hysop/test/__init__.py b/HySoP/hysop/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/HySoP/hysop/test/main_unit_tests.py b/HySoP/hysop/test/main_unit_tests.py new file mode 100644 index 000000000..7837dff17 --- /dev/null +++ b/HySoP/hysop/test/main_unit_tests.py @@ -0,0 +1,32 @@ +""" +Launch tests for parmepy +""" +import unittest +import doctest +import sys +import os +# Insert parmepy sources path to sys.path from sys.path[0] (i.e. absolute path to __file__) +# This file is desined to be launched after calling: setup.py build +# Then this file is located in ./build/lib._platform_dependent_directory/parmepy/test +# Tests are run on parmepy sources located in ./build/lib._platform_dependent_directory +if sys.path[0].find("build/lib.") >= 0: + sys.path.insert(1, os.path.split(os.path.split(sys.path[0])[0])[0]) +import parmepy + +# Automatic recursive finding unittest.TestCase implemetations in package 'test' +suite = unittest.TestLoader().discover(sys.path[0], pattern='test*.py') + +# Add doctests from python files +suite.addTest(doctest.DocFileSuite('domain/box.py', package=parmepy)) + +runner = unittest.TextTestRunner(verbosity=2).run(suite) + +if sys.path[0].find("build/lib.") >= 0: + if not runner.wasSuccessful(): + fails = "\nFAILURES in " + __file__ + " : (" + str(len(runner.failures)) + ")\n" + for fail in runner.failures: + fails += fail[1] + log_failures = open('Testing/Temporary/PythonFailures.log', 'w') + log_failures.write(fails) + log_failures.close() + raise Exception("FAILED") diff --git a/HySoP/hysop/test/test_obstacle/__init__.py b/HySoP/hysop/test/test_obstacle/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/HySoP/hysop/test/test_obstacle/test_obstacle.py b/HySoP/hysop/test/test_obstacle/test_obstacle.py new file mode 100644 index 000000000..7154dac26 --- /dev/null +++ b/HySoP/hysop/test/test_obstacle/test_obstacle.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +import unittest +import time +import parmepy as pp +import numpy as np +import numpy.testing as npt +from parmepy.constants import * +from math import * + + + +def run(): + # Parameters + nb = 65 + timeStep = 0.02 + finalTime = 1. +# outputFilePrefix = './parmepy/test/test_obstacle/Domain_' + outputFilePrefix = './res/Domain_' + outputModulo = 1 + + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Obstacle + sphere = pp.Obstacle(box, name='sphere', zlayer=0.1, radius=0.2, center=[0.5,0.5,0.5], orientation='West', porousLayer=0.1) + + ## ChiDomain + chiDomain = pp.ContinuousField(domain=box, name='ChiDomain', vector=False) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3, periods = [False, False, False]) + + ## Obstacle discretization + chiDomain.discretize(topo3D) + chiDomainD = chiDomain.discreteField[0] + sphere.discretize(topo3D) + sphereD = sphere.discreteObstacle[0] + sphereD.chiFunctions() + for x in sphereD.chiBoundary[:] : + chiDomainD[x[0], x[1], x[2]]=1. + for x in sphereD.chiSolid[:] : + chiDomainD[x[0], x[1], x[2]]=1. + for x in sphereD.chiPorous[:] : + chiDomainD[x[0], x[1], x[2]]=0.5 +# for k in xrange (topo3D.mesh.resolution[2]): +# for j in xrange (topo3D.mesh.resolution[2]): +# for i in xrange (topo3D.mesh.resolution[2]): +# if ([i,j,k] in sphereD.chiBoundary) : +# chiDomainD[i,j,k]=1. +# if ([i,j,k] in sphereD.chiSolid) : +# chiDomainD[i,j,k]=1. +# if ([i,j,k] in sphereD.chiPorous) : +# chiDomainD[i,j,k]=0.5 + io=pp.Printer(fields=[chiDomain], frequency=outputModulo, outputPrefix=outputFilePrefix) + io.step() + + t1 = time.time() + + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/HySoP/hysop/test/test_operator/__init__.py b/HySoP/hysop/test/test_operator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/HySoP/hysop/test/test_operator/test_CondStability.py b/HySoP/hysop/test/test_operator/test_CondStability.py new file mode 100755 index 000000000..e8b0c1271 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_CondStability.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +import time +from parmepy.operator.differentialOperator_d import DifferentialOperator_d +from parmepy.particular_solvers.integrator.euler import Euler +#from parmepy.particular_solvers.integrator.runge_kutta2 import RK2 +#from parmepy.particular_solvers.integrator.runge_kutta3 import RK3 +#from parmepy.particular_solvers.integrator.runge_kutta4 import RK4 +import parmepy as pp +from parmepy.constants import * +import numpy as np +from math import * +import unittest +#import sys +import struct +import array + + +class test_CondStability(unittest.TestCase): + """ + Condition Stability test class + """ + + def vitesse(self,x, y, z): + vx = 1. + vy = 1. + vz = 1. + return vx, vy, vz + + def vorticite(self,x, y, z): + wx = 1. + wy = 1. + wz = 1. + return wx, wy, wz + + def scalaire(self,x, y, z): + if x < 0.5 and y < 0.5 and z < 0.5: + return 1. + else: + return 0. + + + def testCondStab(self): + # Parameters + nb = 128 + timeStep = 0.09 + finalTime = 0.09 + self.t = 0. + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Fields + velo = pp.AnalyticalField(domain=box, formula=self.vitesse, name='Velocity', vector=True) + vorti = pp.AnalyticalField(domain=box, formula=self.vorticite, name='Vorticity', vector=True) + + inputJBField = [np.zeros((nb,nb,nb), dtype=PARMES_REAL, order=ORDER) for d in xrange(3)] + + f1 = open('./parmepy/test/data/Fields_sav0_U.data','rb') + f2 = open('./parmepy/test/data/Fields_sav0_V.data','rb') + f3 = open('./parmepy/test/data/Fields_sav0_W.data','rb') + + nbx = np.asarray(struct.unpack("i",f1.read(4))) + nby = np.asarray(struct.unpack("i",f1.read(4))) + nbz = np.asarray(struct.unpack("i",f1.read(4))) + + binvalues = array.array('d') + binvalues.read(f1, nbx*nby*nbz) + + data = np.array(binvalues, dtype=PARMES_REAL) + inputJBField[0] = np.reshape(data, (nbx,nby,nbz)) + f1.close() + + nbx = np.asarray(struct.unpack("i",f2.read(4))) + nby = np.asarray(struct.unpack("i",f2.read(4))) + nbz = np.asarray(struct.unpack("i",f2.read(4))) + + binvalues = array.array('d') + binvalues.read(f2, nbx*nby*nbz) + + data = np.array(binvalues, dtype=PARMES_REAL) + inputJBField[1] = np.reshape(data, (nbx,nby,nbz)) + f2.close() + + nbx = np.asarray(struct.unpack("i",f3.read(4))) + nby = np.asarray(struct.unpack("i",f3.read(4))) + nbz = np.asarray(struct.unpack("i",f3.read(4))) + + binvalues = array.array('d') + binvalues.read(f3, nbx*nby*nbz) + + data = np.array(binvalues, dtype=PARMES_REAL) + inputJBField[2] = np.reshape(data, (nbx,nby,nbz)) + f3.close() + + ## Operators + stretch = pp.Stretching(velo,vorti) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nbx[0]+1, nby[0]+1, nbz[0]+1], dim=3, ghosts=[2,2,2]) + + ##Problem + pb = pp.Problem(topo3D, [stretch]) + + ## Setting solver to Problem + pb.setSolver(finalTime, timeStep, solver_type='basic') + pb.solver.ODESolver= Euler#RK4# RK3# RK2# + pb.initSolver() + + +# self.result = [np.ones((nbx, nby, nbz), dtype=PARMES_REAL, order=ORDER) for d in xrange(3)] +# vortidata= [np.zeros((128,128,128), dtype=PARMES_REAL, order=ORDER) for d in xrange(3)] + ## Input of JB velocity Fields +# print 'shape', stretch.velocity.discreteField[0].data[1][2:nb+2, 2:nb+2,2:nb+2].shape ,inputJBField[1].shape + stretch.velocity.discreteField[0].data[0][2:nb+2,2:nb+2,2:nb+2] = inputJBField[0] + stretch.velocity.discreteField[0].data[1][2:nb+2,2:nb+2,2:nb+2] = inputJBField[1] + stretch.velocity.discreteField[0].data[2][2:nb+2,2:nb+2,2:nb+2] = inputJBField[2] +# print 'shape', np.asarray(stretch.velocity.discreteField[0].data).shape + + ## Calculation of vorticity Fields from velocity input data (JB) + self.curl = DifferentialOperator_d(stretch.velocity.discreteField[0].data, stretch.velocity.discreteField[0].data, choice='curl', topology=topo3D) + stretch.vorticity.discreteField[0].data = self.curl.discreteOperator.apply() + t1 = time.time() + + ## Solve problem to deduce the LCFL + pb.solve() + + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testCondStab() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_CondStability)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_Curl.py b/HySoP/hysop/test/test_operator/test_Curl.py new file mode 100755 index 000000000..db99cda64 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_Curl.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +import unittest + +#import parmepy + +from parmepy.operator.transport import * +from parmepy.operator.continuous import * +from parmepy.operator.differentialOperator import * +from parmepy.operator.stretching import * +from parmepy.fields.discrete import * +from parmepy.fields.continuous import * +from parmepy.fields.analytical import * +from parmepy.domain.topology import * +from parmepy.domain.box import * +from parmepy.constants import * +from parmepy.particular_solvers.basic import * +from parmepy.particular_solvers.integrator.euler import * +from parmepy.particular_solvers.solver import * +import numpy as np +import numpy.testing as npt +import math + + +class test_Curl(unittest.TestCase): + """ + DiscreteVariable test class + """ + def setUp(self): + self.e = 0.0001 # Accepted error between result and analytical result + self.dim = 3 + self.boxLength = [2.*np.pi, 2.*np.pi, 2.*np.pi] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [33, 33, 33] + self.t = 0. + self.timeStep = 0.02 + self.box = Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + + def testOperatorCurl(self): + # Continuous fields and operator declaration + self.velo = AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + self.curl = DifferentialOperator(self.velo, self.velo, choice='curl') + # Topology definition + self.topo3D = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[2,2,2]) + self.topo3DnoG = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[0,0,0]) + self.result = [np.ones((self.topo3D.mesh.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + # Fields and operator discretization + self.velo.discretize(self.topo3D) + self.velo.initialize() + self.curl.discretize(self.velo.discreteField[self.velo._fieldId], self.velo.discreteField[self.velo._fieldId], topology=self.topo3D) + self.result = self.curl.discreteOperator.apply() + self.FinalTime = 0.02 + self.anal = np.vectorize(self.vorticite)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + # Comparison with analytical solution +# print "max:",np.max(abs(self.anal[0]-self.result[0])) + ind0a = self.topo3D.ghosts[0] + ind0b = self.topo3D.mesh.resolution[0]-self.topo3D.ghosts[0] + ind1a = self.topo3D.ghosts[1] + ind1b = self.topo3D.mesh.resolution[1]-self.topo3D.ghosts[1] + ind2a = self.topo3D.ghosts[2] + ind2b = self.topo3D.mesh.resolution[2]-self.topo3D.ghosts[2] + npt.assert_array_less(abs(self.anal[0] - \ + self.result[0][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[1]-self.result[1])) + npt.assert_array_less(abs(self.anal[1] - \ + self.result[1][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[2]-self.result[2])) + npt.assert_array_less(abs(self.anal[2] - \ + self.result[2][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) + + def vitesse(self, x, y, z): +# amodul = np.cos(np.pi*self.t/3) +# pix = np.pi*x +# piy = np.pi*y +# piz = np.pi*z +# pi2x = 2.*pix +# pi2y = 2.*piy +# pi2z = 2.*piz +# vx = 2.*np.sin(pix)*np.sin(pix)*np.sin(pi2y)*np.sin(pi2z)*amodul +# vy = -np.sin(pi2x)*np.sin(piy)*np.sin(piy)*np.sin(pi2z)*amodul +# vz = -np.sin(pi2x)*np.sin(piz)*np.sin(piz)*np.sin(pi2y)*amodul +# vx = np.cos(y) +# vy = np.cos(z) +# vz = np.cos(x) + vx = np.cos(y) * np.cos(z) + vy = np.cos(z) * np.cos(x) + vz = np.cos(x) * np.cos(y) + return vx, vy, vz + + def vorticite(self, x, y, z): +# amodul = np.cos(np.pi*self.t/3) +# pix = np.pi*x +# piy = np.pi*y +# piz = np.pi*z +# pi2x = 2.*pix +# pi2y = 2.*piy +# pi2z = 2.*piz +# wx = 2.* np.pi * np.sin(pi2x) * amodul*( - np.cos(pi2y)*np.sin(piz)*np.sin(piz)+ np.sin(piy)*np.sin(piy)*np.cos(pi2z) ) +# wy = 2.* np.pi * np.sin(pi2y) * amodul*( 2.*np.cos(pi2z)*np.sin(pix)*np.sin(pix)+ np.sin(piz)*np.sin(piz)*np.cos(pi2x) ) +# wz = -2.* np.pi * np.sin(pi2z) * amodul*( np.cos(pi2x)*np.sin(piy)*np.sin(piy)+ np.sin(pix)*np.sin(pix)*np.cos(pi2y) ) +# wx = np.sin(z) +# wy = np.sin(x) +# wz = np.sin(y) + wx = np.cos(x) * (np.sin(z) - np.sin(y)) + wy = np.cos(y) * (np.sin(x) - np.sin(z)) + wz = np.cos(z) * (np.sin(y) - np.sin(x)) + return wx, wy, wz + + def runTest(self): + self.setUp() + self.testOperatorCurl() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Curl)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_DivProduct.py b/HySoP/hysop/test/test_operator/test_DivProduct.py new file mode 100755 index 000000000..0a5abf49a --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_DivProduct.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +import unittest + +#import parmepy + +from parmepy.operator.transport import * +from parmepy.operator.continuous import * +from parmepy.operator.differentialOperator import * +from parmepy.operator.stretching import * +from parmepy.fields.discrete import * +from parmepy.fields.continuous import * +from parmepy.fields.analytical import * +from parmepy.domain.topology import * +from parmepy.domain.box import * +from parmepy.constants import * +from parmepy.particular_solvers.basic import * +from parmepy.particular_solvers.integrator.euler import * +from parmepy.particular_solvers.solver import * +import numpy as np +import numpy.testing as npt +import math + + +class test_DivProduct(unittest.TestCase): + """ + DiscreteVariable test class + """ + def setUp(self): + self.e = 0.0002 # Accepted error between result and analytical result + self.dim = 3 + self.boxLength = [2.*np.pi, 2.*np.pi, 2.*np.pi] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [32, 32, 32] + self.timeStep = 0.02 + self.ghosts = [2,2,2] + self.box = Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + + def testOperatorDiv(self): + # Continuous fields and operator declaration + self.velo = AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + self.vorti = AnalyticalField(domain=self.box, formula=self.vorticite, name='Vorticity', vector=True) + # chercher cas test de tel sorte que le stretching serait periodique et analytique + self.div = DifferentialOperator(self.vorti, self.velo, choice='divWU') + # Topology definition / Fields and operator discretization +# self.result = [np.ones((self.nbPts), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + self.topo3D = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=self.ghosts) + self.topo3DnoG = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[0,0,0]) + self.vorti.discretize(self.topo3D) + self.velo.discretize(self.topo3D) + self.vorti.initialize() + self.velo.initialize() +# print 'size velo', self.velo.discreteField[self.velo._fieldId] + self.div.discretize(self.vorti.discreteField[self.vorti._fieldId], self.velo.discreteField[self.velo._fieldId], topology=self.topo3D) + self.result = self.div.discreteOperator.apply() + self.resol = self.topo3D.mesh.resolution + self.FinalTime = 0.2 + self.anal=np.vectorize(self.analyticalDivProduct)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + # Comparison with analytical solution +# npt.assert_array_less(abs(self.anal[0][self.ghosts[0]:self.nbPts[0]+self.ghosts[0],\ +# self.ghosts[1]:self.nbPts[1]+self.ghosts[1],\ +# self.ghosts[2]:self.nbPts[2]+self.ghosts[2]]-self.result[0]), self.e) +# npt.assert_array_less(abs(self.anal[1][self.ghosts[0]:self.nbPts[0]+self.ghosts[0],\ +# self.ghosts[1]:self.nbPts[1]+self.ghosts[1],\ +# self.ghosts[2]:self.nbPts[2]+self.ghosts[2]]-self.result[1]), self.e) +# npt.assert_array_less(abs(self.anal[2][self.ghosts[0]:self.nbPts[0]+self.ghosts[0],\ +# self.ghosts[1]:self.nbPts[1]+self.ghosts[1],\ +# self.ghosts[2]:self.nbPts[2]+self.ghosts[2]]-self.result[2]), self.e) +# print "max:",np.max(abs(self.anal[2][self.ghosts[0]:self.nbPts[0]+self.ghosts[0],\ +# self.ghosts[1]:self.nbPts[1]+self.ghosts[1],\ +# self.ghosts[2]:self.nbPts[2]+self.ghosts[2]]-self.result[2])) + + npt.assert_array_less(abs(self.anal[0]-self.result[0]), self.e) + npt.assert_array_less(abs(self.anal[1]-self.result[1]), self.e) + npt.assert_array_less(abs(self.anal[2]-self.result[2]), self.e) + print "max:",np.max(abs(self.anal[2]-self.result[2])) + + def vitesse(self, x, y, z): + vx = np.sin(x) + vy = np.sin(y) + vz = np.sin(z) + return vx, vy, vz + + def vorticite(self, x, y, z): + wx = 1. + wy = 1. + wz = 1. + return wx, wy, wz + + def analyticalDivProduct(self, x, y, z): + sx = np.cos(x) + sy = np.cos(y) + sz = np.cos(z) + return sx, sy, sz + + def runTest(self): + self.setUp() + self.testOperatorDiv() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_DivProduct)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_Forces.py b/HySoP/hysop/test/test_operator/test_Forces.py new file mode 100755 index 000000000..ae5f758e6 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_Forces.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +import time +from parmepy.physics.compute_forces import Compute_forces +import parmepy as pp +import numpy as np +from math import * +import unittest + + + +class test_Forces(unittest.TestCase): + """ + DiscreteVariable test class + """ + + def vitesse(self,x, y, z): +# vx = 1. + x +# vy = - x * y +# vz = x * y * z + 10. + amodul = np.cos(np.pi*self.t/3) + pix = np.pi*x + piy = np.pi*y + piz = np.pi*z + pi2x = 2.*pix + pi2y = 2.*piy + pi2z = 2.*piz + vx = 2.*np.sin(pix)*np.sin(pix)*np.sin(pi2y)*np.sin(pi2z)*amodul + vy = -np.sin(pi2x)*np.sin(piy)*np.sin(piy)*np.sin(pi2z)*amodul + vz = -np.sin(pi2x)*np.sin(piz)*np.sin(piz)*np.sin(pi2y)*amodul + return vx, vy, vz + + def vorticite(self,x, y, z): +# wx = x * y +# wy = y * z +# wz = - y + amodul = np.cos(np.pi*self.t/3) + pix = np.pi*x + piy = np.pi*y + piz = np.pi*z + pi2x = 2.*pix + pi2y = 2.*piy + pi2z = 2.*piz + wx = 2.* np.pi * np.sin(pi2x) * amodul*( - np.cos(pi2y)*np.sin(piz)*np.sin(piz)+ np.sin(piy)*np.sin(piy)*np.cos(pi2z) ) + wy = 2.* np.pi * np.sin(pi2y) * amodul*( 2.*np.cos(pi2z)*np.sin(pix)*np.sin(pix)+ np.sin(piz)*np.sin(piz)*np.cos(pi2x) ) + wz = -2.* np.pi * np.sin(pi2z) * amodul*( np.cos(pi2x)*np.sin(piy)*np.sin(piy)+ np.sin(pix)*np.sin(pix)*np.cos(pi2y) ) + return wx, wy, wz + + def scalaire(self,x, y, z): + if x < 0.5 and y < 0.5 and z < 0.5: + return 1. + else: + return 0. + + + def testComputeForces(self): + # Parameters + nb = 11 + timeStep = 0.09 + finalTime = 0.36 + self.t = 0. + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Obstacle + sphere = pp.Obstacle(box, zlayer=0.1, radius=0.1, + center=[0.5, 0.5, 0.5], name='sphere', + orientation='West', porousLayer=0.05) + + ## Fields + velo = pp.AnalyticalField(domain=box, formula=self.vitesse, name='Velocity', vector=True) + vorti = pp.AnalyticalField(domain=box, formula=self.vorticite, name='Vorticity', vector=True) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3, ghosts=[2,2,2]) + + ## Fields discretization + vorti.discretize(topo3D) + velo.discretize(topo3D) + vorti.initialize() + velo.initialize() + + # Forces computation + Re = 200. + noca = Compute_forces(topo3D, sphere, boxMin= [0.2, 0.2, 0.2], boxMax=[0.8, 0.8, 0.8]) + if (topo3D.rank == 0): + f = open('./parmepy/test/test_operator/NocaForces.dat', 'w') + + while (self.t <= finalTime): + nocares = noca.apply(self.t, timeStep, velo.discreteField[velo._fieldId], vorti.discreteField[vorti._fieldId], Re) + if (topo3D.rank == 0): + # print time and forces values in the following order : time, cX, cY, cZ + f.write("%s %s %s %s\n" % (self.t, nocares[0], nocares[1], nocares[2])) + + + self.t = self.t + timeStep + + if (topo3D.rank == 0): + f.close() + + t1 = time.time() + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testComputeForces() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Forces)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_Grad.py b/HySoP/hysop/test/test_operator/test_Grad.py new file mode 100755 index 000000000..ac8364907 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_Grad.py @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +import unittest + +#import parmepy + +from parmepy.operator.transport import * +from parmepy.operator.continuous import * +from parmepy.operator.differentialOperator import * +from parmepy.operator.stretching import * +from parmepy.fields.discrete import * +from parmepy.fields.continuous import * +from parmepy.fields.analytical import * +from parmepy.domain.topology import * +from parmepy.domain.box import * +from parmepy.constants import * +from parmepy.particular_solvers.basic import * +from parmepy.particular_solvers.integrator.euler import * +from parmepy.particular_solvers.solver import * +import numpy as np +import numpy.testing as npt +import math + + +class test_Grad(unittest.TestCase): + """ + DiscreteVariable test class + """ + def setUp(self): + self.e = 0.0001 # Accepted error between numerical and analytical results + self.dim = 3 + self.boxLength = [2.*np.pi, 2.*np.pi, 2.*np.pi] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [33, 33, 33] + self.t = 0. + self.timeStep = 0.02 + self.box = Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + + def testOperatorGrad(self): + # Continuous fields and operator declaration + self.velo = AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + self.grad = DifferentialOperator(self.velo, self.velo, choice='gradV') + # Topology definition + self.topo3D = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[2,2,2]) + self.topo3DnoG = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[0,0,0]) + self.result = [np.ones((self.topo3D.mesh.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim * self.dim)] + # Fields and operator discretization + self.velo.discretize(self.topo3D) + self.velo.initialize() + self.grad.discretize(self.velo.discreteField[self.velo._fieldId], self.velo.discreteField[self.velo._fieldId], topology=self.topo3D) + self.result, maxgersh = self.grad.discreteOperator.apply() + self.FinalTime = 0.02 + self.analX = np.vectorize(self.gradientUx)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + self.analY = np.vectorize(self.gradientUy)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + self.analZ = np.vectorize(self.gradientUz)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + # Comparison with analytical solution +# print "max:",np.max(abs(self.anal[0]-self.result[0])) + ind0a = self.topo3D.ghosts[0] + ind0b = self.topo3D.mesh.resolution[0]-self.topo3D.ghosts[0] + ind1a = self.topo3D.ghosts[1] + ind1b = self.topo3D.mesh.resolution[1]-self.topo3D.ghosts[1] + ind2a = self.topo3D.ghosts[2] + ind2b = self.topo3D.mesh.resolution[2]-self.topo3D.ghosts[2] + + npt.assert_array_less(abs(self.analX[0] - \ + self.result[0][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[1]-self.result[1])) + npt.assert_array_less(abs(self.analX[1] - \ + self.result[1][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[2]-self.result[2])) + npt.assert_array_less(abs(self.analX[2] - \ + self.result[2][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) + + npt.assert_array_less(abs(self.analY[0] - \ + self.result[3][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[1]-self.result[1])) + npt.assert_array_less(abs(self.analY[1] - \ + self.result[4][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[2]-self.result[2])) + npt.assert_array_less(abs(self.analY[2] - \ + self.result[5][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) + + npt.assert_array_less(abs(self.analZ[0] - \ + self.result[6][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[1]-self.result[1])) + npt.assert_array_less(abs(self.analZ[1] - \ + self.result[7][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[2]-self.result[2])) + npt.assert_array_less(abs(self.analZ[2] - \ + self.result[8][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) + + def vitesse(self, x, y, z): +# amodul = np.cos(np.pi*self.t/3) +# pix = np.pi*x +# piy = np.pi*y +# piz = np.pi*z +# pi2x = 2.*pix +# pi2y = 2.*piy +# pi2z = 2.*piz +# vx = 2.*np.sin(pix)*np.sin(pix)*np.sin(pi2y)*np.sin(pi2z)*amodul +# vy = -np.sin(pi2x)*np.sin(piy)*np.sin(piy)*np.sin(pi2z)*amodul +# vz = -np.sin(pi2x)*np.sin(piz)*np.sin(piz)*np.sin(pi2y)*amodul +# vx = np.cos(y) +# vy = np.cos(z) +# vz = np.cos(x) + vx = np.cos(y) * np.cos(z) + vy = np.cos(z) * np.cos(x) + vz = np.cos(x) * np.cos(y) + return vx, vy, vz + + def gradientUx(self, x, y, z): + dUxdx = 0. + dUxdy = - np.sin(y) * np.cos(z) + dUxdz = - np.sin(z) * np.cos(y) + return dUxdx, dUxdy, dUxdz + + def gradientUy(self, x, y, z): + dUydx = - np.sin(x) * np.cos(z) + dUydy = 0. + dUydz = - np.sin(z) * np.cos(x) + return dUydx, dUydy, dUydz + + def gradientUz(self, x, y, z): + dUzdx = - np.sin(x) * np.cos(y) + dUzdy = - np.sin(y) * np.cos(x) + dUzdz = 0. + return dUzdx, dUzdy, dUzdz + + def runTest(self): + self.setUp() + self.testOperatorGrad() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Grad)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_GradUomega.py b/HySoP/hysop/test/test_operator/test_GradUomega.py new file mode 100755 index 000000000..9ebccb53b --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_GradUomega.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +import unittest + +#import parmepy + +from parmepy.operator.transport import * +from parmepy.operator.continuous import * +from parmepy.operator.differentialOperator import * +from parmepy.operator.fct2op import * +from parmepy.operator.stretching import * +from parmepy.fields.discrete import * +from parmepy.fields.continuous import * +from parmepy.fields.analytical import * +from parmepy.domain.topology import * +from parmepy.domain.box import * +from parmepy.constants import * +from parmepy.particular_solvers.basic import * +from parmepy.particular_solvers.integrator.euler import * +from parmepy.particular_solvers.solver import * +import numpy as np +import numpy.testing as npt +import math + + +class test_GradUomega(unittest.TestCase): + """ + DiscreteVariable test class + """ + def setUp(self): + self.e = 0.0001 # Accepted error between numerical and analytical results + self.dim = 3 + self.boxLength = [2.*np.pi, 2.*np.pi, 2.*np.pi] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [33, 33, 33] + self.t = 0. + self.timeStep = 0.02 + self.box = Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + + def testOperatorGradUomega(self): + # Continuous fields and operator declaration + self.velo = AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + self.curl = DifferentialOperator(self.velo, self.velo, choice='curl') + self.grad = DifferentialOperator(self.velo, self.velo, choice='gradV') + # Topology definition + self.topo3D = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[2,2,2]) + self.topo3DnoG = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, ghosts=[0,0,0]) + self.omega = [np.ones((self.topo3D.mesh.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + self.gradientU = [np.ones((self.topo3D.mesh.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim * self.dim)] + self.result = [np.ones((self.topo3D.mesh.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + # Fields and operator discretization + self.velo.discretize(self.topo3D) + self.velo.initialize() + self.curl.discretize(self.velo.discreteField[self.velo._fieldId], self.velo.discreteField[self.velo._fieldId], topology=self.topo3D) + self.grad.discretize(self.velo.discreteField[self.velo._fieldId], self.velo.discreteField[self.velo._fieldId], topology=self.topo3D) + self.omega = self.curl.discreteOperator.apply() + self.gradientU, maxgersh = self.grad.discreteOperator.apply() + self.gradUomega = Fct2Op(self.omega, self.gradientU, choice = 'gradV', topology=self.topo3D) + self.result = self.gradUomega.apply(self.t, self.omega) + + self.FinalTime = 0.02 + self.anal = np.vectorize(self.stretch)(self.topo3DnoG.mesh.coords[0], \ + self.topo3DnoG.mesh.coords[1], \ + self.topo3DnoG.mesh.coords[2]) + + + # Comparison with analytical solution +# print "max:",np.max(abs(self.anal[0]-self.result[0])) + ind0a = self.topo3D.ghosts[0] + ind0b = self.topo3D.mesh.resolution[0]-self.topo3D.ghosts[0] + ind1a = self.topo3D.ghosts[1] + ind1b = self.topo3D.mesh.resolution[1]-self.topo3D.ghosts[1] + ind2a = self.topo3D.ghosts[2] + ind2b = self.topo3D.mesh.resolution[2]-self.topo3D.ghosts[2] + + npt.assert_array_less(abs(self.anal[0] - \ + self.result[0][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[1]-self.result[1])) + npt.assert_array_less(abs(self.anal[1] - \ + self.result[1][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) +# print "max:",np.max(abs(self.anal[2]-self.result[2])) + npt.assert_array_less(abs(self.anal[2] - \ + self.result[2][ind0a:ind0b,ind1a:ind1b,ind2a:ind2b]), self.e) + + def vitesse(self, x, y, z): +# amodul = np.cos(np.pi*self.t/3) +# pix = np.pi*x +# piy = np.pi*y +# piz = np.pi*z +# pi2x = 2.*pix +# pi2y = 2.*piy +# pi2z = 2.*piz +# vx = 2.*np.sin(pix)*np.sin(pix)*np.sin(pi2y)*np.sin(pi2z)*amodul +# vy = -np.sin(pi2x)*np.sin(piy)*np.sin(piy)*np.sin(pi2z)*amodul +# vz = -np.sin(pi2x)*np.sin(piz)*np.sin(piz)*np.sin(pi2y)*amodul +# vx = np.cos(y) +# vy = np.cos(z) +# vz = np.cos(x) + vx = np.cos(y) * np.cos(z) + vy = np.cos(z) * np.cos(x) + vz = np.cos(x) * np.cos(y) + return vx, vy, vz + + def stretch(self, x, y, z): + sx = - np.cos(z) * np.cos(y) * ( np.sin(x) * np.sin(y) - np.sin(z) * np.sin(x)) + sy = - np.cos(z) * np.cos(x) * ( - np.sin(x) * np.sin(y) + np.sin(z) * np.sin(y)) + sz = - np.cos(y) * np.cos(x) * ( np.sin(x) * np.sin(z) - np.sin(y) * np.sin(z)) + return sx, sy, sz + + def runTest(self): + self.setUp() + self.testOperatorGrad() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_GradUomega)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_Penalization.py b/HySoP/hysop/test/test_operator/test_Penalization.py new file mode 100644 index 000000000..4f5529385 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_Penalization.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +import unittest +import time +import parmepy as pp +import numpy as np +from parmepy.particular_solvers.integrator.runge_kutta4 import RK4 +import numpy.testing as npt +from parmepy.constants import * +from math import * + +def vitesse(x, y, z): + vx = 2. + vy = 2. + vz = 2. + return vx, vy, vz + +def vorticite(x, y, z): + wx = 3. + wy = 3. + wz = 3. + return wx, wy, wz + + +def run(): + # Parameters + nb = 129 + timeStep = 0.09 + finalTime = 0.09 + outputFilePrefix = './parmepy/test/test_operator/Penalization_' + outputModulo = 1 + + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Obstacle + lambd=np.array([0, 10, 10**8],dtype = PARMES_REAL, order=ORDER) + sphere = pp.Obstacle(box, zlayer=0.1, radius=0.2, center=[0.5, 0.5, 0.5], + name='sphere', orientation='West', porousLayer=0.1) + + ## ChiDomain + chiDomain = pp.ContinuousField(domain=box, name='ChiDomain', vector=False) + + ## Fields + velo = pp.AnalyticalField(domain=box, formula=vitesse, name='Velocity', vector=True) + vorti = pp.AnalyticalField(domain=box, formula=vorticite, name='Vorticity', vector=True) + + ## Operators + penal = pp.Penalization(velo, vorti, sphere, lambd) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3, ghosts=[2,2,2]) + + pb = pp.Problem(topo3D, [penal]) + + ## Setting solver to Problem + pb.setSolver(finalTime, timeStep, solver_type='basic', io=pp.Printer(fields=[velo, vorti], frequency=outputModulo, outputPrefix=outputFilePrefix)) + pb.solver.ODESolver= RK4# RK3# RK2# Euler# + pb.initSolver() + t1 = time.time() + + ## Solve problem + pb.solve() + + tf = time.time() + + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + +if __name__ == "__main__": + run() diff --git a/HySoP/hysop/test/test_operator/test_Stretching.py b/HySoP/hysop/test/test_operator/test_Stretching.py new file mode 100755 index 000000000..1ee8a2e57 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_Stretching.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +import time +from parmepy.particular_solvers.integrator.euler import Euler +from parmepy.particular_solvers.integrator.runge_kutta2 import RK2 +from parmepy.particular_solvers.integrator.runge_kutta3 import RK3 +from parmepy.particular_solvers.integrator.runge_kutta4 import RK4 +import parmepy as pp +import numpy as np +from math import * +import unittest + + + +class test_Stretching(unittest.TestCase): + """ + DiscreteVariable test class + """ + + def vitesse(self,x, y, z): +# vx = 1. + x +# vy = - x * y +# vz = x * y * z + 10. + amodul = np.cos(np.pi*self.t/3) + pix = np.pi*x + piy = np.pi*y + piz = np.pi*z + pi2x = 2.*pix + pi2y = 2.*piy + pi2z = 2.*piz + vx = 2.*np.sin(pix)*np.sin(pix)*np.sin(pi2y)*np.sin(pi2z)*amodul + vy = -np.sin(pi2x)*np.sin(piy)*np.sin(piy)*np.sin(pi2z)*amodul + vz = -np.sin(pi2x)*np.sin(piz)*np.sin(piz)*np.sin(pi2y)*amodul + return vx, vy, vz + + def vorticite(self,x, y, z): +# wx = x * y +# wy = y * z +# wz = - y + amodul = np.cos(np.pi*self.t/3) + pix = np.pi*x + piy = np.pi*y + piz = np.pi*z + pi2x = 2.*pix + pi2y = 2.*piy + pi2z = 2.*piz + wx = 2.* np.pi * np.sin(pi2x) * amodul*( - np.cos(pi2y)*np.sin(piz)*np.sin(piz)+ np.sin(piy)*np.sin(piy)*np.cos(pi2z) ) + wy = 2.* np.pi * np.sin(pi2y) * amodul*( 2.*np.cos(pi2z)*np.sin(pix)*np.sin(pix)+ np.sin(piz)*np.sin(piz)*np.cos(pi2x) ) + wz = -2.* np.pi * np.sin(pi2z) * amodul*( np.cos(pi2x)*np.sin(piy)*np.sin(piy)+ np.sin(pix)*np.sin(pix)*np.cos(pi2y) ) + return wx, wy, wz + + def scalaire(self,x, y, z): + if x < 0.5 and y < 0.5 and z < 0.5: + return 1. + else: + return 0. + + + def testOperatorStretching(self): + # Parameters + nb = 16 + timeStep = 0.09 + finalTime = 0.09 + self.t = 0. + t0 = time.time() + + ## Domain + box = pp.Box(3, length=[1., 1., 1.], origin=[0., 0., 0.]) + + ## Fields + velo = pp.AnalyticalField(domain=box, formula=self.vitesse, name='Velocity', vector=True) + vorti = pp.AnalyticalField(domain=box, formula=self.vorticite, name='Vorticity', vector=True) + + ## Operators + stretch = pp.Stretching(velo,vorti) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3, ghosts=[2.,2.,2.]) + + ##Problem + pb = pp.Problem(topo3D, [stretch]) + + ## Setting solver to Problem + pb.setSolver(finalTime, timeStep, solver_type='basic') + pb.solver.ODESolver= RK3#RK2#Euler#RK4# + pb.initSolver() + + t1 = time.time() + + ## Solve problem + pb.solve() + + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testOperatorStretching() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Stretching)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_operator/test_transport_d.py b/HySoP/hysop/test/test_operator/test_transport_d.py new file mode 100644 index 000000000..14585b5f5 --- /dev/null +++ b/HySoP/hysop/test/test_operator/test_transport_d.py @@ -0,0 +1,122 @@ +""" +Module for testing parmepy.operator.transport_d +""" + +import unittest +import parmepy as pp +import numpy as np +import pyopencl as cl + + +class Transport_dTestCase(unittest.TestCase): + + def setUp_OpenCL_basic(self): + self.b = pp.Box() + self.nbElem = [32, 32, 32] + self.topo = pp.CartesianTopology(domain=self.b, + resolution=self.nbElem, + dim=len(self.nbElem)) + build_options = "-cl-single-precision-constant -cl-opt-disable" + build_options += " -D WIDTH=32" + build_options += " -D WGN=32" + build_options += " -D PADDING=0" + build_options += " -D BASIC=1" + self.prg_basic = cl.Program(self.ctx, self.gpu_src).build(build_options) + self.p_positions = pp.fields.continuous.ContinuousField(self.b, + name="test_field_positions") + self.p_scalar = pp.fields.continuous.ContinuousField(self.b, + name="test_field_scalar") + self.true_p_positions = pp.fields.analytical.AnalyticalField(self.b, + formula=lambda x,y,z:x, + name="test_field_true_positions") + self.g_velocity = pp.fields.analytical.AnalyticalField(self.b, + formula=lambda x, y, z: (0., 1., 0.), + name="test_field_g_velocity", vector=True) + self.g_scalar = pp.fields.analytical.AnalyticalField(self.b, + formula=lambda x, y, z: 1., + name="test_field_g_scalar") + self.b.discretize(self.topo.resolution) + self.pos, self.pos_id = self.p_positions.discretize(self.topo) + self.scal, self.velo_id = self.p_scalar.discretize(self.topo) + self.gvelo, self.pos_id = self.g_velocity.discretize(self.topo) + self.gscal, self.velo_id = self.g_scalar.discretize(self.topo) + self.true_pos, self.velo_id = self.true_p_positions.discretize(self.topo) + self.true_p_positions.initialize() + self.g_velocity.initialize() + self.g_scalar.initialize() + self.pos.data = np.asarray(self.pos.data, dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.scal.data = np.asarray(self.scal.data, dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.gvelo.data[0] = np.asarray(self.gvelo.data[0], dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.gvelo.data[1] = np.asarray(self.gvelo.data[1], dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.gvelo.data[2] = np.asarray(self.gvelo.data[2], dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.gscal.data = np.asarray(self.gscal.data, dtype=pp.constants.PARMES_REAL_GPU, order='F') + self.pos.gpu_data = cl.Buffer(self.ctx, cl.mem_flags.READ_WRITE, + size=self.pos.data.nbytes) + self.scal.gpu_data = cl.Buffer(self.ctx, cl.mem_flags.READ_WRITE, + size=self.scal.data.nbytes) + self.gvelo.gpu_data = [cl.Buffer(self.ctx, cl.mem_flags.READ_WRITE, + size=gvelo.nbytes) for gvelo in self.gvelo.data] + self.gscal.gpu_data = cl.Buffer(self.ctx, cl.mem_flags.READ_WRITE, + size=self.gscal.data.nbytes) + cl.enqueue_copy(self.queue, self.gscal.gpu_data, self.gscal.data) + cl.enqueue_copy(self.queue, self.gvelo.gpu_data[0], self.gvelo.data[0]) + cl.enqueue_copy(self.queue, self.gvelo.gpu_data[1], self.gvelo.data[1]) + cl.enqueue_copy(self.queue, self.gvelo.gpu_data[2], self.gvelo.data[2]) + self.transport = pp.Transport(self.g_velocity, self.g_scalar) + self.transport.discretize(result_position=self.p_positions, result_scalar=self.p_scalar) + self.transport.setMethod(pp.particular_solvers.gpu.KernelLauncher(self.prg_basic.advection, + self.queue, + (32, 32, 32), None)) + self.transport.discreteOperator.init_copy = pp.particular_solvers.gpu.KernelLauncher(self.prg_basic.advec_init_copy, + self.queue, + (32, 32, 32), None) + self.transport.discreteOperator.init_transpose = pp.particular_solvers.gpu.KernelListLauncher([self.prg_basic.advec_init_transpose_3D_01, + self.prg_basic.advec_init_transpose_3D_02], + self.queue, + [(2 * int(self.nbElem[0]), + int(self.nbElem[1]) / 32, + int(self.nbElem[2])), + (2 * int(self.nbElem[0]), + int(self.nbElem[1]), + int(self.nbElem[2]) / 32) + ], + [None, + None]) + + def setUp(self): + try: + self.platform = cl.get_platforms()[0] + self.device = self.platform.get_devices(cl.device_type.GPU)[0] + self.ctx = cl.Context([self.device]) + self.queue = cl.CommandQueue(self.ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) + f = open(pp.constants.GPU_SRC, 'r') + self.gpu_src = "".join(f.readlines()) + f.close() + self.test = True + print "Testing on " + self.device.name + except Exception: + self.test = False + print "No tests because no GPU" + + def tearDown(self): + pass + + def test_apply_basic(self): + """Test advection basic""" + if self.test: + self.setUp_OpenCL_basic() + self.transport.discreteOperator.apply(0., 0.1, 0) + print self.scal.domain.step + self.queue.finish() + cl.enqueue_copy(self.queue, self.pos.data, self.pos.gpu_data) + cl.enqueue_copy(self.queue, self.scal.data, self.scal.gpu_data) + self.queue.finish() + print np.max(self.pos.data),np.min(self.pos.data) + print self.pos.data[1,1,1], self.true_pos.data[1,1,1] + np.testing.assert_array_almost_equal(self.pos.data, self.true_pos.data) + np.testing.assert_array_almost_equal(self.scal.data, self.gscal.data) + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run( + unittest.TestLoader().loadTestsFromTestCase(Transport_dTestCase) + ) diff --git a/HySoP/hysop/test/test_particular_solvers/__init__.py b/HySoP/hysop/test/test_particular_solvers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/HySoP/hysop/test/test_particular_solvers/test_EDO_erreur.py b/HySoP/hysop/test/test_particular_solvers/test_EDO_erreur.py new file mode 100644 index 000000000..c07c30400 --- /dev/null +++ b/HySoP/hysop/test/test_particular_solvers/test_EDO_erreur.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +from parmepy.particular_solvers.integrator.euler import Euler +from parmepy.particular_solvers.integrator.runge_kutta2 import RK2 +from parmepy.particular_solvers.integrator.runge_kutta3 import RK3 +from parmepy.particular_solvers.integrator.runge_kutta4 import RK4 +from math import * +import unittest +import numpy as np +import numpy.testing as npt +import copy +import matplotlib.pyplot as plt +from parmepy.constants import * + + +class test_EDO(unittest.TestCase): + """ + DiscreteVariable test class + """ + + def analyticalSolution(self,t, x, y, z): + sx = (t*np.exp(t) + 1.) * np.exp(-t) + sy = (t*np.exp(t) + 1.) * np.exp(-t) + sz = (t*np.exp(t) + 1.) * np.exp(-t) + return sx, sy, sz + + def f (self, t, u): + fx = -u[0][:,:,:] + t + 1. + fy = -u[1][:,:,:] + t + 1. + fz = -u[2][:,:,:] + t + 1. + return fx , fy ,fz + + def testIntegratorEDO(self): + # Parameters + nb = 32 + timeStep = 0.1 + finalTime = 1.0 + multi = 2. + maxerror=0. + + t0 = time.time() + self.t = 0. + ## Domain + box = pp.Box(3, length=[4.*np.pi, 4.*np.pi, 4.*np.pi], + origin=[- 2.*np.pi,- 2.*np.pi,- 2.*np.pi]) + + +##################################################################################### + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3, periods=[False, False, False]) + + Result=np.asarray([np.zeros([nb, nb, nb], + dtype=PARMES_REAL, order=ORDER) for d in xrange(3)]) + Analvorty=np.asarray([np.zeros([nb, nb, nb], + dtype=PARMES_REAL, order=ORDER) for d in xrange(3)]) + + compteur = 0 + taille = int(finalTime / timeStep) +1 + compteur = 0 + dt = np.zeros([taille], dtype=PARMES_REAL, order=ORDER) + errEuler = np.zeros([taille], dtype=PARMES_REAL, order=ORDER) + errRK2 = np.zeros([taille], dtype=PARMES_REAL, order=ORDER) + errRK3 = np.zeros([taille], dtype=PARMES_REAL, order=ORDER) + errRK4 = np.zeros([taille], dtype=PARMES_REAL, order=ORDER) + UEuler = np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, + order=ORDER) for d in xrange(3)]) + URK2 = np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, + order=ORDER) for d in xrange(3)]) + URK3 = np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, + order=ORDER) for d in xrange(3)]) + URK4 = np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, + order=ORDER) for d in xrange(3)]) + + UEuler[:,:,:,:] = 1. + URK2[:,:,:,:] = 1. + URK3[:,:,:,:] = 1. + URK4[:,:,:,:] = 1. + + Analvorty[:,:,:,:]=np.vectorize(self.analyticalSolution)(timeStep, + topo3D.mesh.coords[0], \ + topo3D.mesh.coords[1], \ + topo3D.mesh.coords[2])[:] + + while self.t < finalTime : + print "t", self.t + + # Euler + self.method= Euler + methodInt=self.method(self.f) + Result = methodInt.integrate(self.f, self.t , timeStep , UEuler) + UEuler = Result + errEuler[compteur]= np.max (abs(Analvorty[:,:,:,:] - Result[:,:,:,:])) + + # RK2 + self.method= RK2 + methodInt=self.method(self.f) + Result = methodInt.integrate(self.f, self.t , timeStep , URK2) + URK2 = Result + errRK2[compteur]= np.max (abs(Analvorty[:,:,:,:] - Result[:,:,:,:])) + + # RK3 + self.method= RK3 + methodInt=self.method(self.f) + Result = methodInt.integrate(self.f, self.t , timeStep , URK3) + URK3 = Result + errRK3[compteur]= np.max (abs(Analvorty[:,:,:,:] - Result[:,:,:,:])) + + # RK4 + self.method= RK4 + methodInt=self.method(self.f) + Result = methodInt.integrate(self.f, self.t , timeStep , URK4) + URK4 = Result + errRK4[compteur]= np.max (abs(Analvorty[:,:,:,:] - Result[:,:,:,:])) + dt[compteur] = self.t + + self.t = self.t + timeStep + Analvorty[:,:,:,:]=np.vectorize(self.analyticalSolution)(self.t + timeStep, + topo3D.mesh.coords[0], \ + topo3D.mesh.coords[1], \ + topo3D.mesh.coords[2])[:] + compteur = compteur + 1 + + # Check the convergence order of each time integration scheme : + npt.assert_array_less(errEuler,timeStep) + npt.assert_array_less(errRK2,timeStep**2) + npt.assert_array_less(errRK3,timeStep**3) + npt.assert_array_less(errRK4,timeStep**4) + + ## Table of error values +# print "erreur Euler", errEuler +# print "erreur RK2", errRK2 +# print "erreur RK3", errRK3 +# print "erreur RK4", errRK4 + + ## Plot error_scheme vs time +# plt.figure(1) +# plt.subplot(211) +# plt.xlabel('dt') +# plt.xscale('log') +# plt.ylabel('Erreur') +# plt.yscale('log') +# plt.plot(dt, errEuler, '+-',dt ,errRK2, '+-' ,dt, errRK3, '+-',dt,errRK4, '+-') +# plt.legend([u"Euler", u"RK2", u"RK3", u"RK4"], loc=4) +# plt.subplot(212) +# plt.xlabel('dt') +# plt.ylabel('Erreur') +# plt.plot(dt, errEuler, '+-',dt ,errRK2, '+-' ,dt, errRK3, '+-',dt,errRK4, '+-') +# plt.legend([u"Euler", u"RK2", u"RK3", u"RK4"], loc=4) + + plt.show() + + t1 = time.time() + + print "\n" +# print "Total time : ", tf - t0, "sec (CPU)" +# print "Init time : ", t1 - t0, "sec (CPU)" +# print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testIntegratorEDO() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_EDO)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_particular_solvers/test_RK.py b/HySoP/hysop/test/test_particular_solvers/test_RK.py new file mode 100644 index 000000000..70ed6aa89 --- /dev/null +++ b/HySoP/hysop/test/test_particular_solvers/test_RK.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +from parmepy.particular_solvers.integrator.euler import Euler +from parmepy.particular_solvers.integrator.runge_kutta2 import RK2 +from parmepy.particular_solvers.integrator.runge_kutta3 import RK3 +from parmepy.particular_solvers.integrator.runge_kutta4 import RK4 +from parmepy.particular_solvers.integrator.runge_kutta2stretching import RK2Stretch +from parmepy.particular_solvers.integrator.runge_kutta3stretching import RK3Stretch +from parmepy.particular_solvers.integrator.runge_kutta4stretching import RK4Stretch +from math import * +import unittest +import numpy as np +import numpy.testing as npt +import copy +import matplotlib.pyplot as plt +from parmepy.constants import * + + + +class test_RK(unittest.TestCase): + """ + DiscreteVariable test class + """ + + def vitesse(self, x, y, z): + vx = np.sin(x) + vy = np.sin(y) + vz = np.sin(z) + return vx, vy, vz + + def vorticite(self, x, y, z): + wx = self.t**2+1. + wy = self.t**2+1. + wz = self.t**2+1. + return wx, wy, wz + + def analyticalSolution(self,t, x, y, z): + sx = t**2 - (t + t**3 /3.) * np.cos(x) + sy = t**2 - (t + t**3 /3.) * np.cos(y) + sz = t**2 - (t + t**3 /3.) * np.cos(z) + return sx, sy, sz + + def f (self, t, u): + fx = 2.*t -u[0][:,:,:] + fy = 2.*t -u[1][:,:,:] + fz = 2.*t -u[2][:,:,:] + return fx , fy ,fz + + + def wgradu (self, t, x, y, z) : + wx =( 1 + t**2 )* np.cos(x) + wy =( 1 + t**2 )* np.cos(y) + wz =( 1 + t**2 )* np.cos(z) + return wx, wy, wz + + + def testIntegratorRK(self): + # Parameters + nb = 32 + timeStep = 0.01 + finalTime = 0.01 + maxerror=0. + + t0 = time.time() + self.t = 0. + ## Domain + box = pp.Box(3, length=[4.*np.pi, 4.*np.pi, 4.*np.pi], origin=[- 2.*np.pi,- 2.*np.pi,- 2.*np.pi]) + + +##################################################################################### + + ## Fields +# velo = pp.AnalyticalField(domain=box, formula=self.vitesse, name='Velocity', vector=True) +# vorti = pp.AnalyticalField(domain=box, formula=self.vorticite, name='Vorticity', vector=True) + + ## Operators +# stretch = pp.Stretching(velo,vorti) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=box, resolution=[nb, nb, nb], dim=3) + + ##Problem +# pb = pp.Problem(topo3D, [stretch]) + + ## Setting solver to Problem +# pb.setSolver(finalTime, timeStep, solver_type='basic') + + Result=np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, order=ORDER) for d in xrange(3)]) + Analvorty=np.asarray([np.zeros([nb, nb, nb], dtype=PARMES_REAL, order=ORDER) for d in xrange(3)]) + Analvorty[:,:,:,:]= np.vectorize(self.wgradu)(self.t,topo3D.mesh.coords[0], \ + topo3D.mesh.coords[1], \ + topo3D.mesh.coords[2])[:] + + self.method= RK3 # RK3Stretch #RK2Stretch #RK4Stretch #Euler #RK4 # + + print "\nODE SOLVER :: ", self.method + + methodInt=self.method(self.f) + Result = methodInt.integrate(self.f, self.t , timeStep , self.wgradu, topo3D) + + if Euler == self.method : + maxerror = abs((timeStep**2 - 1./3. * timeStep**3)-.0) + timeStep**3 + if RK2 == self.method : + maxerror = abs((-1./3. * timeStep**3) - (0.5* timeStep**2)) + timeStep**8 + if RK3 == self.method : + maxerror = abs(0. - (0.5* timeStep**2 - 1./6. * timeStep**3)) + timeStep**3 + if RK4 == self.method : + maxerror = abs((timeStep**2 - 1./3. * timeStep**3) - (7./6.* timeStep**2 - 1./2. * timeStep**3 + 1./8. * timeStep**4)) + + +# pb.initSolver() + t1 = time.time() + + ## Solve problem +# pb.solve() + self.t = self.t + timeStep + Analvorty[:,:,:,:]=Analvorty[:,:,:,:]+np.vectorize(self.analyticalSolution)(self.t, topo3D.mesh.coords[0], \ + topo3D.mesh.coords[1], \ + topo3D.mesh.coords[2])[:] + +## Visual comparison between the numerical resolution and the analytical resolution + for i in range(1): + plt.figure(1) + plt.subplot(211) + plt.axis([-2*np.pi,2*np.pi,np.min(Analvorty[i][:,0,0]),np.max(Analvorty[i][:,0,0])]) + plt.plot(topo3D.mesh.coords[0][:,0,0], Analvorty[i][:,0,0], '-' ,topo3D.mesh.coords[0][:,0,0],Result[i][:,0,0], '-' ) + plt.legend([u"Solution Analytique", u"Solution Numérique"]) + plt.subplot(212) + plt.axis([-2*np.pi,2*np.pi,0,max(abs(Analvorty[i][:,0,0] - Result[i][:,0,0]))]) + plt.plot(topo3D.mesh.coords[0][:,0,0], abs(Analvorty[i][:,0,0] - Result[i][:,0,0]), '-' ) + plt.legend([u"Erreur"]) + plt.ax = plt.gca() + plt.ax.ticklabel_format(style='sci', axis='y') + plt.show() + npt.assert_array_less(abs(Analvorty[:,:,:,:] - Result[:,:,:,:]),maxerror) + tf = time.time() + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testIntegratorRK() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_RK)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_particular_solvers/test_euler.py b/HySoP/hysop/test/test_particular_solvers/test_euler.py new file mode 100644 index 000000000..12b0dac2d --- /dev/null +++ b/HySoP/hysop/test/test_particular_solvers/test_euler.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +import unittest +from parmepy.fields.discrete import * +from parmepy.fields.continuous import * +from parmepy.fields.analytical import * +from parmepy.domain.topology import * +from parmepy.domain.box import * +from parmepy.constants import * +from parmepy.particular_solvers.integrator.integrator import ODESolver +from parmepy.particular_solvers.integrator.euler import Euler +import numpy as np +import numpy.testing as npt +import math + + +class test_Euler(unittest.TestCase): + """ + Euler test + solve u'(t) = f( u(t),t ) + u(t) = a t + U0 + f(u,t) = a + (u - (at + U0))^4 + """ + def setUp(self): + self.e = 0.0002 # Accepted error between result and analytical result + self.dim = 3 + self.boxLength = [1., 1., 1.] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [6, 6, 6] + self.box = Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + self.dt = 0.1 + self.FinalTime = 3 + self.U0 = [1.0 , 2.0, 3.0 ] + + def testEulerInt(self): + # Continuous fields and operator declaration + self.velo = AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + # Topology definition / Fields and operator discretization + self.result = [np.ones((self.nbPts), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + self.topo3D = CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim) + self.velo.discretize(self.topo3D) + self.velo.initialize() + self.resol = self.topo3D.mesh.resolution + #test for t=0 and initialization of the fonction f + t = 0. + fctInter = [np.ones((self.nbPts), dtype=PARMES_REAL, order=ORDER) for d in xrange(self.dim)] + method = Euler() + + #Solution calculated with Euler + fctInter = self.fctTest(t,self.velo.discreteField[self.velo._fieldId].data[0]\ + ,self.velo.discreteField[self.velo._fieldId].data[1]\ + ,self.velo.discreteField[self.velo._fieldId].data[2]) + for d in xrange(self.dim) : + self.result[d][...] = method.integrate(self.velo.discreteField[self.velo._fieldId], fctInter, t, self.dt, d ) + + t=t+self.dt + + #Analytical solution + self.anal=self.analyticalSolution(t,self.velo.discreteField[self.velo._fieldId].data[0]\ + ,self.velo.discreteField[self.velo._fieldId].data[1]\ + ,self.velo.discreteField[self.velo._fieldId].data[2]) + npt.assert_array_less(abs(self.anal[0]-self.result[0]), self.e) + npt.assert_array_less(abs(self.anal[1]-self.result[1]), self.e) + npt.assert_array_less(abs(self.anal[2]-self.result[2]), self.e) + + # time loop + while t < self.FinalTime : + #print "T=" , t + fctInter = self.fctTest(t,self.result[0],self.result[1],self.result[2]) + for d in xrange(self.dim) : + self.result[d][...] = method.integrate(self.result, fctInter, t, self.dt, d ) + + t = t + self.dt + + self.anal=self.analyticalSolution(t,self.velo.discreteField[self.velo._fieldId].data[0]\ + ,self.velo.discreteField[self.velo._fieldId].data[1]\ + ,self.velo.discreteField[self.velo._fieldId].data[2]) + # Comparison with analytical solution + npt.assert_array_less(abs(self.anal[0]-self.result[0]), self.e) + npt.assert_array_less(abs(self.anal[1]-self.result[1]), self.e) + npt.assert_array_less(abs(self.anal[2]-self.result[2]), self.e) + + + def vitesse(self, x, y, z): + vx = 1.0 + vy = 2.0 + vz = 3.0 + return vx, vy, vz + + def fctTest(self, t, x, y, z): + wx = 0.2 +( x - self.analyticalSolution(t, 1., 2., 3.)[0])**4 + wy = 0.5 +( y - self.analyticalSolution(t, 1., 2., 3.)[1])**4 + wz = 1. +( z - self.analyticalSolution(t, 1., 2., 3.)[2])**4 + return [wx,wy,wz] + + def analyticalSolution(self, t, x, y, z): + sx = 0.2 *t + x + sy = 0.5 *t + y + sz = 1. *t + z + return [sx, sy, sz] + + def runTest(self): + self.setUp() + self.testOperatorDiv() + + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Euler)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/HySoP/hysop/test/test_tools/__init__.py b/HySoP/hysop/test/test_tools/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/HySoP/hysop/tools/tests/test_timers.py b/HySoP/hysop/tools/tests/test_timers.py new file mode 100644 index 000000000..43ab66918 --- /dev/null +++ b/HySoP/hysop/tools/tests/test_timers.py @@ -0,0 +1,44 @@ +""" +Unitary tests for parmepy.tools.timers module +""" +from parmepy.tools.timers import Timer, timed_function + + +class A_class(object): + def __init__(self): + self.name = 'A_class' + self.timer = Timer(self) + self.n = 0 + + @timed_function + def call(self): + self.n += 1 + + @timed_function + def call_other(self): + self.n += 10 + + +def test_timer_from_decorator(): + a = A_class() + assert a.n == 0 + a.call() + assert len(a.timer.f_timers.keys()) == 1 + fun1 = a.timer.f_timers.keys()[0] + assert a.n == 1 # the call function have been called + assert a.timer.f_timers[fun1].ncalls == 1 + #assert a.timer.f_timers[fun1].t == a.timer.f_timers[fun1].times[0] + a.call() + a.call_other() + assert len(a.timer.f_timers.keys()) == 2 + fun2 = [f for f in a.timer.f_timers.keys() if f != fun1][0] + assert a.n == 12 # the call and call_other functions have been called + assert a.timer.f_timers[fun1].ncalls == 2 + #assert a.timer.f_timers[fun1].t == \ + # a.timer.f_timers[fun1].times[0] + a.timer.f_timers[fun1].times[1] + assert a.timer.f_timers[fun2].ncalls == 1 + #assert a.timer.f_timers[fun2].t == a.timer.f_timers[fun2].times[0] + + +if __name__ == '__main__': + test_timer_from_decorator() diff --git a/HySoP/hysop/tools/timers.py b/HySoP/hysop/tools/timers.py new file mode 100644 index 000000000..de2b5167f --- /dev/null +++ b/HySoP/hysop/tools/timers.py @@ -0,0 +1,194 @@ +""" +@file timers.py + +Contains class for monitoring computational time in a non-intrusive way +thanks to decorator. +""" +from parmepy.mpi import MPI, main_rank +from parmepy import __VERBOSE__ +ftime = MPI.Wtime + + +def timed_function(f): + """ + Decorator for function timing. Get the corresponding function timer in the + operator (represented in args[0]). + + @remark : Works only with methods that belongs to object with Timer + member named timer. + """ + def wrapper(*args, **kwargs): + f_timer = args[0].timer.getFunctionTimer(f) + res = f_timer(f)(*args, **kwargs) + return res + # def wrapper(*args, **kwargs): + # return f(*args, **kwargs) + return wrapper + + +class FunctionTimer(object): + """ + Class for timing functions with the timed_function decorator. + + The FunctionTimer is instancied with a given function. Calling the timer + will call the function timed with execution time computation. + """ + + def __init__(self, func): + """ + Creates a timer for the given function. + + @param func : function to time. + """ + ## Timed function name + self.func_name = func.func_name + ## Total time spent in the function (in seconds). + self.t = 0. + # ## Times per calls + # self.times = [] + ## Calls number + self.ncalls = 0 + + def __call__(self, func): + """ + The function given is wrapped with time computations instructions + through MPI.Wtime function. + It returns the wrapped function. + @param func function to time. + @return wrapped function. + """ + def f(*args, **kwargs): + t0 = ftime() + res = func(*args, **kwargs) + t = ftime() - t0 + self.t += t + self.ncalls += 1 + #self.times.append(t) + if __VERBOSE__: + print (args[0].__class__.__name__, ' -- ',) + print (self.func_name, " : ", t, 's') + return res + return f + + def __str__(self): + s = self.func_name + s += ' : ' + str(self.t) + " s ({0} calls)".format(self.ncalls) + return s + + +class ManualFunctionTimer(FunctionTimer): + """ + Class for manual timing some code. For instance, this class is desined for + monitoring OpenCL kernels where function call does not reflect + computational time. + """ + def __init__(self, name): + def fun(): + pass + fun.func_name = name + FunctionTimer.__init__(self, fun) + + def append_time(self, t): + """Manual computational time append""" + self.t += t + self.ncalls += 1 + #self.times.append(t) + if __VERBOSE__: + print (self.func_name, " : ", t, 's') + + +class Timer(object): + """ + Manages a dictionary of FunctionTimer objects for monitoring functions + member of the given operator. + """ + + def __init__(self, op, suffix=''): + """ + Creates an Timer. + @param op : Timer owner. + """ + ## Parent object name + self._obj = op + self.name = self._obj.name + suffix + ## FunctionTimer dictionary with functions or operators as keys. + self.f_timers = {} + ## Total time spent in the operator (in seconds). + self.t = 0. + self._isEmpty = True + + def __add__(self, t): + """ + Overrides operator +. + @param t : Other Timer object + """ + t.compute_summary() + #self.t += t.t + self._isEmpty = False + self.f_timers[t] = t + return self + + def getFunctionTimer(self, func): + """ + Get the FunctionTimer related to given function, or created + if not exists. + + @param func : Function to get the corresponding timer. + @return : FunctionTimer related to func. + """ + try: + return self.f_timers[func] + except KeyError: + self.f_timers[func] = FunctionTimer(func) + return self.f_timers[func] + + def addFunctionTimer(self, ft): + """ + Add a function timer to Timer. + + @param ft : FunctionTimer to add. + """ + self.f_timers[ft] = ft + + def addSubTimer(self, t, prefix=''): + if len(t.f_timers.keys()) > 0: + t.compute_summary() + t.name += prefix + self.f_timers[t] = t + + def compute_summary(self): + """ + Compute a summary of the different functions referenced herein. + """ + self.t = 0. + for f in self.f_timers.keys(): + # if self.f_timers[f] is a Timer, these times are already + # in the current Timer sum. + if not isinstance(self.f_timers[f], Timer): + self.t += self.f_timers[f].t + self._isEmpty = False + + def rTimes(self): + s = "" + for f in sorted(self.f_timers.keys()): + nl = "@@F@@[" + str(main_rank) + "]@@S@@" + if isinstance(self.f_timers[f], Timer): + if len(self.f_timers[f].f_timers) > 0: + s += nl + ' |-- ' + f.name + if self.f_timers[f].t > 0.: + s += " : " + str(self.f_timers[f].t) + subTimer = self.f_timers[f] + s += subTimer.rTimes().replace('@@S@@', '@@S@@ ') + else: + s += nl + ' |-- ' + str(self.f_timers[f]) + return s + + def __str__(self): + self.compute_summary() + if not self._isEmpty: + s = "[" + str(main_rank) + "] Time spent in " + s += self.name + ' = ' + str(self.t) + ' s' + s += self.rTimes().replace('@@F@@', '\n').replace('@@S@@', '') + else: + s = "" + return s diff --git a/HySoP/src/Unstable/LEGI/changelog b/HySoP/src/Unstable/LEGI/changelog new file mode 100644 index 000000000..d6e0a8347 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/changelog @@ -0,0 +1,16 @@ +2012-XX-XX X.X +[new] Adding 2 new scheme into particles methods: lambda 4 corrected + (fourth psace order, corrected for large time step) and M'6 +[optim] Faster particles method. + +2012-02-23 1.0 +[new] Parallel fft. +[new] Parallel pseudo spectral solver for NS equation and convection-diffusion problem. +[new] Advection solver based on particles method. +[new] Avs i/o in parallel context only in the spectral solver context. +[new] Distribued vtk xml output in context of advection solver. +[new] Both spectral and particle solver used the same mpi-topology. +[new] Solve scalar equation with particles method mixed to spectral solver. +[new] Use different resolution for velocity and scalars (for all scalars solvers) +[new] Post-processing: obtain spectrum +[optim] Optimisation of advection solver based on particles methods. diff --git a/HySoP/src/Unstable/LEGI/doc/benchmark/Benchmark/description.tex b/HySoP/src/Unstable/LEGI/doc/benchmark/Benchmark/description.tex new file mode 100644 index 000000000..cd5fb817a --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/benchmark/Benchmark/description.tex @@ -0,0 +1,49 @@ +%----------------------------------------------------------------------------------------------------------------- +%--------------------------------------------------- Algo basique ---------------------------------------------------- +%----------------------------------------------------------------------------------------------------------------- + +\section{Mathematical description of the benchmarks} + + Different benchmark are provided. The purpose is to evaluate the advection solver and its implement in both simple cases and complex cases.For reader convenience, let us sum up all these benchmark : +\begin{enumerate} + \item 2D turning sphere : simple case where analytic solution are known. + \item Radial constant field with a velocity involving shear: this test-case allows to test how efficient the solver is in complex cases with large time step. The analytic solution is known. +\end{enumerate} + + +\subsection{(2D-)Turning sphere} + + Let us denote by $\Omega = [0,1]^2$ the numerical domain. + + The velocity field is defined by: +\begin{equation} + \vect{v}\bigl( \begin{smallmatrix} x \\y \end{smallmatrix} \bigr) = \frac{2\pi}{T} \Biggl( \begin{matrix} 0.5 -y \\ x - 0.5 \end{matrix} \Biggr) +\end{equation} +with the period $T=1$ and $r_0 = \min(dx, dy)$ where $dx$, $dy$ denote the space step . + The scalar is initialized as following : +\begin{equation} + u \bigl( \begin{smallmatrix} x \\y \end{smallmatrix} \bigr) = \begin{cases} + 0 & \text{if $r^2 = \bigl(x - 3/5 \bigr)^2 + \bigl(y - 3/5 \bigr)^2 > r_0^2$} + \\ \bigl( 1 - r^2/r_0^2)^4 \bigr) & \text{else, with $r^2 = \bigl(x - 3/5 \bigr)^2 + \bigl(y - 3/5 \bigr)^2$} + \end{cases} +\end{equation} + + The analytic solution at time t consists of a rotation of the initial scalar value along Z-axis of angle $\frac{2\pi}{T} \times t$. + +\subsection{Radial constant field with a velocity involving shear} + + Let us denote by $\Omega = [-1,1]^2$ the numerical domain. + + The velocity field is defined by: +\begin{equation} + \vect{v}\bigl( \begin{smallmatrix} x \\y \end{smallmatrix} \bigr) = \cos\Bigl( \frac{3\pi}{2} \Bigr) \bigl( \begin{smallmatrix} -y \\ x \end{smallmatrix} \bigr) +\end{equation} + The scalar is initialized as following : +\begin{equation} + u \bigl( \begin{smallmatrix} x \\y \end{smallmatrix} \bigr) = \begin{cases} + 0 & \text{if $r^2 = x^2 + y^2 > 1$} + \\ \bigl( 1 - r^2)^6 \bigr) & \text{else, with $r^2 = x^2 + y^2$} + \end{cases} +\end{equation} + + As the radial component of the velocity vanishes, the initial scalar value match to a stationary solution. Therefore, the scalar field remains constant. As there is some tangent shear, this test will show how the implementation deals with large time step. For instance, if it is based on $\Lambda_{\tilde{2}}$ or $\Lambda_{\tilde{4}}$ remeshing formula, the corrected cases will appears (\ie some particles will be tagged). Note that for a CFL number larger than one, classical $\lambda_6$ formula are only of order 1. \ No newline at end of file diff --git a/HySoP/src/Unstable/LEGI/doc/benchmark/bench.pdf b/HySoP/src/Unstable/LEGI/doc/benchmark/bench.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7b051d7e5f9586d2d1b4061fec2fedfe44837df4 GIT binary patch literal 156971 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 E7xa9h`v3p{ literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/doc/benchmark/bench.tex b/HySoP/src/Unstable/LEGI/doc/benchmark/bench.tex new file mode 100644 index 000000000..94b8a7b61 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/benchmark/bench.tex @@ -0,0 +1,131 @@ + +%----------------------------------------------------------------------------------------------------------------- +%--------------------------------------------------- Préambule ---------------------------------------------------- +%----------------------------------------------------------------------------------------------------------------- + +\documentclass[a4paper, 12pt, twoside, openright]{article} + + +%--------------------------------------------------- Packages ----------------------------------------------------- + % Basiques +\usepackage[T1]{fontenc} +\usepackage[english, french]{babel} % parce que le texte est en français +\usepackage[utf8]{inputenc} % pour avoir les accents (car encodage en utf8) + + % Mathématiques +\usepackage{amssymb} +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amsthm} +\usepackage{amsxtra} + + % Figures +\usepackage{graphicx} % pour insérer et mettre en page des figures +\usepackage{algorithm} % pour mettre en page des algorithmes +\usepackage{algorithmic} +\usepackage{subfigure} % pour mettre des figures côte à côtes. +\usepackage{tikz} % pour insérer des figures via Tkiz +%\usepackage{gnuplot-lua-tikz} % version modifier de Tikz pour utiliser les sortie gnuplot-lua +\usetikzlibrary{% + calc,% + through,% + intersections,% + arrows,% + shapes.misc,% wg. rounded rectangle + shapes.geometric,% + chains,% + positioning,% wg. " of " + scopes,% + backgrounds,% + fit,% + mindmap,% + plotmarks + } +%\usepackage[margin=10pt,font=small, labelfont=bf, labelsep=endash]{caption} + % Pour avoir des légendes d'images "plus mieux" + + % Tableau +\usepackage{multirow} % Pour fusionner des lignes + + + % Outils et rédaction +\usepackage{url} % pour pouvoir mettre des url. +\urlstyle{sf} + + +% Pour la rédaction : +\usepackage{pdfsync} % lorsque l'on clique sur le pdf, on arrive à la bonne ligne de code du .tex +\usepackage[disable, textsize=tiny, french, textwidth=2.cm, color=orange!60!, linecolor=black]{todonotes} + +\usepgfmodule{plot} + + + +%----------------------------------------------------- Paramètres ------------------------------------------------------ + +% ///// Auteur, titre ///// + +\author{Jean-Baptiste Lagaert} +\title{Benchmark for advection solver based on particles method} + + +% ///// Nouvelles commandes et paramètres ///// + +% Paramètres +\graphicspath{{../Figures/}} % Répertoire contenant les illustrations + +% Numérotations +\numberwithin{equation}{section} % Numérotation des équations par section +\setcounter{tocdepth}{1} % Profondeur maximale des titres dans la table des matières + + +% Nouvelles commandes + % Pour les dérivées partielles : +\newcommand{\dt}{\partial_t} +\newcommand{\dx}{\partial_x} +\newcommand{\dy}{\partial_y} +\newcommand{\dz}{\partial_z} +\newcommand{\dn}{\partial_n} + % Lemma and remarks : +\theoremstyle{plain}% default +\newtheorem{thm}{Théorème}[section] +\newtheorem{lem}[thm]{Lemme} +\newtheorem{lemEng}[thm]{Lemma} +\newtheorem{prop}[thm]{Proposition} +\theoremstyle{remark} +\newtheorem*{rem}{Remarque} +\newtheorem*{rem_en}{Remark} + % Quelques raccourcis : +\newcommand{\R}{\mathbb{R}} +\newcommand{\ie}{\emph{ie }} +\newcommand{\vect}[1]{\mathbf{#1}} +\newcommand{\el}{\emph{eLYSe }} + %Other +\newcommand{\Lag}{\mathcal{L}} +\newcommand{\J}{\mathcal{J}} +%\floatname{algorithm}{Algorithme} % Francisation de l'environnement algorithm + +%\input{Divers/page_garde} + +%----------------------------------------------------------------------------------------------------------------- +%-------------------------------------------------- Document ----------------------------------------------------- +%---------------------------------------------------------------------------------------------------------------- + +\begin{document} + +\maketitle + + +\begin{otherlanguage}{english} +%\begin{hyphenrules}{english} + +Some benchmark are provided in order to measure the implementation efficiency, the drawback and the benefits of our numerical method and there precision. These tests are design in order to present "easy" cases as complex cases hard to simulate. +\vspace{1cm} + +\input{Benchmark/description} +%\input{Benchmark/setup} +%\input{Benchmark/resultats} +%\end{hyphenrules} +\end{otherlanguage} + +\end{document} diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/Doxyfile b/HySoP/src/Unstable/LEGI/doc/doxygen/Doxyfile new file mode 100644 index 000000000..15804ff83 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/Doxyfile @@ -0,0 +1,1525 @@ +# Doxyfile 1.5.9 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = codescalar + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./codescalar_doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = YES + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = f90=Fortran F90=Fortran f=Fortran F=Fortran + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +#EXTRACT_ALL = NO +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +#EXTRACT_PRIVATE = NO +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +#EXTRACT_STATIC = NO +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = "../../src" "../../test/src" "../../example/src/" "ext_doc" + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.f90 *.F90 *.F *.f + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */~* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = ./images + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# If the HTML_FOOTER_DESCRIPTION tag is set to YES, Doxygen will +# add generated date, project name and doxygen version to HTML footer. + +HTML_FOOTER_DESCRIPTION= NO + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = YES + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +#HAVE_DOT = NO +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +#CALL_GRAPH = NO +CALL_GRAPH = YES + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +#CALLER_GRAPH = NO +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/ext_doc/main_ext.f b/HySoP/src/Unstable/LEGI/doc/doxygen/ext_doc/main_ext.f new file mode 100644 index 000000000..84c0e75d1 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/ext_doc/main_ext.f @@ -0,0 +1,140 @@ +!> \mainpage CodeScalar Documentation +!! +!! \section intro_sec Introduction +!! +!! This is Code_scalar documentation ! +!! +!! \section install_sec Installation +!! +!! \subsection tools_subsec Tools required: +!! - cmake +!! - fftw +!! - mpi +!! +!! \subsection compile Compilation +!! - Obtain the code from the svn repositories. +!! - Go the the code location (the folder must contains at least "src" and "CMake" folders and a "CMakeList" file) +!! - Create a build folder : \verbatim $ mkdir build \endverbatim +!! - Run cmake : \verbatim $ cmake .. \endverbatim +!! - Compile : \verbatim $ make \endverbatim +!! +!! \subsection add_comp Advanced compilation options +!! This section explain how to perform advanced task. All these task can +!! only be performed after having running at least one time cmake. +!! +!! - Update the fortran file generated with the .fortran file : <tt>$ make fortran_file</tt> +!! - Generate (or update) doxygen documentation : <tt> $ make doc</tt> +!! - Obtain the list of possible target for a make : <tt>$ make help</tt> +!! - A <tt>$ make VERBOSE=1</tt> shows all the command running by the make command. +!! +!! The CMakeLists contains some flag wich can be changed +!! - <tt> WITH_TESTS</tt>: to compile tests. +!! - <tt>WITH_EXAMPLE</tt>: to compile benchmark +!! - <tt>GENERATE_SRC</tt>: to (re-) generate source file from *.fortran file +!! +!! \section running Running the program +!! Run ScaleExe +!! +!! \section doc Additionnal documentation +!!This manual is divided in the following sections: +!!- \subpage part_doc : some information about particle method implementation +!!- \subpage output_doc : some information about posprocessing and input/output +!! + +!----------------------------------------------------------- +! +!> \page part_doc About particle method implementation +!! This page described the implementation of the advection solver based +!! on particle method. +!! +!! \section part_intro Introduction +!! +!! \subsection notation Some notation +!! All the file using some common notation +!! - local domain of each processus are indiced from 1 to N_proc. +!! - d_sc = (scalar) space step +!! - ind = mesh (or particles) indice. As we use fortran, it goes +!! from 1 to N_proc +!! - pos = particles position. In accordance to ind, if there is one +!! particle at each mesh point, it goes from d_sci to (N_proc)*d_sc. +!! A particle "i" belong to the local subdomain if and only if pos(i) +!! belongs to [d_sc;d_sc*(N_proc+1)[. +!! - pos_adim = adimensionned particles position. In accordance to ind, if there is one +!! particle at each mesh point, it goes from 1 to N_proc +!! +!! \subsection Todo +!! \todo +!! - travailler par bloc de lignes plutôt que par ligne 1D +!! - petits groupes => moins d'usage mémoire en local, plus de +!! messages qui sont chacun plus petits. +!! - grands groupes => mutualisation des communications (moins +!! nombreux mais message plus grands) et nécessite plus de mémoire +!! en local. (à éviter si la ram est légère.) +!! - add new remeshing schemes: +!! - corrected lambda 4 +!! - M'6 +!! - Au sein d'un group de ligne, on peut utiliser un autre niveau de +!! parallélisme type open_mp. +! +!----------------------------------------------------------- + + +!----------------------------------------------------------- +! +!> \page output_doc About input and output +!! This page described the implementation of the IO +!! +!! \section io_intro Introduction +!! Two output format are implemented : avs files and parallel vtk xml +!! files. +!! The first one is provided by the "avs" module (see avs.F90) and the +!! second one by "parallel_io" module. The both can be used for output +!! during a simulation on a parrallel computer. +!! +!! \section Main differences between the two output format +!! - avs file can also be used as input files (input at format "vtk xml" +!! will be implement later) +!! - number of files created and parallel context: +!! - the "vtk xml" standart allows to write output in more than one +!! files. The module provided in scale will perform write in a file +!! per processus. More precisly, output will not need any communication +!! neither mpi_io. But it also means it will create a lot of file +!! if the number of processes is high. +!! - on the contrary, the avs module produces only one ouput file +!! containing all the data. +!! - Note that in "small" cluster, the write on hard disk are +!! sequential. In future update, the number of output for "vtk +!! xml" file will be defined by the user. +!! - both output are done at binary format. +!! +!! \subsection Todo +!! \todo +!! - implement hdf5 output: +!! - in first time, by creating one output file by mpi processus +!! - then allow the user to gather some processus in one output file in +!! oder to limit the number of output and initialize this to a reasonnable +!! default value. +!! - implement hdf5 input in order to restart computation to a given state. +!! - define the specification: what is conserved from the previous +!! computations ? +!! - obviously input parameters, last field values, current time ... +!! - ... but it is also possible to re-initialize memomry to its last +!! state +!! - implement the corresponding output (more than the standart ouput) +!! and the corresponding input. +!! - to deal with unexpected bug, add minimal information to standart +!! output and implement matching input routines in order to also be able +!! to restart a bugged simulation. +!! - implement xml input +! +!----------------------------------------------------------- + +!> @defgroup part Particular method +!! Details about particle method for scalar advection + +!> @defgroup output Input/Ouput procedures +!! This group gather all the IO tools, including AVS IO and vtk xml output. + +!> @defgroup cart_structure Cartesian mpi topology and mesh +!! This group gather module devoted to mpi topology and some of the +!! associated mesh informations. diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.eps b/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.eps new file mode 100644 index 000000000..9a178fc06 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.eps @@ -0,0 +1,264 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: datalayout.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Tue Jul 19 12:09:38 2011 +%%For: begou@thor (Patrick Begou) +%%BoundingBox: 0 0 580 470 +%Magnification: 1.0000 +%%EndComments +%%BeginProlog +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 470 moveto 0 0 lineto 580 0 lineto 580 470 lineto closepath clip newpath +-27.6 496.8 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +%%EndProlog +% +% Fig objects follow +% +% +% here starts figure with depth 50 +% Polyline +0 slj +0 slc +7.500 slw +n 4605 2070 m 4500 2070 4500 3315 105 arcto 4 {pop} repeat + 4500 3420 7320 3420 105 arcto 4 {pop} repeat + 7425 3420 7425 2175 105 arcto 4 {pop} repeat + 7425 2070 4605 2070 105 arcto 4 {pop} repeat + cp gs col0 s gr +/Times-Bold ff 222.25 scf sf +6030 2430 m +gs 1 -1 sc (module maindatalayout) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +5895 2925 m +gs 1 -1 sc (Global parameters) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +5895 3195 m +gs 1 -1 sc (Global function) dup sw pop 2 div neg 0 rm col0 sh gr +% Polyline +n 450 3150 m 3645 3150 l 3645 4500 l 450 4500 l + cp gs col0 s gr +/Times-BoldItalic ff 222.25 scf sf +2025 3420 m +gs 1 -1 sc (implementdatalayout.Fortran) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Italic ff 190.50 scf sf +1935 3870 m +gs 1 -1 sc (Module generic implementation) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Italic ff 190.50 scf sf +1890 4185 m +gs 1 -1 sc (with tags.) dup sw pop 2 div neg 0 rm col0 sh gr +% Polyline +n 4830 450 m 4725 450 4725 1290 105 arcto 4 {pop} repeat + 4725 1395 7140 1395 105 arcto 4 {pop} repeat + 7245 1395 7245 555 105 arcto 4 {pop} repeat + 7245 450 4830 450 105 arcto 4 {pop} repeat + cp gs col0 s gr +/Times-Bold ff 222.25 scf sf +5940 720 m +gs 1 -1 sc (module mpilayout) dup sw pop 2 div neg 0 rm col0 sh gr +% Polyline +n 6810 4950 m 6705 4950 6705 6150 105 arcto 4 {pop} repeat + 6705 6255 9525 6255 105 arcto 4 {pop} repeat + 9630 6255 9630 5055 105 arcto 4 {pop} repeat + 9630 4950 6810 4950 105 arcto 4 {pop} repeat + cp gs col0 s gr +/Times-Bold ff 222.25 scf sf +8145 5220 m +gs 1 -1 sc (module cmplxdatalayout) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +8145 5625 m +gs 1 -1 sc (Datalayout code and functions) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +8055 5850 m +gs 1 -1 sc (for complex type values.) dup sw pop 2 div neg 0 rm col0 sh gr +% Polyline +n 4920 6975 m 4815 6975 4815 7770 105 arcto 4 {pop} repeat + 4815 7875 7815 7875 105 arcto 4 {pop} repeat + 7920 7875 7920 7080 105 arcto 4 {pop} repeat + 7920 6975 4920 6975 105 arcto 4 {pop} repeat + cp gs col0 s gr +/Times-Bold ff 222.25 scf sf +6435 7290 m +gs 1 -1 sc (module datalayout) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +6435 7695 m +gs 1 -1 sc (Generic interface for datalayout) dup sw pop 2 div neg 0 rm col0 sh gr +% Polyline +30.000 slw +gs clippath +5962 1674 m 5962 1380 l 5827 1380 l 5827 1674 l 5827 1674 l 5895 1449 l 5962 1674 l cp +eoclip +n 5895 2070 m + 5895 1395 l gs col0 s gr gr + +% arrowhead +n 5962 1674 m 5895 1449 l 5827 1674 l 5895 1629 l 5962 1674 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +6340 3531 m 6103 3356 l 6022 3465 l 6259 3640 l 6259 3640 l 6119 3452 l 6340 3531 l cp +eoclip +n 8145 4950 m + 6075 3420 l gs col0 s gr gr + +% arrowhead +n 6340 3531 m 6119 3452 l 6259 3640 l 6263 3558 l 6340 3531 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +5695 3685 m 5868 3447 l 5759 3368 l 5586 3606 l 5586 3606 l 5773 3464 l 5695 3685 l cp +eoclip +n 4725 4905 m + 5805 3420 l gs col0 s gr gr + +% arrowhead +n 5695 3685 m 5773 3464 l 5586 3606 l 5667 3609 l 5695 3685 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +5143 6351 m 4873 6232 l 4819 6355 l 5088 6474 l 5088 6474 l 4910 6322 l 5143 6351 l cp +eoclip +n 6390 6975 m + 4860 6300 l gs col0 s gr gr + +% arrowhead +n 5143 6351 m 4910 6322 l 5088 6474 l 5074 6394 l 5143 6351 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7868 6425 m 8140 6311 l 8087 6186 l 7816 6301 l 7816 6301 l 8050 6276 l 7868 6425 l cp +eoclip +n 6390 6975 m + 8100 6255 l gs col0 s gr gr + +% arrowhead +n 7868 6425 m 8050 6276 l 7816 6301 l 7884 6345 l 7868 6425 l + cp gs 0.00 setgray ef gr col0 s +% Polyline + [120] 0 sd +gs clippath +4221 4764 m 4364 4957 l 4473 4876 l 4330 4684 l 4330 4684 l 4383 4869 l 4221 4764 l cp +eoclip +n 3645 3870 m + 4410 4905 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 4221 4764 m 4383 4869 l 4330 4684 l 4221 4764 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [120] 0 sd +gs clippath +7460 4957 m 7692 5019 l 7726 4888 l 7495 4827 l 7495 4827 l 7652 4939 l 7460 4957 l cp +eoclip +n 3645 3870 m + 7695 4950 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 7460 4957 m 7652 4939 l 7495 4827 l 7460 4957 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +7.500 slw +n 3480 4905 m 3375 4905 3375 6195 105 arcto 4 {pop} repeat + 3375 6300 6195 6300 105 arcto 4 {pop} repeat + 6300 6300 6300 5010 105 arcto 4 {pop} repeat + 6300 4905 3480 4905 105 arcto 4 {pop} repeat + cp gs col0 s gr +/Times-Roman ff 190.50 scf sf +6390 4500 m +gs 1 -1 sc 344.0 rot (automatic code generation) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +4860 4635 m +gs 1 -1 sc 52.0 rot (use) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +7240 4182 m +gs 1 -1 sc 328.0 rot (use) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +4725 5580 m +gs 1 -1 sc (Datalayout code and functions) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +4680 5850 m +gs 1 -1 sc (for real type values.) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Bold ff 222.25 scf sf +4815 5175 m +gs 1 -1 sc (module realdatalayout) dup sw pop 2 div neg 0 rm col0 sh gr +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.fig b/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.fig new file mode 100644 index 000000000..474af97dd --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.fig @@ -0,0 +1,70 @@ +#FIG 3.2 Produced by xfig version 3.2.5 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +6 4500 2070 7425 3420 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 7425 3420 7425 2070 4500 2070 4500 3420 7425 3420 +4 1 0 50 -1 2 14 0.0000 4 210 2400 6030 2430 module maindatalayout\001 +4 1 0 50 -1 0 12 0.0000 4 180 1470 5895 2925 Global parameters\001 +4 1 0 50 -1 0 12 0.0000 4 135 1290 5895 3195 Global function\001 +-6 +6 450 3150 3645 4500 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 450 3150 3645 3150 3645 4500 450 4500 450 3150 +4 1 0 50 -1 3 14 0.0000 4 210 2865 2025 3420 implementdatalayout.Fortran\001 +4 1 0 50 -1 1 12 0.0000 4 180 2610 1935 3870 Module generic implementation\001 +4 1 0 50 -1 1 12 0.0000 4 180 795 1890 4185 with tags.\001 +-6 +6 4725 450 7245 1395 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 7245 1395 7245 450 4725 450 4725 1395 7245 1395 +4 1 0 50 -1 2 14 0.0000 4 210 1830 5940 720 module mpilayout\001 +-6 +6 6705 4950 9630 6255 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 9630 6255 9630 4950 6705 4950 6705 6255 9630 6255 +4 1 0 50 -1 2 14 0.0000 4 210 2505 8145 5220 module cmplxdatalayout\001 +4 1 0 50 -1 0 12 0.0000 4 180 2490 8145 5625 Datalayout code and functions\001 +4 1 0 50 -1 0 12 0.0000 4 180 1995 8055 5850 for complex type values.\001 +-6 +6 4815 6975 7920 7875 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 7920 7875 7920 6975 4815 6975 4815 7875 7920 7875 +4 1 0 50 -1 2 14 0.0000 4 210 1890 6435 7290 module datalayout\001 +4 1 0 50 -1 0 12 0.0000 4 180 2565 6435 7695 Generic interface for datalayout\001 +-6 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 5895 2070 5895 1395 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 8145 4950 6075 3420 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 4725 4905 5805 3420 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 6390 6975 4860 6300 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 6390 6975 8100 6255 +2 1 1 3 0 7 50 -1 -1 8.000 0 0 -1 1 0 2 + 1 0 3.00 135.00 180.00 + 3645 3870 4410 4905 +2 1 1 3 0 7 50 -1 -1 8.000 0 0 -1 1 0 2 + 1 0 3.00 135.00 180.00 + 3645 3870 7695 4950 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 6300 6300 6300 4905 3375 4905 3375 6300 6300 6300 +4 1 0 50 -1 0 12 6.0039 4 180 2160 6390 4500 automatic code generation\001 +4 1 0 50 -1 0 12 0.9076 4 90 270 4860 4635 use\001 +4 1 0 50 -1 0 12 5.7247 4 90 270 7240 4182 use\001 +4 1 0 50 -1 0 12 0.0000 4 180 2490 4725 5580 Datalayout code and functions\001 +4 1 0 50 -1 0 12 0.0000 4 180 1590 4680 5850 for real type values.\001 +4 1 0 50 -1 2 14 0.0000 4 210 2280 4815 5175 module realdatalayout\001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.png b/HySoP/src/Unstable/LEGI/doc/doxygen/images/datalayout.png new file mode 100644 index 0000000000000000000000000000000000000000..185db320b4302bf7add1f420f86560eea5cb059b GIT binary patch literal 12132 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 literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.eps b/HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.eps new file mode 100644 index 000000000..87459da49 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.eps @@ -0,0 +1,3766 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: (atend) +%%LanguageLevel: 2 +%%Creator: Grace-5.1.21 +%%CreationDate: Thu Jan 26 09:34:17 2012 +%%DocumentData: Clean8Bit +%%Orientation: Portrait +%%Title: Untitled +%%For: begou +%%DocumentNeededResources: (atend) +%%EndComments +%%BeginProlog +/m {moveto} def +/l {lineto} def +/s {stroke} def +/n {newpath} def +/c {closepath} def +/RL {rlineto} def +/SLW {setlinewidth} def +/GS {gsave} def +/GR {grestore} def +/SC {setcolor} def +/SGRY {setgray} def +/SRGB {setrgbcolor} def +/SD {setdash} def +/SLC {setlinecap} def +/SLJ {setlinejoin} def +/SCS {setcolorspace} def +/FFSF {findfont setfont} def +/CC {concat} def +/PXL {n m 0 0 RL s} def +/Color0 {1.0000 1.0000 1.0000} def +/Color1 {0.0000 0.0000 0.0000} def +/Color2 {1.0000 0.0000 0.0000} def +/Color3 {0.0000 1.0000 0.0000} def +/Color4 {0.0000 0.0000 1.0000} def +/Color5 {1.0000 1.0000 0.0000} def +/Color6 {0.7373 0.5608 0.5608} def +/Color7 {0.8627 0.8627 0.8627} def +/Color8 {0.5804 0.0000 0.8275} def +/Color9 {0.0000 1.0000 1.0000} def +/Color10 {1.0000 0.0000 1.0000} def +/Color11 {1.0000 0.6471 0.0000} def +/Color12 {0.4471 0.1294 0.7373} def +/Color13 {0.4039 0.0275 0.2824} def +/Color14 {0.2510 0.8784 0.8157} def +/Color15 {0.0000 0.5451 0.0000} def +/Color16 {0.7529 0.7529 0.7529} def +/Color17 {0.5059 0.5059 0.5059} def +/Color18 {0.2588 0.2588 0.2588} def +/PTRN { + /pat_bits exch def + << + /PaintType 2 + /PatternType 1 /TilingType 1 + /BBox[0 0 16 16] + /XStep 16 /YStep 16 + /PaintProc { + pop + 16 16 true [-1 0 0 -1 16 16] pat_bits imagemask + } + >> + [0.0017 0 0 0.0017 0 0] + makepattern +} def +/Pattern0 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def +/Pattern1 {<ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff> PTRN} bind def +/Pattern2 {<eeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffff> PTRN} bind def +/Pattern3 {<eeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbb> PTRN} bind def +/Pattern4 {<5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa> PTRN} bind def +/Pattern5 {<1111444411114444111144441111444411114444111144441111444411114444> PTRN} bind def +/Pattern6 {<1111000044440000111100004444000011110000444400001111000044440000> PTRN} bind def +/Pattern7 {<1010000000000000010100000000000010100000000000000101000000000000> PTRN} bind def +/Pattern8 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def +/Pattern9 {<1e1e0f0f8787c3c3e1e1f0f078783c3c1e1e0f0f8787c3c3e1e1f0f078783c3c> PTRN} bind def +/Pattern10 {<7878f0f0e1e1c3c387870f0f1e1e3c3c7878f0f0e1e1c3c387870f0f1e1e3c3c> PTRN} bind def +/Pattern11 {<3333333333333333333333333333333333333333333333333333333333333333> PTRN} bind def +/Pattern12 {<ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000> PTRN} bind def +/Pattern13 {<8181424224241818181824244242818181814242242418181818242442428181> PTRN} bind def +/Pattern14 {<8080404020201010080804040202010180804040202010100808040402020101> PTRN} bind def +/Pattern15 {<0101020204040808101020204040808001010202040408081010202040408080> PTRN} bind def +/Pattern16 {<2222222222222222222222222222222222222222222222222222222222222222> PTRN} bind def +/Pattern17 {<0000ffff000000000000ffff000000000000ffff000000000000ffff00000000> PTRN} bind def +/Pattern18 {<2222ffff222222222222ffff222222222222ffff222222222222ffff22222222> PTRN} bind def +/Pattern19 {<ffffffff33333333ffffffff33333333ffffffff33333333ffffffff33333333> PTRN} bind def +/Pattern20 {<0f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f00f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f0> PTRN} bind def +/Pattern21 {<ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff00ff00ff00ff00ff00ff00ff> PTRN} bind def +/Pattern22 {<8001800180018001800180018001ffffffff8001800180018001800180018001> PTRN} bind def +/Pattern23 {<c003c003c003c003c003c003ffffffffffffffffc003c003c003c003c003c003> PTRN} bind def +/Pattern24 {<040404040404ffff404040404040ffff040404040404ffff404040404040ffff> PTRN} bind def +/Pattern25 {<180018001800180018001800ffffffff001800180018001800180018ffffffff> PTRN} bind def +/Pattern26 {<1111b8b87c7c3a3a1111a3a3c7c78b8b1111b8b87c7c3a3a1111a3a3c7c78b8b> PTRN} bind def +/Pattern27 {<101010102828c7c70101010182827c7c101010102828c7c70101010182827c7c> PTRN} bind def +/Pattern28 {<1c1c121211112121c1c12121111112121c1c121211112121c1c1212111111212> PTRN} bind def +/Pattern29 {<3e3e414180808080e3e31414080808083e3e414180808080e3e3141408080808> PTRN} bind def +/Pattern30 {<4848888884848383848488884848383848488888848483838484888848483838> PTRN} bind def +/Pattern31 {<03030404080808080c0c12122121c0c003030404080808080c0c12122121c0c0> PTRN} bind def +/ellipsedict 8 dict def +ellipsedict /mtrx matrix put +/EARC { + ellipsedict begin + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y translate + xrad yrad scale + 0 0 1 startangle endangle arc + savematrix setmatrix + end +} def +/TL { + /kcomp exch def + /linewidth exch def + /offset exch def + GS + 0 offset rmoveto + linewidth SLW + dup stringwidth exch kcomp add exch RL s + GR +} def +/KINIT +{ + /kvector exch def + /kid 0 def +} def +/KPROC +{ + pop pop + kvector kid get + 0 rmoveto + /kid 1 kid add def +} def +/DefEncoding [ + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclam + /quotedbl + /numbersign + /dollar + /percent + /ampersand + /quoteright + /parenleft + /parenright + /asterisk + /plus + /comma + /hyphen + /period + /slash + /zero + /one + /two + /three + /four + /five + /six + /seven + /eight + /nine + /colon + /semicolon + /less + /equal + /greater + /question + /at + /A + /B + /C + /D + /E + /F + /G + /H + /I + /J + /K + /L + /M + /N + /O + /P + /Q + /R + /S + /T + /U + /V + /W + /X + /Y + /Z + /bracketleft + /backslash + /bracketright + /asciicircum + /underscore + /grave + /a + /b + /c + /d + /e + /f + /g + /h + /i + /j + /k + /l + /m + /n + /o + /p + /q + /r + /s + /t + /u + /v + /w + /x + /y + /z + /braceleft + /bar + /braceright + /asciitilde + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclamdown + /cent + /sterling + /currency + /yen + /brokenbar + /section + /dieresis + /copyright + /ordfeminine + /guillemotleft + /logicalnot + /hyphen + /registered + /macron + /degree + /plusminus + /twosuperior + /threesuperior + /acute + /mu + /paragraph + /periodcentered + /cedilla + /onesuperior + /ordmasculine + /guillemotright + /onequarter + /onehalf + /threequarters + /questiondown + /Agrave + /Aacute + /Acircumflex + /Atilde + /Adieresis + /Aring + /AE + /Ccedilla + /Egrave + /Eacute + /Ecircumflex + /Edieresis + /Igrave + /Iacute + /Icircumflex + /Idieresis + /Eth + /Ntilde + /Ograve + /Oacute + /Ocircumflex + /Otilde + /Odieresis + /multiply + /Oslash + /Ugrave + /Uacute + /Ucircumflex + /Udieresis + /Yacute + /Thorn + /germandbls + /agrave + /aacute + /acircumflex + /atilde + /adieresis + /aring + /ae + /ccedilla + /egrave + /eacute + /ecircumflex + /edieresis + /igrave + /iacute + /icircumflex + /idieresis + /eth + /ntilde + /ograve + /oacute + /ocircumflex + /otilde + /odieresis + /divide + /oslash + /ugrave + /uacute + /ucircumflex + /udieresis + /yacute + /thorn + /ydieresis +] def +%%EndProlog +%%BeginSetup +%%EndSetup +594.96 594.96 scale +n +0.0000 0.0000 m +0.0000 1.0000 l +1.4151 1.0000 l +1.4151 0.0000 l +c +[/DeviceRGB] SCS +Color0 SC +fill +[/DeviceRGB] SCS +Color2 SC +[] 0 SD +0.0015 SLW +0 SLC +0 SLJ +n +0.1500 0.8127 m +0.1507 0.8121 l +0.1513 0.8115 l +0.1520 0.8108 l +0.1527 0.8100 l +0.1533 0.8093 l +0.1540 0.8086 l +0.1547 0.8079 l +0.1553 0.8071 l +0.1560 0.8063 l +0.1567 0.8056 l +0.1573 0.8049 l +0.1580 0.8041 l +0.1587 0.8033 l +0.1593 0.8024 l +0.1600 0.8017 l +0.1607 0.8009 l +0.1613 0.8001 l +0.1620 0.7992 l +0.1627 0.7983 l +0.1633 0.7975 l +0.1640 0.7967 l +0.1647 0.7959 l +0.1653 0.7950 l +0.1660 0.7940 l +0.1667 0.7932 l +0.1673 0.7924 l +0.1680 0.7915 l +0.1687 0.7906 l +0.1693 0.7896 l +0.1700 0.7887 l +0.1707 0.7879 l +0.1713 0.7870 l +0.1720 0.7861 l +0.1727 0.7852 l +0.1733 0.7842 l +0.1740 0.7832 l +0.1747 0.7824 l +0.1753 0.7815 l +0.1760 0.7806 l +0.1767 0.7797 l +0.1773 0.7787 l +0.1780 0.7777 l +0.1787 0.7767 l +0.1793 0.7758 l +0.1800 0.7749 l +0.1807 0.7739 l +0.1813 0.7730 l +0.1820 0.7719 l +0.1827 0.7709 l +0.1833 0.7699 l +0.1840 0.7689 l +0.1847 0.7680 l +0.1853 0.7670 l +0.1860 0.7661 l +0.1867 0.7651 l +0.1873 0.7642 l +0.1880 0.7632 l +0.1887 0.7621 l +0.1893 0.7611 l +0.1900 0.7600 l +0.1907 0.7590 l +0.1913 0.7580 l +0.1920 0.7570 l +0.1927 0.7560 l +0.1933 0.7549 l +0.1940 0.7539 l +0.1947 0.7528 l +0.1953 0.7517 l +0.1960 0.7505 l +0.1967 0.7494 l +0.1973 0.7489 l +0.1980 0.7484 l +0.1987 0.7479 l +0.1993 0.7476 l +0.2000 0.7472 l +0.2007 0.7468 l +0.2013 0.7464 l +0.2020 0.7460 l +0.2027 0.7456 l +0.2033 0.7452 l +0.2040 0.7449 l +0.2047 0.7445 l +0.2053 0.7441 l +0.2060 0.7437 l +0.2067 0.7434 l +0.2073 0.7430 l +0.2080 0.7426 l +0.2087 0.7422 l +0.2093 0.7419 l +0.2100 0.7415 l +0.2107 0.7411 l +0.2113 0.7408 l +0.2120 0.7404 l +0.2127 0.7401 l +0.2133 0.7398 l +0.2140 0.7395 l +0.2147 0.7393 l +0.2153 0.7391 l +0.2160 0.7388 l +0.2167 0.7386 l +0.2173 0.7384 l +0.2180 0.7381 l +0.2187 0.7379 l +0.2193 0.7377 l +0.2200 0.7375 l +0.2207 0.7373 l +0.2213 0.7371 l +0.2220 0.7369 l +0.2227 0.7366 l +0.2233 0.7364 l +0.2240 0.7362 l +0.2247 0.7360 l +0.2253 0.7358 l +0.2260 0.7356 l +0.2267 0.7353 l +0.2273 0.7351 l +0.2280 0.7349 l +0.2287 0.7346 l +0.2293 0.7344 l +0.2300 0.7342 l +0.2307 0.7339 l +0.2313 0.7337 l +0.2320 0.7334 l +0.2327 0.7331 l +0.2333 0.7329 l +0.2340 0.7326 l +0.2347 0.7324 l +0.2353 0.7321 l +0.2360 0.7318 l +0.2367 0.7316 l +0.2373 0.7313 l +0.2380 0.7310 l +0.2387 0.7307 l +0.2393 0.7303 l +0.2400 0.7300 l +0.2407 0.7297 l +0.2413 0.7294 l +0.2420 0.7291 l +0.2427 0.7287 l +0.2433 0.7284 l +0.2440 0.7281 l +0.2447 0.7277 l +0.2453 0.7273 l +0.2460 0.7269 l +0.2467 0.7266 l +0.2473 0.7262 l +0.2480 0.7258 l +0.2487 0.7253 l +0.2493 0.7249 l +0.2500 0.7245 l +0.2507 0.7241 l +0.2513 0.7237 l +0.2520 0.7233 l +0.2527 0.7229 l +0.2533 0.7224 l +0.2540 0.7220 l +0.2547 0.7215 l +0.2553 0.7211 l +0.2560 0.7206 l +0.2567 0.7201 l +0.2573 0.7196 l +0.2580 0.7191 l +0.2587 0.7186 l +0.2593 0.7181 l +0.2600 0.7175 l +0.2607 0.7170 l +0.2613 0.7164 l +0.2620 0.7158 l +0.2627 0.7152 l +0.2633 0.7146 l +0.2640 0.7140 l +0.2647 0.7135 l +0.2653 0.7129 l +0.2660 0.7123 l +0.2667 0.7117 l +0.2673 0.7111 l +0.2680 0.7105 l +0.2687 0.7098 l +0.2693 0.7092 l +0.2700 0.7085 l +0.2707 0.7079 l +0.2713 0.7072 l +0.2720 0.7065 l +0.2727 0.7058 l +0.2733 0.7051 l +0.2740 0.7044 l +0.2747 0.7036 l +0.2753 0.7029 l +0.2760 0.7021 l +0.2767 0.7014 l +0.2773 0.7007 l +0.2780 0.6999 l +0.2787 0.6991 l +0.2793 0.6984 l +0.2800 0.6976 l +0.2807 0.6967 l +0.2813 0.6959 l +0.2820 0.6951 l +0.2827 0.6943 l +0.2833 0.6934 l +0.2840 0.6926 l +0.2847 0.6917 l +0.2853 0.6908 l +0.2860 0.6900 l +0.2867 0.6891 l +0.2873 0.6882 l +0.2880 0.6873 l +0.2887 0.6864 l +0.2893 0.6855 l +0.2900 0.6846 l +0.2907 0.6837 l +0.2913 0.6828 l +0.2920 0.6818 l +0.2927 0.6809 l +0.2933 0.6799 l +0.2940 0.6790 l +0.2947 0.6780 l +0.2953 0.6770 l +0.2960 0.6760 l +0.2967 0.6751 l +0.2973 0.6741 l +0.2980 0.6732 l +0.2987 0.6722 l +0.2993 0.6712 l +0.3000 0.6702 l +0.3007 0.6692 l +0.3013 0.6682 l +0.3020 0.6673 l +0.3027 0.6663 l +0.3033 0.6653 l +0.3040 0.6643 l +0.3047 0.6633 l +0.3053 0.6624 l +0.3060 0.6614 l +0.3067 0.6604 l +0.3073 0.6595 l +0.3080 0.6585 l +0.3087 0.6575 l +0.3093 0.6566 l +0.3100 0.6556 l +0.3107 0.6546 l +0.3113 0.6536 l +0.3120 0.6526 l +0.3127 0.6517 l +0.3133 0.6507 l +0.3140 0.6498 l +0.3147 0.6489 l +0.3153 0.6479 l +0.3160 0.6470 l +0.3167 0.6461 l +0.3173 0.6452 l +0.3180 0.6442 l +0.3187 0.6433 l +0.3193 0.6424 l +0.3200 0.6415 l +0.3207 0.6407 l +0.3213 0.6398 l +0.3220 0.6389 l +0.3227 0.6380 l +0.3233 0.6371 l +0.3240 0.6362 l +0.3247 0.6353 l +0.3253 0.6344 l +0.3260 0.6335 l +0.3267 0.6327 l +0.3273 0.6318 l +0.3280 0.6310 l +0.3287 0.6301 l +0.3293 0.6293 l +0.3300 0.6284 l +0.3307 0.6276 l +0.3313 0.6267 l +0.3320 0.6259 l +0.3327 0.6251 l +0.3333 0.6243 l +0.3340 0.6235 l +0.3347 0.6227 l +0.3353 0.6219 l +0.3360 0.6211 l +0.3367 0.6203 l +0.3373 0.6195 l +0.3380 0.6188 l +0.3387 0.6180 l +0.3393 0.6172 l +0.3400 0.6165 l +0.3407 0.6157 l +0.3413 0.6150 l +0.3420 0.6142 l +0.3427 0.6135 l +0.3433 0.6127 l +0.3440 0.6120 l +0.3447 0.6112 l +0.3453 0.6105 l +0.3460 0.6098 l +0.3467 0.6090 l +0.3473 0.6083 l +0.3480 0.6076 l +0.3487 0.6069 l +0.3493 0.6062 l +0.3500 0.6055 l +0.3507 0.6048 l +0.3513 0.6040 l +0.3520 0.6033 l +0.3527 0.6026 l +0.3533 0.6020 l +0.3540 0.6013 l +0.3547 0.6006 l +0.3553 0.5999 l +0.3560 0.5993 l +0.3567 0.5986 l +0.3573 0.5980 l +0.3580 0.5973 l +0.3587 0.5967 l +0.3593 0.5961 l +0.3600 0.5954 l +0.3607 0.5948 l +0.3613 0.5942 l +0.3620 0.5935 l +0.3627 0.5929 l +0.3633 0.5923 l +0.3640 0.5917 l +0.3647 0.5911 l +0.3653 0.5905 l +0.3660 0.5899 l +0.3667 0.5893 l +0.3673 0.5888 l +0.3680 0.5882 l +0.3687 0.5876 l +0.3693 0.5870 l +0.3700 0.5864 l +0.3707 0.5859 l +0.3713 0.5853 l +0.3720 0.5848 l +0.3727 0.5842 l +0.3733 0.5837 l +0.3740 0.5832 l +0.3747 0.5826 l +0.3753 0.5821 l +0.3760 0.5816 l +0.3767 0.5810 l +0.3773 0.5805 l +0.3780 0.5800 l +0.3787 0.5795 l +0.3793 0.5790 l +0.3800 0.5785 l +0.3807 0.5780 l +0.3813 0.5775 l +0.3820 0.5770 l +0.3827 0.5766 l +0.3833 0.5761 l +0.3840 0.5756 l +0.3847 0.5751 l +0.3853 0.5747 l +0.3860 0.5742 l +0.3867 0.5737 l +0.3873 0.5733 l +0.3880 0.5728 l +0.3887 0.5724 l +0.3893 0.5719 l +0.3900 0.5715 l +0.3907 0.5711 l +0.3913 0.5706 l +0.3920 0.5702 l +0.3927 0.5698 l +0.3933 0.5694 l +0.3940 0.5690 l +0.3947 0.5686 l +0.3953 0.5682 l +0.3960 0.5678 l +0.3967 0.5674 l +0.3973 0.5670 l +0.3980 0.5666 l +0.3987 0.5662 l +0.3993 0.5658 l +0.4000 0.5655 l +0.4007 0.5651 l +0.4013 0.5647 l +0.4020 0.5644 l +0.4027 0.5640 l +0.4033 0.5637 l +0.4040 0.5633 l +0.4047 0.5629 l +0.4053 0.5626 l +0.4060 0.5622 l +0.4067 0.5619 l +0.4073 0.5616 l +0.4080 0.5612 l +0.4087 0.5609 l +0.4093 0.5606 l +0.4100 0.5602 l +0.4107 0.5599 l +0.4113 0.5596 l +0.4120 0.5593 l +0.4127 0.5590 l +0.4133 0.5586 l +0.4140 0.5583 l +0.4147 0.5580 l +0.4153 0.5577 l +0.4160 0.5574 l +0.4167 0.5571 l +0.4173 0.5568 l +0.4180 0.5565 l +0.4187 0.5562 l +0.4193 0.5559 l +0.4200 0.5556 l +0.4207 0.5553 l +0.4213 0.5550 l +0.4220 0.5547 l +0.4227 0.5544 l +0.4233 0.5541 l +0.4240 0.5538 l +0.4247 0.5535 l +0.4253 0.5533 l +0.4260 0.5530 l +0.4267 0.5527 l +0.4273 0.5524 l +0.4280 0.5521 l +0.4287 0.5518 l +0.4293 0.5516 l +0.4300 0.5513 l +0.4307 0.5510 l +0.4313 0.5508 l +0.4320 0.5505 l +0.4327 0.5502 l +0.4333 0.5500 l +0.4340 0.5497 l +0.4347 0.5494 l +0.4353 0.5492 l +0.4360 0.5489 l +0.4367 0.5486 l +0.4373 0.5484 l +0.4380 0.5481 l +0.4387 0.5478 l +0.4393 0.5476 l +0.4400 0.5473 l +0.4407 0.5471 l +0.4413 0.5468 l +0.4420 0.5466 l +0.4427 0.5463 l +0.4433 0.5461 l +0.4440 0.5458 l +0.4447 0.5456 l +0.4453 0.5453 l +0.4460 0.5451 l +0.4467 0.5448 l +0.4473 0.5446 l +0.4480 0.5443 l +0.4487 0.5441 l +0.4493 0.5439 l +0.4500 0.5436 l +0.4507 0.5434 l +0.4513 0.5432 l +0.4520 0.5429 l +0.4527 0.5427 l +0.4533 0.5425 l +0.4540 0.5422 l +0.4547 0.5420 l +0.4553 0.5418 l +0.4560 0.5416 l +0.4567 0.5413 l +0.4573 0.5411 l +0.4580 0.5409 l +0.4587 0.5407 l +0.4593 0.5405 l +0.4600 0.5402 l +0.4607 0.5400 l +0.4613 0.5398 l +0.4620 0.5396 l +0.4627 0.5394 l +0.4633 0.5392 l +0.4640 0.5390 l +0.4647 0.5388 l +0.4653 0.5386 l +0.4660 0.5383 l +0.4667 0.5381 l +0.4673 0.5379 l +0.4680 0.5377 l +0.4687 0.5375 l +0.4693 0.5373 l +0.4700 0.5371 l +0.4707 0.5369 l +0.4713 0.5367 l +0.4720 0.5365 l +0.4727 0.5363 l +0.4733 0.5361 l +0.4740 0.5359 l +0.4747 0.5358 l +0.4753 0.5356 l +0.4760 0.5354 l +0.4767 0.5352 l +0.4773 0.5350 l +0.4780 0.5348 l +0.4787 0.5346 l +0.4793 0.5344 l +0.4800 0.5342 l +0.4807 0.5341 l +0.4813 0.5339 l +0.4820 0.5337 l +0.4827 0.5335 l +0.4833 0.5333 l +0.4840 0.5331 l +0.4847 0.5330 l +0.4853 0.5328 l +0.4860 0.5326 l +0.4867 0.5324 l +0.4873 0.5322 l +0.4880 0.5321 l +0.4887 0.5319 l +0.4893 0.5317 l +0.4900 0.5315 l +0.4907 0.5314 l +0.4913 0.5312 l +0.4920 0.5310 l +0.4927 0.5309 l +0.4933 0.5307 l +0.4940 0.5305 l +0.4947 0.5304 l +0.4953 0.5302 l +0.4960 0.5300 l +0.4967 0.5299 l +0.4973 0.5297 l +0.4980 0.5295 l +0.4987 0.5294 l +0.4993 0.5292 l +0.5000 0.5290 l +0.5007 0.5289 l +0.5013 0.5287 l +0.5020 0.5285 l +0.5027 0.5284 l +0.5033 0.5282 l +0.5040 0.5281 l +0.5047 0.5279 l +0.5053 0.5278 l +0.5060 0.5276 l +0.5067 0.5274 l +0.5073 0.5273 l +0.5080 0.5272 l +0.5087 0.5271 l +0.5093 0.5270 l +0.5100 0.5268 l +0.5107 0.5267 l +0.5113 0.5266 l +0.5120 0.5265 l +0.5127 0.5264 l +0.5133 0.5262 l +0.5140 0.5261 l +0.5147 0.5260 l +0.5153 0.5259 l +0.5160 0.5258 l +0.5167 0.5257 l +0.5173 0.5255 l +0.5180 0.5254 l +0.5187 0.5253 l +0.5193 0.5252 l +0.5200 0.5251 l +0.5207 0.5250 l +0.5213 0.5249 l +0.5220 0.5247 l +0.5227 0.5246 l +0.5233 0.5245 l +0.5240 0.5244 l +0.5247 0.5243 l +0.5253 0.5242 l +0.5260 0.5241 l +0.5267 0.5240 l +0.5273 0.5239 l +0.5280 0.5237 l +0.5287 0.5236 l +0.5293 0.5235 l +0.5300 0.5234 l +0.5307 0.5233 l +0.5313 0.5232 l +0.5320 0.5231 l +0.5327 0.5230 l +0.5333 0.5229 l +0.5340 0.5228 l +0.5347 0.5227 l +0.5353 0.5225 l +0.5360 0.5224 l +0.5367 0.5223 l +0.5373 0.5222 l +0.5380 0.5221 l +0.5387 0.5220 l +0.5393 0.5219 l +0.5400 0.5218 l +0.5407 0.5217 l +0.5413 0.5216 l +0.5420 0.5215 l +0.5427 0.5214 l +0.5433 0.5213 l +0.5440 0.5212 l +0.5447 0.5211 l +0.5453 0.5210 l +0.5460 0.5209 l +0.5467 0.5208 l +0.5473 0.5207 l +0.5480 0.5206 l +0.5487 0.5205 l +0.5493 0.5204 l +0.5500 0.5203 l +0.5507 0.5202 l +0.5513 0.5201 l +0.5520 0.5200 l +0.5527 0.5199 l +0.5533 0.5198 l +0.5540 0.5197 l +0.5547 0.5196 l +0.5553 0.5195 l +0.5560 0.5194 l +0.5567 0.5193 l +0.5573 0.5192 l +0.5580 0.5191 l +0.5587 0.5190 l +0.5593 0.5189 l +0.5600 0.5188 l +0.5607 0.5187 l +0.5613 0.5186 l +0.5620 0.5185 l +0.5627 0.5184 l +0.5633 0.5183 l +0.5640 0.5182 l +0.5647 0.5181 l +0.5653 0.5180 l +0.5660 0.5180 l +0.5667 0.5179 l +0.5673 0.5178 l +0.5680 0.5177 l +0.5687 0.5176 l +0.5693 0.5175 l +0.5700 0.5174 l +0.5707 0.5173 l +0.5713 0.5172 l +0.5720 0.5171 l +0.5727 0.5170 l +0.5733 0.5169 l +0.5740 0.5169 l +0.5747 0.5168 l +0.5753 0.5167 l +0.5760 0.5166 l +0.5767 0.5165 l +0.5773 0.5164 l +0.5780 0.5163 l +0.5787 0.5162 l +0.5793 0.5161 l +0.5800 0.5161 l +0.5807 0.5160 l +0.5813 0.5159 l +0.5820 0.5158 l +0.5827 0.5157 l +0.5833 0.5156 l +0.5840 0.5156 l +0.5847 0.5155 l +0.5853 0.5154 l +0.5860 0.5153 l +0.5867 0.5152 l +0.5873 0.5152 l +0.5880 0.5151 l +0.5887 0.5150 l +0.5893 0.5149 l +0.5900 0.5148 l +0.5907 0.5148 l +0.5913 0.5147 l +0.5920 0.5146 l +0.5927 0.5145 l +0.5933 0.5145 l +0.5940 0.5144 l +0.5947 0.5143 l +0.5953 0.5143 l +0.5960 0.5142 l +0.5967 0.5141 l +0.5973 0.5140 l +0.5980 0.5140 l +0.5987 0.5139 l +0.5993 0.5138 l +0.6000 0.5137 l +0.6007 0.5137 l +0.6013 0.5136 l +0.6020 0.5135 l +0.6027 0.5135 l +0.6033 0.5134 l +0.6040 0.5133 l +0.6047 0.5133 l +0.6053 0.5132 l +0.6060 0.5131 l +0.6067 0.5130 l +0.6073 0.5130 l +0.6080 0.5129 l +0.6087 0.5128 l +0.6093 0.5128 l +0.6100 0.5127 l +0.6107 0.5126 l +0.6113 0.5126 l +0.6120 0.5125 l +0.6127 0.5124 l +0.6133 0.5124 l +0.6140 0.5123 l +0.6147 0.5122 l +0.6153 0.5121 l +0.6160 0.5121 l +0.6167 0.5120 l +0.6173 0.5119 l +0.6180 0.5119 l +0.6187 0.5118 l +0.6193 0.5117 l +0.6200 0.5117 l +0.6207 0.5116 l +0.6213 0.5115 l +0.6220 0.5115 l +0.6227 0.5114 l +0.6233 0.5113 l +0.6240 0.5113 l +0.6247 0.5112 l +0.6253 0.5111 l +0.6260 0.5111 l +0.6267 0.5110 l +0.6273 0.5109 l +0.6280 0.5109 l +0.6287 0.5108 l +0.6293 0.5107 l +0.6300 0.5107 l +0.6307 0.5106 l +0.6313 0.5105 l +0.6320 0.5105 l +0.6327 0.5104 l +0.6333 0.5103 l +0.6340 0.5103 l +0.6347 0.5102 l +0.6353 0.5101 l +0.6360 0.5101 l +0.6367 0.5100 l +0.6373 0.5099 l +0.6380 0.5099 l +0.6387 0.5098 l +0.6393 0.5098 l +0.6400 0.5097 l +0.6407 0.5096 l +0.6413 0.5096 l +0.6420 0.5095 l +0.6427 0.5094 l +0.6433 0.5094 l +0.6440 0.5093 l +0.6447 0.5092 l +0.6453 0.5092 l +0.6460 0.5091 l +0.6467 0.5091 l +0.6473 0.5090 l +0.6480 0.5089 l +0.6487 0.5089 l +0.6493 0.5088 l +0.6500 0.5087 l +0.6507 0.5087 l +0.6513 0.5086 l +0.6520 0.5086 l +0.6527 0.5085 l +0.6533 0.5084 l +0.6540 0.5084 l +0.6547 0.5083 l +0.6553 0.5082 l +0.6560 0.5082 l +0.6567 0.5081 l +0.6573 0.5081 l +0.6580 0.5080 l +0.6587 0.5079 l +0.6593 0.5079 l +0.6600 0.5078 l +0.6607 0.5078 l +0.6613 0.5077 l +0.6620 0.5076 l +0.6627 0.5076 l +0.6633 0.5075 l +0.6640 0.5075 l +0.6647 0.5074 l +0.6653 0.5073 l +0.6660 0.5073 l +0.6667 0.5072 l +0.6673 0.5072 l +0.6680 0.5071 l +0.6687 0.5070 l +0.6693 0.5070 l +0.6700 0.5069 l +0.6707 0.5069 l +0.6713 0.5068 l +0.6720 0.5067 l +0.6727 0.5067 l +0.6733 0.5066 l +0.6740 0.5066 l +0.6747 0.5065 l +0.6753 0.5065 l +0.6760 0.5064 l +0.6767 0.5063 l +0.6773 0.5063 l +0.6780 0.5062 l +0.6787 0.5062 l +0.6793 0.5061 l +0.6800 0.5061 l +0.6807 0.5060 l +0.6813 0.5059 l +0.6820 0.5059 l +0.6827 0.5058 l +0.6833 0.5058 l +0.6840 0.5057 l +0.6847 0.5057 l +0.6853 0.5056 l +0.6860 0.5056 l +0.6867 0.5055 l +0.6873 0.5054 l +0.6880 0.5054 l +0.6887 0.5053 l +0.6893 0.5053 l +0.6900 0.5052 l +0.6907 0.5052 l +0.6913 0.5051 l +0.6920 0.5051 l +0.6927 0.5050 l +0.6933 0.5050 l +0.6940 0.5049 l +0.6947 0.5049 l +0.6953 0.5048 l +0.6960 0.5048 l +0.6967 0.5047 l +0.6973 0.5047 l +0.6980 0.5046 l +0.6987 0.5046 l +0.6993 0.5045 l +0.7000 0.5045 l +0.7007 0.5044 l +0.7013 0.5044 l +0.7020 0.5043 l +0.7027 0.5043 l +0.7033 0.5042 l +0.7040 0.5042 l +0.7047 0.5041 l +0.7053 0.5041 l +0.7060 0.5040 l +0.7067 0.5040 l +0.7073 0.5039 l +0.7080 0.5039 l +0.7087 0.5038 l +0.7093 0.5038 l +0.7100 0.5037 l +0.7107 0.5037 l +0.7113 0.5036 l +0.7120 0.5036 l +0.7127 0.5035 l +0.7133 0.5035 l +0.7140 0.5035 l +0.7147 0.5034 l +0.7153 0.5034 l +0.7160 0.5033 l +0.7167 0.5033 l +0.7173 0.5032 l +0.7180 0.5032 l +0.7187 0.5031 l +0.7193 0.5031 l +0.7200 0.5030 l +0.7207 0.5030 l +0.7213 0.5030 l +0.7220 0.5029 l +0.7227 0.5029 l +0.7233 0.5028 l +0.7240 0.5028 l +0.7247 0.5027 l +0.7253 0.5027 l +0.7260 0.5027 l +0.7267 0.5026 l +0.7273 0.5026 l +0.7280 0.5025 l +0.7287 0.5025 l +0.7293 0.5025 l +0.7300 0.5024 l +0.7307 0.5024 l +0.7313 0.5023 l +0.7320 0.5023 l +0.7327 0.5023 l +0.7333 0.5022 l +0.7340 0.5022 l +0.7347 0.5021 l +0.7353 0.5021 l +0.7360 0.5021 l +0.7367 0.5020 l +0.7373 0.5020 l +0.7380 0.5019 l +0.7387 0.5019 l +0.7393 0.5019 l +0.7400 0.5018 l +0.7407 0.5018 l +0.7413 0.5018 l +0.7420 0.5017 l +0.7427 0.5017 l +0.7433 0.5017 l +0.7440 0.5016 l +0.7447 0.5016 l +0.7453 0.5015 l +0.7460 0.5015 l +0.7467 0.5015 l +0.7473 0.5014 l +0.7480 0.5014 l +0.7487 0.5014 l +0.7493 0.5013 l +0.7500 0.5013 l +0.7507 0.5013 l +0.7513 0.5012 l +0.7520 0.5012 l +0.7527 0.5012 l +0.7533 0.5011 l +0.7540 0.5011 l +0.7547 0.5011 l +0.7553 0.5010 l +0.7560 0.5010 l +0.7567 0.5010 l +0.7573 0.5010 l +0.7580 0.5009 l +0.7587 0.5009 l +0.7593 0.5009 l +0.7600 0.5008 l +0.7607 0.5008 l +0.7613 0.5008 l +0.7620 0.5007 l +0.7627 0.5007 l +0.7633 0.5007 l +0.7640 0.5007 l +0.7647 0.5006 l +0.7653 0.5006 l +0.7660 0.5006 l +0.7667 0.5005 l +0.7673 0.5005 l +0.7680 0.5005 l +0.7687 0.5005 l +0.7693 0.5004 l +0.7700 0.5004 l +0.7707 0.5004 l +0.7713 0.5004 l +0.7720 0.5003 l +0.7727 0.5003 l +0.7733 0.5003 l +0.7740 0.5003 l +0.7747 0.5002 l +0.7753 0.5002 l +0.7760 0.5002 l +0.7767 0.5002 l +0.7773 0.5001 l +0.7780 0.5001 l +0.7787 0.5001 l +0.7793 0.5001 l +0.7800 0.5000 l +0.7807 0.5000 l +0.7813 0.5000 l +0.7820 0.5000 l +0.7827 0.4999 l +0.7833 0.4999 l +0.7840 0.4999 l +0.7847 0.4999 l +0.7853 0.4998 l +0.7860 0.4998 l +0.7867 0.4998 l +0.7873 0.4998 l +0.7880 0.4998 l +0.7887 0.4997 l +0.7893 0.4997 l +0.7900 0.4997 l +0.7907 0.4997 l +0.7913 0.4997 l +0.7920 0.4996 l +0.7927 0.4996 l +0.7933 0.4996 l +0.7940 0.4996 l +0.7947 0.4996 l +0.7953 0.4995 l +0.7960 0.4995 l +0.7967 0.4995 l +0.7973 0.4995 l +0.7980 0.4995 l +0.7987 0.4994 l +0.7993 0.4994 l +0.8000 0.4994 l +0.8007 0.4994 l +0.8013 0.4994 l +0.8020 0.4993 l +0.8027 0.4993 l +0.8033 0.4993 l +0.8040 0.4993 l +0.8047 0.4993 l +0.8053 0.4993 l +0.8060 0.4992 l +0.8067 0.4992 l +0.8073 0.4992 l +0.8080 0.4992 l +0.8087 0.4992 l +0.8093 0.4991 l +0.8100 0.4991 l +0.8107 0.4991 l +0.8113 0.4991 l +0.8120 0.4991 l +0.8127 0.4991 l +0.8133 0.4990 l +0.8140 0.4990 l +0.8147 0.4990 l +0.8153 0.4990 l +0.8160 0.4990 l +s +n +0.1500 0.1936 m +0.1507 0.1946 l +0.1513 0.1957 l +0.1520 0.1967 l +0.1527 0.1978 l +0.1533 0.1989 l +0.1540 0.2000 l +0.1547 0.2011 l +0.1553 0.2021 l +0.1560 0.2031 l +0.1567 0.2042 l +0.1573 0.2052 l +0.1580 0.2063 l +0.1587 0.2074 l +0.1593 0.2085 l +0.1600 0.2095 l +0.1607 0.2106 l +0.1613 0.2117 l +0.1620 0.2128 l +0.1627 0.2139 l +0.1633 0.2148 l +0.1640 0.2159 l +0.1647 0.2169 l +0.1653 0.2179 l +0.1660 0.2189 l +0.1667 0.2200 l +0.1673 0.2208 l +0.1680 0.2217 l +0.1687 0.2226 l +0.1693 0.2235 l +0.1700 0.2243 l +0.1707 0.2250 l +0.1713 0.2257 l +0.1720 0.2265 l +0.1727 0.2272 l +0.1733 0.2280 l +0.1740 0.2286 l +0.1747 0.2293 l +0.1753 0.2301 l +0.1760 0.2308 l +0.1767 0.2315 l +0.1773 0.2322 l +0.1780 0.2330 l +0.1787 0.2337 l +0.1793 0.2344 l +0.1800 0.2352 l +0.1807 0.2359 l +0.1813 0.2367 l +0.1820 0.2376 l +0.1827 0.2383 l +0.1833 0.2391 l +0.1840 0.2399 l +0.1847 0.2407 l +0.1853 0.2416 l +0.1860 0.2425 l +0.1867 0.2434 l +0.1873 0.2442 l +0.1880 0.2450 l +0.1887 0.2457 l +0.1893 0.2463 l +0.1900 0.2468 l +0.1907 0.2472 l +0.1913 0.2475 l +0.1920 0.2478 l +0.1927 0.2482 l +0.1933 0.2485 l +0.1940 0.2489 l +0.1947 0.2492 l +0.1953 0.2496 l +0.1960 0.2500 l +0.1967 0.2504 l +0.1973 0.2507 l +0.1980 0.2511 l +0.1987 0.2515 l +0.1993 0.2519 l +0.2000 0.2523 l +0.2007 0.2527 l +0.2013 0.2532 l +0.2020 0.2536 l +0.2027 0.2540 l +0.2033 0.2544 l +0.2040 0.2549 l +0.2047 0.2553 l +0.2053 0.2557 l +0.2060 0.2561 l +0.2067 0.2565 l +0.2073 0.2569 l +0.2080 0.2573 l +0.2087 0.2577 l +0.2093 0.2580 l +0.2100 0.2584 l +0.2107 0.2588 l +0.2113 0.2592 l +0.2120 0.2597 l +0.2127 0.2601 l +0.2133 0.2605 l +0.2140 0.2609 l +0.2147 0.2614 l +0.2153 0.2618 l +0.2160 0.2623 l +0.2167 0.2627 l +0.2173 0.2632 l +0.2180 0.2637 l +0.2187 0.2641 l +0.2193 0.2646 l +0.2200 0.2651 l +0.2207 0.2656 l +0.2213 0.2659 l +0.2220 0.2662 l +0.2227 0.2666 l +0.2233 0.2669 l +0.2240 0.2672 l +0.2247 0.2676 l +0.2253 0.2680 l +0.2260 0.2684 l +0.2267 0.2687 l +0.2273 0.2691 l +0.2280 0.2695 l +0.2287 0.2699 l +0.2293 0.2704 l +0.2300 0.2708 l +0.2307 0.2712 l +0.2313 0.2717 l +0.2320 0.2722 l +0.2327 0.2726 l +0.2333 0.2731 l +0.2340 0.2736 l +0.2347 0.2741 l +0.2353 0.2747 l +0.2360 0.2752 l +0.2367 0.2757 l +0.2373 0.2763 l +0.2380 0.2768 l +0.2387 0.2774 l +0.2393 0.2780 l +0.2400 0.2785 l +0.2407 0.2790 l +0.2413 0.2794 l +0.2420 0.2799 l +0.2427 0.2803 l +0.2433 0.2808 l +0.2440 0.2812 l +0.2447 0.2817 l +0.2453 0.2822 l +0.2460 0.2827 l +0.2467 0.2831 l +0.2473 0.2836 l +0.2480 0.2841 l +0.2487 0.2846 l +0.2493 0.2851 l +0.2500 0.2856 l +0.2507 0.2861 l +0.2513 0.2866 l +0.2520 0.2871 l +0.2527 0.2876 l +0.2533 0.2881 l +0.2540 0.2886 l +0.2547 0.2891 l +0.2553 0.2897 l +0.2560 0.2902 l +0.2567 0.2907 l +0.2573 0.2913 l +0.2580 0.2918 l +0.2587 0.2923 l +0.2593 0.2929 l +0.2600 0.2934 l +0.2607 0.2939 l +0.2613 0.2945 l +0.2620 0.2950 l +0.2627 0.2956 l +0.2633 0.2961 l +0.2640 0.2967 l +0.2647 0.2973 l +0.2653 0.2978 l +0.2660 0.2984 l +0.2667 0.2990 l +0.2673 0.2995 l +0.2680 0.3001 l +0.2687 0.3007 l +0.2693 0.3013 l +0.2700 0.3018 l +0.2707 0.3024 l +0.2713 0.3030 l +0.2720 0.3036 l +0.2727 0.3042 l +0.2733 0.3048 l +0.2740 0.3054 l +0.2747 0.3060 l +0.2753 0.3066 l +0.2760 0.3072 l +0.2767 0.3078 l +0.2773 0.3084 l +0.2780 0.3090 l +0.2787 0.3096 l +0.2793 0.3103 l +0.2800 0.3109 l +0.2807 0.3115 l +0.2813 0.3121 l +0.2820 0.3128 l +0.2827 0.3134 l +0.2833 0.3140 l +0.2840 0.3146 l +0.2847 0.3153 l +0.2853 0.3159 l +0.2860 0.3166 l +0.2867 0.3172 l +0.2873 0.3179 l +0.2880 0.3185 l +0.2887 0.3192 l +0.2893 0.3198 l +0.2900 0.3205 l +0.2907 0.3211 l +0.2913 0.3218 l +0.2920 0.3224 l +0.2927 0.3231 l +0.2933 0.3238 l +0.2940 0.3244 l +0.2947 0.3251 l +0.2953 0.3258 l +0.2960 0.3265 l +0.2967 0.3271 l +0.2973 0.3278 l +0.2980 0.3285 l +0.2987 0.3292 l +0.2993 0.3299 l +0.3000 0.3306 l +0.3007 0.3313 l +0.3013 0.3320 l +0.3020 0.3327 l +0.3027 0.3334 l +0.3033 0.3341 l +0.3040 0.3348 l +0.3047 0.3355 l +0.3053 0.3362 l +0.3060 0.3369 l +0.3067 0.3376 l +0.3073 0.3383 l +0.3080 0.3391 l +0.3087 0.3398 l +0.3093 0.3405 l +0.3100 0.3412 l +0.3107 0.3419 l +0.3113 0.3426 l +0.3120 0.3433 l +0.3127 0.3440 l +0.3133 0.3448 l +0.3140 0.3455 l +0.3147 0.3462 l +0.3153 0.3469 l +0.3160 0.3476 l +0.3167 0.3483 l +0.3173 0.3490 l +0.3180 0.3498 l +0.3187 0.3505 l +0.3193 0.3512 l +0.3200 0.3519 l +0.3207 0.3526 l +0.3213 0.3533 l +0.3220 0.3540 l +0.3227 0.3548 l +0.3233 0.3555 l +0.3240 0.3562 l +0.3247 0.3569 l +0.3253 0.3576 l +0.3260 0.3583 l +0.3267 0.3590 l +0.3273 0.3597 l +0.3280 0.3604 l +0.3287 0.3611 l +0.3293 0.3618 l +0.3300 0.3625 l +0.3307 0.3632 l +0.3313 0.3639 l +0.3320 0.3646 l +0.3327 0.3653 l +0.3333 0.3660 l +0.3340 0.3666 l +0.3347 0.3673 l +0.3353 0.3680 l +0.3360 0.3687 l +0.3367 0.3694 l +0.3373 0.3700 l +0.3380 0.3707 l +0.3387 0.3714 l +0.3393 0.3720 l +0.3400 0.3727 l +0.3407 0.3734 l +0.3413 0.3740 l +0.3420 0.3747 l +0.3427 0.3753 l +0.3433 0.3760 l +0.3440 0.3766 l +0.3447 0.3773 l +0.3453 0.3779 l +0.3460 0.3786 l +0.3467 0.3792 l +0.3473 0.3798 l +0.3480 0.3805 l +0.3487 0.3811 l +0.3493 0.3817 l +0.3500 0.3824 l +0.3507 0.3830 l +0.3513 0.3836 l +0.3520 0.3842 l +0.3527 0.3849 l +0.3533 0.3855 l +0.3540 0.3861 l +0.3547 0.3867 l +0.3553 0.3873 l +0.3560 0.3879 l +0.3567 0.3885 l +0.3573 0.3891 l +0.3580 0.3897 l +0.3587 0.3903 l +0.3593 0.3909 l +0.3600 0.3915 l +0.3607 0.3920 l +0.3613 0.3926 l +0.3620 0.3932 l +0.3627 0.3938 l +0.3633 0.3943 l +0.3640 0.3949 l +0.3647 0.3955 l +0.3653 0.3960 l +0.3660 0.3966 l +0.3667 0.3971 l +0.3673 0.3977 l +0.3680 0.3982 l +0.3687 0.3987 l +0.3693 0.3993 l +0.3700 0.3998 l +0.3707 0.4003 l +0.3713 0.4009 l +0.3720 0.4014 l +0.3727 0.4019 l +0.3733 0.4024 l +0.3740 0.4029 l +0.3747 0.4035 l +0.3753 0.4040 l +0.3760 0.4045 l +0.3767 0.4050 l +0.3773 0.4055 l +0.3780 0.4060 l +0.3787 0.4065 l +0.3793 0.4070 l +0.3800 0.4075 l +0.3807 0.4079 l +0.3813 0.4084 l +0.3820 0.4089 l +0.3827 0.4094 l +0.3833 0.4099 l +0.3840 0.4103 l +0.3847 0.4108 l +0.3853 0.4113 l +0.3860 0.4118 l +0.3867 0.4122 l +0.3873 0.4127 l +0.3880 0.4132 l +0.3887 0.4136 l +0.3893 0.4141 l +0.3900 0.4145 l +0.3907 0.4150 l +0.3913 0.4154 l +0.3920 0.4159 l +0.3927 0.4163 l +0.3933 0.4168 l +0.3940 0.4172 l +0.3947 0.4177 l +0.3953 0.4181 l +0.3960 0.4186 l +0.3967 0.4190 l +0.3973 0.4194 l +0.3980 0.4199 l +0.3987 0.4203 l +0.3993 0.4207 l +0.4000 0.4212 l +0.4007 0.4216 l +0.4013 0.4220 l +0.4020 0.4224 l +0.4027 0.4228 l +0.4033 0.4233 l +0.4040 0.4237 l +0.4047 0.4241 l +0.4053 0.4245 l +0.4060 0.4249 l +0.4067 0.4253 l +0.4073 0.4257 l +0.4080 0.4261 l +0.4087 0.4265 l +0.4093 0.4269 l +0.4100 0.4273 l +0.4107 0.4277 l +0.4113 0.4281 l +0.4120 0.4285 l +0.4127 0.4289 l +0.4133 0.4293 l +0.4140 0.4297 l +0.4147 0.4300 l +0.4153 0.4304 l +0.4160 0.4308 l +0.4167 0.4312 l +0.4173 0.4316 l +0.4180 0.4320 l +0.4187 0.4323 l +0.4193 0.4327 l +0.4200 0.4331 l +0.4207 0.4334 l +0.4213 0.4338 l +0.4220 0.4342 l +0.4227 0.4345 l +0.4233 0.4349 l +0.4240 0.4353 l +0.4247 0.4356 l +0.4253 0.4360 l +0.4260 0.4364 l +0.4267 0.4367 l +0.4273 0.4371 l +0.4280 0.4374 l +0.4287 0.4378 l +0.4293 0.4381 l +0.4300 0.4385 l +0.4307 0.4388 l +0.4313 0.4391 l +0.4320 0.4395 l +0.4327 0.4398 l +0.4333 0.4402 l +0.4340 0.4405 l +0.4347 0.4408 l +0.4353 0.4411 l +0.4360 0.4415 l +0.4367 0.4418 l +0.4373 0.4421 l +0.4380 0.4424 l +0.4387 0.4428 l +0.4393 0.4431 l +0.4400 0.4434 l +0.4407 0.4437 l +0.4413 0.4440 l +0.4420 0.4444 l +0.4427 0.4447 l +0.4433 0.4450 l +0.4440 0.4453 l +0.4447 0.4456 l +0.4453 0.4459 l +0.4460 0.4462 l +0.4467 0.4465 l +0.4473 0.4468 l +0.4480 0.4471 l +0.4487 0.4474 l +0.4493 0.4477 l +0.4500 0.4480 l +0.4507 0.4482 l +0.4513 0.4485 l +0.4520 0.4488 l +0.4527 0.4491 l +0.4533 0.4494 l +0.4540 0.4496 l +0.4547 0.4499 l +0.4553 0.4502 l +0.4560 0.4505 l +0.4567 0.4507 l +0.4573 0.4510 l +0.4580 0.4512 l +0.4587 0.4515 l +0.4593 0.4518 l +0.4600 0.4520 l +0.4607 0.4523 l +0.4613 0.4525 l +0.4620 0.4528 l +0.4627 0.4530 l +0.4633 0.4533 l +0.4640 0.4535 l +0.4647 0.4538 l +0.4653 0.4540 l +0.4660 0.4543 l +0.4667 0.4545 l +0.4673 0.4547 l +0.4680 0.4550 l +0.4687 0.4552 l +0.4693 0.4554 l +0.4700 0.4557 l +0.4707 0.4559 l +0.4713 0.4561 l +0.4720 0.4563 l +0.4727 0.4566 l +0.4733 0.4568 l +0.4740 0.4570 l +0.4747 0.4572 l +0.4753 0.4574 l +0.4760 0.4577 l +0.4767 0.4579 l +0.4773 0.4581 l +0.4780 0.4583 l +0.4787 0.4585 l +0.4793 0.4587 l +0.4800 0.4589 l +0.4807 0.4591 l +0.4813 0.4594 l +0.4820 0.4596 l +0.4827 0.4598 l +0.4833 0.4600 l +0.4840 0.4602 l +0.4847 0.4604 l +0.4853 0.4606 l +0.4860 0.4608 l +0.4867 0.4610 l +0.4873 0.4612 l +0.4880 0.4613 l +0.4887 0.4615 l +0.4893 0.4617 l +0.4900 0.4619 l +0.4907 0.4621 l +0.4913 0.4623 l +0.4920 0.4625 l +0.4927 0.4627 l +0.4933 0.4628 l +0.4940 0.4630 l +0.4947 0.4632 l +0.4953 0.4634 l +0.4960 0.4635 l +0.4967 0.4637 l +0.4973 0.4639 l +0.4980 0.4641 l +0.4987 0.4642 l +0.4993 0.4644 l +0.5000 0.4646 l +0.5007 0.4647 l +0.5013 0.4649 l +0.5020 0.4651 l +0.5027 0.4652 l +0.5033 0.4654 l +0.5040 0.4656 l +0.5047 0.4657 l +0.5053 0.4659 l +0.5060 0.4661 l +0.5067 0.4662 l +0.5073 0.4664 l +0.5080 0.4665 l +0.5087 0.4667 l +0.5093 0.4668 l +0.5100 0.4670 l +0.5107 0.4671 l +0.5113 0.4673 l +0.5120 0.4674 l +0.5127 0.4676 l +0.5133 0.4677 l +0.5140 0.4678 l +0.5147 0.4680 l +0.5153 0.4681 l +0.5160 0.4683 l +0.5167 0.4684 l +0.5173 0.4685 l +0.5180 0.4687 l +0.5187 0.4688 l +0.5193 0.4689 l +0.5200 0.4690 l +0.5207 0.4692 l +0.5213 0.4693 l +0.5220 0.4694 l +0.5227 0.4695 l +0.5233 0.4696 l +0.5240 0.4697 l +0.5247 0.4698 l +0.5253 0.4699 l +0.5260 0.4700 l +0.5267 0.4702 l +0.5273 0.4703 l +0.5280 0.4704 l +0.5287 0.4705 l +0.5293 0.4706 l +0.5300 0.4707 l +0.5307 0.4708 l +0.5313 0.4709 l +0.5320 0.4710 l +0.5327 0.4711 l +0.5333 0.4712 l +0.5340 0.4713 l +0.5347 0.4715 l +0.5353 0.4716 l +0.5360 0.4717 l +0.5367 0.4718 l +0.5373 0.4719 l +0.5380 0.4720 l +0.5387 0.4721 l +0.5393 0.4722 l +0.5400 0.4723 l +0.5407 0.4724 l +0.5413 0.4725 l +0.5420 0.4726 l +0.5427 0.4727 l +0.5433 0.4728 l +0.5440 0.4729 l +0.5447 0.4730 l +0.5453 0.4731 l +0.5460 0.4732 l +0.5467 0.4733 l +0.5473 0.4734 l +0.5480 0.4735 l +0.5487 0.4736 l +0.5493 0.4737 l +0.5500 0.4738 l +0.5507 0.4739 l +0.5513 0.4740 l +0.5520 0.4740 l +0.5527 0.4741 l +0.5533 0.4742 l +0.5540 0.4743 l +0.5547 0.4744 l +0.5553 0.4745 l +0.5560 0.4746 l +0.5567 0.4747 l +0.5573 0.4748 l +0.5580 0.4749 l +0.5587 0.4750 l +0.5593 0.4751 l +0.5600 0.4751 l +0.5607 0.4752 l +0.5613 0.4753 l +0.5620 0.4754 l +0.5627 0.4755 l +0.5633 0.4756 l +0.5640 0.4757 l +0.5647 0.4758 l +0.5653 0.4758 l +0.5660 0.4759 l +0.5667 0.4760 l +0.5673 0.4761 l +0.5680 0.4762 l +0.5687 0.4763 l +0.5693 0.4764 l +0.5700 0.4764 l +0.5707 0.4765 l +0.5713 0.4766 l +0.5720 0.4767 l +0.5727 0.4768 l +0.5733 0.4769 l +0.5740 0.4770 l +0.5747 0.4770 l +0.5753 0.4771 l +0.5760 0.4772 l +0.5767 0.4773 l +0.5773 0.4774 l +0.5780 0.4775 l +0.5787 0.4775 l +0.5793 0.4776 l +0.5800 0.4777 l +0.5807 0.4778 l +0.5813 0.4779 l +0.5820 0.4780 l +0.5827 0.4780 l +0.5833 0.4781 l +0.5840 0.4782 l +0.5847 0.4783 l +0.5853 0.4784 l +0.5860 0.4785 l +0.5867 0.4785 l +0.5873 0.4786 l +0.5880 0.4787 l +0.5887 0.4788 l +0.5893 0.4789 l +0.5900 0.4789 l +0.5907 0.4790 l +0.5913 0.4791 l +0.5920 0.4792 l +0.5927 0.4793 l +0.5933 0.4794 l +0.5940 0.4794 l +0.5947 0.4795 l +0.5953 0.4796 l +0.5960 0.4797 l +0.5967 0.4798 l +0.5973 0.4798 l +0.5980 0.4799 l +0.5987 0.4800 l +0.5993 0.4801 l +0.6000 0.4802 l +0.6007 0.4802 l +0.6013 0.4803 l +0.6020 0.4804 l +0.6027 0.4805 l +0.6033 0.4805 l +0.6040 0.4806 l +0.6047 0.4807 l +0.6053 0.4808 l +0.6060 0.4809 l +0.6067 0.4809 l +0.6073 0.4810 l +0.6080 0.4811 l +0.6087 0.4812 l +0.6093 0.4812 l +0.6100 0.4813 l +0.6107 0.4814 l +0.6113 0.4815 l +0.6120 0.4815 l +0.6127 0.4816 l +0.6133 0.4817 l +0.6140 0.4818 l +0.6147 0.4818 l +0.6153 0.4819 l +0.6160 0.4820 l +0.6167 0.4821 l +0.6173 0.4821 l +0.6180 0.4822 l +0.6187 0.4823 l +0.6193 0.4824 l +0.6200 0.4824 l +0.6207 0.4825 l +0.6213 0.4826 l +0.6220 0.4826 l +0.6227 0.4827 l +0.6233 0.4828 l +0.6240 0.4829 l +0.6247 0.4829 l +0.6253 0.4830 l +0.6260 0.4831 l +0.6267 0.4831 l +0.6273 0.4832 l +0.6280 0.4833 l +0.6287 0.4834 l +0.6293 0.4834 l +0.6300 0.4835 l +0.6307 0.4836 l +0.6313 0.4836 l +0.6320 0.4837 l +0.6327 0.4838 l +0.6333 0.4839 l +0.6340 0.4839 l +0.6347 0.4840 l +0.6353 0.4841 l +0.6360 0.4841 l +0.6367 0.4842 l +0.6373 0.4843 l +0.6380 0.4843 l +0.6387 0.4844 l +0.6393 0.4845 l +0.6400 0.4845 l +0.6407 0.4846 l +0.6413 0.4847 l +0.6420 0.4847 l +0.6427 0.4848 l +0.6433 0.4849 l +0.6440 0.4849 l +0.6447 0.4850 l +0.6453 0.4851 l +0.6460 0.4851 l +0.6467 0.4852 l +0.6473 0.4853 l +0.6480 0.4853 l +0.6487 0.4854 l +0.6493 0.4855 l +0.6500 0.4855 l +0.6507 0.4856 l +0.6513 0.4857 l +0.6520 0.4857 l +0.6527 0.4858 l +0.6533 0.4858 l +0.6540 0.4859 l +0.6547 0.4860 l +0.6553 0.4860 l +0.6560 0.4861 l +0.6567 0.4862 l +0.6573 0.4862 l +0.6580 0.4863 l +0.6587 0.4863 l +0.6593 0.4864 l +0.6600 0.4865 l +0.6607 0.4865 l +0.6613 0.4866 l +0.6620 0.4867 l +0.6627 0.4867 l +0.6633 0.4868 l +0.6640 0.4868 l +0.6647 0.4869 l +0.6653 0.4870 l +0.6660 0.4870 l +0.6667 0.4871 l +0.6673 0.4871 l +0.6680 0.4872 l +0.6687 0.4873 l +0.6693 0.4873 l +0.6700 0.4874 l +0.6707 0.4874 l +0.6713 0.4875 l +0.6720 0.4875 l +0.6727 0.4876 l +0.6733 0.4877 l +0.6740 0.4877 l +0.6747 0.4878 l +0.6753 0.4878 l +0.6760 0.4879 l +0.6767 0.4880 l +0.6773 0.4880 l +0.6780 0.4881 l +0.6787 0.4881 l +0.6793 0.4882 l +0.6800 0.4882 l +0.6807 0.4883 l +0.6813 0.4883 l +0.6820 0.4884 l +0.6827 0.4885 l +0.6833 0.4885 l +0.6840 0.4886 l +0.6847 0.4886 l +0.6853 0.4887 l +0.6860 0.4887 l +0.6867 0.4888 l +0.6873 0.4888 l +0.6880 0.4889 l +0.6887 0.4889 l +0.6893 0.4890 l +0.6900 0.4891 l +0.6907 0.4891 l +0.6913 0.4892 l +0.6920 0.4892 l +0.6927 0.4893 l +0.6933 0.4893 l +0.6940 0.4894 l +0.6947 0.4894 l +0.6953 0.4895 l +0.6960 0.4895 l +0.6967 0.4896 l +0.6973 0.4896 l +0.6980 0.4897 l +0.6987 0.4897 l +0.6993 0.4898 l +0.7000 0.4898 l +0.7007 0.4899 l +0.7013 0.4899 l +0.7020 0.4900 l +0.7027 0.4900 l +0.7033 0.4901 l +0.7040 0.4901 l +0.7047 0.4902 l +0.7053 0.4902 l +0.7060 0.4903 l +0.7067 0.4903 l +0.7073 0.4904 l +0.7080 0.4904 l +0.7087 0.4905 l +0.7093 0.4905 l +0.7100 0.4905 l +0.7107 0.4906 l +0.7113 0.4906 l +0.7120 0.4907 l +0.7127 0.4907 l +0.7133 0.4908 l +0.7140 0.4908 l +0.7147 0.4909 l +0.7153 0.4909 l +0.7160 0.4910 l +0.7167 0.4910 l +0.7173 0.4911 l +0.7180 0.4911 l +0.7187 0.4911 l +0.7193 0.4912 l +0.7200 0.4912 l +0.7207 0.4913 l +0.7213 0.4913 l +0.7220 0.4914 l +0.7227 0.4914 l +0.7233 0.4915 l +0.7240 0.4915 l +0.7247 0.4915 l +0.7253 0.4916 l +0.7260 0.4916 l +0.7267 0.4917 l +0.7273 0.4917 l +0.7280 0.4918 l +0.7287 0.4918 l +0.7293 0.4918 l +0.7300 0.4919 l +0.7307 0.4919 l +0.7313 0.4920 l +0.7320 0.4920 l +0.7327 0.4920 l +0.7333 0.4921 l +0.7340 0.4921 l +0.7347 0.4922 l +0.7353 0.4922 l +0.7360 0.4922 l +0.7367 0.4923 l +0.7373 0.4923 l +0.7380 0.4924 l +0.7387 0.4924 l +0.7393 0.4924 l +0.7400 0.4925 l +0.7407 0.4925 l +0.7413 0.4926 l +0.7420 0.4926 l +0.7427 0.4926 l +0.7433 0.4927 l +0.7440 0.4927 l +0.7447 0.4927 l +0.7453 0.4928 l +0.7460 0.4928 l +0.7467 0.4929 l +0.7473 0.4929 l +0.7480 0.4929 l +0.7487 0.4930 l +0.7493 0.4930 l +0.7500 0.4930 l +0.7507 0.4931 l +0.7513 0.4931 l +0.7520 0.4931 l +0.7527 0.4932 l +0.7533 0.4932 l +0.7540 0.4933 l +0.7547 0.4933 l +0.7553 0.4933 l +0.7560 0.4934 l +0.7567 0.4934 l +0.7573 0.4934 l +0.7580 0.4935 l +0.7587 0.4935 l +0.7593 0.4935 l +0.7600 0.4936 l +0.7607 0.4936 l +0.7613 0.4936 l +0.7620 0.4937 l +0.7627 0.4937 l +0.7633 0.4937 l +0.7640 0.4938 l +0.7647 0.4938 l +0.7653 0.4938 l +0.7660 0.4938 l +0.7667 0.4939 l +0.7673 0.4939 l +0.7680 0.4939 l +0.7687 0.4940 l +0.7693 0.4940 l +0.7700 0.4940 l +0.7707 0.4941 l +0.7713 0.4941 l +0.7720 0.4941 l +0.7727 0.4942 l +0.7733 0.4942 l +0.7740 0.4942 l +0.7747 0.4942 l +0.7753 0.4943 l +0.7760 0.4943 l +0.7767 0.4943 l +0.7773 0.4944 l +0.7780 0.4944 l +0.7787 0.4944 l +0.7793 0.4944 l +0.7800 0.4945 l +0.7807 0.4945 l +0.7813 0.4945 l +0.7820 0.4945 l +0.7827 0.4946 l +0.7833 0.4946 l +0.7840 0.4946 l +0.7847 0.4947 l +0.7853 0.4947 l +0.7860 0.4947 l +0.7867 0.4947 l +0.7873 0.4948 l +0.7880 0.4948 l +0.7887 0.4948 l +0.7893 0.4948 l +0.7900 0.4949 l +0.7907 0.4949 l +0.7913 0.4949 l +0.7920 0.4949 l +0.7927 0.4950 l +0.7933 0.4950 l +0.7940 0.4950 l +0.7947 0.4950 l +0.7953 0.4951 l +0.7960 0.4951 l +0.7967 0.4951 l +0.7973 0.4951 l +0.7980 0.4951 l +0.7987 0.4952 l +0.7993 0.4952 l +0.8000 0.4952 l +0.8007 0.4952 l +0.8013 0.4953 l +0.8020 0.4953 l +0.8027 0.4953 l +0.8033 0.4953 l +0.8040 0.4953 l +0.8047 0.4954 l +0.8053 0.4954 l +0.8060 0.4954 l +0.8067 0.4954 l +0.8073 0.4955 l +0.8080 0.4955 l +0.8087 0.4955 l +0.8093 0.4955 l +0.8100 0.4955 l +0.8107 0.4956 l +0.8113 0.4956 l +0.8120 0.4956 l +0.8127 0.4956 l +0.8133 0.4956 l +0.8140 0.4956 l +0.8147 0.4957 l +0.8153 0.4957 l +0.8160 0.4957 l +s +[/DeviceRGB] SCS +Color1 SC +n +0.1500 0.4974 m +0.1567 0.4974 l +0.1633 0.4974 l +0.1700 0.4974 l +0.1767 0.4974 l +0.1833 0.4974 l +0.1900 0.4974 l +0.1967 0.4974 l +0.2033 0.4974 l +0.2100 0.4974 l +0.2167 0.4974 l +0.2233 0.4974 l +0.2300 0.4974 l +0.2367 0.4974 l +0.2433 0.4974 l +0.2500 0.4974 l +0.2567 0.4974 l +0.2633 0.4974 l +0.2700 0.4974 l +0.2767 0.4974 l +0.2833 0.4974 l +0.2900 0.4974 l +0.2967 0.4974 l +0.3033 0.4974 l +0.3100 0.4974 l +0.3167 0.4974 l +0.3233 0.4974 l +0.3300 0.4974 l +0.3367 0.4974 l +0.3433 0.4974 l +0.3500 0.4974 l +0.3567 0.4974 l +0.3633 0.4974 l +0.3700 0.4974 l +0.3767 0.4974 l +0.3833 0.4974 l +0.3900 0.4974 l +0.3967 0.4974 l +0.4033 0.4974 l +0.4100 0.4974 l +0.4167 0.4974 l +0.4233 0.4974 l +0.4300 0.4974 l +0.4367 0.4974 l +0.4433 0.4974 l +0.4500 0.4974 l +0.4567 0.4974 l +0.4633 0.4974 l +0.4700 0.4974 l +0.4767 0.4974 l +0.4833 0.4974 l +0.4900 0.4974 l +0.4967 0.4974 l +0.5033 0.4974 l +0.5100 0.4974 l +0.5167 0.4974 l +0.5233 0.4974 l +0.5300 0.4974 l +0.5367 0.4974 l +0.5433 0.4974 l +0.5500 0.4974 l +0.5567 0.4974 l +0.5633 0.4974 l +0.5700 0.4974 l +0.5767 0.4974 l +0.5833 0.4974 l +0.5900 0.4974 l +0.5967 0.4974 l +0.6033 0.4974 l +0.6100 0.4974 l +0.6167 0.4974 l +0.6233 0.4974 l +0.6300 0.4974 l +0.6367 0.4974 l +0.6433 0.4974 l +0.6500 0.4974 l +0.6567 0.4974 l +0.6633 0.4974 l +0.6700 0.4974 l +0.6767 0.4974 l +0.6833 0.4974 l +0.6900 0.4974 l +0.6967 0.4974 l +0.7033 0.4974 l +0.7100 0.4974 l +0.7167 0.4974 l +0.7233 0.4974 l +0.7300 0.4974 l +0.7367 0.4974 l +0.7433 0.4974 l +0.7500 0.4974 l +0.7567 0.4974 l +0.7633 0.4974 l +0.7700 0.4974 l +0.7767 0.4974 l +0.7833 0.4974 l +0.7900 0.4974 l +0.7967 0.4974 l +0.8033 0.4974 l +0.8100 0.4974 l +0.8167 0.4974 l +0.8233 0.4974 l +0.8300 0.4974 l +0.8367 0.4974 l +0.8433 0.4974 l +0.8500 0.4974 l +0.8567 0.4974 l +0.8633 0.4974 l +0.8700 0.4974 l +0.8767 0.4974 l +0.8833 0.4974 l +0.8900 0.4974 l +0.8967 0.4974 l +0.9033 0.4974 l +0.9100 0.4974 l +0.9167 0.4974 l +0.9233 0.4974 l +0.9300 0.4974 l +0.9367 0.4974 l +0.9433 0.4974 l +0.9500 0.4974 l +0.9567 0.4974 l +0.9633 0.4974 l +0.9700 0.4974 l +0.9767 0.4974 l +0.9833 0.4974 l +0.9900 0.4974 l +0.9967 0.4974 l +1.0033 0.4974 l +1.0100 0.4974 l +1.0167 0.4974 l +1.0233 0.4974 l +1.0300 0.4974 l +1.0367 0.4974 l +1.0433 0.4974 l +1.0500 0.4974 l +1.0567 0.4974 l +1.0633 0.4974 l +1.0700 0.4974 l +1.0767 0.4974 l +1.0833 0.4974 l +1.0900 0.4974 l +1.0967 0.4974 l +1.1033 0.4974 l +1.1100 0.4974 l +1.1167 0.4974 l +1.1233 0.4974 l +1.1300 0.4974 l +1.1367 0.4974 l +1.1433 0.4974 l +1.1500 0.4974 l +1.1501 0.4974 l +s +[/DeviceRGB] SCS +Color2 SC +n 0.1500 0.1925 0.0024 0.0024 0 360 EARC s +n 0.1567 0.2031 0.0024 0.0024 0 360 EARC s +n 0.1633 0.2139 0.0024 0.0024 0 360 EARC s +n 0.1700 0.2235 0.0024 0.0024 0 360 EARC s +n 0.1767 0.2308 0.0024 0.0024 0 360 EARC s +n 0.1833 0.2383 0.0024 0.0024 0 360 EARC s +n 0.1900 0.2463 0.0024 0.0024 0 360 EARC s +n 0.1967 0.2500 0.0024 0.0024 0 360 EARC s +n 0.2033 0.2540 0.0024 0.0024 0 360 EARC s +n 0.2100 0.2580 0.0024 0.0024 0 360 EARC s +n 0.2167 0.2623 0.0024 0.0024 0 360 EARC s +n 0.2233 0.2666 0.0024 0.0024 0 360 EARC s +n 0.2300 0.2704 0.0024 0.0024 0 360 EARC s +n 0.2367 0.2752 0.0024 0.0024 0 360 EARC s +n 0.2433 0.2803 0.0024 0.0024 0 360 EARC s +n 0.2500 0.2851 0.0024 0.0024 0 360 EARC s +n 0.2567 0.2902 0.0024 0.0024 0 360 EARC s +n 0.2633 0.2956 0.0024 0.0024 0 360 EARC s +n 0.2700 0.3013 0.0024 0.0024 0 360 EARC s +n 0.2767 0.3072 0.0024 0.0024 0 360 EARC s +n 0.2833 0.3134 0.0024 0.0024 0 360 EARC s +n 0.2900 0.3198 0.0024 0.0024 0 360 EARC s +n 0.2967 0.3265 0.0024 0.0024 0 360 EARC s +n 0.3033 0.3334 0.0024 0.0024 0 360 EARC s +n 0.3100 0.3405 0.0024 0.0024 0 360 EARC s +n 0.3167 0.3476 0.0024 0.0024 0 360 EARC s +n 0.3233 0.3548 0.0024 0.0024 0 360 EARC s +n 0.3300 0.3618 0.0024 0.0024 0 360 EARC s +n 0.3367 0.3687 0.0024 0.0024 0 360 EARC s +n 0.3433 0.3753 0.0024 0.0024 0 360 EARC s +n 0.3500 0.3817 0.0024 0.0024 0 360 EARC s +n 0.3567 0.3879 0.0024 0.0024 0 360 EARC s +n 0.3633 0.3938 0.0024 0.0024 0 360 EARC s +n 0.3700 0.3993 0.0024 0.0024 0 360 EARC s +n 0.3767 0.4045 0.0024 0.0024 0 360 EARC s +n 0.3833 0.4094 0.0024 0.0024 0 360 EARC s +n 0.3900 0.4141 0.0024 0.0024 0 360 EARC s +n 0.3967 0.4186 0.0024 0.0024 0 360 EARC s +n 0.4033 0.4228 0.0024 0.0024 0 360 EARC s +n 0.4100 0.4269 0.0024 0.0024 0 360 EARC s +n 0.4167 0.4308 0.0024 0.0024 0 360 EARC s +n 0.4233 0.4345 0.0024 0.0024 0 360 EARC s +n 0.4300 0.4381 0.0024 0.0024 0 360 EARC s +n 0.4367 0.4415 0.0024 0.0024 0 360 EARC s +n 0.4433 0.4447 0.0024 0.0024 0 360 EARC s +n 0.4500 0.4477 0.0024 0.0024 0 360 EARC s +n 0.4567 0.4505 0.0024 0.0024 0 360 EARC s +n 0.4633 0.4530 0.0024 0.0024 0 360 EARC s +n 0.4700 0.4554 0.0024 0.0024 0 360 EARC s +n 0.4767 0.4577 0.0024 0.0024 0 360 EARC s +n 0.4833 0.4598 0.0024 0.0024 0 360 EARC s +n 0.4900 0.4617 0.0024 0.0024 0 360 EARC s +n 0.4967 0.4635 0.0024 0.0024 0 360 EARC s +n 0.5033 0.4652 0.0024 0.0024 0 360 EARC s +n 0.5100 0.4668 0.0024 0.0024 0 360 EARC s +n 0.5167 0.4683 0.0024 0.0024 0 360 EARC s +n 0.5233 0.4695 0.0024 0.0024 0 360 EARC s +n 0.5300 0.4706 0.0024 0.0024 0 360 EARC s +n 0.5367 0.4717 0.0024 0.0024 0 360 EARC s +n 0.5433 0.4727 0.0024 0.0024 0 360 EARC s +n 0.5500 0.4737 0.0024 0.0024 0 360 EARC s +n 0.5567 0.4746 0.0024 0.0024 0 360 EARC s +n 0.5633 0.4755 0.0024 0.0024 0 360 EARC s +n 0.5700 0.4764 0.0024 0.0024 0 360 EARC s +n 0.5767 0.4772 0.0024 0.0024 0 360 EARC s +n 0.5833 0.4780 0.0024 0.0024 0 360 EARC s +n 0.5900 0.4789 0.0024 0.0024 0 360 EARC s +n 0.5967 0.4797 0.0024 0.0024 0 360 EARC s +n 0.6033 0.4805 0.0024 0.0024 0 360 EARC s +n 0.6100 0.4812 0.0024 0.0024 0 360 EARC s +n 0.6167 0.4820 0.0024 0.0024 0 360 EARC s +n 0.6233 0.4827 0.0024 0.0024 0 360 EARC s +n 0.6300 0.4834 0.0024 0.0024 0 360 EARC s +n 0.6367 0.4841 0.0024 0.0024 0 360 EARC s +n 0.6433 0.4848 0.0024 0.0024 0 360 EARC s +n 0.6500 0.4855 0.0024 0.0024 0 360 EARC s +n 0.6567 0.4861 0.0024 0.0024 0 360 EARC s +n 0.6633 0.4867 0.0024 0.0024 0 360 EARC s +n 0.6700 0.4873 0.0024 0.0024 0 360 EARC s +n 0.6767 0.4879 0.0024 0.0024 0 360 EARC s +n 0.6833 0.4885 0.0024 0.0024 0 360 EARC s +n 0.6900 0.4890 0.0024 0.0024 0 360 EARC s +n 0.6967 0.4895 0.0024 0.0024 0 360 EARC s +n 0.7033 0.4900 0.0024 0.0024 0 360 EARC s +n 0.7100 0.4905 0.0024 0.0024 0 360 EARC s +n 0.7167 0.4910 0.0024 0.0024 0 360 EARC s +n 0.7233 0.4914 0.0024 0.0024 0 360 EARC s +n 0.7300 0.4918 0.0024 0.0024 0 360 EARC s +n 0.7367 0.4922 0.0024 0.0024 0 360 EARC s +n 0.7433 0.4926 0.0024 0.0024 0 360 EARC s +n 0.7500 0.4930 0.0024 0.0024 0 360 EARC s +n 0.7567 0.4934 0.0024 0.0024 0 360 EARC s +n 0.7633 0.4937 0.0024 0.0024 0 360 EARC s +n 0.7700 0.4940 0.0024 0.0024 0 360 EARC s +n 0.7767 0.4943 0.0024 0.0024 0 360 EARC s +n 0.7833 0.4946 0.0024 0.0024 0 360 EARC s +n 0.7900 0.4948 0.0024 0.0024 0 360 EARC s +n 0.7967 0.4951 0.0024 0.0024 0 360 EARC s +n 0.8033 0.4953 0.0024 0.0024 0 360 EARC s +n 0.8100 0.4955 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4957 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4959 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4960 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4962 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4963 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4965 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4966 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4967 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4968 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4968 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4969 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4970 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4970 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +n 0.1500 0.8138 0.0024 0.0024 0 360 EARC s +n 0.1567 0.8063 0.0024 0.0024 0 360 EARC s +n 0.1633 0.7983 0.0024 0.0024 0 360 EARC s +n 0.1700 0.7896 0.0024 0.0024 0 360 EARC s +n 0.1767 0.7806 0.0024 0.0024 0 360 EARC s +n 0.1833 0.7709 0.0024 0.0024 0 360 EARC s +n 0.1900 0.7611 0.0024 0.0024 0 360 EARC s +n 0.1967 0.7505 0.0024 0.0024 0 360 EARC s +n 0.2033 0.7456 0.0024 0.0024 0 360 EARC s +n 0.2100 0.7419 0.0024 0.0024 0 360 EARC s +n 0.2167 0.7388 0.0024 0.0024 0 360 EARC s +n 0.2233 0.7366 0.0024 0.0024 0 360 EARC s +n 0.2300 0.7344 0.0024 0.0024 0 360 EARC s +n 0.2367 0.7318 0.0024 0.0024 0 360 EARC s +n 0.2433 0.7287 0.0024 0.0024 0 360 EARC s +n 0.2500 0.7249 0.0024 0.0024 0 360 EARC s +n 0.2567 0.7206 0.0024 0.0024 0 360 EARC s +n 0.2633 0.7152 0.0024 0.0024 0 360 EARC s +n 0.2700 0.7092 0.0024 0.0024 0 360 EARC s +n 0.2767 0.7021 0.0024 0.0024 0 360 EARC s +n 0.2833 0.6943 0.0024 0.0024 0 360 EARC s +n 0.2900 0.6855 0.0024 0.0024 0 360 EARC s +n 0.2967 0.6760 0.0024 0.0024 0 360 EARC s +n 0.3033 0.6663 0.0024 0.0024 0 360 EARC s +n 0.3100 0.6566 0.0024 0.0024 0 360 EARC s +n 0.3167 0.6470 0.0024 0.0024 0 360 EARC s +n 0.3233 0.6380 0.0024 0.0024 0 360 EARC s +n 0.3300 0.6293 0.0024 0.0024 0 360 EARC s +n 0.3367 0.6211 0.0024 0.0024 0 360 EARC s +n 0.3433 0.6135 0.0024 0.0024 0 360 EARC s +n 0.3500 0.6062 0.0024 0.0024 0 360 EARC s +n 0.3567 0.5993 0.0024 0.0024 0 360 EARC s +n 0.3633 0.5929 0.0024 0.0024 0 360 EARC s +n 0.3700 0.5870 0.0024 0.0024 0 360 EARC s +n 0.3767 0.5816 0.0024 0.0024 0 360 EARC s +n 0.3833 0.5766 0.0024 0.0024 0 360 EARC s +n 0.3900 0.5719 0.0024 0.0024 0 360 EARC s +n 0.3967 0.5678 0.0024 0.0024 0 360 EARC s +n 0.4033 0.5640 0.0024 0.0024 0 360 EARC s +n 0.4100 0.5606 0.0024 0.0024 0 360 EARC s +n 0.4167 0.5574 0.0024 0.0024 0 360 EARC s +n 0.4233 0.5544 0.0024 0.0024 0 360 EARC s +n 0.4300 0.5516 0.0024 0.0024 0 360 EARC s +n 0.4367 0.5489 0.0024 0.0024 0 360 EARC s +n 0.4433 0.5463 0.0024 0.0024 0 360 EARC s +n 0.4500 0.5439 0.0024 0.0024 0 360 EARC s +n 0.4567 0.5416 0.0024 0.0024 0 360 EARC s +n 0.4633 0.5394 0.0024 0.0024 0 360 EARC s +n 0.4700 0.5373 0.0024 0.0024 0 360 EARC s +n 0.4767 0.5354 0.0024 0.0024 0 360 EARC s +n 0.4833 0.5335 0.0024 0.0024 0 360 EARC s +n 0.4900 0.5317 0.0024 0.0024 0 360 EARC s +n 0.4967 0.5300 0.0024 0.0024 0 360 EARC s +n 0.5033 0.5284 0.0024 0.0024 0 360 EARC s +n 0.5100 0.5270 0.0024 0.0024 0 360 EARC s +n 0.5167 0.5258 0.0024 0.0024 0 360 EARC s +n 0.5233 0.5246 0.0024 0.0024 0 360 EARC s +n 0.5300 0.5235 0.0024 0.0024 0 360 EARC s +n 0.5367 0.5224 0.0024 0.0024 0 360 EARC s +n 0.5433 0.5214 0.0024 0.0024 0 360 EARC s +n 0.5500 0.5204 0.0024 0.0024 0 360 EARC s +n 0.5567 0.5194 0.0024 0.0024 0 360 EARC s +n 0.5633 0.5184 0.0024 0.0024 0 360 EARC s +n 0.5700 0.5175 0.0024 0.0024 0 360 EARC s +n 0.5767 0.5166 0.0024 0.0024 0 360 EARC s +n 0.5833 0.5157 0.0024 0.0024 0 360 EARC s +n 0.5900 0.5149 0.0024 0.0024 0 360 EARC s +n 0.5967 0.5142 0.0024 0.0024 0 360 EARC s +n 0.6033 0.5135 0.0024 0.0024 0 360 EARC s +n 0.6100 0.5128 0.0024 0.0024 0 360 EARC s +n 0.6167 0.5121 0.0024 0.0024 0 360 EARC s +n 0.6233 0.5114 0.0024 0.0024 0 360 EARC s +n 0.6300 0.5107 0.0024 0.0024 0 360 EARC s +n 0.6367 0.5101 0.0024 0.0024 0 360 EARC s +n 0.6433 0.5094 0.0024 0.0024 0 360 EARC s +n 0.6500 0.5088 0.0024 0.0024 0 360 EARC s +n 0.6567 0.5082 0.0024 0.0024 0 360 EARC s +n 0.6633 0.5076 0.0024 0.0024 0 360 EARC s +n 0.6700 0.5070 0.0024 0.0024 0 360 EARC s +n 0.6767 0.5064 0.0024 0.0024 0 360 EARC s +n 0.6833 0.5058 0.0024 0.0024 0 360 EARC s +n 0.6900 0.5053 0.0024 0.0024 0 360 EARC s +n 0.6967 0.5048 0.0024 0.0024 0 360 EARC s +n 0.7033 0.5043 0.0024 0.0024 0 360 EARC s +n 0.7100 0.5038 0.0024 0.0024 0 360 EARC s +n 0.7167 0.5033 0.0024 0.0024 0 360 EARC s +n 0.7233 0.5029 0.0024 0.0024 0 360 EARC s +n 0.7300 0.5025 0.0024 0.0024 0 360 EARC s +n 0.7367 0.5021 0.0024 0.0024 0 360 EARC s +n 0.7433 0.5017 0.0024 0.0024 0 360 EARC s +n 0.7500 0.5013 0.0024 0.0024 0 360 EARC s +n 0.7567 0.5010 0.0024 0.0024 0 360 EARC s +n 0.7633 0.5007 0.0024 0.0024 0 360 EARC s +n 0.7700 0.5004 0.0024 0.0024 0 360 EARC s +n 0.7767 0.5002 0.0024 0.0024 0 360 EARC s +n 0.7833 0.4999 0.0024 0.0024 0 360 EARC s +n 0.7900 0.4997 0.0024 0.0024 0 360 EARC s +n 0.7967 0.4995 0.0024 0.0024 0 360 EARC s +n 0.8033 0.4993 0.0024 0.0024 0 360 EARC s +n 0.8100 0.4991 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4990 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4988 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4987 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4986 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4984 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4983 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4982 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4981 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4981 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4980 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4979 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4978 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4978 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +[/DeviceRGB] SCS +Color4 SC +n 0.1500 0.1925 0.0024 0.0024 0 360 EARC s +n 0.1567 0.2028 0.0024 0.0024 0 360 EARC s +n 0.1633 0.2124 0.0024 0.0024 0 360 EARC s +n 0.1700 0.2213 0.0024 0.0024 0 360 EARC s +n 0.1767 0.2297 0.0024 0.0024 0 360 EARC s +n 0.1833 0.2378 0.0024 0.0024 0 360 EARC s +n 0.1900 0.2457 0.0024 0.0024 0 360 EARC s +n 0.1967 0.2507 0.0024 0.0024 0 360 EARC s +n 0.2033 0.2545 0.0024 0.0024 0 360 EARC s +n 0.2100 0.2583 0.0024 0.0024 0 360 EARC s +n 0.2167 0.2622 0.0024 0.0024 0 360 EARC s +n 0.2233 0.2659 0.0024 0.0024 0 360 EARC s +n 0.2300 0.2678 0.0024 0.0024 0 360 EARC s +n 0.2367 0.2703 0.0024 0.0024 0 360 EARC s +n 0.2433 0.2734 0.0024 0.0024 0 360 EARC s +n 0.2500 0.2769 0.0024 0.0024 0 360 EARC s +n 0.2567 0.2810 0.0024 0.0024 0 360 EARC s +n 0.2633 0.2855 0.0024 0.0024 0 360 EARC s +n 0.2700 0.2905 0.0024 0.0024 0 360 EARC s +n 0.2767 0.2958 0.0024 0.0024 0 360 EARC s +n 0.2833 0.3004 0.0024 0.0024 0 360 EARC s +n 0.2900 0.3052 0.0024 0.0024 0 360 EARC s +n 0.2967 0.3103 0.0024 0.0024 0 360 EARC s +n 0.3033 0.3156 0.0024 0.0024 0 360 EARC s +n 0.3100 0.3211 0.0024 0.0024 0 360 EARC s +n 0.3167 0.3266 0.0024 0.0024 0 360 EARC s +n 0.3233 0.3323 0.0024 0.0024 0 360 EARC s +n 0.3300 0.3380 0.0024 0.0024 0 360 EARC s +n 0.3367 0.3436 0.0024 0.0024 0 360 EARC s +n 0.3433 0.3492 0.0024 0.0024 0 360 EARC s +n 0.3500 0.3548 0.0024 0.0024 0 360 EARC s +n 0.3567 0.3603 0.0024 0.0024 0 360 EARC s +n 0.3633 0.3658 0.0024 0.0024 0 360 EARC s +n 0.3700 0.3711 0.0024 0.0024 0 360 EARC s +n 0.3767 0.3764 0.0024 0.0024 0 360 EARC s +n 0.3833 0.3815 0.0024 0.0024 0 360 EARC s +n 0.3900 0.3866 0.0024 0.0024 0 360 EARC s +n 0.3967 0.3915 0.0024 0.0024 0 360 EARC s +n 0.4033 0.3963 0.0024 0.0024 0 360 EARC s +n 0.4100 0.4010 0.0024 0.0024 0 360 EARC s +n 0.4167 0.4055 0.0024 0.0024 0 360 EARC s +n 0.4233 0.4100 0.0024 0.0024 0 360 EARC s +n 0.4300 0.4143 0.0024 0.0024 0 360 EARC s +n 0.4367 0.4185 0.0024 0.0024 0 360 EARC s +n 0.4433 0.4225 0.0024 0.0024 0 360 EARC s +n 0.4500 0.4264 0.0024 0.0024 0 360 EARC s +n 0.4567 0.4301 0.0024 0.0024 0 360 EARC s +n 0.4633 0.4337 0.0024 0.0024 0 360 EARC s +n 0.4700 0.4370 0.0024 0.0024 0 360 EARC s +n 0.4767 0.4403 0.0024 0.0024 0 360 EARC s +n 0.4833 0.4434 0.0024 0.0024 0 360 EARC s +n 0.4900 0.4463 0.0024 0.0024 0 360 EARC s +n 0.4967 0.4492 0.0024 0.0024 0 360 EARC s +n 0.5033 0.4520 0.0024 0.0024 0 360 EARC s +n 0.5100 0.4547 0.0024 0.0024 0 360 EARC s +n 0.5167 0.4573 0.0024 0.0024 0 360 EARC s +n 0.5233 0.4598 0.0024 0.0024 0 360 EARC s +n 0.5300 0.4623 0.0024 0.0024 0 360 EARC s +n 0.5367 0.4646 0.0024 0.0024 0 360 EARC s +n 0.5433 0.4668 0.0024 0.0024 0 360 EARC s +n 0.5500 0.4689 0.0024 0.0024 0 360 EARC s +n 0.5567 0.4709 0.0024 0.0024 0 360 EARC s +n 0.5633 0.4727 0.0024 0.0024 0 360 EARC s +n 0.5700 0.4744 0.0024 0.0024 0 360 EARC s +n 0.5767 0.4760 0.0024 0.0024 0 360 EARC s +n 0.5833 0.4776 0.0024 0.0024 0 360 EARC s +n 0.5900 0.4789 0.0024 0.0024 0 360 EARC s +n 0.5967 0.4802 0.0024 0.0024 0 360 EARC s +n 0.6033 0.4814 0.0024 0.0024 0 360 EARC s +n 0.6100 0.4825 0.0024 0.0024 0 360 EARC s +n 0.6167 0.4835 0.0024 0.0024 0 360 EARC s +n 0.6233 0.4844 0.0024 0.0024 0 360 EARC s +n 0.6300 0.4852 0.0024 0.0024 0 360 EARC s +n 0.6367 0.4860 0.0024 0.0024 0 360 EARC s +n 0.6433 0.4868 0.0024 0.0024 0 360 EARC s +n 0.6500 0.4874 0.0024 0.0024 0 360 EARC s +n 0.6567 0.4881 0.0024 0.0024 0 360 EARC s +n 0.6633 0.4887 0.0024 0.0024 0 360 EARC s +n 0.6700 0.4892 0.0024 0.0024 0 360 EARC s +n 0.6767 0.4897 0.0024 0.0024 0 360 EARC s +n 0.6833 0.4902 0.0024 0.0024 0 360 EARC s +n 0.6900 0.4907 0.0024 0.0024 0 360 EARC s +n 0.6967 0.4911 0.0024 0.0024 0 360 EARC s +n 0.7033 0.4915 0.0024 0.0024 0 360 EARC s +n 0.7100 0.4919 0.0024 0.0024 0 360 EARC s +n 0.7167 0.4922 0.0024 0.0024 0 360 EARC s +n 0.7233 0.4926 0.0024 0.0024 0 360 EARC s +n 0.7300 0.4929 0.0024 0.0024 0 360 EARC s +n 0.7367 0.4932 0.0024 0.0024 0 360 EARC s +n 0.7433 0.4935 0.0024 0.0024 0 360 EARC s +n 0.7500 0.4938 0.0024 0.0024 0 360 EARC s +n 0.7567 0.4940 0.0024 0.0024 0 360 EARC s +n 0.7633 0.4943 0.0024 0.0024 0 360 EARC s +n 0.7700 0.4945 0.0024 0.0024 0 360 EARC s +n 0.7767 0.4947 0.0024 0.0024 0 360 EARC s +n 0.7833 0.4949 0.0024 0.0024 0 360 EARC s +n 0.7900 0.4951 0.0024 0.0024 0 360 EARC s +n 0.7967 0.4953 0.0024 0.0024 0 360 EARC s +n 0.8033 0.4955 0.0024 0.0024 0 360 EARC s +n 0.8100 0.4957 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4958 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4960 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4961 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4962 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4963 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4964 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4965 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4966 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4967 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4968 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4969 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4969 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4970 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4970 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +n 0.1500 0.8138 0.0024 0.0024 0 360 EARC s +n 0.1567 0.8063 0.0024 0.0024 0 360 EARC s +n 0.1633 0.7982 0.0024 0.0024 0 360 EARC s +n 0.1700 0.7889 0.0024 0.0024 0 360 EARC s +n 0.1767 0.7785 0.0024 0.0024 0 360 EARC s +n 0.1833 0.7677 0.0024 0.0024 0 360 EARC s +n 0.1900 0.7564 0.0024 0.0024 0 360 EARC s +n 0.1967 0.7488 0.0024 0.0024 0 360 EARC s +n 0.2033 0.7451 0.0024 0.0024 0 360 EARC s +n 0.2100 0.7417 0.0024 0.0024 0 360 EARC s +n 0.2167 0.7379 0.0024 0.0024 0 360 EARC s +n 0.2233 0.7338 0.0024 0.0024 0 360 EARC s +n 0.2300 0.7309 0.0024 0.0024 0 360 EARC s +n 0.2367 0.7281 0.0024 0.0024 0 360 EARC s +n 0.2433 0.7250 0.0024 0.0024 0 360 EARC s +n 0.2500 0.7216 0.0024 0.0024 0 360 EARC s +n 0.2567 0.7179 0.0024 0.0024 0 360 EARC s +n 0.2633 0.7138 0.0024 0.0024 0 360 EARC s +n 0.2700 0.7095 0.0024 0.0024 0 360 EARC s +n 0.2767 0.7049 0.0024 0.0024 0 360 EARC s +n 0.2833 0.6999 0.0024 0.0024 0 360 EARC s +n 0.2900 0.6947 0.0024 0.0024 0 360 EARC s +n 0.2967 0.6892 0.0024 0.0024 0 360 EARC s +n 0.3033 0.6833 0.0024 0.0024 0 360 EARC s +n 0.3100 0.6772 0.0024 0.0024 0 360 EARC s +n 0.3167 0.6709 0.0024 0.0024 0 360 EARC s +n 0.3233 0.6645 0.0024 0.0024 0 360 EARC s +n 0.3300 0.6581 0.0024 0.0024 0 360 EARC s +n 0.3367 0.6517 0.0024 0.0024 0 360 EARC s +n 0.3433 0.6454 0.0024 0.0024 0 360 EARC s +n 0.3500 0.6391 0.0024 0.0024 0 360 EARC s +n 0.3567 0.6328 0.0024 0.0024 0 360 EARC s +n 0.3633 0.6267 0.0024 0.0024 0 360 EARC s +n 0.3700 0.6208 0.0024 0.0024 0 360 EARC s +n 0.3767 0.6149 0.0024 0.0024 0 360 EARC s +n 0.3833 0.6093 0.0024 0.0024 0 360 EARC s +n 0.3900 0.6037 0.0024 0.0024 0 360 EARC s +n 0.3967 0.5984 0.0024 0.0024 0 360 EARC s +n 0.4033 0.5932 0.0024 0.0024 0 360 EARC s +n 0.4100 0.5882 0.0024 0.0024 0 360 EARC s +n 0.4167 0.5833 0.0024 0.0024 0 360 EARC s +n 0.4233 0.5787 0.0024 0.0024 0 360 EARC s +n 0.4300 0.5742 0.0024 0.0024 0 360 EARC s +n 0.4367 0.5699 0.0024 0.0024 0 360 EARC s +n 0.4433 0.5657 0.0024 0.0024 0 360 EARC s +n 0.4500 0.5618 0.0024 0.0024 0 360 EARC s +n 0.4567 0.5581 0.0024 0.0024 0 360 EARC s +n 0.4633 0.5546 0.0024 0.0024 0 360 EARC s +n 0.4700 0.5513 0.0024 0.0024 0 360 EARC s +n 0.4767 0.5481 0.0024 0.0024 0 360 EARC s +n 0.4833 0.5452 0.0024 0.0024 0 360 EARC s +n 0.4900 0.5423 0.0024 0.0024 0 360 EARC s +n 0.4967 0.5396 0.0024 0.0024 0 360 EARC s +n 0.5033 0.5370 0.0024 0.0024 0 360 EARC s +n 0.5100 0.5345 0.0024 0.0024 0 360 EARC s +n 0.5167 0.5321 0.0024 0.0024 0 360 EARC s +n 0.5233 0.5298 0.0024 0.0024 0 360 EARC s +n 0.5300 0.5277 0.0024 0.0024 0 360 EARC s +n 0.5367 0.5256 0.0024 0.0024 0 360 EARC s +n 0.5433 0.5237 0.0024 0.0024 0 360 EARC s +n 0.5500 0.5219 0.0024 0.0024 0 360 EARC s +n 0.5567 0.5202 0.0024 0.0024 0 360 EARC s +n 0.5633 0.5186 0.0024 0.0024 0 360 EARC s +n 0.5700 0.5171 0.0024 0.0024 0 360 EARC s +n 0.5767 0.5158 0.0024 0.0024 0 360 EARC s +n 0.5833 0.5146 0.0024 0.0024 0 360 EARC s +n 0.5900 0.5134 0.0024 0.0024 0 360 EARC s +n 0.5967 0.5124 0.0024 0.0024 0 360 EARC s +n 0.6033 0.5114 0.0024 0.0024 0 360 EARC s +n 0.6100 0.5106 0.0024 0.0024 0 360 EARC s +n 0.6167 0.5098 0.0024 0.0024 0 360 EARC s +n 0.6233 0.5090 0.0024 0.0024 0 360 EARC s +n 0.6300 0.5084 0.0024 0.0024 0 360 EARC s +n 0.6367 0.5077 0.0024 0.0024 0 360 EARC s +n 0.6433 0.5072 0.0024 0.0024 0 360 EARC s +n 0.6500 0.5066 0.0024 0.0024 0 360 EARC s +n 0.6567 0.5061 0.0024 0.0024 0 360 EARC s +n 0.6633 0.5056 0.0024 0.0024 0 360 EARC s +n 0.6700 0.5052 0.0024 0.0024 0 360 EARC s +n 0.6767 0.5047 0.0024 0.0024 0 360 EARC s +n 0.6833 0.5043 0.0024 0.0024 0 360 EARC s +n 0.6900 0.5039 0.0024 0.0024 0 360 EARC s +n 0.6967 0.5035 0.0024 0.0024 0 360 EARC s +n 0.7033 0.5032 0.0024 0.0024 0 360 EARC s +n 0.7100 0.5028 0.0024 0.0024 0 360 EARC s +n 0.7167 0.5025 0.0024 0.0024 0 360 EARC s +n 0.7233 0.5022 0.0024 0.0024 0 360 EARC s +n 0.7300 0.5019 0.0024 0.0024 0 360 EARC s +n 0.7367 0.5016 0.0024 0.0024 0 360 EARC s +n 0.7433 0.5013 0.0024 0.0024 0 360 EARC s +n 0.7500 0.5010 0.0024 0.0024 0 360 EARC s +n 0.7567 0.5008 0.0024 0.0024 0 360 EARC s +n 0.7633 0.5005 0.0024 0.0024 0 360 EARC s +n 0.7700 0.5003 0.0024 0.0024 0 360 EARC s +n 0.7767 0.5001 0.0024 0.0024 0 360 EARC s +n 0.7833 0.4999 0.0024 0.0024 0 360 EARC s +n 0.7900 0.4997 0.0024 0.0024 0 360 EARC s +n 0.7967 0.4995 0.0024 0.0024 0 360 EARC s +n 0.8033 0.4993 0.0024 0.0024 0 360 EARC s +n 0.8100 0.4992 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4990 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4989 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4987 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4986 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4985 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4984 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4983 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4982 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4981 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4980 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4980 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4979 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4978 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4978 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4975 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +[/DeviceRGB] SCS +Color3 SC +n 0.1500 0.1925 0.0024 0.0024 0 360 EARC s +n 0.1567 0.2048 0.0024 0.0024 0 360 EARC s +n 0.1633 0.2034 0.0024 0.0024 0 360 EARC s +n 0.1700 0.2006 0.0024 0.0024 0 360 EARC s +n 0.1767 0.1988 0.0024 0.0024 0 360 EARC s +n 0.1833 0.1977 0.0024 0.0024 0 360 EARC s +n 0.1900 0.1974 0.0024 0.0024 0 360 EARC s +n 0.1967 0.1976 0.0024 0.0024 0 360 EARC s +n 0.2033 0.1987 0.0024 0.0024 0 360 EARC s +n 0.2100 0.2001 0.0024 0.0024 0 360 EARC s +n 0.2167 0.2023 0.0024 0.0024 0 360 EARC s +n 0.2233 0.2050 0.0024 0.0024 0 360 EARC s +n 0.2300 0.2086 0.0024 0.0024 0 360 EARC s +n 0.2367 0.2127 0.0024 0.0024 0 360 EARC s +n 0.2433 0.2176 0.0024 0.0024 0 360 EARC s +n 0.2500 0.2226 0.0024 0.0024 0 360 EARC s +n 0.2567 0.2272 0.0024 0.0024 0 360 EARC s +n 0.2633 0.2320 0.0024 0.0024 0 360 EARC s +n 0.2700 0.2372 0.0024 0.0024 0 360 EARC s +n 0.2767 0.2427 0.0024 0.0024 0 360 EARC s +n 0.2833 0.2484 0.0024 0.0024 0 360 EARC s +n 0.2900 0.2543 0.0024 0.0024 0 360 EARC s +n 0.2967 0.2604 0.0024 0.0024 0 360 EARC s +n 0.3033 0.2670 0.0024 0.0024 0 360 EARC s +n 0.3100 0.2740 0.0024 0.0024 0 360 EARC s +n 0.3167 0.2812 0.0024 0.0024 0 360 EARC s +n 0.3233 0.2888 0.0024 0.0024 0 360 EARC s +n 0.3300 0.2967 0.0024 0.0024 0 360 EARC s +n 0.3367 0.3047 0.0024 0.0024 0 360 EARC s +n 0.3433 0.3128 0.0024 0.0024 0 360 EARC s +n 0.3500 0.3210 0.0024 0.0024 0 360 EARC s +n 0.3567 0.3291 0.0024 0.0024 0 360 EARC s +n 0.3633 0.3373 0.0024 0.0024 0 360 EARC s +n 0.3700 0.3452 0.0024 0.0024 0 360 EARC s +n 0.3767 0.3530 0.0024 0.0024 0 360 EARC s +n 0.3833 0.3607 0.0024 0.0024 0 360 EARC s +n 0.3900 0.3682 0.0024 0.0024 0 360 EARC s +n 0.3967 0.3754 0.0024 0.0024 0 360 EARC s +n 0.4033 0.3823 0.0024 0.0024 0 360 EARC s +n 0.4100 0.3888 0.0024 0.0024 0 360 EARC s +n 0.4167 0.3948 0.0024 0.0024 0 360 EARC s +n 0.4233 0.4007 0.0024 0.0024 0 360 EARC s +n 0.4300 0.4061 0.0024 0.0024 0 360 EARC s +n 0.4367 0.4111 0.0024 0.0024 0 360 EARC s +n 0.4433 0.4159 0.0024 0.0024 0 360 EARC s +n 0.4500 0.4204 0.0024 0.0024 0 360 EARC s +n 0.4567 0.4246 0.0024 0.0024 0 360 EARC s +n 0.4633 0.4285 0.0024 0.0024 0 360 EARC s +n 0.4700 0.4323 0.0024 0.0024 0 360 EARC s +n 0.4767 0.4359 0.0024 0.0024 0 360 EARC s +n 0.4833 0.4392 0.0024 0.0024 0 360 EARC s +n 0.4900 0.4425 0.0024 0.0024 0 360 EARC s +n 0.4967 0.4456 0.0024 0.0024 0 360 EARC s +n 0.5033 0.4485 0.0024 0.0024 0 360 EARC s +n 0.5100 0.4514 0.0024 0.0024 0 360 EARC s +n 0.5167 0.4541 0.0024 0.0024 0 360 EARC s +n 0.5233 0.4567 0.0024 0.0024 0 360 EARC s +n 0.5300 0.4592 0.0024 0.0024 0 360 EARC s +n 0.5367 0.4616 0.0024 0.0024 0 360 EARC s +n 0.5433 0.4639 0.0024 0.0024 0 360 EARC s +n 0.5500 0.4660 0.0024 0.0024 0 360 EARC s +n 0.5567 0.4680 0.0024 0.0024 0 360 EARC s +n 0.5633 0.4699 0.0024 0.0024 0 360 EARC s +n 0.5700 0.4716 0.0024 0.0024 0 360 EARC s +n 0.5767 0.4732 0.0024 0.0024 0 360 EARC s +n 0.5833 0.4747 0.0024 0.0024 0 360 EARC s +n 0.5900 0.4761 0.0024 0.0024 0 360 EARC s +n 0.5967 0.4774 0.0024 0.0024 0 360 EARC s +n 0.6033 0.4785 0.0024 0.0024 0 360 EARC s +n 0.6100 0.4795 0.0024 0.0024 0 360 EARC s +n 0.6167 0.4805 0.0024 0.0024 0 360 EARC s +n 0.6233 0.4814 0.0024 0.0024 0 360 EARC s +n 0.6300 0.4822 0.0024 0.0024 0 360 EARC s +n 0.6367 0.4829 0.0024 0.0024 0 360 EARC s +n 0.6433 0.4836 0.0024 0.0024 0 360 EARC s +n 0.6500 0.4842 0.0024 0.0024 0 360 EARC s +n 0.6567 0.4847 0.0024 0.0024 0 360 EARC s +n 0.6633 0.4852 0.0024 0.0024 0 360 EARC s +n 0.6700 0.4857 0.0024 0.0024 0 360 EARC s +n 0.6767 0.4862 0.0024 0.0024 0 360 EARC s +n 0.6833 0.4867 0.0024 0.0024 0 360 EARC s +n 0.6900 0.4872 0.0024 0.0024 0 360 EARC s +n 0.6967 0.4877 0.0024 0.0024 0 360 EARC s +n 0.7033 0.4882 0.0024 0.0024 0 360 EARC s +n 0.7100 0.4887 0.0024 0.0024 0 360 EARC s +n 0.7167 0.4891 0.0024 0.0024 0 360 EARC s +n 0.7233 0.4896 0.0024 0.0024 0 360 EARC s +n 0.7300 0.4901 0.0024 0.0024 0 360 EARC s +n 0.7367 0.4906 0.0024 0.0024 0 360 EARC s +n 0.7433 0.4910 0.0024 0.0024 0 360 EARC s +n 0.7500 0.4914 0.0024 0.0024 0 360 EARC s +n 0.7567 0.4919 0.0024 0.0024 0 360 EARC s +n 0.7633 0.4923 0.0024 0.0024 0 360 EARC s +n 0.7700 0.4926 0.0024 0.0024 0 360 EARC s +n 0.7767 0.4930 0.0024 0.0024 0 360 EARC s +n 0.7833 0.4934 0.0024 0.0024 0 360 EARC s +n 0.7900 0.4937 0.0024 0.0024 0 360 EARC s +n 0.7967 0.4940 0.0024 0.0024 0 360 EARC s +n 0.8033 0.4943 0.0024 0.0024 0 360 EARC s +n 0.8100 0.4946 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4948 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4951 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4953 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4955 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4957 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4959 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4961 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4962 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4963 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4965 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4966 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4967 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4968 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4969 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4969 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4970 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4971 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4972 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4973 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4974 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +n 0.1500 0.8138 0.0024 0.0024 0 360 EARC s +n 0.1567 0.8059 0.0024 0.0024 0 360 EARC s +n 0.1633 0.7996 0.0024 0.0024 0 360 EARC s +n 0.1700 0.8039 0.0024 0.0024 0 360 EARC s +n 0.1767 0.8067 0.0024 0.0024 0 360 EARC s +n 0.1833 0.8075 0.0024 0.0024 0 360 EARC s +n 0.1900 0.8069 0.0024 0.0024 0 360 EARC s +n 0.1967 0.8050 0.0024 0.0024 0 360 EARC s +n 0.2033 0.8039 0.0024 0.0024 0 360 EARC s +n 0.2100 0.8032 0.0024 0.0024 0 360 EARC s +n 0.2167 0.8013 0.0024 0.0024 0 360 EARC s +n 0.2233 0.7982 0.0024 0.0024 0 360 EARC s +n 0.2300 0.7941 0.0024 0.0024 0 360 EARC s +n 0.2367 0.7892 0.0024 0.0024 0 360 EARC s +n 0.2433 0.7836 0.0024 0.0024 0 360 EARC s +n 0.2500 0.7772 0.0024 0.0024 0 360 EARC s +n 0.2567 0.7701 0.0024 0.0024 0 360 EARC s +n 0.2633 0.7646 0.0024 0.0024 0 360 EARC s +n 0.2700 0.7593 0.0024 0.0024 0 360 EARC s +n 0.2767 0.7538 0.0024 0.0024 0 360 EARC s +n 0.2833 0.7480 0.0024 0.0024 0 360 EARC s +n 0.2900 0.7418 0.0024 0.0024 0 360 EARC s +n 0.2967 0.7353 0.0024 0.0024 0 360 EARC s +n 0.3033 0.7284 0.0024 0.0024 0 360 EARC s +n 0.3100 0.7212 0.0024 0.0024 0 360 EARC s +n 0.3167 0.7138 0.0024 0.0024 0 360 EARC s +n 0.3233 0.7063 0.0024 0.0024 0 360 EARC s +n 0.3300 0.6988 0.0024 0.0024 0 360 EARC s +n 0.3367 0.6918 0.0024 0.0024 0 360 EARC s +n 0.3433 0.6861 0.0024 0.0024 0 360 EARC s +n 0.3500 0.6804 0.0024 0.0024 0 360 EARC s +n 0.3567 0.6745 0.0024 0.0024 0 360 EARC s +n 0.3633 0.6686 0.0024 0.0024 0 360 EARC s +n 0.3700 0.6626 0.0024 0.0024 0 360 EARC s +n 0.3767 0.6566 0.0024 0.0024 0 360 EARC s +n 0.3833 0.6505 0.0024 0.0024 0 360 EARC s +n 0.3900 0.6445 0.0024 0.0024 0 360 EARC s +n 0.3967 0.6385 0.0024 0.0024 0 360 EARC s +n 0.4033 0.6326 0.0024 0.0024 0 360 EARC s +n 0.4100 0.6266 0.0024 0.0024 0 360 EARC s +n 0.4167 0.6208 0.0024 0.0024 0 360 EARC s +n 0.4233 0.6150 0.0024 0.0024 0 360 EARC s +n 0.4300 0.6094 0.0024 0.0024 0 360 EARC s +n 0.4367 0.6039 0.0024 0.0024 0 360 EARC s +n 0.4433 0.5986 0.0024 0.0024 0 360 EARC s +n 0.4500 0.5934 0.0024 0.0024 0 360 EARC s +n 0.4567 0.5886 0.0024 0.0024 0 360 EARC s +n 0.4633 0.5839 0.0024 0.0024 0 360 EARC s +n 0.4700 0.5796 0.0024 0.0024 0 360 EARC s +n 0.4767 0.5755 0.0024 0.0024 0 360 EARC s +n 0.4833 0.5716 0.0024 0.0024 0 360 EARC s +n 0.4900 0.5679 0.0024 0.0024 0 360 EARC s +n 0.4967 0.5643 0.0024 0.0024 0 360 EARC s +n 0.5033 0.5610 0.0024 0.0024 0 360 EARC s +n 0.5100 0.5578 0.0024 0.0024 0 360 EARC s +n 0.5167 0.5547 0.0024 0.0024 0 360 EARC s +n 0.5233 0.5517 0.0024 0.0024 0 360 EARC s +n 0.5300 0.5488 0.0024 0.0024 0 360 EARC s +n 0.5367 0.5461 0.0024 0.0024 0 360 EARC s +n 0.5433 0.5434 0.0024 0.0024 0 360 EARC s +n 0.5500 0.5409 0.0024 0.0024 0 360 EARC s +n 0.5567 0.5386 0.0024 0.0024 0 360 EARC s +n 0.5633 0.5363 0.0024 0.0024 0 360 EARC s +n 0.5700 0.5342 0.0024 0.0024 0 360 EARC s +n 0.5767 0.5322 0.0024 0.0024 0 360 EARC s +n 0.5833 0.5303 0.0024 0.0024 0 360 EARC s +n 0.5900 0.5285 0.0024 0.0024 0 360 EARC s +n 0.5967 0.5267 0.0024 0.0024 0 360 EARC s +n 0.6033 0.5251 0.0024 0.0024 0 360 EARC s +n 0.6100 0.5235 0.0024 0.0024 0 360 EARC s +n 0.6167 0.5220 0.0024 0.0024 0 360 EARC s +n 0.6233 0.5206 0.0024 0.0024 0 360 EARC s +n 0.6300 0.5193 0.0024 0.0024 0 360 EARC s +n 0.6367 0.5180 0.0024 0.0024 0 360 EARC s +n 0.6433 0.5168 0.0024 0.0024 0 360 EARC s +n 0.6500 0.5156 0.0024 0.0024 0 360 EARC s +n 0.6567 0.5145 0.0024 0.0024 0 360 EARC s +n 0.6633 0.5134 0.0024 0.0024 0 360 EARC s +n 0.6700 0.5124 0.0024 0.0024 0 360 EARC s +n 0.6767 0.5115 0.0024 0.0024 0 360 EARC s +n 0.6833 0.5105 0.0024 0.0024 0 360 EARC s +n 0.6900 0.5097 0.0024 0.0024 0 360 EARC s +n 0.6967 0.5089 0.0024 0.0024 0 360 EARC s +n 0.7033 0.5081 0.0024 0.0024 0 360 EARC s +n 0.7100 0.5073 0.0024 0.0024 0 360 EARC s +n 0.7167 0.5066 0.0024 0.0024 0 360 EARC s +n 0.7233 0.5060 0.0024 0.0024 0 360 EARC s +n 0.7300 0.5053 0.0024 0.0024 0 360 EARC s +n 0.7367 0.5047 0.0024 0.0024 0 360 EARC s +n 0.7433 0.5042 0.0024 0.0024 0 360 EARC s +n 0.7500 0.5036 0.0024 0.0024 0 360 EARC s +n 0.7567 0.5031 0.0024 0.0024 0 360 EARC s +n 0.7633 0.5027 0.0024 0.0024 0 360 EARC s +n 0.7700 0.5022 0.0024 0.0024 0 360 EARC s +n 0.7767 0.5018 0.0024 0.0024 0 360 EARC s +n 0.7833 0.5015 0.0024 0.0024 0 360 EARC s +n 0.7900 0.5011 0.0024 0.0024 0 360 EARC s +n 0.7967 0.5008 0.0024 0.0024 0 360 EARC s +n 0.8033 0.5005 0.0024 0.0024 0 360 EARC s +n 0.8100 0.5002 0.0024 0.0024 0 360 EARC s +n 0.8167 0.4999 0.0024 0.0024 0 360 EARC s +n 0.8233 0.4997 0.0024 0.0024 0 360 EARC s +n 0.8300 0.4995 0.0024 0.0024 0 360 EARC s +n 0.8367 0.4992 0.0024 0.0024 0 360 EARC s +n 0.8433 0.4991 0.0024 0.0024 0 360 EARC s +n 0.8500 0.4989 0.0024 0.0024 0 360 EARC s +n 0.8567 0.4987 0.0024 0.0024 0 360 EARC s +n 0.8633 0.4986 0.0024 0.0024 0 360 EARC s +n 0.8700 0.4984 0.0024 0.0024 0 360 EARC s +n 0.8767 0.4983 0.0024 0.0024 0 360 EARC s +n 0.8833 0.4982 0.0024 0.0024 0 360 EARC s +n 0.8900 0.4981 0.0024 0.0024 0 360 EARC s +n 0.8967 0.4980 0.0024 0.0024 0 360 EARC s +n 0.9033 0.4979 0.0024 0.0024 0 360 EARC s +n 0.9100 0.4979 0.0024 0.0024 0 360 EARC s +n 0.9167 0.4978 0.0024 0.0024 0 360 EARC s +n 0.9233 0.4978 0.0024 0.0024 0 360 EARC s +n 0.9300 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9367 0.4977 0.0024 0.0024 0 360 EARC s +n 0.9433 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9500 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9567 0.4976 0.0024 0.0024 0 360 EARC s +n 0.9633 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9700 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9767 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9833 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9900 0.4975 0.0024 0.0024 0 360 EARC s +n 0.9967 0.4975 0.0024 0.0024 0 360 EARC s +n 1.0033 0.4975 0.0024 0.0024 0 360 EARC s +n 1.0100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0500 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0567 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0633 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0700 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0767 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0833 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0900 0.4974 0.0024 0.0024 0 360 EARC s +n 1.0967 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1033 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1100 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1167 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1233 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1300 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1367 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1433 0.4974 0.0024 0.0024 0 360 EARC s +n 1.1500 0.4974 0.0024 0.0024 0 360 EARC s +[/DeviceRGB] SCS +Color1 SC +n +0.1500 0.1500 m +1.1500 0.1500 l +s +n +0.1500 0.8500 m +1.1500 0.8500 l +s +n +0.3167 0.1500 m +0.3167 0.1600 l +s +n +0.3167 0.8500 m +0.3167 0.8400 l +s +n +0.6500 0.1500 m +0.6500 0.1600 l +s +n +0.6500 0.8500 m +0.6500 0.8400 l +s +n +0.9833 0.1500 m +0.9833 0.1600 l +s +n +0.9833 0.8500 m +0.9833 0.8400 l +s +n +0.1500 0.1500 m +0.1500 0.1700 l +s +n +0.1500 0.8500 m +0.1500 0.8300 l +s +n +0.4833 0.1500 m +0.4833 0.1700 l +s +n +0.4833 0.8500 m +0.4833 0.8300 l +s +n +0.8167 0.1500 m +0.8167 0.1700 l +s +n +0.8167 0.8500 m +0.8167 0.8300 l +s +n +1.1500 0.1500 m +1.1500 0.1700 l +s +n +1.1500 0.8500 m +1.1500 0.8300 l +s +/Times-Roman findfont +dup length dict begin + {1 index /FID ne {def} {pop pop} ifelse} forall + /Encoding DefEncoding def + currentdict +end +/Font0 exch definefont pop +/Font0 FFSF +0.1433 0.1210 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(0) show +GR +/Font0 FFSF +0.4628 0.1206 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(500) show +GR +/Font0 FFSF +0.7890 0.1210 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(1000) show +GR +/Font0 FFSF +1.1224 0.1206 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(1500) show +GR +/Font0 FFSF +0.5978 0.0909 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(Iterations) show +GR +n +0.1500 0.1500 m +0.1500 0.8500 l +s +n +1.1500 0.1500 m +1.1500 0.8500 l +s +n +0.1500 0.1500 m +0.1600 0.1500 l +s +n +1.1500 0.1500 m +1.1400 0.1500 l +s +n +0.1500 0.3833 m +0.1600 0.3833 l +s +n +1.1500 0.3833 m +1.1400 0.3833 l +s +n +0.1500 0.6167 m +0.1600 0.6167 l +s +n +1.1500 0.6167 m +1.1400 0.6167 l +s +n +0.1500 0.8500 m +0.1600 0.8500 l +s +n +1.1500 0.8500 m +1.1400 0.8500 l +s +n +0.1500 0.2667 m +0.1700 0.2667 l +s +n +1.1500 0.2667 m +1.1300 0.2667 l +s +n +0.1500 0.5000 m +0.1700 0.5000 l +s +n +1.1500 0.5000 m +1.1300 0.5000 l +s +n +0.1500 0.7333 m +0.1700 0.7333 l +s +n +1.1500 0.7333 m +1.1300 0.7333 l +s +/Font0 FFSF +0.1267 0.2574 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(0) show +GR +/Font0 FFSF +0.1069 0.4923 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(0,5) show +GR +/Font0 FFSF +0.1291 0.7239 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(1) show +GR +/Font0 FFSF +0.0909 0.3626 m +GS +[0.0000 0.0280 -0.0280 0.0000 0 0] CC +(Scalaire \(min, avg, max\)) show +GR +n +0.1500 0.1500 m +0.1500 0.8500 l +1.1500 0.8500 l +1.1500 0.1500 l +0.1500 0.1500 l +c +s +n +0.8500 0.8000 m +0.8500 0.6604 l +1.1494 0.6604 l +1.1494 0.8000 l +c +[/DeviceRGB] SCS +Color0 SC +fill +[/DeviceRGB] SCS +Color1 SC +n +0.8500 0.8000 m +0.8500 0.6604 l +1.1494 0.6604 l +1.1494 0.8000 l +0.8500 0.8000 l +c +s +/Font0 FFSF +0.9208 0.7706 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(isotrope \(reference\)) show +GR +[/DeviceRGB] SCS +Color2 SC +n +0.8608 0.7773 m +0.9008 0.7773 l +s +/Font0 FFSF +[/DeviceRGB] SCS +Color1 SC +0.9208 0.7352 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(isotrope) show +GR +[/DeviceRGB] SCS +Color2 SC +n 0.8808 0.7419 0.0024 0.0024 0 360 EARC s +/Font0 FFSF +[/DeviceRGB] SCS +Color1 SC +0.9208 0.7063 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(none) show +GR +[/DeviceRGB] SCS +Color4 SC +n 0.8808 0.7125 0.0024 0.0024 0 360 EARC s +/Font0 FFSF +[/DeviceRGB] SCS +Color1 SC +0.9208 0.6765 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(anisotrope) show +GR +[/DeviceRGB] SCS +Color3 SC +n 0.8808 0.6832 0.0024 0.0024 0 360 EARC s +/Font0 FFSF +[/DeviceRGB] SCS +Color1 SC +0.2115 0.9193 m +GS +[0.0420 0.0000 0.0000 0.0420 0 0] CC +(Evolution du scalaire pour 3 methodes de dealiasing) show +GR +/Font0 FFSF +0.4947 0.8740 m +GS +[0.0280 0.0000 0.0000 0.0280 0 0] CC +(Schmidt=0.1, 128x128x128) show +GR +%%Trailer +%%BoundingBox: 41 52 702 565 +%%DocumentNeededResources: font Times-Roman +%%EOF diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.png b/HySoP/src/Unstable/LEGI/doc/doxygen/images/dealias.png new file mode 100644 index 0000000000000000000000000000000000000000..ccc247514effb77ac0c9d2cd0e7bb543c0c0c81f GIT binary patch literal 16369 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 S@lM8N`}-Q&w@YtXhW|e%qanQj literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.eps b/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.eps new file mode 100644 index 000000000..39b0e196f --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.eps @@ -0,0 +1,209 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: parallel.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Tue Jul 19 12:08:34 2011 +%%For: begou@thor (Patrick Begou) +%%BoundingBox: 0 0 396 407 +%Magnification: 1.0000 +%%EndComments +%%BeginProlog +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 407 moveto 0 0 lineto 396 0 lineto 396 407 lineto closepath clip newpath +-211.8 496.8 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +%%EndProlog +% +% Fig objects follow +% +% +% here starts figure with depth 50 +% Polyline +0 slj +0 slc +30.000 slw +gs clippath +5143 6351 m 4873 6232 l 4819 6355 l 5088 6474 l 5088 6474 l 4910 6322 l 5143 6351 l cp +eoclip +n 6390 6975 m + 4860 6300 l gs col0 s gr gr + +% arrowhead +n 5143 6351 m 4910 6322 l 5088 6474 l 5074 6394 l 5143 6351 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +gs clippath +7868 6425 m 8140 6311 l 8087 6186 l 7816 6301 l 7816 6301 l 8050 6276 l 7868 6425 l cp +eoclip +n 6390 6975 m + 8100 6255 l gs col0 s gr gr + +% arrowhead +n 7868 6425 m 8050 6276 l 7816 6301 l 7884 6345 l 7868 6425 l + cp gs 0.00 setgray ef gr col0 s +% Polyline + [120] 0 sd +gs clippath +4484 4682 m 4346 4878 l 4456 4956 l 4594 4760 l 4594 4760 l 4436 4869 l 4484 4682 l cp +eoclip +n 5895 2790 m + 4410 4905 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 4484 4682 m 4436 4869 l 4594 4760 l 4484 4682 l cp gs col7 1.00 shd ef gr col0 s +% Polyline + [120] 0 sd +gs clippath +7501 4817 m 7652 5004 l 7756 4919 l 7605 4732 l 7605 4732 l 7667 4915 l 7501 4817 l cp +eoclip +n 5940 2790 m + 7695 4950 l gs col0 s gr gr + [] 0 sd +% arrowhead +n 7501 4817 m 7667 4915 l 7605 4732 l 7501 4817 l cp gs col7 1.00 shd ef gr col0 s +% Polyline +7.500 slw +n 3480 4905 m 3375 4905 3375 6195 105 arcto 4 {pop} repeat + 3375 6300 6195 6300 105 arcto 4 {pop} repeat + 6300 6300 6300 5010 105 arcto 4 {pop} repeat + 6300 4905 3480 4905 105 arcto 4 {pop} repeat + cp gs col0 s gr +% Polyline +n 6810 4950 m 6705 4950 6705 6150 105 arcto 4 {pop} repeat + 6705 6255 9525 6255 105 arcto 4 {pop} repeat + 9630 6255 9630 5055 105 arcto 4 {pop} repeat + 9630 4950 6810 4950 105 arcto 4 {pop} repeat + cp gs col0 s gr +% Polyline +n 4920 6975 m 4815 6975 4815 7770 105 arcto 4 {pop} repeat + 4815 7875 7815 7875 105 arcto 4 {pop} repeat + 7920 7875 7920 7080 105 arcto 4 {pop} repeat + 7920 6975 4920 6975 105 arcto 4 {pop} repeat + cp gs col0 s gr +% Polyline +n 4500 1440 m 7695 1440 l 7695 2790 l 4500 2790 l + cp gs col0 s gr +/Times-Roman ff 190.50 scf sf +6075 4545 m +gs 1 -1 sc (automatic code generation) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +5850 6615 m +gs 1 -1 sc 328.0 rot (use) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +7020 6615 m +gs 1 -1 sc 30.0 rot (use) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +4680 5850 m +gs 1 -1 sc (for real type values.) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +8055 5850 m +gs 1 -1 sc (for complex type values.) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +6435 7695 m +gs 1 -1 sc (Generic interface for parallel) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Italic ff 190.50 scf sf +5985 2160 m +gs 1 -1 sc (Module generic implementation) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Italic ff 190.50 scf sf +5940 2475 m +gs 1 -1 sc (with tags.) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-BoldItalic ff 222.25 scf sf +6075 1710 m +gs 1 -1 sc (implementparallel.Fortran) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Bold ff 222.25 scf sf +4815 5175 m +gs 1 -1 sc (module realparallel) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +4725 5580 m +gs 1 -1 sc (Parallel code and functions) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Bold ff 222.25 scf sf +8145 5220 m +gs 1 -1 sc (module cmplxparallel) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Roman ff 190.50 scf sf +8145 5625 m +gs 1 -1 sc (Parallel code and functions) dup sw pop 2 div neg 0 rm col0 sh gr +/Times-Bold ff 222.25 scf sf +6435 7290 m +gs 1 -1 sc (module parallel) dup sw pop 2 div neg 0 rm col0 sh gr +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.fig b/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.fig new file mode 100644 index 000000000..998b3e50b --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.fig @@ -0,0 +1,43 @@ +#FIG 3.2 Produced by xfig version 3.2.5 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 6390 6975 4860 6300 +2 1 0 3 0 7 50 -1 -1 0.000 0 0 -1 1 0 2 + 2 1 3.00 135.00 180.00 + 6390 6975 8100 6255 +2 1 1 3 0 7 50 -1 -1 8.000 0 0 -1 1 0 2 + 1 0 3.00 135.00 180.00 + 5895 2790 4410 4905 +2 1 1 3 0 7 50 -1 -1 8.000 0 0 -1 1 0 2 + 1 0 3.00 135.00 180.00 + 5940 2790 7695 4950 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 6300 6300 6300 4905 3375 4905 3375 6300 6300 6300 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 9630 6255 9630 4950 6705 4950 6705 6255 9630 6255 +2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5 + 7920 7875 7920 6975 4815 6975 4815 7875 7920 7875 +2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 4500 1440 7695 1440 7695 2790 4500 2790 4500 1440 +4 1 0 50 -1 0 12 0.0000 4 180 2160 6075 4545 automatic code generation\001 +4 1 0 50 -1 0 12 5.7247 4 90 270 5850 6615 use\001 +4 1 0 50 -1 0 12 0.5236 4 90 270 7020 6615 use\001 +4 1 0 50 -1 0 12 0.0000 4 180 1590 4680 5850 for real type values.\001 +4 1 0 50 -1 0 12 0.0000 4 180 1995 8055 5850 for complex type values.\001 +4 1 0 50 -1 0 12 0.0000 4 180 2310 6435 7695 Generic interface for parallel\001 +4 1 0 50 -1 1 12 0.0000 4 180 2610 5985 2160 Module generic implementation\001 +4 1 0 50 -1 1 12 0.0000 4 180 795 5940 2475 with tags.\001 +4 1 0 50 -1 3 14 0.0000 4 210 2580 6075 1710 implementparallel.Fortran\001 +4 1 0 50 -1 2 14 0.0000 4 210 1965 4815 5175 module realparallel\001 +4 1 0 50 -1 0 12 0.0000 4 135 2205 4725 5580 Parallel code and functions\001 +4 1 0 50 -1 2 14 0.0000 4 210 2190 8145 5220 module cmplxparallel\001 +4 1 0 50 -1 0 12 0.0000 4 135 2205 8145 5625 Parallel code and functions\001 +4 1 0 50 -1 2 14 0.0000 4 210 1575 6435 7290 module parallel\001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.png b/HySoP/src/Unstable/LEGI/doc/doxygen/images/parallel.png new file mode 100644 index 0000000000000000000000000000000000000000..642d7dd9e129d8928dad1bd901b0246d42674d0c GIT binary patch literal 8436 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 literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.eps b/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.eps new file mode 100644 index 000000000..5d79e4368 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.eps @@ -0,0 +1,246 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: xycommunicator.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Thu Jun 30 17:38:58 2011 +%%For: begou@thor (Patrick Begou) +%%BoundingBox: 0 0 399 148 +%Magnification: 1.0000 +%%EndComments +%%BeginProlog +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 148 moveto 0 0 lineto 399 0 lineto 399 148 lineto closepath clip newpath +-70.0 259.6 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +%%EndProlog +% +% Fig objects follow +% +% +% here starts figure with depth 51 +% Polyline +2 slj +0 slc +7.500 slw +gs clippath +4360 3919 m 4556 3788 l 4490 3688 l 4294 3819 l 4294 3819 l 4499 3755 l 4360 3919 l cp +eoclip +n 3185 3362 m 3183 3364 l 3179 3368 l 3171 3374 l 3161 3385 l 3147 3398 l + 3131 3414 l 3113 3433 l 3095 3453 l 3077 3475 l 3060 3499 l + 3044 3524 l 3029 3550 l 3017 3579 l 3008 3609 l 3002 3643 l + 3001 3679 l 3004 3716 l 3011 3746 l 3020 3775 l 3030 3801 l + 3040 3824 l 3049 3843 l 3058 3859 l 3065 3872 l 3071 3883 l + 3077 3892 l 3082 3900 l 3087 3907 l 3092 3914 l 3099 3922 l + 3107 3929 l 3118 3939 l 3131 3949 l 3148 3961 l 3169 3975 l + 3194 3991 l 3225 4008 l 3259 4025 l 3298 4041 l 3335 4054 l + 3372 4064 l 3407 4073 l 3438 4080 l 3465 4085 l 3489 4089 l + 3508 4092 l 3523 4094 l 3536 4095 l 3547 4096 l 3556 4097 l + 3564 4097 l 3573 4096 l 3583 4096 l 3594 4095 l 3608 4094 l + 3626 4092 l 3648 4089 l 3675 4086 l 3708 4081 l 3746 4076 l + 3789 4068 l 3836 4059 l 3886 4048 l 3933 4036 l 3978 4022 l + 4021 4008 l 4063 3993 l 4102 3978 l 4138 3963 l 4173 3947 l + 4206 3931 l 4238 3915 l 4268 3899 l 4297 3883 l 4325 3867 l + 4351 3851 l 4377 3836 l 4400 3821 l 4422 3807 l 4442 3794 l + 4460 3782 l 4475 3772 l 4487 3764 l 4496 3757 l + 4511 3747 l gs col0 s gr gr + +% arrowhead +0 slj +n 4360 3919 m 4499 3755 l 4294 3819 l 4361 3846 l 4360 3919 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +n 4500 2700 m 5850 2700 l 5850 3600 l 4500 3600 l + cp gs col0 s gr +% Polyline +n 4500 2700 m 5850 1800 l 7200 1800 l 5850 2700 l 5850 3600 l 7200 2700 l + + 7200 1800 l gs col0 s gr +% Polyline +7.500 slw +n 4500 3150 m + 5850 3150 l gs col0 s gr +% Polyline +n 5850 3150 m + 7200 2250 l gs col0 s gr +% Polyline +15.000 slw +n 1350 2700 m 2700 2700 l 2700 3600 l 1350 3600 l + cp gs col0 s gr +% Polyline +n 1350 2700 m 2700 1800 l 4050 1800 l 2700 2700 l 2700 3600 l 4050 2700 l + + 4050 1800 l gs col0 s gr +% Polyline +7.500 slw +n 1800 3600 m 1800 2700 l + 3150 1800 l gs col0 s gr +% Polyline +n 1350 3150 m + 2700 3150 l gs col0 s gr +% Polyline +n 2700 3150 m + 4050 2250 l gs col0 s gr +% Polyline +n 6300 3285 m 6300 2385 l + 4950 2385 l gs col0 s gr +% Polyline +n 6750 3015 m 6750 2115 l + 5355 2115 l gs col0 s gr +% Polyline +n 2250 3600 m 2250 2700 l + 3600 1800 l gs col0 s gr +/Times-Roman ff 190.50 scf sf +6030 2835 m +gs 1 -1 sc (3) col0 sh gr +/Times-Roman ff 190.50 scf sf +1980 3015 m +gs 1 -1 sc (4) col0 sh gr +/Times-Roman ff 190.50 scf sf +2430 3015 m +gs 1 -1 sc (3) col0 sh gr +/Times-Roman ff 190.50 scf sf +1530 3015 m +gs 1 -1 sc (5) col0 sh gr +/Times-Roman ff 190.50 scf sf +2430 3420 m +gs 1 -1 sc (0) col0 sh gr +/Times-Roman ff 190.50 scf sf +1980 3420 m +gs 1 -1 sc (1) col0 sh gr +/Times-Roman ff 190.50 scf sf +1530 3420 m +gs 1 -1 sc (2) col0 sh gr +/Times-Roman ff 190.50 scf sf +6030 3330 m +gs 1 -1 sc (0) col0 sh gr +/Times-Roman ff 190.50 scf sf +6480 3015 m +gs 1 -1 sc (1) col0 sh gr +/Times-Roman ff 190.50 scf sf +6930 2700 m +gs 1 -1 sc (2) col0 sh gr +/Times-Roman ff 190.50 scf sf +6930 2250 m +gs 1 -1 sc (5) col0 sh gr +/Times-Roman ff 190.50 scf sf +6435 2565 m +gs 1 -1 sc (4) col0 sh gr +/Times-Roman ff 190.50 scf sf +1170 3645 m +gs 1 -1 sc (Y) col0 sh gr +/Times-Roman ff 190.50 scf sf +4140 2700 m +gs 1 -1 sc (X) col0 sh gr +/Times-Roman ff 190.50 scf sf +2610 2655 m +gs 1 -1 sc (Z) col0 sh gr +/Times-Roman ff 190.50 scf sf +5760 2610 m +gs 1 -1 sc (Z) col0 sh gr +/Times-Roman ff 190.50 scf sf +4275 3690 m +gs 1 -1 sc (Y) col0 sh gr +/Times-Roman ff 190.50 scf sf +7290 2700 m +gs 1 -1 sc (X) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +1755 3780 m +gs 1 -1 sc (ncpus1) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +4455 3420 m +gs 1 -1 sc 90.0 rot (ncpus2) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +1260 3375 m +gs 1 -1 sc 90.0 rot (ncpus2) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +6460 3388 m +gs 1 -1 sc 30.0 rot (ncpus1) col0 sh gr +/Times-Roman ff 190.50 scf sf +4500 4052 m +gs 1 -1 sc (alongY distribution) col0 sh gr +/Times-Roman ff 190.50 scf sf +1342 4044 m +gs 1 -1 sc (alongX distribution) col0 sh gr +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.fig b/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.fig new file mode 100644 index 000000000..3ff50e224 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.fig @@ -0,0 +1,63 @@ +#FIG 3.2 Produced by xfig version 3.2.5 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 4500 2700 5850 2700 5850 3600 4500 3600 4500 2700 +2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 7 + 4500 2700 5850 1800 7200 1800 5850 2700 5850 3600 7200 2700 + 7200 1800 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 4500 3150 5850 3150 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 5850 3150 7200 2250 +2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 1350 2700 2700 2700 2700 3600 1350 3600 1350 2700 +2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 7 + 1350 2700 2700 1800 4050 1800 2700 2700 2700 3600 4050 2700 + 4050 1800 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 1800 3600 1800 2700 3150 1800 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 1350 3150 2700 3150 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 2700 3150 4050 2250 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 6300 3285 6300 2385 4950 2385 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 6750 3015 6750 2115 5355 2115 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 2250 3600 2250 2700 3600 1800 +3 2 0 1 0 7 51 -1 -1 0.000 0 1 0 5 + 2 1 1.00 120.00 165.00 + 3185 3362 3004 3716 3298 4041 3886 4048 4511 3747 + 0.000 -1.000 -1.000 -1.000 0.000 +4 0 0 50 -1 0 12 0.0000 4 135 105 6030 2835 3\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 1980 3015 4\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 2430 3015 3\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 1530 3015 5\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 2430 3420 0\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 1980 3420 1\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 1530 3420 2\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6030 3330 0\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6480 3015 1\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6930 2700 2\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6930 2250 5\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6435 2565 4\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 1170 3645 Y\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 4140 2700 X\001 +4 0 0 50 -1 0 12 0.0000 4 135 120 2610 2655 Z\001 +4 0 0 50 -1 0 12 0.0000 4 135 120 5760 2610 Z\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 4275 3690 Y\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 7290 2700 X\001 +4 0 0 50 -1 3 12 0.0000 4 165 585 1755 3780 ncpus1\001 +4 0 0 50 -1 3 12 1.5708 4 165 585 4455 3420 ncpus2\001 +4 0 0 50 -1 3 12 1.5708 4 165 585 1260 3375 ncpus2\001 +4 0 0 50 -1 3 12 0.5236 4 165 585 6460 3388 ncpus1\001 +4 0 0 50 -1 0 12 0.0000 4 180 1605 4500 4052 alongY distribution\001 +4 0 0 50 -1 0 12 0.0000 4 180 1605 1342 4044 alongX distribution\001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.png b/HySoP/src/Unstable/LEGI/doc/doxygen/images/xycommunicator.png new file mode 100644 index 0000000000000000000000000000000000000000..7237fe05aba08ddab9531a36db3f7a946407faf9 GIT binary patch literal 4602 zcmeHK`8$+<+n$guTSCPM6|$CL?2+tQ(;~}|WEsoM#2DK&vSj2dLdJ|NQ-}y*>}rr~ zGm$N1-$Ir!g^}f%dV1e_|A6<W=edvL-aglPpVxU_*LB>-@p)ivY0S+j%n1MhxJ^wA zYyf}*b&Tg6b|%I(eCKF6<Hmt7vGWH2xGa922YNb-EE$WUNW&Y*D{yyYpo^ayz}VVc z+}IQDkMwu-gCdaP>WZo=UY14M007URse#_rp!DU8Vcdu;m%*sV?0#5qC$n69D=V0l z<>1op%<bC#8;YFa@GQo`3;=+(lxq(xuF}y)YI>s4bDhL?pi?`4t53rVGihV?wcVx9 zG<r2FugIXAM;khJ@xr>QhPu0g=u*#cr{hDN=DfiL4kxI!j2W;Tc*#sFXpq>8il*jy zCLITs^D!2xozW(GpSkTN*;>)uxw)d+J|Cc3`k$|m-gCv%dHw*>q}f`j_j`JHPN>e4 zG9+j+>7YngcReVSZSx;qnYQ|HXFmk>thN28#<#2)mCCnu?gzRf%n$t`&^*o78mG^| z^NJupbv~jCj4}v}h$K?vk9Sys+harz27&Wm1cv+63H<&az)cedV46tU5&9pETvV=j zQz%{Xw}%!f5AW6-1|gPP)0a^U&imA*Mf_tN3PIj_6hRe<IqhNmf8sBwK68J?^Cdk_ z{f-}otS}R-o)QQUU^2t=%26?!5hu{w!bi{Y+x_nT27w`pyacPuJD<xIvBCVt5`QvX zmBRk$pgjE}CANc#bm+a&t0beaJb_u0I7m>-x3a`Hg$^jShA=$*sS3C9k&`Urw?&oz zDxG!`Z3EryAauw4uMXnXl;zZ=7#$lqtCJ&6W4$8n0sFVGhsOgnz>Ef5afkIHI(M3X z>iF?4jG_}*p6}+wNuK#uFAlx*+eD(J2nxm4dzDhp<3-TW3JRB>^Z%Kq+Igo6S*>o# zQb9F)ic9a{(Mfi-`PtnT;o5Ze3hE*eN01Ul3;&{Fupi2m1ctOj`x~VZ|5ka!JawCq zj;(@9TAujw%j4!h`$Ct@)W0S5)<-UC{?xAR^RmFqt`AfaY44t{S)KnY#qJdOeh)v- z>zS<pgvM`6vjH;imJ42s7Aq)RFyI&yb)@_*<@iM?2iD0?lWS7;cO8Gs+b~2gA{0o1 zNxi=8slW96v}0}Gw5FxO=`C;`yW030d@=*q!|w%}ewwwXzh&~bnSRtzt%hs#s?y&` zS>@gx`ZZ?k>VZFoD93|^ugqG$kn~vM8|(ii%Y_+&GE$&{wG-?u+y+i7bKlQ77q$7n zbv-j*#_L5WnS-XjtCR9f<;1?gx+*%_f9$%~r&$!Es71ulKMRO;R1#`763e7axhGfR zYY<R74Q89gQkz<&p#trMfK|(|)SPh6pkgjha`w-!S-spZcx7C-NX6v4jU^m>u7x#s zwX6sFPxh3RouBs;@FHwx69bVZmU>v5>ZkKYp{<T@NO73iWobjr<-wlyV0f7`rVsSh z7+Kmj=v_e-2wc6MSJ1hfFD0V&8J0WSJ^)w9rbMU5YCk#L5nEYgL#dZ@@lXRcb)CiN zWC?TJ?Z2(uI`WD{-Jb&0BBx{nm&&4F*!CpUhQ>Cb3Tx1pl6`^x!#(SZT%M8;&BLe1 z>Rr4DsTUPAQbg<NPRG(-22g#?D5qRmNqEIw&o?b4xM0yf(6o|GWv!xYLAz}0NF|AD z=~dbome%aKd)SszFW}X_<`4ztXGAZyj?|E-94Az-_q#a=t6C}0H1pkBvLn^vpq^#T zN@`~n$gDr7Z>?uNrf4Wt^zN^z29kL&(M68F$|?&%%afJzC6ub1xE~*rvr?O0?{b(( zfFPk-QFCl$4)HmM?iO_aZPSMfpLky%q6UlX7aYeX-O1ZSdb_wq8gAG=Wa=f{S=o{; zE6sBT%dEMpc*ewdi-jcXZN)BLD?JIye=Hea!y~uAzpd;FrN>I8H7gx;QGzrv$!kPS z<9o|<6kXWgmw5OH7DZPwVsq}-AWeMskPQE}He!wZ9jcw3L+Uvh3h$))=g0CTX83rE z=vCcru@4K65Uxic7sF(~it}~ftCHFWl9dHFcF-`aiIDiK1jVPi7BD%W8Jpc+&2B^R z5w|Zc#^+dG9N?;px)(2B2VH*?-~Q5(FXOFJhnyYQX8PNu`?Upm^83Kj)WVq4Ovsj1 z{RTze>km~v953DWUe}S+h2Ba7d$*Tha)S}~AIx>u);AU;vV)ng`3rI<&X(BG6+|sQ zO}<vfjJi*-SQp$AhNar#Q+RVg%UyGM{iGS;a%nP<2CRDWZIDN@p>-L&`WT0evn}&d z0Y<MThdvDMzqR{_|FbpLy!c&WM@kIj`KNnORHVdC$F3v2!s2_Z_97xL*Jz+QVCB*L zy28|Z2SD_y^jh8NVV;Q-vlrOHpzBv7fFInXY#!L3h+aLj89<${l<NA&l2!Hju?(Eq z0_f6k0Lnxn#R+UDmDT*TH#ysJSZb_KfI;RvFeDLcc^wQsUQ>H!Ra=i9JFMd9mF2(s zCP@H->qcdW79)=}b;&dhIG4I<y!sSF?I<~tbt_~gt`%P61pg|$FX%rs%Yhn7*U=B^ zv_kjK4C;#!QcfA`o>B0w1_wOD$tjQW>3k$km9IzJ>LOgmCsC`q`N@HPE^3;m?oj z(jsju-E1HQ-HcVCV@+6O;Y{zCW|iwTp%1yjFNOQx@;RCBWM<jfpXI6bIaFx$-6UWY zZTCfGI4wnv1h>iIua1T|HOf)&NcIFB#9WA$epg1B`>ZBC<4{I@(Ok;aR5z+lR9<}0 z{u?1e%Kpv{k#g&mnQo`3oqNLexffDasR_8`Y}A*55*>wgQm40m9T;XLkW-Us%Nn<P z5yv`KwRXEDtip?q%+$}e+4C#bmNiIZCJOC*n6E1QG@IhtWfv6YjkiqhX3g>+pR79) zhDwA4MM!A{NiHt+CdyD~o?||1Kv6+X>a_Y^-QF~fu3bo(w1@(#YB&v46m|QCpH0Wy z5-Xv(T4mRt^!t!(6<RlT|M>@NlhOyanc6@2dx=scK^qJ-SX+o0Zo;9pfIoMzZpf`u zQ%m5;`SEoe(Be7f;-pWt#SA1VAHj*DbwmcBtco|T(jF(H>*6x0HHvOtoIl9J<dUL3 zA0?o}r`bl$I#og;PFiCC%*h|7<Gzo&Af;|NQQ2vktAPu#>-1wGXUVaNzB1#R@rDvW zxJ9T~;+09~2YvW~Lqyrl#tLkgNIjrpgDX4$1%A`9jsnjr?MI2%#M_Z=#pWFPUb9Ii zhH~*NturkyS?<)MO+7jba=QaFPmRmFPLhRbAxwojE3`g`yHprS6F!(D>7g90av?U| zdy|OY!KBGh`bM?7;qRZVhQ-r+zXki3FOflmZjYl2jS#2uNYtI%!{hyvlu%6Cz>`PJ zPJ}7V;sh84)z{`nIIOsLIzBt&<mC+qA4su89n+^`;YPXG*XyXxygTJaH%D!q#CB^} zS)ALuKUTK;)OoSc<=ul*M!Hhe@+R9iVfE+XgHhB&;EAnJr<AB5+J<W8nSbanr<2uT zixwDLix9kh7wreVYH9<TAb+CJ=ut!uC^p*_WkTBgj>j}wy`q3jV#I=S4_JkY7(G`k zHJj%^K_gw`57e=MS37_R>e$R8e_a&pW-4I<57A2{vZkRA#t%KHs?BML;<=d$Z&V7s z2Z<04ay!oWX@oo+Ugl8Bso>&gj}WKa!i>`V?=}wwM3QiqpPO--uV%OVYHJ+{dxqE# zWjV?Wi4cE```$br*J4oz?we1NkZoYP?9k>UH)S=YE<HW7sqh$QaWgz$V$e-LNzkHT z@ae|RrBX$ibMO(TD=y<9<0W=SB8u(Tw!fUT;T>&r7Qcv-ITk%UwTCvpCwxP^AgaDX zas@x<FHKki0MeU1W)CHpy^LVKpfvoxL+KLWjJsBARL#wB_8h(t{?=fbcHb%V?p*n> zfo|9jE6byuhuC;>9u+FVS5W0`bNAn4hhAh#Q4WP4ARc=vtc(a537Do6`UbN0Vl<d8 z$dSCL=|?pj)rxyJh66p&R+@mA>?wTLP#{t@<H$_?<(UQY)Rpzjv!>3`UCu^oER`2v z*H5VLu51sI7M&BYYonRgn>)8iI`>UY6%fqTpdrxs`eG90>rKgS`=mHMH3M(z87*pk zwa}LbcSqU<zZtlR(&VZ%z)KAS2QMx0YbskjthqK$q*B8L^up!|u@iW;XPY71P!69? zmGbqX2~f6N4imCLNiWSBmIt!}%yY%daJspFQDs@;X9c|{hz+t$3o$S8w?w#pDVwYy zY%Je!$YoN2evoh&MFwR=>14%0_mSb{j__s`%+%t*>!D_qC*!rT@{N(Ki}<4W4>b*8 zq3q9hw<smPCPl2D(F5%L7O8YNG2^lS>oVU<A|0UG(i-_H!!>HxGC|l?B)g%AWXCF9 z;?t?H-{$ARnQ-@;;o&M>(S=QO16=|qOs#?a2RhIYW0q+J#zb##f1ii<zcO-uukps> zq*nX7Nfp}44rXZj5ZZTeE(@0QdT&m-ZMbk5Mqb}RBbidX+Uf1{+lhx|D=5xkh4>+l z`GIFWZxyxLdOYcsWh1ftt<<Heci5TAt&Hu$(fTsylE;_X1X+u^W}jq{t5H|scAtC{ zDR<A1Yv=P;_!qO9z0qmr+TMK{2fJ(axyeIS;mPt(Ue(J764BRTJ7C=ymsAu1YOGTb z+9_w05}Nk?bJ4RUcRoxR72YsFUJ<8M$Q)m@F`inuqq~p-b+yy{9-hW(;BagI<1+1q zwex1Km85zOF?4S`pA`rzi)%?(IaM|i?&2TS^_7MP)?ELlRPsbi-hb<n<X~Kl+4^&e zgzt?M?^_OnnO&}=oD^}htq%O<t1kRif^^)`fLM$8!(~w==e`aKgm!ZSo=xBZfSMiN z^CQQ;ho`Q5XKaQ6riPXV#TRczJox|KPBW?e-cI-FaRbEp8qPJ4=iWA9qH?ai8rY!9 r10raefC-U!4r>jm3$u7YiYwFA|GxZ(*C61)H#m!-eA9Hp-=q33a?h64 literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.eps b/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.eps new file mode 100644 index 000000000..a8dece8fb --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.eps @@ -0,0 +1,230 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: yzcommunicator.fig +%%Creator: fig2dev Version 3.2 Patchlevel 5 +%%CreationDate: Thu Jun 30 17:40:20 2011 +%%For: begou@thor (Patrick Begou) +%%BoundingBox: 0 0 414 149 +%Magnification: 1.0000 +%%EndComments +%%BeginProlog +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 149 moveto 0 0 lineto 414 0 lineto 414 149 lineto closepath clip newpath +-268.3 260.1 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +10 setmiterlimit +0 slj 0 slc + 0.06299 0.06299 sc +%%EndProlog +% +% Fig objects follow +% +% +% here starts figure with depth 51 +% Arc +7.500 slw +0 slc +gs clippath +6695 3364 m 6574 3566 l 6677 3627 l 6798 3425 l 6798 3425 l 6641 3572 l 6695 3364 l cp +eoclip +n 7125.6 3774.7 527.3 35.6485 -158.7948 arcn +gs col0 s gr + gr + +% arrowhead +0 slj +n 6695 3364 m 6641 3572 l 6798 3425 l 6725 3430 l 6695 3364 l + cp gs 0.00 setgray ef gr col0 s +% Polyline +15.000 slw +n 4500 2700 m 5850 2700 l 5850 3600 l 4500 3600 l + cp gs col0 s gr +% Polyline +n 4500 2700 m 5850 1800 l 7200 1800 l 5850 2700 l 5850 3600 l 7200 2700 l + + 7200 1800 l gs col0 s gr +% Polyline +7.500 slw +n 4500 3150 m + 5850 3150 l gs col0 s gr +% Polyline +n 5850 3150 m + 7200 2250 l gs col0 s gr +% Polyline +n 6300 3285 m 6300 2385 l + 4950 2385 l gs col0 s gr +% Polyline +n 6750 3015 m 6750 2115 l + 5355 2115 l gs col0 s gr +% Polyline +15.000 slw +n 7863 2702 m 9213 2702 l 9213 3602 l 7863 3602 l + cp gs col0 s gr +% Polyline +n 7863 2702 m 9213 1802 l 10563 1802 l 9213 2702 l 9213 3602 l 10563 2702 l + + 10563 1802 l gs col0 s gr +% Polyline +7.500 slw +n 9879 1790 m + 8533 2694 l gs col0 s gr +% Polyline +n 10122 3003 m 10122 2084 l + 8761 2077 l gs col0 s gr +% Polyline +n 9680 3305 m 9680 2386 l + 8313 2393 l gs col0 s gr +% Polyline +n 8548 2687 m + 8548 3606 l gs col0 s gr +/Times-Roman ff 190.50 scf sf +6030 2835 m +gs 1 -1 sc (3) col0 sh gr +/Times-Roman ff 190.50 scf sf +6030 3330 m +gs 1 -1 sc (0) col0 sh gr +/Times-Roman ff 190.50 scf sf +6480 3015 m +gs 1 -1 sc (1) col0 sh gr +/Times-Roman ff 190.50 scf sf +6930 2700 m +gs 1 -1 sc (2) col0 sh gr +/Times-Roman ff 190.50 scf sf +6930 2250 m +gs 1 -1 sc (5) col0 sh gr +/Times-Roman ff 190.50 scf sf +6435 2565 m +gs 1 -1 sc (4) col0 sh gr +/Times-Roman ff 190.50 scf sf +5760 2610 m +gs 1 -1 sc (Z) col0 sh gr +/Times-Roman ff 190.50 scf sf +4275 3690 m +gs 1 -1 sc (Y) col0 sh gr +/Times-Roman ff 190.50 scf sf +7290 2700 m +gs 1 -1 sc (X) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +4455 3420 m +gs 1 -1 sc 90.0 rot (ncpus2) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +6460 3388 m +gs 1 -1 sc 30.0 rot (ncpus1) col0 sh gr +/Times-Roman ff 190.50 scf sf +10671 2692 m +gs 1 -1 sc (X) col0 sh gr +/Times-Roman ff 190.50 scf sf +7683 3647 m +gs 1 -1 sc (Y) col0 sh gr +/Times-Roman ff 190.50 scf sf +9031 2614 m +gs 1 -1 sc (0) col0 sh gr +/Times-Roman ff 190.50 scf sf +9544 2304 m +gs 1 -1 sc (1) col0 sh gr +/Times-Roman ff 190.50 scf sf +9918 2003 m +gs 1 -1 sc (2) col0 sh gr +/Times-Roman ff 190.50 scf sf +8347 2591 m +gs 1 -1 sc (3) col0 sh gr +/Times-Roman ff 190.50 scf sf +8817 2282 m +gs 1 -1 sc (4) col0 sh gr +/Times-Roman ff 190.50 scf sf +9264 2002 m +gs 1 -1 sc (5) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +9804 3456 m +gs 1 -1 sc 30.0 rot (ncpus1) col0 sh gr +/Times-BoldItalic ff 190.50 scf sf +8270 3780 m +gs 1 -1 sc (ncpus2) col0 sh gr +/Times-Roman ff 190.50 scf sf +9049 2907 m +gs 1 -1 sc (Z) col0 sh gr +/Times-Roman ff 190.50 scf sf +4512 4060 m +gs 1 -1 sc (alongY distribution) col0 sh gr +/Times-Roman ff 190.50 scf sf +7853 4037 m +gs 1 -1 sc (alongZ distribution) col0 sh gr +% here ends figure; +$F2psEnd +rs +showpage +%%Trailer +%EOF diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.fig b/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.fig new file mode 100644 index 000000000..be95b8cff --- /dev/null +++ b/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.fig @@ -0,0 +1,61 @@ +#FIG 3.2 Produced by xfig version 3.2.5 +Landscape +Center +Metric +A4 +100.00 +Single +-2 +1200 2 +5 1 0 1 0 7 51 -1 -1 0.000 0 1 1 0 7125.552 3774.712 7554 4082 7418 3336 6634 3584 + 2 1 1.00 120.00 165.00 +2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 4500 2700 5850 2700 5850 3600 4500 3600 4500 2700 +2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 7 + 4500 2700 5850 1800 7200 1800 5850 2700 5850 3600 7200 2700 + 7200 1800 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 4500 3150 5850 3150 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 5850 3150 7200 2250 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 6300 3285 6300 2385 4950 2385 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 6750 3015 6750 2115 5355 2115 +2 2 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 5 + 7863 2702 9213 2702 9213 3602 7863 3602 7863 2702 +2 1 0 2 0 7 50 -1 -1 0.000 0 0 -1 0 0 7 + 7863 2702 9213 1802 10563 1802 9213 2702 9213 3602 10563 2702 + 10563 1802 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 9879 1790 8533 2694 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 10122 3003 10122 2084 8761 2077 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3 + 9680 3305 9680 2386 8313 2393 +2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 + 8548 2687 8548 3606 +4 0 0 50 -1 0 12 0.0000 4 135 105 6030 2835 3\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6030 3330 0\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6480 3015 1\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6930 2700 2\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6930 2250 5\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 6435 2565 4\001 +4 0 0 50 -1 0 12 0.0000 4 135 120 5760 2610 Z\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 4275 3690 Y\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 7290 2700 X\001 +4 0 0 50 -1 3 12 1.5708 4 165 585 4455 3420 ncpus2\001 +4 0 0 50 -1 3 12 0.5236 4 165 585 6460 3388 ncpus1\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 10671 2692 X\001 +4 0 0 50 -1 0 12 0.0000 4 135 135 7683 3647 Y\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 9031 2614 0\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 9544 2304 1\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 9918 2003 2\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 8347 2591 3\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 8817 2282 4\001 +4 0 0 50 -1 0 12 0.0000 4 135 105 9264 2002 5\001 +4 0 0 50 -1 3 12 0.5236 4 165 585 9804 3456 ncpus1\001 +4 0 0 50 -1 3 12 0.0000 4 165 585 8270 3780 ncpus2\001 +4 0 0 50 -1 0 12 0.0000 4 135 120 9049 2907 Z\001 +4 0 0 50 -1 0 12 0.0000 4 180 1605 4512 4060 alongY distribution\001 +4 0 0 50 -1 0 12 0.0000 4 180 1590 7853 4037 alongZ distribution\001 diff --git a/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.png b/HySoP/src/Unstable/LEGI/doc/doxygen/images/yzcommunicator.png new file mode 100644 index 0000000000000000000000000000000000000000..6a87434637ccec072559ae23894300d310764ca4 GIT binary patch literal 4788 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 literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/example/CMakeLists.txt b/HySoP/src/Unstable/LEGI/example/CMakeLists.txt new file mode 100644 index 000000000..febd4f0ab --- /dev/null +++ b/HySoP/src/Unstable/LEGI/example/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/HySoP/src/Unstable/LEGI/example/advec/shear_tag b/HySoP/src/Unstable/LEGI/example/advec/shear_tag new file mode 100755 index 0000000000000000000000000000000000000000..6d8fb7de7294159d887edb1d63b56d5bc437afd2 GIT binary patch literal 769936 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�R#{JPE>pMq_g&OZq**Utxr9_ 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 literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/example/advec/turn_sphere b/HySoP/src/Unstable/LEGI/example/advec/turn_sphere new file mode 100755 index 0000000000000000000000000000000000000000..5f9e61b8db4885a59e619527d4779ccdf4113100 GIT binary patch literal 769936 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ɴYTC|pc<xOfh<Yp1U$Bhj0e>-|eug<G^Gucwk?sW4CEa@xHQQNv>; z){9nGR$$6GJXLF%KgUjA@jzm-ERp8iQ)|7ZLmXLpQ3Jr=u98<1wdiP4vFNCj8jw~T zPva<DxSZs`XM*vs39zDs7*#>5s1kLc&IW}g(I2bR(bN$nt48T0I_yPX<4ZuFmtV?K zeWy}&j#q~Up?*`TH?_xnvA9yAqS?y$qN4d8ho62X+8U$0)!@aOEH=iQ>4xty*Jj~5 zRk_9rm$4$rYDEr1W%;I)+N-r_d{5;)S$NrYl)kH`gIM{V!`fL`>v5n&CIhX6HIKC_ zcEdVwe>6jo^`E{^jAT1A{$($EE4W3ha(PF&Rnd|!2Kl_SlPUx6tJQuz*E(w*{jm>9 z4<reqHT@CjJf`XIxyNpL={A^x<m5XGRSI#3aWxiU3Kx<~?ILwNBpoH><kzV`mgpS| zLj4>a_(i4vWglul?uarKppy>9sOvGFfV{B(0JD@bkGP_qGQL$vf7Sw~fHaKG&IwYu zC;1Yj@ICYsKDu_Bbk5h5{cM)cbTDs%6uW~l<78pHO&JdmM$^YyMD1e~q>8z~4B<UV zdB1E&O0mbMWL1c}lNsLG!rM}LpB7%}WYs)4C2z)rt2=UoNIyI9ACjjf;-qu$Gv%bS zbIQ3Rj?Q?x+#s?Xc7M|&XWZW!=-`y=eDit;LX&v%?u*`?PDIO2(YxtKEyc(_rtivU zZMk2tj<L{nuUAFyhH-yk9IA{@3!~_LyYnR;_q%Q81xE|-Vaj`j@Rrc)IBq-U1;$0> z*1O^DE4)omzjVnXgqQV>xvWXX6Iw#kU1YkEPd!Nkq_n6_8AtQubr0fSdCS5U8R}5} zXW2!crQUZ3?vwvMe-45QLLc%GnV}8rjy6Yo?BrGCSe_?+V5iFRL>iQrGYH8V4K-du ztRU=8el)d|mAg#ouLr#;>k|&zh;f{*SPFVj8IR|Jik*Tw+XY!!bwYfl67RvKd?xlJ zFZD4yAFJ1*^pO|%IAvR&N|nj4%QI<Uk-^n#Q{E7cB;}Y!9OT8eZp83aoI!`_emc!c zN4CfOj`%@-YyMajp0rJAAdT~;4xIs_Exhq)2{SR1&7R^)+UY5-q=y6P8&kFHIiO?s zfJ`%sr!-o_($BmUTDD2Ddn6LVZE9@$5iO;J$4NM7FKe826w(bTGNpV`Zk*H+ZYSlS z;l|uJZqC7t)U9bzv@gkR7DdmWZ+GBJ_l{f?)#0AKD0&x^jos-6(i0I>h`(|KU1Xw$ zyt+g_eY>)?r9oV>k-|5&?7LbeNt#YSjk1P-1W*HPCi5slS+N$KRu88slF`+nGrWX? z9|015A!!m6p2OWKYukDJlAMKK@`9hXm&shf2@36%W(LVkO8t?V*eJCayuy?UCV!H` z5x8e7btEVozi7isWvEa^SJ6a0RP5_ut4ZrFoi)<$+R_I6iQB=V>g+FeFr%!A7n7E< zmJVcPmExDwyA!I!SDtK+H6$>yL0n-g>PYYj!?$}zD(W=Si&>JN4$8)A5TW-mOsJyH zRtH+XIIUm!k`!G~A(5jci6BlD0gn&?3su0|0fj9rPV*IS4ReolgR7PCWRfA)TH$x0 z&Q<F6pw_u98wlUrmhbT_bqGtEo2<MmTcaezg;9U-pZKGD%yp}9y*I>G<kP~%ZzxXt zk&a?!aV#pZSAH1Nb;;*R-gqO`2ur>VfThu#-X+ep8j-I+MS2LbV0g*YilnhfVh^z} zaScjxk1O(uaBbI$tlERB?`@zcF8GkBe1Y;kMSR>qN-Yj3+L8KAs2@=3kz9)83Q%=9 znHx_C^16<eQ=NeV4N#_~j-*w~WK8odqSld4Wf7G()}BeD9%LCI78V<3Or}W%-*i?C z#iE19Rk}}Fu@1<T;ziK&?ZnFW99F77ls;5h9|fy67`s<d33q}CzQ?NnM0gKV-ixHz zAylld!T26?Z4|CeI3_2ra5uX|N(wH0-TN7DyRY+v`G&zP@T<!H{q9^>>F!7ZXVgT2 z0elaIGUG&HyhRyb5yn<%6n&Gm>De%bsOf8pxxhZkcMI{w>L|xiw2+m%k5ZowYF<ZB zY6-T)+1}I=e2;{rID~^mIoGI4+pv%pn`|)Jek-aS-?JGf3uAX>{BSo?i^VoCJeO^r zom!%YKefb|d|oKh_PxCSlFGuHS|Wp5HC!=({-n<QFle0*`f?t1EPDw`sV2&0;-8P% zem_?t#(FF*?`Lb8buay~lT2)ZoG~X&lPUiqja+Q1!{-}IO}ojpXd#~JCS+T3F63sJ zqs{VKz}0JF*_LAAnxI^F2v>7m<|yeh{gv+&;)~T~o)GE`rS8b37~4`Urr7m;y-!b8 z+cE=_2YOj)tt5TRyH=9EWtKd(gIEV?T2568>3~1ZNSlK0wUYEL!+5;BIV<o--q@Rk zQTmo8eap2oT#P}1vlwzRk!6iXqCSvPgWufK;v61~WoS0LXiM4FX4OckUumhyT&fwx zYa0jBPuIqUb`#Hto_gQ9J$I#}w8Lx_@9#n_HQX|Rj&h`MS;|!`T+MZqlz(w)#md)- z_+oXGn}qr>rT(!6$rf`EdbN*slv*5)!Q0K_Ml*v+E2+zVT1tpZk%1%rU@}Trzd%Qm zj?y2jcK?*I#M?h*EHT~eZsDG$+-Y2JxeO=X{wc$WVSHQ|uTaJn$)uNZu~_hOvc<wN z^dMO{u~;d|;gq{V`Li6Qz||6Egf;GxpJg6+p%yWcix8!dLhTeX?jhFjUL<pe4CU<! z-h{PsgK&QhQzSawp2U@FRx1;Q@i}FjFN~2|Y2nw(YxvqqxcD`X<F_`ygi_$*2`y6d z;bVA>FQx`-^C!}1$u}rzU~?%+1%dOC5=OWPED2{KwR7eUr$(jq(<83+Q~N?&Ny~P& zj95Q)r}~>^K@U(iJ`N%*3m7WIL3n5tny019JdOYOo!!}aI!~KA%ATi@R(Q2o=9=DO zsnZ*S-k1yM9nbpebbi(E!Y^sZ<EV7bqJf^7wScK|_te(fM;=dgPoz479?B>B6J==n zRN>a_Xvv)l?w$l@QAfy_(@%?g2JB#Lb{5rF7#%sU7RKf*-K|hK?COUqZ+GI0W$D%n z^>n2UFg0yIwJAk|11eD0D}hN1w=KTWOTERD56eta;FiQ_#hI|I@@drUp>#<cy%9~9 zdnSa&uB|;+IX6mOqeO$v2y$IdQt40q!>+4RJ4=g>1x(#msrMsl*_#=OI=c6-*x5FV z_OYj82P<6knw8!*IP@pjI;v<vXnCR3m0!bEc!djxE@8r1Ot?H;G$%afHLFc(aOk!m zK7#!Ce0;iTJ}(hy=G(8!eEw1mj976E_Ck%LiDtn|#Ks<=QjYi?QaTVh`EcengE2uc zR^X4k0>^kUC^pv(L4LQIJ`z}A&vW|<#uUY9`pqlHD4!hBK>iTZ*k3_r5J+fKu-kmv zEAGS6VaK>2HCR`e{hs;0cw-^n)`IK?4WRAPm>=Sgj^ndVNZ&(GdH-0}8$pruVJ)N& z3h|;%WwgiSTjcT4wu{K8E85T7{b*%H*>%xngTo?!s>oId&$5;EqM(r;q$Q?DpiO18 zXtG714HmSSigqs0ib8b--5Lszx3JG#dSi=9Yl>2X?-Y=X<@)vYV+)Zoyjw#MWR4Hh z{-)IHf_tvw?%YOgz1_42qHLT`zjvuKZ9(7ILEn|HsiCTEW#qmDf269jeIPl-HICL| zp}co4zoZ8$%19qdDLyK1zCy2}_`4p3r{5(&AL5UQbA%5lXG|1vq9OGZq>v(gwY4R_ z7`nBfTRm(2O-JkV{aUAJm~QpawLVc4cC6xtfD03dAR2U`f^Ic<>&IrnEe<1fKHM1; znk>F@+O6nWn7rzzKJb+<7hgF&X`8Z&ifW>dnaa2=k#0lJCZ%SrIE!^VP<7jp3N)mM z4ZEIxIw4FLqbc+u(!;*rFEHO4s3g%6;r+$8M=QpMVROxjk=9E?$lCj2A^D!YNBOLn z@s282$rh4}BU$|GrC~gDnEB{DVf<1xc&adtCL-Q_bnOrEP55JYK(Mlw3-8m)yQlD$ z2yfiIrEi7z3gun4nFY>c;Xc7iVK`q!-&+c&OrVKu={Y>hOK|^f+^O7lg<9l=QY7oc zx2E*y=n-MuM;Q+mMx!IRyQ1iboibL|%fh<?t`>QRzWbHy$vUEaU>7UjbKG4Eh4nFI zeNk9hMMgi8Ni#^QvQjAN8zNljoAJD?&0r1k>7HUpY)|8d(Cv7g>HJezQMYNq-KF4W z6?KC!_EpC1zi?%ZqOfXl)z<DzX5~>Tyt^syJmF=fjN6V?i;I_ULQ{tKVc}hZ`JO2G zF5%6ini@?ZbSY6~bwzcdtf)SKD{=A<FD@e+AHY+2Y#QeDXRTGJ5P$qkmDjH^pG`8k zzQ!Duj{_NygL!6^b+dp}Dab4V;e`<FOR9j-PcoT+XD65e8OtwK)^P%|P(elr2$KS2 z3H_{PP6J}9!vU;(4XS5^ihdfZ8d9eTtmSJ^-62%;(<=~T*(DB)D3L2<u<XhmCseM= z84Ju<e2o&@2o?S067O6@p|Si`Yl)bpZ&`Q5>lX~o<t0L>I*q2(q4HMzheOd3ExQ#W zBU+Y4tj#ZDEZOJdEvaVr`7B9L8<J+M<+VBrK<}tXqCZw()p4}^T7VwNC0jx%e)9{4 z{!aaf9;idtbZ~pyo2Iho^01RT6@R2>S8hVv@lr&oo$2|zLVcA|-%8XnJ%2Zor{|&i z<QinzbyE2wijPOdw9tX~@W{6=0kMYn;=cZ*7SuMLSYHeE2&G=L5n_eQsdd8baMa3` zEb(X(Gm)ID;HMT0kwc(4EzZwjaZghLE+GM8X|cPAd!SPH5OJv&`NbW3Oyc5FPlLF% z`O{38GRe=4Pr+*PCYztLKvl^jh~DN+DVw9Y=;Zu5X0FYzm(G!2L;X;Lk{QMyluY8G z_-N%s-%EDq!Z%yR#R%D7KI$eI364fS7J8R%+q5Cl$8pAwXawWq7y!z~*&yO?afb%+ z3WbA^$KVp5VkEBxwrOb1h1lbws$fLmaXuEo`*K5Pb&>Xd6_Yh7{zgJ3=M8_-7NJ_? zmIw>gTBRx^Dpw&W(Hn1kXavTof-y}oTKO;_=zLjhnwVv*zaTvpz3u?xB!M|kVdno3 zA&NJ;I4aDWCvrb;r!cn?3@Y2ri7PI`;YU|c@evTE9%{iyo!#NYokgHJI2A;LnS>NB z!aRJN6H6R}`D+m)tjs^JC+0!ugo%U@n@%q0rD;;!7|w5`N%7-w3}aH9zzaW1B)C{5 zxPc^y^}-)6mF=$7Co{DtfOxkf*n@+q)u{DBt7t8zSgV6pexomX_%J{<&fx0WRtYZ@ z&GU@ER^$DSI)U4&gBJRJ6NyOCTuN%@*-r^+(*V0Mo+eVC*&}BJzFOiQJeC~KMeM0X zT+Kz$Nk64_29I7+%I8{2E|<c4^WkHI)?Nod1>tO7s&(5&)2UlA$h9AHIPUhE9WHK6 zow)*@n{f+TWPg%sT?t^AXt9|*#8`o|h!klr@<BQu@7bh&Ok^u6X3ENYq%|K^$)5f` zPHX-y)YmHYD591@u&^5>pcw15D1Q7bUOhCD7xh9Kv3(lV0hVnk?5CAAq$g|iO2ytU zo+QhKI!CFS)?s2<+{jVDWWt<}U3MnRBxdO|k$;eKRfCHSk1Ife=w}JNsqaxrUn=zU zo?~fZTAEx9WcTdP`F4;#zvT?OPn{uL=&Vk_FEO!IU=3JVWY6IkU7$?+3lm;Rd`#Ht zaU6`vR4lAJNRV%@w!V|C^AF?TOT0wYLrCFPG2SE5y;Zc{MEH6mE?aYvS<j+Kjqtq* zrJ@tjP9jDI*Gh(B=AcEhw4IX8(vDPVuW2Mj!t3u^>=6qTX;`X+rH`^?3k!7V3bRyQ zn)h>waP6sFErkol(iLE-$~0VSh3jKX*2TpB=Q|d!EEvM_w+P14v-X8E9lq4slnK-p zO?#pKp#?Zngq_4tn$vS*7@L~oSQYcNtc$6vsKzF%JCi=Bq{p*Z-j`I(hx2L-k|JJL zz8&9E5iyL-GNGQR)b&J-&*0G<i;T_7hvH4$!|Jt1xTvw8)d$XW$|%}Cm2Ris(<gOi zy_LQ%rjD>R_g;lFbFeisodms;XlM05L7p-(b>?Ec@Avg(I&V#)yyORn+3csX_0XCq zHMb#~1WTwpDD`ecE#~I)L)_-38cb+5GB*PgGdG*0E!rve^WWGyjUvg=9^7(ki|h_{ zJE)sAH`j{%yJ;DxP#H8=if(R9eLvAsItV?P8!Yhs=EkhhpOsRkDc9<?Tnf!6u(Wq^ zvAr=|^M&gw<$7MY#NKeox6kB6e8ji^!M4dU-xC>~V$2S=fn#=h$cL=9k}a^>PvMfY zGHD~sK3K35g_GH#88VDDdXyb%<g(uX$l^vwRgt%>p^D1v)gIYh*1NaRe_3cZTCLDS zo%HIMses?&3>2>Cl<R)sf;zWidgkI{bsCFvqi~H-t_#3r3@Hsqb@~|@uOU56I#!PI z9n7Us7r_|_({^4%dWEpGQkIQhb9+-Sai$;sYTYSZ%b|5KiL-^vJL~it(np2sG36RB zTri}|cwoY22_0P91P4%SnER>pr8E4EYiP;CSkt0!DCO>^z1_BUKni|2o}oq#nr=j> z!T3vmO=t>X@~WJo(th$4G!tuTx}_g?r;bWpNz@1h4YxKnW>W^+7+TjS*JG_wx(MTg zGa$sARFxmY$Q=~9e>^#M&tz)K>nAOf!PK59@|w;xMaCIBj7dSuG9x^Ob^6Aw#k+p8 zW4V%+KGt480}QWPS2l84?~u3Ce$^h~S~hE`vrlHJUR9~?Ssh20F9`K`rM{4;NtdU= zCU6eAXHW&q4;^JLO-z}=qgjwU6*@VdAhU(~UrPPqmn61FnGgPhlnGZZD{~+OH1=x% zF7u&OidVBtJU|Mzff3P)u(iD&XFp>55052*vWAmm)ZP)!=jyWG3+w#I<<&4m6Z4)! zvoot~=?&kbEa?sHr~+|kR_6%I8_M$K7t9iWW;I;6?o_Vlge(5c>K@@bUAaaGSF<lX zZ0GnRG4|kX9Jx1bFpNJ2rgL3)%o~iEj5psrSl*~3wb<W3Z%!+D!m<s1TT$e@!a`bc zwiVP&nrZm?!nIJjrU;iTG|kLFt)yWZB~14!(_mr3Sc<tOyT*Bn>E1-ZO4sx--b6@) z8WYgN0n)v1*OGqutT{dO6qW*InJ+A)2WQtn^<bt4X9?Fn$`uwa>K)F0fhxjqT_aqd z!`_I_i-k)RVQ&*Or;8M5Z{7ZYOh6&6k7DaU`#DnLnopZk$YH`#rYu#$5?>*GgzJ3e zx>dO1E93&<Iz+kp3D>SE<YzFgBhPsP3fXo9E2OoSxO`P}3h8hpv#fwY6CFMwEb-rz zOyQzDlEQVRaK(L7P8X(Yl&Oa>?ZTV#EjZw1h(1wxL;{7&g4q6O1N#oMRNHtwm0@o~ zU`qpvyuh0PWEgH?OQQ~M+F+<!_Fu|p@h|>}Ft#)*@e5lT)97YclKX}8I#M|;n&k8E z1))Xy1ZY^@+jIl4Z*Q|?&?Fe~B^ai$7Y?$zqR=;z9fZoo=n->Tac@4i(=z-Kjc;i{ z#bQlwl4yLga-US{cZpiY;;N3cb}J(R5J#3@15MSSDv+`{8Cr`BO^P}qo(#7O^<1US zcVswHWMBcvc|0pI0YWlsTcD6Xtw6P6Dd9Jven6=g5w$4cg?&9rsDcbtp5PPg`1;RY zZ6S7q5+tCh)iNczL5nVkC+Jxs=*dcbfFo!Nub|T)=ro_8E&YP_7eV31X|_oZLz(C( z!?fsWpTyDV!$N(cQr}3_;c|L+a5fVDC!Xz{)_yl+{7Y+tqmqN?BlLsv{WUAephH-a zI~2P^JV}-b^#G-A{FvnSO!Zz!H}htzXd>pxBiS>?<F1+2(QZZi>AWkIwU_{LR;e$S zI%ZmuXSFxY<>BigN*JR>UyGtq-N4WAP8EjMVT1BwC?K2^S}_0n&hRaLuvOkQEM{n* z9&s>Z>Htski7u-`%S)G!#HIsn6iB?1?MWOd<+Rsw0#ro>!G#+FR;IYlj*~N9x8nri zLv$~(84EvhBj`zcBSkcbAHj?MQKk?j0#O)RBXS~N$>HQ!OP%>MKG3l@)`e*Gv^F~~ z$JZS5Qm2@6x}!3Kl*r@*h<`_$;5^zBPD<K3wyAY+9$E$e{Wuo3cdB%wQu+%wz}Vig zfgiFD0H;UNr0n3r=Khp=9`(HZspx{VFTWbFW(%73<aqv8%hPtA!PM$kuY;DP1vB4{ zmQ#`>CAOe>V6XxgQQv}}${en-%vYwrpdqKBAGV;!#p^<w`m$EPhLw<pIs8L3O!MzZ zb{FP*Uip4n4!&6S?**a0U8xr_wdWnVyDhyVlu?N$W@dw3mX!3?aBc|8%A~r7+F&)b zsQ^iv*pu_mLrIpb%gNhnFE6tatHzBPT#XzR?1*^PSS!?fDfJ&8P^CT9s7W)`&??B= zj@)OiYVgY0SB=5{<Z3)YTMBkHhLJeUx5jU|T#cn@OlieSS+E!hAFu7r)Q>Cm@kA{K zvlCiDhGZP#59i|}j}5WT>%T5tXQ#sah^=Ux*Po_7t%J~(WUnLwbpi*`<StYCw?R+V zDj#0A!qA2U>S^-aPEv^5smNHpuINCn=U}DoPt;P+=TcG6^fFk;lh9zWkn`uSgN01~ zV5=T8kbQE`OeBg^Ja_;XvaOG;`gO}}k(AnTCC?V>_muiAqL$=49Y~~<iI|DN?@0dA zZM>^UC|$O3AT+OzY~zd`|Jg}g_83LGme7<tr`Y)JVz5^Tdv9ew+QUv}-Boxrn|y&F z{En8Dez*R8j{uZFr5T8h0`aCoJVy}j4ei3vcl4fT&mVgvyh??sGi!^iHkpWiuK(#| z*!McJ?|o9I*g?Ex;O8edEhDqtCdd;MW8i0#;S>X3?lti9$-pnc$gu*BL-IG*BL#3; zn*{`&`jA;}w~s=SvVaSl8?^p~X@_IvQ|js6i8+P7O)7n$R{FL7pwj%&5K|alonpK? zX81f^-tYBb6FrY7`fxdSPLA@R{b$lN_J?)<xm-Hi>&n%ixOhuQNsZsQwY(}}B|Vr) z@r5I+O*xH_n4WyQCtEhz@uP3gwj@JcE|E~@!)ImYH9liKZhng2V2{k8ew$TIZb949 zNsXGFo6X;!yZnhN=&ehsPBAQ9chNu_r7mP@kHJorYGKAGL#;)gI5Y0Z2etinJ4%h7 z>dZA-LwjC!jb5a(!p+v`B-ui)fl-#Wt$Z&|jb0Jz$x3}IQHxEx7&Yk!<6WEo8BHVl zW#=OY%l)`ym)~bXGyp{5B;+5n2B2{RefX!}`i1f*#kc*ld8(Q_RK@st3B-tP`_2A- zccotldb0fma5%yChw~?qxwQhXv?lRd;%DM!@MGCd{{%0IXz+3pCSf!9ps+ur?1y>S z6EK5k3qr9XeDkhHfCS87TY+e&5Kj?AOf&c{%;2&jEB)9)1njUG{J@yO`T4K{`K9mv zRWsPeF@sBDm_dgmWl1bE$eqxWmgWW|oWuSc)<JUq(`+N~OT|9ONmTQ=lh$7H66B&2 zN`sH8YmQ|PVQH-_eTjvpns9Z5c%F~$X#cfFW1Ns$W23DeS2d}R(3aaC_3*T`B1)nl zexA{Db*wzPWyg%Z4?EB}p9^W$1oV>at#@+l`b@8-`ou75FAMcUN_{g?%iBG8cbY?x zN5xFvVh%xDMIp~A%CUqJdkCtNjoMq3J{k1pTT#&lpQ(ahp!6RsCj4T|4$a_0Tcp#d zi(6S&3;2Ob{0tFOJOH0$N?#HTc}8qBKv9YIO6s3z9~wFLSb{Zd0FP<94G(}cPzrot zgQnp}70qR7<%|A0h8EVu(`AXSe5cuyD|_W@;@rBcV0)5a3Sxg)!9ZY<0a0`I=ep zG<mT%;g9syci(X%u*q~u5e;IHK)kFF698d6FP{ce3qHhJmbJPGwW>m`c*?bjr;N0o zukzPwjsOy_$dtu0*&u511cD}hRd%h+gydF1I6x78UPQIB5%^ofE-9ixoFEVlSha}| zRe<2oGvJ_BbrhOeZu-jM&VwKnYosU?h;oIv77%^r&~myU`?Imf7g^UFva`TC`w;F3 z^rZ*itKL`%23kAkSN091R~C$0l-%@=^c8Fau{RR^1u~FkslT}DM4FB0FRx0k|4k+O zbfIZ&2BH4qf{51G!v*0@MR?eQ!2P8eh@%AJCWSZ$5JrL2U*5yIB2Utg!9Rf>lb8B9 zJ2ATK2yI4QvZ#G#qJVZ$&}5d&0U}Hf43dK6YrmnlJYOKbz#nPxc?(E64n$6Im62<+ z5hVg6Suh?^j9Y=hUK{|SZa)RH-_J`ew|z2)aY6EE0eMNRtbGMxpd$2SDbRKC8vX=* z)S#XDjr>XNf}Y^B?ZS-$vX6rNJm2(x2B9~|1wq|kPmY?tn<)q%AS6?i@rnl_Ctn0w z-bJK{2JwT0bKa{E*8#%u$QIO7d`~&a0i$@B^T0mP7!VQqEC12pmtzCj4P#G~W$AFX z!LX=pkPwD{REE=E{VDZuXL0lsRwA@75$Ykw3+5*<>n)HSsU=$Wt2IzytRe3$p?*xM z#}l;-c~>W4$iw%8ko6AlJ?9;~MCZK0p<DTTJ|<ko4xOc=kIw=O{=`Pb%p}a5F|$1G z3j_|r-VnX%H?x#J3G_Tm-pHTv@fAVobB+`RmnzGD-lif(Re6f2;v$H?pU@X8eFf-I z1UYSE`(YM?92M!TTvu=@gQAtP3Z;A@^gm+Em7aHkltL5mXkpBoh5l`&-<|QJr%P-r zRhX>AtLAAHXfC41QZbLRTZ7)p`=yZcmG3F=VLIZRJ_Q3Uifh#R&k&Zwl;wJ2!KZ-= zty9oxM^*L>_n1&<os8>2xIS=P_7@`$<3pm-UBl^*1g(L1%A0E8l&RSZaNdDB5q8q> zFD<aAQMXQ+9g$mcnoeRlo-t@~_Q0Tg?(IF2LuR-X?1(@a_F6hK+~<ja=AJZ}q<P{2 za-&jjw5A((E}{)V-?69BxD^b|W#@0Gx(f1PZbWZiP<92eM@YU6>=BmHP2|bos?_R7 zB5L#3BMKy`HouWSZx=2lsCfH*uk+eAcdY7p_qn9!7_-x^ytdChQ>j<ZA#Lz(OxNE7 zcI=JkfKob}nlMlC>@!N=qFtJkZ0YXY^K-SVYpJYQlJ#!I)Tv5+5>cDJ;5(yq&u@@4 z!81yvXFj9UoVcAt+;0)1CokT-x8jI<pHR<I>N291F6lp`^y&6p6t{0m0_rW^gB5nK zO0ai4d25Awh*GbfO||p*TAtoUh?Jw9k5_yawDKF=J77<Dq32nP2nsu3c~o94Z)lj^ z652SSHxzdpacOo-8tl6kXWqmlj~rv5q1{0G54$D&rdWaf(6F*wLal}OmMP`H-t$NB zfxYIM(e$HbScXY6Zh4a`8smMal3w?uQoqa89<@x`O4X*V50eX9(wbSt4Xh}$^>I5@ z#J6Yg{+_I`tLde){Z1#6-kX1UZkGNvL<P%?SB-T-eVkIah^)ptTYS~vn6?2VwiTq9 zHnca61DIezUO;nt6YS*3d9C(4TXS_DBa36lv|UXFHD8^|-H0`J9ej$?Di_a+(<=K* zb>33y?o91zmCc(?bu7C%sK0*XZjxx*I5|>>hJR2UYDJcp2)+3_tPOA-#;8;kZ^Ws? zIa1>@l=^z6_SE4xt%JN7?A)Yog|HBM2Tj+CR*w<<K4+!5>+ubhfDjgQx{)j&j~pQ^ z<V^x-Nra2ggxdV6{H8khDXN+~IPo-lzELKkwfQytl83N%x7t97<y@%$WFy~1(VikA zQVYlW-ipOTWVpD5=0Bwe(+F#hH=fnP?oMr9k38Nu9QQ!UA6vNrl#QR_0081LN`j$5 z6JdU6^lwLKPPJj1GT0!AB23!gu5_!G(;fX4ojDnb<!G~LPNpV*tMW|R+-?$rTAs|^ z_E7wi?*8p-SVxdfIc=`du51*Lf*&OVZWO#J$!2;1OtQQx#qz&DR%<v5Px>?pPD3e; zw}J>NOd@@SD)`KG*!-$3G>5Rwse6+QGF;u0^<9xie{d|wBpC`@+z$59O_OT~73+_! zjw%i>&6)$@U{k8`ODeV(6(6>^xg?<*n=Z4Y`$mFNk5@f>@o$j3i)2O=`53L>?es?U z6`2@_Qv`9X3NXo!D3vf@=&=#$qdELQ(#zTAHLIV%l`CAXA5H``M`D|U`&HsiPf@rH zuTtx9T$%aCP4*X#zPTN;H;Mnx#zy7Kxn;uKdF6<zBp)SQX#YEuBHF)?;N6JK2t>a+ zV<G+`0#jVPAm;iJMaGqpGD;_6kF_l$t)-q4#FG`V>6NH5u8fp12I2rg+=LKTk?~<d z#HreD@IlFkgR;LEOMQkH6{$1d?{B5=K}*Q&55~5`*HPQ{txdU`4H|8Ot_zM^oZPe& z#-$#{`tO=WeYy!v18+*$ikwAVdJxZ|%-CS;HKj^j9nN1(XMCT-m#ncP1*6#9OzWc^ zNRemdma8tTD(E8COzV`LOnrq?U&Pd&@$jG@sZaI71a#EepjAW@5*iFw`_A~D45-Eh zV8<pimM$dtf>i4QY?dY<^*oW|1eIgO%s5hKijCPrsh=ZiSud4r;Pnzb04RR^QkZi{ zLWj$Kr@3qM`g`CH)<{6Hi{eSLn`nCld@a)RI)gflGtfhqBY=FG|19e?aor~Y9BuTZ za;<wA@>7ao-{G=Kq0bQd8<hS{p`R6TmX%yDw!iH};mT32al%#OKg(L<Vk#D<-IS@n zFqObLfY}6}WyLmB%(JY&Vxf$90CbjWnZy>OzliR2?iBK#W$n$ane}Npy&q=s_dH5P zyJ17q<N$RYXN7-L@`Bnf?M)CC>ZJNgBRujFsZ$agyAHJyBO7a*afnnlSs5=DMm96< zqXv``ly5rP9Vxu;sG|NUylh{|C1m>$!OHg>){wB?qpaV*$nqxfper^?lJc~oJBYBU zO}UHaI8ABLiJWg`heZg#Kf<20yleLkOYB`c>v!(q|I%7tO~uEu5Q~KRpGuue)bg&S zH@V-n26@*KYqMO5CO=eRzkMOGHhWPRe^BMUB#frboMRF0HseVh@_-BPE6RI=@N)aO z4@VHM-DrmQBjFvTyjjBQZZ!Lp1fS4ywVSa(TNATD?Y43I4Aqj}dp=J4j2G%GrLF*V zvli%%Zv4vZM5W}Fxq`}wZGj#a`ejOgg3yx%@*Zzx3uJUQOSm3Zu4Lh=i8$WMCdhCt z7p|eo_1<$Vo0uRy-s-YK5yxAvZ?vtDS;F!0R<cCg297229&df^H`098nQ1OdlmU^O z+WOu*I_^m0vdLh#nvXlK#tz2#^R^~5$~?$Eh};!8@ge&Et};#=w`#+!^_)__Nz~%| z(-V(7zvGwDIiy!hONQnLyr(yFcY8*`FN`Nj`z=g;lTshe)Sd~$rf*4HI`PO>3cg%3 z6sR9#2-!9EW0*saJK7RU`|jJh0qXa5HNbSPYqRs7e(XZX%~HY2pN*r@*M)j_rM`lw zjYjp{<BO<>=iKA6#8f)qS5{K8qVEw;mIXrn;o){)_;dzI?osLE-;jRj+@n#c%T2^b zAE8<~`Y5V(9esS7db8EOVJoY4)Lx|8FQwC+Mq+Wc33Dv9RQzQehmjrea5T3XKRl4t zWjiLKOjw8Fa3ChEcuf);4~{yNq|7~3mGH@QZV*{qc{7K5#_-34@dp?UsZ@n9n(@Fn zF6bT)*kNF0RSEAa%6qZ!vgwaMhQA}MH!16(!s;Flykj_$m6L&Jg|dxS5Ul8$)*OV5 znrXUG^ZCK7j}D5z_!-g%zLn^j&=3ozh-N9hU0Bw1wKXwCSYV@lrzYLA#B@42VdcK0 zT!VxQvqWbSLqW7`qK)F@d)>LCm8q*Rm0$=VpHnN)!#;abFJkRrQp0h?(kgHy+&fZ5 z$RS$Ztfv#}9d`)hVahmG7!#Q-Ocvgz!)$$?EWF%1nwc%k5Z;-}ySwnZyGO)q!Ss+e ziS>}T*zccPs6{;URC7I~L0I-vmK%hHdWbV|qQ-WQ;y(%38uWO1!*YZRqqy%pse2S} zbCC2a<q8OwbP>Dm&GnMkz!Yn!ed0G7YWe%<{MGekov6gD(`CXsNeiCzB<Y15jJ1v5 z(zU(67Zxv=$r8Cy*xLyEbY(AMcH3dr_zWZPPj(n6i03osclfDTOg`7hatwCMapxl1 zpfu+igP}27A?;R#*9U4=2a;UL8!<l$hUUu0&8z7fw4w6#_!pa#{92BiOZSqf5dI82 z5O5-X95W=1ydqpd#N&S3{f<r`Ae7myXgEW1bSwAruiz;BY8s|GCk2P%>uLO49-U5) z7UNNH=tAM>wjen4y`U917EkCUpO?WnwT&}C^(KQ_?bGpa9tHt2E<FiiPdpsA6^F-f z!!iXIWA`F+xF7aa*Dc4cDl&A?;qsQL<Ev1cb#LQVZQ#Q%14%S1tPQ+^E3Ty#xb+K+ z%1K}@9Z!5?)+eQoAA>7MbSfPO3Gs)c;7P`G`$iTZaGl%_;toDEhkrqygza5iC8g0- zin$lG<cqlIDz`j=D$CE=|74h~Oopj#yvun+ovN6B2A0q}?=F0V6uwFB?^5BvKORx| zrwmiu81NR}z?6X^f8isg@R5I_@UfAFPcVf~bRJR7FTl@rShu5rx}sI6xoZQv;Yz0R zfn}fBP4y+7NmDi83QhGGjaF`L-6{evl>57+t@kS;v{lM5wT&yBM<np`{4>zmU-)fO z_$hy)@H3qf?0!;W3P0a@M1>zEg+E1>(OvV~rSNy<{w~%0qsJm@{wc%MHh%6rqQa~2 zbKRAA^=boS&?@vU)dnuW6>d>`9P+8%R43B=$!}G6T;b8CE<S<B2}{R6A@ISDRJOKO zF??;~k<KF$c;};3wZKS!;p3(7N9F!5X=?^U@*8d!{)Z`irt^pjze@_=lHsd)sTBT? zKT&u$rv$t3OjG!A&Lb*3fS>DVBd#{Ee3fkgt8iru;4LfdrYgrBX{vj11#O+;7dR{e zUn}=_Nn4{IiRfF$FidUZoz5c?_-y_ec$c@JUDkJ!6uwdJ?^5BvJseT^Du$_TOz{@J zf++)q{=#Vs4H_BoCknqKvhY$<_}$JUs`>f&+0>z|X`iyDw6dnX%9>i2HSJ#3lu|~{ zdMj{q16rzMc&}8nSf~Lfinn*(vJHWStwRmR)?qiVMKWTqN1YGKBBC6a65eYqE@G1& z1JZ+-v{iVoH{+3}j^`~yD{%S>ySJ2xMh@cLX;(8%!Tnl(D~KZMV0g_`r#X&gn5-s- zscjtPdPD;NreGNmjI=Yvc|<>t!q2y{hTPfM4Oii;ZIDd1w2}P^+cVaAaCV-F{{ttH z%qeA}upOZV^403VYq%XsZ^`E--b1JtXSg=$AkOV`PM_jFXH%Bz29hE)cNi~MC8c7h zd?5c~PXxlfg7}4SFP_R<f%;EKMOdiv*QD}i*<qjbHI`I_gofFRWGJc%kx?jhrju}> zAoL-q8f+?iGrtf=Z9zuyX~eMwanuV6yRAax881Gp!1+$8(=g-HyZ{BEkASz@#uK@w z7KT<6+*C)lk3rRFQ<+lB3PX)VR>q~S=2GVuc3X!)H{SXRm$FuT=`VsI`J|Tp6xzeY z-2TNWFbrFU*{akO7?{r6kePtVAT8T>2IT2wUQZvRISXR*2Ep6W!#mL79pL93E|gvA z&z6SZ5hjE9g5VLH?GP$X6AJP>^$QPAsm)(RwzFUMs70ywy^dZgduj5xXRYLg?w38L zF7>{<%u_2c`y=WVq0%-0sm)(X0AY)MWEU+>y|16ph4YsNhsF$M-Tgqk2v+U@{E?+o zQaRqEoKex@Wht2TW}(ke`uYcG{ZkhwlJx;$`QZS&hzhXaR9UP@*4Ko7uF_x2MJx&; z41`wvCL~u6M1CanmeS`kesQJ7<90^pH5*l1gm{P&r-8VDJ~bI?z#jyy(#}xIZt%3p zOOT$1sA#BAK59ze8NngYrG-Q5iYVWzCp=g_d-IKya3~gQqS2S9;4oZH(KHnYPLcd+ z*wGUDB3{+yZU&ps-vN4Pv~Xxm5tb1CA|PSbCBm{$Sx)C7@~3)=fU!UkM1QN$Pf_{< zxQLh<oh<Z2mA+{*wODbP;*&<pfDiDOg!p(Ro(E#?bTNap7YIvBWeGF>m=eV&6_pS^ z2WhVo`VY0yE+G0aJ8S4zVI8?5WB2hj!v27=AIQa3kH(v#C1UGM-gqjMdit-zHCVa6 zy`Kvm2repg5f|DJ>m2<KVehQ$&k}o11z849p>%_5N|6T~mxXw@{q4?h1GvyHKQ0W_ z;LjrJo(1H!GJyi@$dWBX9CJn$*t{WaYA|^LezCzyow<;EwIp@M&S)Bx3*(ti!v>Ep zq4c^i8<Fh%rS{k6mnPHVcOE<#Y<0|GzdF8K!gpb*%-uzNw~)LYcP^r_jia0U4DNH0 z?Hd@kel*+$cn3$J<0I8@s0iZ#xmE(3m+8oc0R_(3(i+@d?cBw%l@Be~;7?`HH!KvO zvG{fp#sgG`C}=QX$_$@ThLOU9!f;-uA%yW~LcitDH)V|u8bVllCiI*6{8{v6sVxnK z-Efp-VL`XwAo-yrc`M`b$Szu+dS3ySn(Sy^kMWz{XtVF?4wNtHz-IV7eIstUk9te~ zYW?yGc~VzXjrfh;DD>TwzJTa4cOYZ69^#f6OSL}Edy&(T3+<sGDO~8N2JN5p8a8m} zq&MPep-)lzkM5;69Yw@^3mV`(!SM2dz6DQ$1-2g<1dQpVBI>mNZxs3`mHq~zhq=Vm zCWiSB;9Wrx*C|VHE+YCth72L@qr`0me=1L%_#ndq9JO7Zk14RbeKLh_59M2Far?~b zg9fr0sEKB26XgrbC-@_FeFm|N+mMX+cqRU?$D6nhW<s^}a^g!@9Z^kmVR|d^VuaE+ zQs*%**m{1!-h@XiIBwBsJHMD~LOD@9Z>``Y3Wlo5YlJC=_~9(_xnV-t$bYQW1Y!lo zF4fm=77Ek}C5ca`^g>nx5r%ovZO<$5lkd9cmJUO`i@}~^f`f0HX{HUpQ%%f;_*tmD zPGo9&Pi2}$ZEjB_og!+4Z~+mTBBlb9Z@Z_S4#zCvC}WORJb^9)2j4ccP#eG&il2qb zt6bHQ8SX@CnMk23U4%xc5@7Oe6j7oasW_q)CGA(zB=n1rJ>6tB5~Y++qqrMDQaZ{v z%M?`GYifiTX6jnXPf};{Pvwgt%!n`xGlT{u?Bo$93sdGoXKmQ2uxU69Cf6vg$}`c$ zA!?DG?r<qTfjl(1RlXSVthtBfq18~Zmf9H|n`Y6B5h^dCLL?*?!%k9RczPY~6yj)W zA&v*3pFgn#)*+l!5W;H~n9M)&T9LMi(F&CCozWS%9L1LdyW;XHz8u~Ymlxr(FdWP) z!pxIQ7BVvOVO+9aUFt(MIO`MjVC6CUvQ;X<A9?#LL-<^w4MG<@u`>`fWI2Z_3q#9c zZGR9G-&+wbcOw+yRHfL^I1tYZ#BcZ`LL3YTzJdU-xdo{OON!{&v#D4m&Pe(yR_Q-w zyhAXbRm^1*sbU6%F5D1Qu}b@tF=nGQ$C)DtmnnkfMkve~WG3#eiuoaK5r~5n;xs^* zihT-+i&6^~2D86pQDA2S57$vI$jb<3Z}lkc1UwtV&oFDS0yi2mI~H_1q`h2<dZWFq z!!Pefk91+@3R73Y=DgxYZo=;3V0Vau-CD3OQ0#F&?5}EVxy_jD!hVOJ4WO<&TgbZF za+8){1}KKbo$!52+aKn`E;UR+M2Yz2zS6-S90mI<!G2n?-<v>hX+yBvR?I<?xjZb@ zFpw;uOylL$r|_a2Ye;bL(ev8#jApQ4o}rjG1G6yueQm>!7qc#U()VC_^5D|NoBRx` zc`NX;A+vQs6Bi@z&->WAIKYQ}i!kL8wqF;69PG2AU~h)N(DOrz{dTEW?oNiOkaDiO z-Y)7N$%0LWX7f8-y*!aymWGcAc8+2X^<mF9OoZ*1dpbWGK-iB&!R{^CU$(P#vO8g8 zI@@idzYPnsYqSk}7!qF_7SgJTmYSyu>_mmF8V^|O=ADJsb(FMjmN7BLZsKD~HSA!s zLqg9L{-E*?2S1(Q$2ouo*zC8+$x)d7Y3hBGae*PqOfME9Mmhtts3TC_7Z$N9GcmbZ z5Dd>1Q{Ss6ms5y%>a&9QY%IQH!=D$GjYOP;PNBSld(C`^GT2;*tdd98pJt`tixxe4 zVooi|Ql^-WoD!;UYH9V|*(a3p2D|#63yxcuyzVlLPLU(f+=V2K8G)+!2aiC*WdwSh z@9+pTg)eyon#h+t0*%4tpBaH(;;5S3!P<Ea9k+`k(A9!)pdzfj%Y~582-H;|R%&xT z35dTq0^Kf{rHWa^V(r2RbfO@ftO$F$5fU1KwxsfFpQI3VcWT9=jX-bA=RO&A1bUR8 z@d#9A$ZYFHBhY$|Jj*S|AF<?vP?UQFx<HtsjzA|l*gc|PmkD;ZVki5sch=Z)M~*;i z_!*Bt4MOG_fqDq`=TNrDJ-x&$_tS<c+6Z*FgME7x>;`GUI~BWtu>aZ!v{o>WQp{h+ zdM)|SZ?i6<jzBB;8IM3q4Vm4BGy)lUKR~Y$T|Df=en^<2jzG6L*u$e>oA+UqV(0p> za|~0o5va3Z(<qTHWS$WyLv*sAVt;jqS0`W2W1Zwh8-W(`Gai9v88Y|iwn$!~xd^2c zos<&xUmk(}Be0h%?9qTl^{lzFy41l4<CQ%P$7sYcMfPZf7JHw<5RrdDVZIv!n4IES zGKfdvcuY8cz#pkkH8={AKiY+n>wd_Hd8$2f$q>=($VGXO(*l>(rC{V5_@_rMoTg@1 zWVo7lQtTN$!gJ`hcV&R1XeQ6Gcl3Ue!eXu5pHykD-VUWHly7l>uMjedt`8)m=!F9E zl7d|80dc!f%@i;O&^`imsRA7$K$O_SEO~efF0yW<0lP2QGm~ott%IU{avRmnhQft= z;X@)3imPs92f7N#2iiyO_kiTE?mg4Q7(ic2XPc-%K>;#H!sIA#Ij`C!F)_`XaJaIO zTtkv@nD3Z1zN9G@n(8FT9Sq3_ip9x}Uvi?JGjSvH23#SdN}PrrH)f(&iL@r3=-1#l zk@+LUipvY~z^!q52Q3{Zy3|LDnm&RsSrN|iAmj|1=+Rv?h#eBCeuhG%3WU>=<HnRk zR;I*XnY~4n-4&<ymN?ykBq?!KhWf%%k>s5{ZFQ7-5OPMD?GV$+qd|lO;x2{gD-dYm z5;U~w1?)(w<xptT3#Ljhn20~77gW-0w3c(Gm|jptH1I;vAA4)0bU5EEAI&!_*!L5b zV^sQ*kDE)ky&5EYL3jO1>>~0nXl<+DuF-LN1icD`;?g5^iqBAc7@aW+lIsD<VKF`Z zA_mYD0qUVZzue5yxVpw%@>xaJjqdvERv~EL?qSz$2BXEX7lh)f8}*Ta0`jDST<ihK zVckd6EecSo01Z^2jsk=>&p>1DiAKkkr*Wrc;tuzM+R~o5<WM<$C)>Fjv@b&y6sri3 zJe$tA_i9UrC{6V+qQS@W=#T89;#V5qEbmBvtaAQkS;P6)+#05=ZpD8plK5s|8rmfo zqH_Zu@Y&~Wv`>c|A6D)JJZT*M8lO-l;(p;_&W8H6*ihfTx4oe*k27^ceH1p-7t2$# zi){t2ew{~Q%+(jls+t$8R^VUueOl~N&ud2#S-BTzhgmoZ9mWbAE`*qnFO;@10PXDi zHoy%6u)hM_1%PlqZ_HYOHPtK!=9|tJ>kb9{d-i?6SXtEXA;c%zvb{x!=|Y7W<pLFg zxGnoWbKfW2Q<XbOxUXO;=o>`@&KDM$mRJaHK^&{xYDJqD;q*Ik=T6+A<9-|pU<DSx z7F~%i+xKl93=#=us1EKJ$x190!U!c^Yu~p4<_N%L3Xlr`Rbp=;k5J;F_I*}EonUlP zjBO)Wh$NwkP-5f1xpsN1pR85Fy+)PzmT)g%Dx<_|VR0+*DY@lRVo#KZ&w}Emge};Q zHg&8(SKN~w7?blM(9XHj6LcW&ia-3uT7h2yO1ousVEw^d*Gt-sZnWp*xaUF(;h{r6 z4lEY3srblD!4{lB3%ugOcrFqH`_Hb(gx%ShM@b>lKgT44oHA)76-Y|&<yi;fHsrhF z$*SKeH%8`#*n)eY<ir~pplrN^ZopCituQpbBY_GwY%Lr+a-$-X?@L06?4OOlFf6)) zZ`0*-GkGAEqn&8n;6J&0sZ0SX&cuBPzrBQ`mpw}wnQV>BUOu@2<gNm_DSXaUN`%1o zBk{hG;*VFn2|hfom(STrcv9bp#0uqt=ZrVU`|w0QuY)rVUcTTxh(A)_Z--NBYz%g5 z2*Ue^hNAoh*_+1hgNDy$l7bL&aZ-MQM)aXhRRQF!&M<LF{jx7ZNYbzNRyYD^>U9$Y z)=~CaW#eO{9N@cF3%(Ww!`tMnylBrD8?D$+SdNBSEA+Wap9^{ppotlylgvlWa$74) zYc8TFG9*bHv0a3IRV!N;tFC7gQy4o&r?;>?t1Qogr7$PoY;K^=REtWk1vyR!3;oSX ze=`>mFLvuu(8BWfQ<i>ULF`s!q>)6l{9EYLl|G&5?V}iW7){K*{5it@@$R+~KE95M z8#Gmi7pl=zGKoAoekAnMm3}(Whj}B~380A{)3sW7uT<VExvc0BNWTejFD33J1(DrA zR43fP<+Esd8@4x!B_4*Nyjqr4(G$vh53yUy?s%B@rFn~9HoVDMY$9)3fQ7agnWd#U zgtFbF2>ibN?}(N`M>pH{5<{~WmtDaHg%SUvOGYOfwwdBbO+I^>)b3^ck@s-$wNRsi z_|~1YN^mDDrb*<%f^dx@9OyyN4&z#A_#sw9x9Do!6k_EyEJQ@_LG*&Jf$RKU77R1u zHGpVcMYIpJ>Fy-loMNX>kzdBmu~{T}LOISL4sBYzN(XkNPdfNqJ7umyTS}o9DnuJ8 z)Cq5+LfsrBAF6-2a;&<V3*~ObQG>lY^3DXtgR%SLcwr9g^lG#_w-_d^$V|O3x#=sm zN)5V6>N0#Z!n`G={H~>pL@9-Ce+L*SPHi}MY_px(NouoLxq5>O)1NpN_BdggqAYuI zLFMGI(3hDCq8n;w$<9CtgOuyztD3X3=Lw6Wx2M2@SV*%>H%1WAE~v{AXy68+-@cpO z*Kgz^P?wmokQ0QZR#{HsBJv|+2_+WtaiM=m=~JZ^2ruF}V;yEwC0Il3!7HK)vmz?P z9kU{uic7O1nrPp}UJwRBXs6FkSQ`m&pg>YYd%#`<S&L@vTrnC<oQ&F8F^{1n)UK_; zsCHmb3akH6$S-!_oGa-Sw0G})zBRucp#F7$Agt8}O!pw@cOGKc0fJ~~$wEA-5FZR< zA<$PgqPsi6n9=NjWGmuXZMd4vVO-Y~DHR_>A?wM}QleXa<wUpmR!J$nWSAn>kWxd{ zb*x+Ss}@4Z5U`lu8K$5l#^maNMX%vF%9avlLk$IgaLe-1)K=mY1I+@^P$^|piZrG~ z##HdqG<5qRX~ED)e9)H@IAU2^gNe_`O6Z7I6@lyc3OUbck@^)<H#Dv(V0aeGoa*ey ziG{KrM~4K}+uAR0zJg7R8N?djr=L!w3j)RK>|sWNGJ9>JP))3MJwchRaM#uYUbj^H zI#k<uyB85pxTAs!^{H(fB;|8`?Ry1skCkNK%c6UCE}{rDU)X0KcYqp#(St~E%grT? zj|8{;%bJEil;D>CSgdQr;LM<93{5mKqsXs;L5>|`M19G`s3DlmjxUN9)W)wfK9@-h zCRVEo9DEzGT2;YPlq3LlI2b<*m5&Asn)KA^_F{}8Lh~y%kU`^~h7+MFLgL1z;V0ik z2~mRDhPfDAL2Y~+927HZ1K2Y0vrzdEk?G&hs7#1$%P)(RX`m3^LxiS?iNNIBC?ZNw z+W_Gh$Q%+kR{{>c4UQ5KiUDk)_*tktD4fr$P<CV+^_oc0@`&86E<4JNAHbN>U>C{O z)5T_@%XqLt79@INqTNJFMzW>k$D#5}7r(@_$&1Y~<&nj8b&;Fm28yNNCn%17DqoCX zwhou#RSDT)aLh?!m1elmMHqe)<%LvG?O`2V<VKi05r&^Y82YJvB#f0#=K@U{c#6z9 zgEKLf4rPIQy0}@OG*<~CP^OUZAB=P|ui+pv_z>_R537}n#R%0^c=!o~qMwNfweb=b zDucM)A%Bb$Do>(<YI%2ps)R`RA#^8XZT%g8_+&-tM!qbD<tT5YODpiuQ!uZv5uwu6 za$^GD;7E)HxieDkWPqk#?p(rmI3VL(dDs&V>*QfR-x;0f2v9>0FvG{!d#0kuLzsYy zoFyFl2nMWcX_eeb#+|}22Y+mSk}f$2pouRz_+vF+4nrXlv4~FvgA=ihvkJqPRbg+A zYMR7zHi}G4WFAqzfm6TCNV4Y<dtVHF`;ZK-dr|@)zI$bX&(L!nvhoG*9L1YABmysN zF|i(kF*A%<kU#yvBDPe>s{tup&d3R+Gh%8GUpk&kZR{vvYUE@}7ZCPlUQZGFNsPTR znc72y_8=KtzY?Z8KKiifURjMI@tKPE=0&UoHy##7q_G_Pn2t*c(ICqOatHGFiHMg2 z(pCcF77AivYOp4lT~QBk4VJ5Xg1S2b9&@-ayPaSobI>;@@^kKOV+^VBbz$)<?Ru@0 ze}|U;?O;^NS5BTVceTrL2cc0p8BRIvW0Vt+ayn=^cSI?t;c-(RuS0Jn1<}pnXB>v| zijaB2P^Pcv&h$F6CW;>a5e0v=VT=}va-oBNW)%E<!9Pdw=M93M5Q=hyF(a`9BC}j% zzJNN3rYjKa?a25cvR^{j*>mgMZ9S)gb<-1V!1rAaPj2hS_&JBB+;2#=t%(8C`eUV> z$y(0#3nR-pTbT3ga{O)G!zrg*jB?&>;<h+k%b6Udob`{H`a}uVt><SPQu2<FnQ#?3 zD0ZdbFTqq>^mSYm{7Hr}TEOmb2mi7t_<IQcRf@m-0&456Xlv1=x2@fQlNdRa%-7Z$ zJlR^{_f+^11h1~1#O!-@BkQ<>f*kDuNx)w;LJ&Sesx#5z`t#jlB;qg16o~s3;yFMt z7^;IA!(w+_u>Cn7d4Oe@l~u`U)^g8O{wu*xCoWCg#+XEm{J%tqHVSfx8${1<x|X|+ z9TtB?TR~WY42GhKug`Od0Y`@MQ^kRJ|2uAuyA|RIKrk2tKmh)HcPBaA^MD+wq>MF^ zK(U`fTu4%6uTX10`(d$;g;Cy^$N3ps`YDFY4#L_F?7Kz0MtGm4hDko`!NSy)u-$Jw zS>C=5_6bq2j}Yuhiv7$$uiPyRQz2yxbNN3A``f8hC${RJ@@1Z}>f-cY_ARS5Q?Y|S z>=}lMu>Er1<6w`Cf;~d8Kf=C(=w$u5@LGlH3!4dVHzdBdTiS4}V3sK6RA3fmZ_qZ} z{E%3^Lf?)L>0%W>V++2_klAfW{#_&QA&TA0hy92!AxO`=`$O1wIM^eiVDBq(*C7R? z=wkIbUb%Z4ro!yTh&DV(uqn83Um?@r!tWvXTi<XSUZdFKeb`?=$U1@CjS+3Qn4j@T z@RlL7bwbz|33i%dcLg?54-_^V-p(YxHdG5eOkm$cLPSx=2gOi_I^mr7c4HC9lQ+wD zJ=>Gd3m_C+Juj+kliVQc9d;R&SvuvEBQ*O7!c~fJni~ND%x14F4#X#t)A2Bc*c}jD zCkOz$g!41b$qlj4_5(Iby+wrYR1>vllP1=xg|3R6hDUs|u#bQ|r66~?K?uz~`6i#H z`;^qzXy=_$jUkGV=SC>Zxy)?oxisO2m?IFK6ylG6sV3G!6N{o*Xn9~;=nn*9)h~9p zm<<RxFL^3G4&Pf2l~1FYR@mZc!nk#~V@<`K0{XC3Xl@x_Zop;rM4}rv#y*M#FB|ot zN`D_ZW)1hD)j!!K2D!viUIe4}21BJKTw?ifULBW@P7HU&*NoesxEs%+npnKHrA+l9 zYdGVIM=Ml1OmOM*dggQl$y?)>cdX#f`q`FuD&v+{GW!D3&=AJ8Cdz7lAb!b59}9D) zH{wU?eN)&aUpfo~@XaoQez}S`=^iQ{z|7^WQ!5>xo(fE#%*MmS(pn8fkUSsq2bt6j z!!=@<Jb{^rKLr9a*acG<o?C?{{jFX-u^=xoaukNEN%a0!k4)JE%Bk3h->LVlV)sNT z)dUWyg*a}K3ASlqL*^JX?AiELMi1d+?r$AQn8OS$>c*n*VSPDDD&M&rjYIZ`_ARBq zjWuT?VO?VjG|w#X^$n#w*E9qmqaBa|3{NNi8N?iOIkFzVr|~1Wx5J_lq!NfY=n}B{ z?x2${e?Xqqpbw?sTYxy}vLAdibSP)t5O%oR9+;j4DIS<izGM$fS1u?}T}JIe?vM<* z@eJQ!4@^h7Gg<CrfF@1ul<*z)z>JcI<bi1=4~Oy{w+AMP9ylJDzDz(xZl&A=$OkAG z<bl~JcRJ&a@xY|>CC`-h;7j(v?6{8z+#Z-laJoD&R8z<KkcbCnpU?RnTf51A7bcy7 zcWm5T50d%iwto@s5>~R6weT~>dqDAeMdBe}1nH((4~&5vE|7f`a$SFW{%+(%w_#fG zz)%}IN=RgK{<@U#<wjcxccTO-!GmOe`IX>I)6p-bdu3fNc=svZ36XgCa0)A-IS-71 z+(#gLDdgHBM+qz^JTUavcwo|Ssq?wT7MmaP!0>(d{FXc;Gx$08wnq)AuF8o4W82Tt zPv-n+tLRdc4-br|oWa6O9vHswp6gOMy`6Hp$0#Q(<(#eM{9YJY&gMy`K2ba{tN0nu z)t3pGnX5}6$Pt473w&-eX?iRQ{)2`wng`}q2mksg`0q(OJ)ro#2%kMLqDk+n+&!@| z9vCL`&G}^BzD%&mUufpPr;~2xwsN=isxa$@JTQFU-`2DFInUo`8d7a*VnAEJA?4J= z87Ae7j#AEz!b~0*F2~>2XF27Z8l#*uq?}<|PFj?5S{vqQ$E7#iLv`hO_Zq&;^LSu> z{FH4`E5)xmEmB|48^&lJn0p=kaZ&K^6Z}dztVB-(2%lXmqDgOCyQgl(1H)v#w$}N5 znZT3ZP2e{b0Dc!eFx^+M4$fAP7d;>ecwjbt!U*jY;VKV8A|9BR1!5UoN>Y=<0Kr#@ zd0-A*$0FRP{NDv>e!puTm=8pV(-h<>H%KBLnEM2wl_CsrBP8U3DHMozzPB~e2@tG_ zggr19iy!DNg;;eet%4m7OvBw`9iw?*=I}GN^sg8)d!<Sqn7tZU(T6Jb9X{;ag(<2B zW{87b90mIo>4{6wmeL6h@?mEfrf43R6v58GAhK-&SI<~=@xT-d_H~NA_!O^B78#~! z9+*mg#v?{W6zpx%WbG9DDq#Ob4@^Mhork6rU36f19S=;p2+}i}2WD$2TfIE!;s?IW z>uI+kd0>pZmnin^eA0!3JxiFPdSD)Nu<wt8T_L*IO|b|2urD-B(L6ADf=wQnEFtrF zVEPF5^KjIOPFnb|lMGWd56s%}IufkpOM4_J43P)sn~%9)_gCy0{r(OQ%m#to0>6}q zd<I~5)dRC~Ez8zIWozvQNyG#5kRa5k7<DJR#7M{kbGAT?QHWANaGh*NOMDN^9O2JZ z{(Kf;*E}$93&>XZwM3msZjeMgFk=Mabw!xhmo#C-NXP?oqCkvLh}!^RG?AbO<_v+z zREVB{K(Bx3PL7R1hB7M<HrGgS5g1F?II<Ava2FATN=IT<7pjwdu5;-JIZ<$k0x@JX zL!)GWh#jCsW4K(V5bV}zz#Zenspm^};?xlxf}njtsOrVR>v7!&+y%dcA4e2_cOM9x z<H}k|L8xwyUc&K`augE>0$xbIWQrrH5%G-2XBG?bQ#>Ko)w2-KD`bo2gm^<ZMk_~s z9t*)MZx*7;BSa+&5fP57{vl}MQh^+$kYflk$Cbd1G~wnrPB>0hj?-BPi&o~rWTeQm zrm+wb$c4x<{8C?1SDLv;@g=eH*a=j|%;ns);sn|@md8Kam&EQ0_9ab}a$GJcu0F$* z2n_WF<4bzg1p{BwMm&l1C6VZEUs5K^YkWymlbF7wdV1*il34YW{1JXKexh!mU=&}{ z$dlkpsv%#}RuHQ%X_hGvAgmV0A?5ZZtu`ftn>7-{m(+rMNyuGUP9C5bzN88XeX8b& zCdaWpmu`DK%5<od?)qJg2b%u$mHlQN)f@dup?ra|bQY9Q)Wa@o))mY6&B#=c##}c@ z4vXp8@Q49)uK<0w+Lq=C0dg%W=2BfF>qd9|b!!x~hZXHiMvHT(lu%rCquI*S0&=#3 zwDExCu<j%376s^h0oqf67WN_~Z8jm)=J+uOlQnbvm;=}196#m=wUF=l@eouk7_R0( zJZ;`_bLn=ZHtDWkn?JqJjeI&j{UA2DCCeWpq?#I-P+Z!ikm#2LWH$wwm*edz#1o;- zC_tAA(A+O<X+{Z<yQffHBkM+Y{dK!e(5_ds!x$}2Pazan-KeK@6Oh9d<m(f;fz2jQ z4(mRmZc%_%|A#gG6+A(r>4yafJtY$^WYbeJ$n`I0i8<IlR1qZqvYbNZJMgy&4V@(x znrikzBdU^J(Gpx4;zP~Y7U;@1?IVI+QA5WNz>yhMn{?N&&Cw!%7nOfyw!4v|*c3u> zX_I<NcLDhfE*Me510IkZ7BfPdQGmW*%G#WwK&K0kyQffHBYO(n_1EneLCaUPKYF?w z+2^jHw}4Pwb)%j#Q$UgwWR?dcr<!;o>J|m)ashe+ju=tW^#X)mP>-fJ2i23L7p%q~ z?gh1c=*S$)XmIXswJ$?*iX3sHxWjbe(pI<xY?{-R_%OPB_ypC=fXFnfA~HKkX*K_{ zDl({Jne*yl`*>LuDEXVi4f0{44euf3|G9O1E}fo9qW3zInB({FyQ!^xE?pjX)zgyK z;<RL6dCIx8Y5w}*%{&Xq@SjV6%f3(Bk<`&{MY-5uUbxEE;SndGMUnqf2qTVE-)i5t z0agmYT?+91@qE;Wa`57N4MHAqq`JF(A23+|2}W<lm;nrM?<G`u{&VTS-o&-b<D(N< zTZB7FxrYh&GNyvZkIq*t5El25>X~v2Gkg17`a0a9bLluqNlH9g2qKi&!M<<n;2n|R z{gt*7zs+L#e;CDbMkw)P`@Riui1cJj0j2{0C%{CBGlV=siTB#~S&5l~QJ@$Xix9(v zDnf|^?EB2!SGf07?t_K<aHcX!>?AC1CAOAZE+tOG9X^+ygm=Q6OE1GcIdvh&Z1CMH z=T1j@cWU`Fv;2ZufkE<+&!rce>t@cSA8qjTT>5@4jJA;&&7Mo&NN;VFbLm&2t;O2> z);;oE`b9m^@aA0lL{K&^0Z~vA<ltQTRvu$GARVR^=hEdyMH;CfT+Nzr9TVr<-c1y9 zF8xIAaasMO<4uRZN@Tj0iVMq!BjiYv**)Nwy+X(rD|v4scNHiCc$0k6xo^H7iB}|e zH!0qR<GgrMfsGzxPIyvZ&N*+(M<c@@OV}74s(6q4@I*duWKtZwmjv$<xUNJ!{RuD8 zbLo^7*qJM8n1w4`N0;1oxXz;aT!CsW@bhC)pn~|uehN}?($$JRzDp2BD8i#2g!mb6 z1>z)u$W(}d0>O3-Cl_H==;UHO`l2~tH$+Ca)wm-QrHI^5a=>ml(YX%T(OQ<Qr#azV zNk1_NQYW_$*bORksy}W_nRl8&;U9W-*4E)P=~Oqsc_)qbaAq?)EOSjTXiOU{2*)VG zxgLa^LFV+XE6~ReaezRq|Hu|1T_7;jm!Xz)cyTFz)B)iU`DxBsMpi5cjADbN5u9Aa zA6v0<N9P@)*nxD{rPu-VTNRt%k+e#;pjG-49#rGjsvS_{>Y3^Sv9)?5YC_|@R_Nqo zn$c>FPpg@NaHk?9dk}I4)p%ZW>fC;aA3kIudMm`dqge=F&n!U)Y72eAB95l&#$6DK z0w)rkOMxZyTNFsgYNydpdreq9nmTB>Vl)|DeK*I=rQhEENp1tW>z@YyN9u7C{zw<y zd{i7|(lnS*eEOUyAjc}mD;|&>md~To7(gcpP~&o2nqdOu(`u%p)lAW99`2ZK>0dmF zR`YyX?djF(RMBb%sWVh9>nBMChp@k}>9I(rUd<GC#-@rIrav1;Vevt;YcWGYq9$Bk zgG+p*qX6a^UvlAduq$gYf<D}dCdC!}DuqYEoY?Eq#LUT=wcO`!RPCI0B(;?d;#;y% zuXWo38kJH7AyW}rc@T0&#WyDev2-yD@dMnl(qY~?f`w?_ocP?r6YZ`D(0xU&sR}xr zKy!+n6Z7N@b#r_pVqC5qy@^8)cOrm1YC?n(SD`-%#K8*j+u>YjiS$&2s!^eCjvC?E z1Xr8X{axbF^Pwozl@MWHNr+I~kx4Zh!dmp@!l5y<A-p6-e4#~Ljv|l^A&9q5<)S17 zbOY-FiHtSvTB%%_;Nr9kG4stFA}SxHEPr&Pg39y!1<?&IXgM0{c;PxpxoW}1HHw*a z=5%3cqbv__LHuQNPmPAy1yN3fLBjP3d~KrY!CX+h??c@vEac}CmLs?zKBMX>XrNsX z9Wxj&T-PesuU)xDoEgE)FUa1Q%m_(7dsACV_Qov1d*YI<5ZN48W`tH=W0S$<8)r?0 z7@J+6T%5d+U&Is@ycYy_27xFOG`BUN$wjgtEP%U96t?{^H$ozli+KxJh_MRshCnoL z4J6-$cXCl?>n~I>6_*$-C)#%so?Hwk#*i5pjq8+hB5dUQloLUWJmo~_igt13M983K z(wqnbsFm<BDWS1*BBa?gEjbkxtobau6Fn!wkSl0Npf&sXd}VSX{AV`Cf@Q53p2adb z5i;kIGPCY^hjn@z{ASWDLl0#uBQ>aPoJ~KSqrk|1;7h$zvw?CV_%kI;!d+Vrux*qR z!A2bBMZ^>CqM+iO2nAApPg00|FH7#RlI(k3=-!=+CL-y<-<cEPoXcp%O&gO_|Ce$i zbidSg1pM#hM0jGT%2Y<fzaBi-Q}hF=w_1Ulh)@o!^A{!gcHEo@{g~s=<V1K-h5G+< zA_P<Wa|(hM2jf-wU&@Ja!$B+%zvE)`<O@h_?>vbrGQ}?PpZ{`BgwMLLP;89;wwws# zE+$VVX@50^5a9bae8Zg+VTjzx08PEn^yfPqk$<v0L|mnv6X96C<BrI$AucB(KaB~f z$XNona|nA=T{#hcz#S8j|21E7<lG9r<cR#GeCdwJuLPDWB7Y-(I>G3PMC9N35)U+& zU<PEy|IX0&pU;VKtl+g%yyqkFb}=Wy7ca7iZ(~+0BAyFKzOv=S<~!9q_-At>93nyw z(h`3C2P>h`t<GJ@iSUs~yqDrlkHp)>oCtRc<ZR3fL<wgB(pCb?87C*g1B1D%WgvQ* z`m#)fjeCV6<wx>!?rm2ZQsc+eoCxPh`6p`m%R50uzMKe03Ukby2yL8ll4F#!=>=}= z<%{fkUKORBMT1Ozyv}6KiBQSUB)(F}y4pTjn(y8(_%|wk>nQk_8pdc5`9TLiHwyl- zg5OT@pFfc7*WZ#8Axp4d$CO?AK!3va<wU5wkaZI?C&EO2&Jp=z45_wt9lb<WRwpT^ zzn1gu0g>h833DF$6tQ_usdD}cr=0dN%Bg;y+xlCqAEZ8aL@B4?0#lzTC%otIGmglA zMac5(w%(3<6bt?Y#s5bX{LzLnT15VZ4*r=@@PB=d<v&#M=j~5zt;r629|VgMk<SW` z6_LML;A`Rk7WG_2@apPGEGNQ~&&vCxAp3hjqWFva2{11bgfc~F*v~CSA`$rq3Ph1Y zlmkMHS3)@v9(a>0v6u1}gMU{e@=p>W>fnSEb*8yN5{bzFV+M;cK@r~X=n^BLi2T_C zak4^$0m0%V9Ff0l7E6(&5J8f{6_Gz<pjgLf5&8G<Gq&_&4Vk<#h5Whc5hC6*Z`(Rr zzpoejG+~Mwk$<#<eQ*@)eFZzH*kwNK4d>c&*Ly}NI;+2&pRrZ16*6PhB_jW=>8z9W zSUgMH_V8g(HcZhX@^5mmua1I!kzki8c0-519Fc#uVD?hX@xXLP&3}E4SiNWw`HT4( zTky9GncaruoHg>Uo@?u(s}FmEFhz~XzskYBC<=B<k$b#iFKzFY`*6b)Eh2w!!KR4( zmO^H%wM5N7`wX{XSH&Lg!+yV*brLlv!mIp@M}lV!nXMCw$Uj}Mm(H<uk`C;@o)h70 zfgPo=bJL*?XAefd`RCfoipYs@YBkrpL_tQoK@y3`4+uhUML6D#kWfVag4bAx-`=tn z^z%MymlDZ|aJY!@mh%4_{2B_M;Fn{M5|En|<T^J<A`$sbQjH#paHJa{p@{rSf!GB9 zoS2ez?Nk#9M&!>Gh?f;&1|Se7!0X8WN=}3Wp5o?v4CAD+e_Y~U&WW(_Nyeq|S8zXT zOEvk+IT5ZF+)0W%o^k(+IT7wZlZ}TR$KF6Q-9M2N;WQV_|5{Fj7t<&w0)ou{i#ZW? zQXKmZ^kwp!#E4^0C?~>`XHa{PJA@+QF(j1n4R=n2JLFCVXwrn{8ot9Gn2Y5hd0<+} z!!!7f+XItC4;&B7(M&)^Qk*}E>?9bjoCtg3j`6@G@g>ice(g_p*#q-EU%EXojlgnw zU@}qWu6bZ~KFaS{{p<ESHhOQoV}Cv;!c4&{QM|5^c)OSr;X;8tN+Cbq%bvggO*s*s zk`ms-2q1=L1WNb|IT6khyxSD-;7B~lV9<P4%C6kMvUWbg?bKBv>)SX=AR6?Mm^l$% zEoAdU9vJG&p7|}UmM8Ob?rnD)QnQjpbeWX@<zrkvjZdPY0Vv;}6X7&rj+qnTaHpKk zG0M4F%E{Am8uyGW=j+o=eWG|^7V|TntG^{=9uLgEg1`FTc0DFW!N1EeM)Sa2?%-b# z1^*4x{}sP0;r~535#AE)Llk>yYtoH3C&J>>ST`|qBFy0DJb!=GkZN0tEz5dZ%9-=3 zt)ok$lrvbE$pb@d5gwS{PC4CUl#?UnoUP^jzDHzzHW!%sMDf6^;%7YXUM6H756q|X z&iwL<U6042;6G>>qj_L%b?~o`f`6OfKcM)%2>)-(iEz8XXDR&WtpLA^9+=J#@_U=7 zAX7ac33y;WFK2`uRkjw-@gOAPfq6tA-cpEt0KsMi)kz>LWxGli;Wp*}aCe&D?^;fT zxgx~z3UaR-BoPnHZG!O2Oj{F$ZiIw9Fg*q06@}OX5Uh!WJupS$NxDuU7Vk!@U?(TS zqEo~=M)SZ_@-w#d6^6`SsglofoAj1;ihY$2dzdgq^}rN5*nOg4R|xj&FWcJN+lSr8 zFh$FWurZ(N#8&+qzVv3L>?7FcEB31auTH8AQ#23E0}gg53idbBWIM1+BO~8A!2XLl z5jF|t^NQJm<#qBFB#9tVb0Vzm$GXVFz`c?$y*Uw#y!{n>MhfY|!G1=VqIzH^I@n{P zV24ERpRgSxx;V{;9W+eQJTONJHhEyW2${zNbCh5|sMs4?dgWe!GWYAK9+-N5#v{Qy zhRp8Q<bnC%0X85fD)wYx|8)<{DuG>t9Sc!M4vD;r9+-EYX4y6<$mSL<kVHH%;{@SF zMR?7PkdOx^Pav*Th#LT5>{22gm`dUAru@gU2)mXO;ROL%i;WXe=lW#QgaJv!19PPy zJf#TFyAcxdz#J+N7b(OQfH0a!&;yer5C<y6A%H-yAD73mF?<~AW^+wB5w50d3gB(g zhY0?k&xvq;8F#_=FwBbLM<hYucsUWe3dh6B(T6zxQci@A?_(hzRLBhoYK$wy)53A7 za?Bx)a4E06|6ERl0RnlkLS89Cm~ec=nfY@f{6jd7QH~Q>h+WBvFqy;i-H9=4$VCt% zC&D+q*$mpgq(7Sz;c*wtF6Km7Dfu=3dpQw?>}Zih(RQw!2p6GU|JIxc$xSUnIB()f ziLgHci#WaJ#T2TEFnJC%`U@!$_K?nT2{xbP#oGT5^iUljd=avAB!P<boo!fjFTWU_ z6y)RI-5~DBY~$&V0d$)HeS~ckk!F$rxz-fBkP_izL7Sjxy%{aWSpX6#&s#UzE-Dj{ zJ_@q!H>#Trl6XplQw3-%_C%y^RRV-C)e<!3|9nb>FD-85o+|&w?e0d7(o=?bwMpS6 zj|j-m7=J_wFL*$5Du~D9{h?-w0(7PTJ+DBQ2$0h<yYjX93k2;#MN4NiyODisP!fsa z<6Un7^^^_*vaf<H+ve>l#1m1sC_w+2#F~B|n--#^2?B(klIipmj>P_-Oo?!r$iKJB zzj$jiJ%s`#UD~9ck|7}PVkbnDaHj_(@stQF!mP~_1?nk4?w-;W<wu?cqr3K582ez| zSAuq&qJ6)`-N;dT3Zb~_Mm^;*0r_E?UAO5Tki=6W{7ZnIQJ@P22tB19LCpVGr9}Aj z9z^^<SowFQM5sBQCm|XBln9mfefu!}6(|=+C99sW8>8c9v?%g`31P%({wwVJHo#&5 zxLyHP;A7T$n!l%zN1W!*u<!GE{N;jigknqq287t2B`ZpQN`$ZN`^>#oxPN%uu0pYJ z&tWP!{OEYaOkr`K=6_6XxlZ$cf;+C12nPs3gc4iY_iY`#DiXY<5`6dz%fG4z%O9b{ z1@?U#psn=eTNPk3091)nggiotx7qhu4V?tzc*W>1LKF*Co?nT%_I>6)M!2_D*h)+j z?tPicD6zG$xRto2J6F-AL<>azln7&R&zlnA3g=Eom<YVGt?);VMg>ljhny0jueoj} zCBgv)Pg5f7=EB$kAyNEL7sj7XiEs|uT1;}|Pc4$fFqYQXQTv5IlRc~%)dug>C{Q-O z0ixjFpAz9P?r~YiO2?awO%svnd@3$x3WIxu{NGA`1d;#wln5sZ-cZH+bdwh^jhfc? z;g&cl489MsG1^D*!ah9iD!z}k#KC(+@D^epL)4Q)c>l$e2(OfI1!%ug3S6=g1;$!W zL`#Wqy&w!xgoz%6L{cIgDG;3$B3~eUN2Kd9nKFm#hR~6p1im>uoakH!&xi3*p}#pL zf+d}5Fm_i&hZBBmMu+}Wi>C|1fr`-2gOJFn#a05b@?l$uWP!lkw+xm3zb_@iMN_zE z4%7-|ZfHiU{(J_V1fhc>Z1};AkVr~|Rg+nW52xB%eL*06J(CuM|I;ZEW=lQx)OxI0 z?^Z>W#o%b~G?=FNqXcB}L$)#=_kbjx65&Vz8lynP0_4*wEuM^4Gv$5H!=3+^Qz8sG z64M7siEth+eJK$ZkHrZ3#HQca*F!S@iIfPvCvcyei5)00Cnq#fTg6!1MoWqCdnqGa zs|de-??y-@CBmBmakxUfDiF<^lQ=06Qlw@dV_!yUHi$sur9@aRVmz%JM-ay@r9}8r zAciPJ<2o)hc1nbogyU%Cc%3-@)|3d3ND&8U5&uFF&89>!?fMNii9~;$z!g6wLR(S! ztIG0yBNfz4N`!-j>vrXO4P5b4BJ>oN0%f_A3u-1M!fC>_k8+*P1;tB=aFMXAhH)1q zbmW4XNr`ZSa6PYFUw_9n`kzmUka-us%Y9VvZV)`~1kFFW*l;H!?1a%3g?;y}8zGU& z#R~#4M<JdOh~}-q{})ms6dg)K0<GCk<tvjCVfHN;3+B}Bz#t%52~0|aPGhJ&vTh#F z%`)qLyIBT&!&b&lVDK#c{998Z6nhaNRtBwh>{JKGOZh$B_YRVK1KjuarhCn%L};Wf zsL)(a<`k+Pj)5DQH;3^bYY6@nhDrzWA8P>J#0S&(PhLlor$tj>mW=b9ibS6R5&6+< zS_GZgm-s$5(gAcs)=YdwoW7ZtUqibs1i9tYV5ov74j^VR!rn5l{?;diKTCfxzF`6W zieR@|ip3KAs-n<$1zWyEqwhG#b`^M&CKQA|DNHS(?by$V!el0xR*2OcvJy<Q^B5F_ zJ_cDM$f}u4(h*EWECG>Cg*u313$ns5DD3t<lt>v_AR{Re9|rg9E7Sdy>Vu>ShL-DN z*dp{b5&B|Y)>l_TfwLOzj;%RFu8y&@nAsba=<v3WHDC6mCg6`4m<eA~PcCQmw=5Uk z=hw-n@-B8Ao-kNdF08Mv<hSA;#X1pKr(5a0koo~FlS0YyJ3=`6avuF{q_V656#l#f z>I<bcT@k;45-H#oEnwwWP62i%^cs9WukP~HqvxkiS&;hr^3vra1BgU#YDu5yv)W%w z1>qu)(uG^zYX2x*v<sD|Ln8Cx0lK7~LJgSuxIxKyQ+hQe={Z%jHc<r`06`GFi;ZDJ zeNZr5TtoeuKhtUUa|SAX2GOU^G;fHgnUlI3Ri}=xpr%8<&J5E*V@UF!D_H0K6?yS$ zmZZuf30lcWk~@s)X`fo!`$5ptcO3CuM11-%dOLjq8XO>nIRAjMLTT%aa5bId3zsRv zC2L{b;tMxT=s&>jod~z>ORsS8+PEgU2?}d}I}}C@JZOB-Dk{PIGa8K<w91E*84RT# zQV?2M07FA2zx_ueNEv|wuyCs2z{z}7+xW|RSpHhhV$DtqE6~kuhY;_OfomV<&M?BR z<yj2(5i77+G{cE{HyACM{_|e2+d>KfMhZRKj3DTdGWxz_t24BaET0vqGAMPpt~3wl zNiW=D44UP0EwbL4$U*uszx?=uCENeysik4+QKdDvw1u~D$0%FHWnV=46@S4!P_kdK z(@hu&FQOYEHYqU3K|+)b++e5{k>+xP_Y;v=khS4*^U;nX#ZJ4v$7WKkE`t<!n^y9l z+{3Y_C(Yi1iVK%BknBjBpkz+9dK@G|6;4<34?hRFt3VMTGSzAfysxGB->?ZL#gFsh zNd-2#D=?D$fP5dL80u%sM>|fF1@8sL>+Zu7`65%T#=z?<co!(%n$M^;HU_&j@OTD) zFuGIr#<Bb09Zq_an?2NK1wCtO#4BAzR*dY@5@TJ-M0HsbBGX7|LL<HheBL#z;1jjL z8>v7Au`Q8-z(8JHWpBC}E3>a4Y=xU&RGR5Q$jLY6DGtO(SF;e+3h~3IECk-O3@Dsl zOPmuf41I+gw54gL96SRGSzW2mku}449l8veJi8d>wI1?$U!O86{hN^2NN+nz<+x1b zFdB`b49z=hlySHqG{MOy$~f4Akdt32w%Vl(Kg4&^1u7L{^(s+DxO^bYTew|t=n{0u z0p@xYbg~iG;&7EoM{Q}6qor1)liJd)pb>-B2P&G6Vc`9sbuy(Odj|$2S#r<*ANJk^ zys9Dz8zzJ(Dw;TggNkERR8U7ziGqPKAQ^A;f{1{iq9`u74x^xqil8By>-9)nqEQTF zT;mEZ!Kg&TA_?dy;ubf=J%}hW3W(ePR#kW1KIfjB+~~}Fe*g3FJUltKyX)=h>b<JF zx-bVqT!oYnVl(}TV}0fbkro#LA=U?lcq~*a=(5ewkc$X%h5yt-RDGZk;<kctpCYV$ z+ijCN^*TZfLM*$InHZ-KGX(;Is7JX(TV+-}9<P7Ildox6O)LVhQAB_lq+~9Kl-Ei~ zsVkJyWTBJ>h4PW`^IEAD$~L|tg|w{FKsT!rgc}uMX_H?l@K@<n4fWI@#2A4Xq7c^z z1cXwCav7oY;39gx=ubmQ75*5ZR8t5Z(dKw8SMlC8hm@Cch?z0)_>E~nSUlBm3eRKd zd8T`wOfE}zt?x<`aW}Xu-SugF@>IP}ocQ;|h|=7CB`N1>`bchV?#lnXh#SD;*II$! z@s=yD5P=8#;i-Z!K@mpz5Yp+&-2~##3eiO%(0xatT*+NICeJo4$ey>fWGNpwtg<Z$ zlg$MJw-PE6=~+wOM49qORAtXjL6I*M4=cqjpg@;@Gvf6=nA}{G640ToaB@4=lwWB_ zNp2Os++2!Xg@W{=!r$JK+Z*srda!Il`YxOb-=y6RkHiP(JSVeP@3$kx3p3Vyg0ZH} zwfyV^uH|l;<CAZ+v6lZK2=748Cp=%|LrABV4;6^p6yiXENLkC$-TVV~u%9)QP(Mp= z!1i}T`L#e7ZRm!Rus$B6>*H9oJBE379PF%=zbT@1YL}i}s9U~@uRZx|35N39v5#n; zIgb@21vHx&1<8**ZRd^Tm39Bmp(ha$9{4&cLD!7U*U(RAk7{DDsU$y;3>a%@9vet? z)nd|2wBXBe6QUz6C@vyiR;L}zo`tm$g^jufM**{oFszGC!^`^k4@hV>{`FvLD2+PU z)z>FeL@3J3dW<PV2SAz#4hBUngku3%7ZBM`_SZ49@yoiDDBH0=$+@&5(=4(hsH!fb zD0*0j$hZ}e*obOkqB@Y`P)^ZNQdCijD#{f1iWA5cK(0_aEv}5FtY$DQkk)}i0Tbe~ zk!JzXOIZ0p0l~-RDC1Jif|y^hDl>R$;no$X`&c2hJ<i37gmKMdL0;Aw+gp*e?4>c6 zWN)}(36}6qFD`CXvBjpJ%9574t3xK0%<Fg{aSZ5am9BItit^&CR210}njCFu7$#Pp zL;1)~l7}|Df0#q<sw3?m5Ql1wm3P7i9QPta>fFV3^t;`aTVq1HVSE?7O|w<;ri|<v zWAF)WiHZKlmbFO#i&3^^&si8-m?EZx;9?76%egcgzloKcOc|F92RZf#G5+we*qlu) zcCai$Int3ij4Frp+i*C$vvPO~KAA&~4&^X3ri4O$9FAfRhguHl1FrcSVUj~nnt~2x zUk59m(&#@-NIRNFJ7rld*Bm*dunB);II4OD6{jEp6Drn8g^hNpWghdnKoI6B!YMw4 z{4tHb?O_<iz5;QvLhK?C3G-k=Q|CBoNm@)_Ejarr&TB7IVOp>;>Pi@ep&e?0Agsok zTEuaq4<UaN_KWq|^Xd&3RG1*dPi8%?5JLnaQX<E0mt(J4n_M$V9%r(Il~WXF3&yb^ zK${idq}Hh!x}~^CIO(Pci~mL9un756YLf~RgqS7}Z(}Vi^0-PM&~ewHA?|{`Ci+4F zJ`s}GMpXv4QD%~8;MZ4po{rVzQqwiNP%|aC8`e76u<~PG7<?vB9)aza8D6Gfz+~+^ zlvy-XU?olcG2&IO0ukG?H$`F}H1C*)!1x%9_LDG>Pr<e%(N`*xYeW}owy&IYGOwTJ zt1u?M)Jk8eaB76k8tfzpmnp)*K7{-+SS|)CH3;$MNzBAy3i0)e%tWG@r}sp`0izk` zYnW}MX76X57W#^7fup|i<tRpYL=n#PA*5rEe?TD4Rfs(VBGE{Tr_hGckqM1rNgKwk zq%eCZ&O6K8mLAeqbhn3&Pkp69I9YXt6-R{+A%BW_;K1qlL5S%BQK=9k1j64}dZf`; z`be6tXvCp?h1UbA`wA8ifsP{2j>KzZ0Z>O1xYPLC@CZo`3WqiB)0bN@{e5W*U4X7A zOh#UTUhpEQ0WwiR_V<CLf8yq90oqT2K5h*5g*qy-zXj0)D-;@>3a1O&`<L0Wl`~q3 z9zkUz6sK&|DUJ}33I!SJ1Igzq@OAPOKpTJnAswqgTMCfVHMky=%SN>uEZZhQ%TTnZ z8(Qcf#1f%6Wurdwgn-P41z3iRi9V2g<|nCaAwcH}(8UV0p8%n!l%eUHStUn$K^6W; zFQ}}RkO~`O7M2YqwKgPHQ%`A(2Ffg1U1e2Wlf*aDAJL#A^)wC?)r=><Wb(ihibEj? zv);qoX_JwXXB2Gz@*X`ATfOT`enPy*{W|8gLwqzor6P(sCK|t>6nStt;LeB-PKEWv zxI6<ID_@5s(fD8xj{xzQ(!n}c7f(rNf_i2Ix0#bvuCKk&9v6engijytNJ@*B#Oxxj zB_|8QPKt1&ixAD9($WMa5P1Ue=49JSh5&-w3m9NsYSAl$bxoGuWOdarF4)zIxp^@a z%ydoq2o@|cSw(qacZ47mC_=4^5N&y~5{Ms<V<vvO)D~<KAWXqFpu-K$E?P3UWG#09 zTI8iOaSau=9#G8PnJoiCXu*OdW*u?JxSb%Jtq311BGDLxX#NE)O<V%;q7<yVLfi=m zQ?Ru-NPvQU`s=2P4@En_40?VUF$MxT0TtL?q?j)56p#`H`DvjGlKymYya4r6peF&u ze1RpXI2J|vHfER8S_9gaeS8sYt3F=L6+Z$-N;8oeu@gjb8|Ip>!pdU`)zb$RXwWI9 zh}R}^gFIhBK3PD5vHYYz*IXw+dn(XO0GaZ$-x=2_^1i+ZSc_RUmr8+F0ZC*tig~en zjp8=URZ-!lT%or0K?O#!6m!*<0y0!V8tdH&Fa5ddInmb<o)l~<fQ$&B^(tzJ_Fbio z#>z$_V1Z-V%oJW014$tI0ivyLc~&0Fl|5BKHa_owq~n(7PC@9e2sJK3T5fqp3&iG& zY)LKx1eeLU<w@>AHi9MbstEHLr9YTiSfOKPI&U>jjItyqDahLAND>BwK7wPWI~lCN zynV1B9HIyhxd_qx5oNwr3{8|lh_8=fCf5DkN@6@9j3ibRWfv_>?lRzvBW#yB;}nK? zL?QNKE)sjvbS98&Dav>SSye~EFd$)GQQQfH_N4!klI*Prvs?stMQM2gA&Bb);$x`x zrGcLW2qO&kijv$%z!`+Gh^*AyGG>oqVN@wZS3qF#MC&b_ZGjCe>)RhXw8Li(pYw>q zQO}Hzpc6zI-VSBY!HZG6{1T6$&Ai;QI?E-|_`S3M8{&1(btt0oN?LOb!4q`P(i$_0 zvl26k1+@>Y3A5)cipI+cYX~1gvbxhnL%dD|WD^bXI&|ezEYZH-PwjWK*DnJn4z@?T znFfx#Eys_oka{eZlIEb!=mqPuPg%G=dlW2ylxX`7ID)qzW6krC;zb#&C(@d;cuB_U zF1+}ZQ-oe!gnoG*D>vdJrorGhmYDP^X^ooDb4)#el$ew%Q}l=YjhpC5+-_p0;z#Hs zWA(f>l#DPlMG?y1#dV|u<z)1cv3l(n$il3YF)zXoXG8Oc&r;=JpJ@Y@Q@~Y=$;!}z z5h6nBqF5aZEmp(TX0+NdFBh4ilCRy|!Rq@Pkwb_Pf|t`?)+v<GF+y-Kl<Xl!h>ili zKT{-(5F88&V}xJ;tE1+)SUIic!PNTim8mcz#A_7Yq7mXTP7z{+=$<I9-v~i!bvWHX z{$%$g>qZ%w5E4cQCxOknG|b4*K4@e(=owTM85z8+`?y?ko-Y<^OmK1$HpB)NG#)s~ z3^Q^>Dco3)#L}#%i6wh{Z2BfEZ9X@Kwl@lGR1FSlsE`d6_ee3%@ToK;=Llp?y&{>6 zIy@4wXpMb?`xTBeQw-?nr_xc;LQFMlYMEuW$C(^$+hG`-2q82tYu-jJ4J$M;X1MTL znpF;4Vy)?gbYPStz!m*eu9U3FAv2}vA#@xAI{K+}DN3`el!i63CP!NuhKZFgr+gat zOag{SXeP4W-++R#wT4AW)|!`)C~<+fxQ>1sTgYuYsV(Gse6lTsqeE>Wp)n;C>a&G( zqwZ1C83kl(4So1nJe*l1YmIcISa~CJ*a-<~xG%1w--g4NyDEo^@W~u<bSQ_RF(nl0 z<FG4pm}5DlkKbag$&h29E6%kO?fM!tLp$5kM{w!W=;&~0s($_~o@dJxVXhA$9c#@M z0x?)2E)a;s&Lcf*&Fg}br8s*rj@`Zl_CT}<3z}MP5`;xK{4DE^kDnxQScG(}HOC4B zou3wnDuHm+Y-w3*P7s_viZhCF?EWXPX`#XdO)XsnVFQj22q!!G5Yn;MtT>Y^_X&k~ z?Fo_xb=<jVh(@p04xb3A#~-6tYm|^$8)9@;4JA!BBv!ME(%_Xf`V;461u)iWeBCCA zZ<hF8@~evflvhij3@_|D2}`wH3iQf5QkU>*s7qoYLj;M1%$d7TW|cJjW34lk|HvXp zn|xdR>&zU;;`s!fNF@B^<1O?a+E`M~fetiMKxQk*-+UnX%&l+xkOF910UD`5dkava z{TA0zk&_j?6dF|Uo_YkAt)rqfJ?3_WKxZPB2*oKIDX(`HkVR;TBA}anAo*McNo5NG zdi5{N&1DL7v;aB1it91CY&7=<%eJ4ewZEeMIG3BX*)<0G7L|=qoU)Pf`ZHnab950Y z+fzP}eC8*qY#~6E0yIm3E)*btCu_z`&{`+sbxI4Jj299ubTVFi#Q4x5PM}IBtCU4X zO)p3Q>gpc!$LTB-n=Et+4GMkl)42+tI>XBA+BvOs7D91^PP5I2r!mMy3Np|KlF!^G z2|Wa;LV$WI(D#orH*RO4A}5!PLW5<yL(twGXUp~wquF^Qq_Yr;Q#R@>BLw7D1v$$H zlFwC;RJIVHP69Mofp!%jx3f?^CYOyugJs)J(0)PnNjrb#kybhjp*Uru&a!kY*V{7+ za-9z(pW9VZ*+PJ(3DDmaXn+8rYYfFuZ)PO3xEzZRGb4?s$pQC9Y=~KuHn2WG(#UDq zn7RE{!s}GAA4z;&1!2VaVQLHsJo(_F1_#O^Gf#fWtb=`Z4g_J=is(9hkWwu@iwj`s zx$8W(^l;aXdG+Ywa0odHL{XWXqVY!}48d-%kaaB$0`ageDLMu8+PRG42}=1;2CF0# zHQV5Q1&U3seF_cMer-Ni+;M0GQv0tyMCzav7NDe=$-FNnAk;1e<a!q*n$P?s)jqMK z%}9Xu6`)0E1Ojv<fcPua6x4?4ZbBa}=Q)bJ`avqE>A^vRP||cK2A%x`q`QLL<AOxf zneGJWqr;e+cTctDJPAOioFSH>HcWlJgvF~AIfGeDVINAG`ozAoM%e48AoCv}VX29T zTWwN(QX_QgliWk!B|!g%;!^7KVgQ+Ph8c?bgtl7>O=`C%u>@~d<eh+=n79HP8!9KE zD0_4`+snIHK!z*G>(wqu`m@cx0<?_+#R0_S1WRcciuRRbJ}*M2DRMf78L{&VUSkOr z421>-^Yw`=m}v^t&Igs=RP~^M<SWRt_mf~OKj}|ZrwPz{lurtF5rB+f(lite5!udB zhy$4yyHP6UsU>-^qq!w0n>~e_GZgBR``SL$tsKn)-c3Pf`#{p4>dFO(&S!~iMgqvl zCQU=pMN*)f6=DZKIEJD&OaycCxL6T|YP{Eh3Yv>TCW2+?Q0EFrrh*i^AkloDwvq;p zz(hbmy9>}WD4)pYZ~*a_H4i0OUTp+h2W}VHUZ(V$@1fGD-KY&S$Ds$aU=CEMIWAPt zdK5BqkOAqNgBausuqEX=*9Czi5}L@91Ve#3WXY45)dKWS1=<}zMlflbk#-%#yquyC zEAJ-Rs2QmZv&}-`W(S43*@X%klR{=28il6_$jhUwY=*cXK5sCo+%QLZIPWb$B?^=U zAS0VJtx82lvTOz_#KOBULWtSMSe0gd7_=%ii~WapUt(3FrJh)os(D2xi%rDAszhr% zV^y*guqx5A&TmzU2`caT#HvJC#;Rm=yw<8@6Zx!40~1yyz6RnNmS}MsVpuZitZnIO zwk=(Vv}{|-rjO9osndAUpTfU8o@KrF3AWxx{?na()0@KQ3dn~eEy(shko2eUvjwO^ zff}oro5ZZwmRa~5K|5N}E@L!1fu=VLcNdT>1<CV)q(2M4JB%ege}om%m$RvC8-Cq} z@qIzNP|;>Fnw^kCv@0|h>o_LIXDbAxr-F?3fuui+9xFhrhTF2`2+;3h!)PwHdo{d^ zv>V3CT-sC0hLMe;@S|1~d$kDn(0LpyJs5k(51xTbVXuzVoKZ5I;=nq0KXF13uVD<Y zGKT|8dhjlF5MBLbf2`!1ttj?A9b!N7FtT|NPNtX}_`A5SD@fRCOCK4lul<~ob>w7h zH{tK%Ix?AXGWy6^{oH57y5D0?hgm#EvUbVZch^;N81rny-s3RG2>c=iT(vj?EAMYJ z0$=@}wV9D$oED70qbXsVjKKRa#jh~}uYFgU3Nr$~Owra78+sG%VNMZZ1l}!C-2ask zc>g<5RbmAGCztF0yb<{JnZ%Mc0#AL%O8a+g1pe#}W|@0Ri$>tb-qzC4gle|0YL!)M zF0TWOZTf$11nw%O$rT2fl~#?wO-(4+@7oBR$1MK;$O!yngs1;)huA4{?QLj=x@HS3 zw8+#LGy*>(2rmw{2oL!X(lG*GDiEa#F<u~?^_4o;YU#?}D}qy?IJu0IVr3O(1oi~s zXB>o+z1YfINgNg-9V7730`aUu%oGS`L6w#fc$nZ^tT@LrPKu>em=QQf5Drp=?R^O8 z7=izF6gQ8ra3)XW@p3uI<NsPC@YtW|Dt#qs75)=O;9I-1cy?3q%(<n7-jk#lktN-6 z0`kt$R>tT0K+-n?cNCx-6=-(>O0?g$7=cgRoy&HlqP=#r+Z95#DL$2iT!HN(AU_w` zvfbbVNk=O#KriJoH#G`WC_qlHYJ+ZKZ(-|fMca52H*40iEGJC&=u47rLbfR%3QKz^ z$m2ec^o_t30`xYzt8}t+1PI%dxmZ{myVn2pM&R8=x3nHZiWKwe8(Zltw7hZlhNKXB zPn0l^C`f-FNcwyFn+50$1^Tv(xp6y7FXW%BJ*Lp0_PAWoc2u<c7|qTbA)SR#oU)M- zc&LE9`d2HU(|jQ5@9DP`pi%|uDnM>$p?!C9*}^pATM63XineS<E1e}|PrrB|_uuad zZP`kEAnEVvFBhPP6{w#8{Vw+OZ7>2qzXvw*m4koxM&KuQ<%+u=omYD8OCD*2%`${O zf<q-uuG+H2c6*_K9Hk)Fx*%;Z0`Db2Kch(sH-7;TfBjY?@Oe9PIqy;APp+qOnjV~{ z5qNI_IaNVsyC7{a0>8f#bF-rYjRcS>=WjCt?<XwIM>i4){urlnw#^9qnXq@Mf;{Dd zMDx=&0#^#q0Sa^>fJ`}mn-Tbl{w%@Q2iS6U26D=c4NdVOv(1G9GDAULxy}Vif4136 zfc~mL*8qsinVu1NufK3<wov-NG9z|=X^Z;#i+&9CY=ITb4>2l}g-UO#x>rChQIL5) zko2djlLhF{3UmR0j9}6<0vCyFzrevhY0>*KFLtBU79;SVgqzt4^+9Rdr@FWES->YM z$Q?eA^ryNq0oq=HjsuX9O`1mF3#33VqxpzzwgbekGXg*OM=n;eLM^)1flAW|e5Qc> zMM17~LE2yh?j}Irq3)$%c>v-sYwK;<2z-mkwnpi{yM{{hYmC4Lb!Newt56TRP-z;0 zzubXAXq=GpoautJ!3cb}0KJEb7octcGJ;9d2;6mV=H+&Uc)NsT^J|R2b;8XMg}T9o zO4A5DSwOZ@kRlhP4MyMt1*jf%FS2O|AS0VJjlhHUV%bblh`Q+*A$&&Q+ZX*mBQR-K zXovHgP7SY<gC3_HZma9KVt4ip=q6K4;SUK&HwEeB14(}hKV5)c>ub4LbTxC6m^#}s z3!foqC5kqQ(b_f(?<ODx3ew95lKw3GW^ZoQ8~fO@eSQ^{?N=Isn*{9vMZ2BR?1UV$ zWeC|Y-Yg(zD9CUhNcywr(E_xK0&OEezl#myuQLJ{cgEiFojd<SM&My5{<n?5zf9#Z z(q{x-BVj%x@LL?_7=f2iK&wXJQk>DoP2kDUl|}sTsCZe^pR>j?zxB5$_Bx&vSrzfJ zPNx*s>>G`(qI<7;?>F)CNIoYswqEn{2wnCi3bt&?%Ohin2`_8gM7Ck}-LLA9XN&gT zmpDa;efNk2a<YAQ!K$R|urscN2<eFvyv4z!#yDG83R_OliD(k_aY9Y^dk-g$#Ev+b zM|QsBt7gX(mqBwFK%9l*y@vUUF<vm}Piq)2O`#%)G1uon^M1e$icjd6aOx?ybq3)z z(HUE3;|gX*SxXK$&u03`9UAyfJDv2Go9=`9Zpxl<&vu4>C|Kkxq4XgaF7f6FdA+A4 z5nMQb1OGha9+SK|@BU4U{6~kn$1M9ZkFp;gVn^Alu0X*Qgyu5`BFxq{L=a{x!Vx|M zwzahav5i2StPnq5&P<R$YFilcHSfSsVUpZqjuV{Dit{AnSP*iY;Xv#~5ULb{uCu$4 zzk%Z{vJ{)-BhMcJ-<U1Yf3iQzvRvu&gdROoi&2|gj3mdHUkc7(#aVk9iNk`BvvP+G z)X50FYH3{NKPU*>D8fTNg#1D{#%u-RY=LOR8ATDsc!9taRi*|2aZ2gBg%7$gi^e_% zMJ*`g(n@(fkBF6IM4-d_uIn<sjfpEGjg&+kVoqZMuapC8cx;Y)6R6o+XPA{y{>5(1 z_)yYHa^cWnHG8P$ae-t9Z}@lx!@2@=eB+b5JW3VRpAX)Ot8+({z*+w=)xc0x4Gs#H zdgX*-8<eSujso&(FDu5~eIWUqv(Ht33ZUmZGB>3P)HIp7fdtn<H0(ay^-wCus+@-& z#G4<+tW_k*hLUFdp?@enk9&@c=r`J_Q#z6ng$8Bx;l9k(`U7q81`1c<uRBoD2qhq+ zI|bws1^MYxSJ3&KbCQfgfQ}cSGZg4a0YYi%(1(!`?E$1QvU&}XJ#2{j%gaFsBD&%a z{lmpw4)Ht|p2x?Zso6k=>?l2NR4oL7R`>B%Y|Q0Wr_b2%FCA004LUtARU2Ho1<UuN z1FU>Mx`aey$N0eTOxq2&4Z?L5*{7xpNTq^Q`arCIF^8QLK=}eRT!DrINM4=cYa=gW zz%Iz1y`&&}-p}Z2R733wvS-on4ZHsw+fcG$VycEz(Sr;6J%(TzZoZ#H1x>)wrw<9^ zUciT=mp4pMo=}u00x0?1{tS<nr!b_Bf^?1|odYC!qM&32Zpf^U^nJM?yPS)LVp(Tu z6oq#L;ki9;i=JGfeH39I=0!%L^?{LSJwM5lsue8iz)<gDNEYF|H!;yc*3--&eN|9W z3?Nqu$ZZO8n-9b{6151FCqP3KXb6B3>m|Hr)puETISn3oWoVy71pJJ!U>*_CZm0Cy z5hLmescSrIn;Mk2Ldyjh_XW1SKnTa7FYjli@$$u>FW!_XLj<SJq{HZ(+YyqwN>f)+ zYB;~Z^0D}F){1mqF0U5$ZJIhT;zbZM0iz;2g29>dPB4S=Z<>1O4Ep-@*`pU3=SFx} z!KB;117;UIyY#eamONkcM4_(X(il%~6jja&<#zo=iJHc1AhxFE38xg}X;eTw1$o2= zlKyy_DL{i1=nMh+?c*sssKy%<=7@1%K$XWQ@;W?$ijFlj_p11fGkI|ax0shOJxKq# z^Y5)l)g496O#T-ExmH0=@PYXHPojE4fWB+T-26p>wiBQ>NR^jA#<RFHOJVcmG&}as z>9n~}$I^4VFf)%~uoBT+HK7I3&{|X7s~NdmC<uR3gd=<i`Gs(==5P@Pv7bQfuMj`} zjhTQ%Xl=tU5w*Ow!TvmCVZ+aGnx%+1m~|K-aU^*_FA`4f!Vo3mxJWoLAc6izWl;yS zMjTrT!dOM<<wM9Xgo9a!i!g}AP^Dmi+f^afUTDQZOK&5NDtww{Of^0sD|8bHfj2*h zgBQ*Xd_A1jFj0@aM&OLTESEiw_sV5OW7apu!&J?9LX7q9J{V7f;qBBIuc(*DNGU_q zv>CmH{D{WO=_elSiSY;IGyRlrC{=`0t+T1<C#RwhO0{VnG6*<bJD-YamZ|m({wNM} z)GtR#Kp7gkxN19;0`RUaWDz)&e|+SsFDrN=fGhmiBs39Tq2rww>OX^GCFkQ0rh#uC zwi<xKW;BXs-<0Kbd4r;@VuV#Os{$#W;1otN(nQLdCa?$OI}*stfh^B(P!wq<ye^l! z$c;poa0e$TM!U!$gBnPXBafhsK=lDB3_(VH_2;DB0K7k2OY&aah8t3E{F2su&-sv* zm$i*ajj?r;gnW;DA`Orgd%jx3zY21;hD?$CJ^7i-t<B4t@(_!QAGlmVQ8Bzw3qN3z zs;fzL0;gg@p}tYv3h;Fkry1Bs(sVh5(hTcFFW7lqE@7yn3-Ea!e-7-0&m2j@i%jg_ zBd?OLxa>L0BlJ+_YsmKN2Z<Z%m}rlU2v|u01)WSt{Z@?-(Ux3%ejBq~%GhN~$^)+F zN>)rd15)ItF+Xl^1vTls<fk#;Mi^4^)0piuq3s+*0kp`-dInrZVmbJl%U`3&ons+= zauwmt%L`BzIhmRFDRM#g{;IppY&*j7vbrSFQyu=1C*Qm+x8~Gc@k{D()w!Jda}<-% zQHQ;S{tXJzI&9!yT8Fjr)7IhB4<zcalA@#zZ<18D4sYgEfjYd9(`X(3jnddU9L7*w zhez=z*I`tWq^`sLI3K4Dccy^W>+oYFlRC^UxrdsrsmEO~Rg175IVZUuw<iIbdORE{ zo3B73smGfLkn6FOzeaV8m-8SYqY|z$#1=wfNxh=~7O1Y~(I73}l#xAsIGQv*rf!Q; zOn(JGR*%6gq2f*LC;pjMrqdq=(dwhgJ*3yA|DMRj%X?qe0XN{6FuMiu(NI{m70B^- zF87j#Lb$Hu-_^XR^|F4tpP0lD-%wcbBadJ-+&47eHlB(BcbhWG#WCQ~f*|%bMV{~? zjklB#t8hFSx-fhCeUuHpiQ`KCZfIT&jMaBb{;lybDFq+dE%CAJ;Uqq~JACY7_&AOD z;2*8aW9@z6^0@Zw7UWTPa}pnSk(iA<Zs+fY=C^^d`eu=TYw|cV1s}hh)dC;SFAea4 zXa1OniMvs?jYj@!b}U=7L)n^~vNhY5t=YP4&6Z_rI+Q_+j7hHooSn3E(TGUw(*Y+8 z7&&0XfZ;UhH8J<R|Bl2&Wfm(RMNI`yoZ$~1ai@7W8uJRc{ba4bm-<@=eub<S&7{^& za7D2dFiBwU;)Q{z+6(7KW6NnOnwv=V8d5dcR0gOzih>{+J>y3d#v<`f1aF~BwwF8E zRw3J}1fW<#eA(h{b)J3oAv0?TF{w<pWyTOfD+Fr@SrF~H8fEWA*&20Myr3%*xKGyi zaAT>5m1<gfvYz7$a)VFSqnn8aEnd(o5|gWjHe_f)BC=0_kX1E_=m==Lx-1MGm53Y~ zq@@)MqM7H7O_BYK`=5n)UyecW{FtPm`i4ECLqp+W^sRP-`c7J$J>w~iVbp>|a)aW1 z8VX;M*eNf;Kd_1QvfjCy+eM78U^WysQkuBe36OmUH)hWmBnff<CNgdv*_`><C8TP% z>vV#6i`{6n>whf%$S}9t8R!rBlc0j86(myQ!E_id$ZIsEzeLjSrs=;P*S=l6@TJH& z3{}Seqmu<GxNa7bFaKn-m=BUj{un$p>|`;Qv!L`(Nc#Dj{(8=0aRh4`G7=b~UFF$s zFYh%;f4!zZnej(dEB<aMLN(!gc^f40shapeB*r6~uc2S#50(oZ+T;Hg7^kHhbk4!E z^<)X;PD!4UmqVh_agBO@NsAlBi=bZKCz8Wnxwg3fI=y{6xHqp-c1WUCU`NtNkq|ZT z9mu2xDv=%%jgG4yY?nz+7T_@NG$C22B<FG#w0UtPTESUR`hQ6Jn>795oJC5B-YDr$ z*YsN>J>D)ge#yZNNffgcN%Ub!oTrK3KMjdx^AK;BS@=?Mb4Fy`CcPq|Wsy4(HA22Y zD`Xat=TDjDE6X&>i(g9mm!w~!=`Te3mfQG8LUOZ`<Z~7^lhIQ&7ucJm%iEUztx%0o zsw^qjC{R(k7IV2$w)&rh{7*{0WGt1dl7<FfraV?qrquSccjv~?ysK>tWuQX4d?OmG z$DhU2Jd5ZB=(r4*UZ;*|sXWeP&v^?)AWb@k^(B!EIB=E`3+^7cRmWw}VMpRLdUmFX zgQu8S=SI2H-M6q&_JqY4O=#uu+z+&!#IVEr$zqH{6grhdF;tn*#T<GJLNV*n^p>>M zEB<nFBsK+oa1t8+2(-+>m<YfG*448UliMn^s#O^G5&ZM4L@=f<*|JeD4$KU2k%m|V zx5Jcx0?{YU2b?lDFfOw}zdA}Yfh5HE&k6ek6V^+_<cLX#!JZQaNBY9rXsj`^u_@XU z=FUY$J%0e}M-uB14C!CefZTWRm)SFlut+4!a^aV$6{lD1#8p2+`%(ER)L;r%iADm7 zQ;ZuURuQLICF1=vNxzq-Ka<j91wrH0m*BU|3|3#ZF#I333uoF(L2^0MNln^BX|QVI z-bcg#Y)Riv)33uq8Y!wE|I{<UtKB%4W!e{>Au7G+i4lQvY2;j}7p#`_cWC<Ske-B> zVg|@Scfk;PuBJbc@yQ}=#zPvf>Ses@CW-rN;y+6fDtP@=Qa=Fd`a-D33j>Pn{e><| z>ApLe>!)@AD##L071e4L4G@wQ_#;F6LLw>tDg#~lZTw#z@jCB--r7L@6HfZOf=jev z>X@`O=)8^^kLhDyavyt|9KaMWo*c5Qtf1{ntga*LhHBdJpK^BP67$G443?F2Aq>k( zzFX~O&77I&VztOomzBi7ytvy$*~Lo;%&so+lSADVW`bb3Ltq!0px|J$*t7ulayQ3` zYix9$Er=;TGlD77S#u_`sHZI8|ND*v_Z7h8U}T}|&jdxSP&~vGavrA)6dVi+T8df# z%M{0ndqhMz<u9eGu?yiu7RE6TCp6`r20{)-7SohM4!tCun%U(fGz|5D&t$|(NtGi{ zIZ4CQg=}~gRO_q4NiJ-dwQmW>z#aQ|%nwSJf|(mmWM;^sf-*2AGgIcE3o|qqA_@P= zs8?L&r_`Y^{LqRQBpd^N=%>=9;OFPj%uj?U8>pVKQ=+9bW5mj*Q6>q;>u`$Hh!8wt zHW!bWRimjqb32BIc)Ow)`dQW^{G*^FNt+1K4>)9UE<Vfnb5sv}mhk6<KKQ&0pV4@v zz&Y$aWo|p)EhbV|&kdU2_uZL?rOWY0y8oh4&WZ8hF>ji*=33i3)`lxE5H|0`2z?dd zDi;AS#h5j;^DJZ#;$DH+fIq^-UjV^hU;rZ`o<UjWoYbCDom{Z$V8Ol@%)1oxixZsV z-oZ24JR3U&qY?foK^UtD)h+^FeKCu7r(o3qh=~HRt3sR!2ve|k!7-i<!;4xUa5Z6| z&3f`SY6aLJLOagWg26rvaTOfLic-%cE5e@Gt~pPWtRC-bWw?1HTBL(LN{D(8_MJ54 zIN1FX*awARX9@O5#hw+w{_$4Jx0#e3>{T2$l$!1vlB|d2o22{zKrt_F{-fo4U;w+y z5JmbnCGkByf&GsV?7@OPOR+y2LA|so(sL6QAsJi|*sig~-MLtCkVyh#tgqYil4i7E z9<7)+0W;e7Wv#<?<t&Rn5ggYG*5T_Mhb_IAwbUfDvY?fV;rFW@tt<`=VBaD{1%w@} z!^sKk3qr8J0mG2<O^W@_a6jLD3{e!42=d)cuxX&#UXm3E-?BX{7wkh7`^o_Jd$+Jm z3J5#McRj}qCF~lL%*F02*za_)GTDQ$v7qg_E?9@|ds4kkl0Y3ssk_k1bfCZ%E9{HM z1J=6~My?C7dQo2%SohJmnRLQ#n9v`o^l{J^6)(<+#=Rzt+2*aJce7{QgatMx6SKU4 z|GEyjSVrxK;x4(FrP2$ltA)5yAVYn>KIW06SEmk(#2T>zTY%(*unDlngI&(H%b*fm zpM5f(NZKDyCv`X|;`Q!>MfI|?vJY60eY06nc8D!slj#loWk9UMQ~Y$&1MJ@JOw3Nn zGf>k_#EqGOUgRG<15J<_=xGk&8R${|<QeF0{^S{`0-wKT2CCkH8|G+jJOhTcaRxd| z5dNqLzZ~Zvq%{NWDG;w~b<PLGZ=8WH70hXhIiA@v7mm`If${|5FN(0Yi;&g~wEhn) z-5+2O=HfJeJX8x7HUq6F<2D&O1I^<&o`D`R$?WL08C~jg<be^UOtYGdtlSys5+Mqm zflf?d9~*)l7wq1O-7SE<vmv5cA~<^eJcG)_Gtj^Jv%oh49VpmM5VnY@{#ZZX&l#ey z8R)JA_H7~9uSpGFq1a~-_HUbkJ`l_vikSmUcLv%{7zv$$*5AOgpc&|M{w(NY>yTz3 z!|zLIH6n{AhxoA{7oyM^=+*>wJOtbHhY5;3Du6xG5QWV^hYL2%5(i2$-wd>i$fUDk z|2Wvs_hygVb?6MVlH+&=dd(zrXQ1b$3)OCKWl}}hzj+2~6xh=gwg|8&UiI~6)2Oo% zCM-v%+})jyP-Trd-0gN!oD9OrA5km)025e{;#Q&f9Dk&eUx{Mw%6PpEQ`bXa5(`y3 zb;%sj>eSU~Ip(jdskdcf>KgT{r!IIpk_~1JZ4~(^E9N^qC)|d|WoJTK7^}Wip}lkr zghr=g8OmA-%rce^vr?A2x)(+0NCCNDL9X?IxO&u<fwmQ(Qxxbg0_0x8qq6$9J*f`D zo-JrOinb0`;{=p7vN$Xewo^752=)+=7qyK%<O9iP+51LX5>g1z+tS#sR-n@b2)p6s zP}%SSk$5?8+Z*^`IVmI~u}V5zjx<g9!y#sq?;J;u)wHAfkMRjFWX`&P7(dzs17Rc4 z<ALx9S+TWZ(|dAyitzk$w(TH~LOGfM3A7H{JL-`(qa)83gzFXId>=x~FNR9%+5}oO z(ISQDDG-U8ES@sW-y&$GIxV;n?kKEeD9(qG7McSUW?G;vED=tg-_D9-whtkHlCguB z78M3jED%>H#K{7I8lIMD1*}POA1JA$18GQ8nrH>pv>a_HskR}pnz@w5yzyi0Bl6@4 zPHRz|-!odGEwsT`{4T=({B5lW?mVi67C~Ks^i7T&X{-AtN{<@7R6$Pgfu!#e%@d#l z6lgmEa+*dP+`Zo>XsbHeveo~!g$6=pBZZh#HX1L63CK(Zx!ebmzDu;N1ZbE79V|eo z^ITNsHW&<GO)~nlUbYo9@H4Y=%!OS8^O%7fbT&b(aws*027b?m(;59<L&;c8V-79y zn>r|FM243fB8-)Hr9WOd|MI*E{Hv~>{={oK@}J6f9GEo=^&;+w;o%q-12`pKPX{2q z{?icCd|mMmq+O)MI5B}UglN%f8K)m?89!Yv`q_l-VkP4_9b4Hk(o(uYnA&$U7Xrn+ z?PdMF1evo6X_0KTc?audjke*|jMt91#Q36(Xz3tSyO-5V5@MCUNLLU&5#H5?TYysq zprZnm0)VZYq{>=7o%z5bbfNOGH^N`F;ehe-&J&EqTHAw!iH9T=mYEBc38KE)hBNgP zp}t0`w-D+JI2GyuS!9hB5?QKvoih<MSb}iGu0#8H=c^EMEka^B=8S-s^%4#+gbDFU z8*XKAjBs#^%3%7DEX24ZOcLV7HrxU{C;-PRz>xq@Ar6w{NkZJ;hO-#v2}ZVJ{4$W4 z*g{ez3Gu6|xpW0$YibngS5=4$gu0Pa86iF^B(4yvCCCxtUyvV;zBMGSN_klaAWUo} z{5mT{-8B)?hdP*ZdCJTB0iZ}et`Q0UZNAOjik@VNO6crxOf9<zqiWVmk_-p27Z+`O z4*^d(7;};_V3>A}ENsadK04Rg`F$)rQ0x4FD<vtpfmb3p&>?3#zg7v|J|Ou_;7<rc zN<Q1U9YoqZo&w~AeKdA&S1PJtV}gdZM*=E)ad-_&0xxUR!4X*2L{|Q-ERKNUoNkwT zaDk4qjQ{liL3!GSvNH!lgx>D!XzJNhDtV$dk@pIa+{sWF@M~BPOpW)NWZzx!t`FdG zxdIwc!jtmywK>ZlO&`UA_qrCRUjR?|^J_g@z&k|nrYqi;M^J67i}Y-wJ2t2&I@Q?s zo2fgX;`{P0s3_I}dkDNQ-i$W1=Ty3bJvMRX=}eq?`p#O&7e~h}SJMc_S2?UC=8(~w zGig{oQFFcsIYS4P*p87M8TMCWK3OX1_to?Rk)Ds%q&&UznUHMU#!lGToW<be!%Cu_ z-QovksX^0!@E0CqS~$J4r;yyDBoBimnqQbWuSBJ&=2DP4^+-v7hNiy)>CukYVVX)D zut|Bs>k808XnQGne<IJHRHcJIWmiQ57N77UzL5UAt*r#M<r3krP|C9|4+zOZC3&Ym zWih70mqi6<K|N-Hq`yhiKS=50Y@enQHS*D#@Y7!Z655eUdm-l)em1FD68F@^10<sy zUVSt`Ib2=~DI#k!E8?e|l%exqnI&^62ybr_+nHiCkMl#+Y`GURIH{1$nVj|@A;Tk+ zWXdbxII$FanNEs+{mEvWqd`OWotW8{^XAuDu$8KCmY7p2l6M~%h3i>=El;XrT_~lS zi9e!i7}pPCOy!r2whnq7#?*C=AdFUo-F*o8lS~adyN@8mzaU#QmmL*iWj-^J)Ie$I zZAO6;72Ft9y;Ru}qK$MB)}GU<yM}P{M<kjpsa{-)kA;)#m0~ziWZ+~UuI44q4H8+I zlhKbtHbTjEm5dUH-GUU$gkn#nSaUcs(gOtxqh1G`<fx-2#ik0(1ygq?#UxI89PM?Y zsbm%6xX!Sa#m&S;8Ef951roYQ$yjO>#dY+@v;k5x$zex0f1y|}?>1qfNm&@rEJ$=d zUwYKOhn=f<(?B~`fUg9AaHQ?*0|2azqT@EHhfZho-HbdlrAE$Bl5hLcxWxyVH8VO! zN16&Ay@<-x;{i(b9H@8<UZ*ZHos4M0+E+6AVJpj9oHLqKs=3gJg#$7e<|+L^N&ljz zKZ&zIS(?dBr9CieXOb^Ka)OXlC`k{_;sUeV21As^G|qz3|4q`5*YunEa4B#ii5HZO zSZYnfreiDKLRC(qT5>kqa{J3{p>)Fy>k(#1^qv7U^vID2I(`bDEEr474v9BIu}ax& zkHHvW^=NWsj;v9pcanx8X^c2vOYWW<Rs2VQ@dQYSy2b6_G+2MR1tZib!cT{}2s+BA z7$XSc0fD$kA)XNkv=#p(7B)tRE^8+U51T<Alg((ItkQ~!kBZ_iGOSE_bQhUsLZ+*z zUaT6crjfUlMyb`%{N16@)W#NrDVZLYP`{xh)NlAG4@UbJaQc!ahbls%ih=?;(_HD` zqcTX-fOzhwnI&a58A5n9T1ng4XzYycIg!{zJg^h%B#-sfV_|gSrI0i-^RkBX7w&@4 z#`gZ7Gut&U#TFS{@SZrfkWS9`U5Ga7aY!`w8BH>WqW~0x)(hZ<=4bHRmIkZm-LS%4 z$=77_`k);Hd9*g?o=#FwPNScRBQ<f4x5R@3$3Q<`htZt3*h%L`s}PmQdSbTy26lHp zHe$G?Tc)#w6PA_@`zDVIGMOZ3!``Pb+_6Br2%I)`?^;yg416S3$ISrREUy0YYX0L< z72;4_1^@B5ro5~_OkxWGtz$757uKUsr9Rh0c;>Jg4$#>%O<@P=rcsu0UQ*bb9CPuT zgK<7=E-ji3fIWi7anQ06rI+>9#l~_0rmDeIwVs~P!&VcVJoE%z35OyJy}gk*v__R0 zV2V!CaWE(_)(}$+V432$n3;vLMiWz#RT+3HOXg{maNo<}z7&`oj4VP<(hU`gpD&{F z%3-}}px|IoOcSOUz%s>gvGRye4o&1`?{HAVN#?D<DZcM)9Y<h5o)Ajb$075dvEvwX z#!lE|B+Dj8$I5#-^pdTN3_L(2bJ@d5Zn7K2BS{IzAUpc0bSaL|J$o>EON^C^5GGR+ zTP3*;x-i3?QTn8UY7^_~Bsa_y2s0c5X6UEV5i?%r659KV4+lCAbS#FohUR^Rp*{{Z zGnC`xAPn`AB>V@nrL3Cx=o*w1%W!X~qeEht>LD~71E%O_I!u)x#8S#7YWJWa<HX9_ zQATp<or*+{s8LAF+k}gLX#Z6Z=sNx!fw7~!nLfR&et*YUi(V2dStSAcaR8tHXp)ef zBqSGUmP^Q%9Ky#yew;w`1$_|ND3M=q$mD_q1N9UUpHvl%53WF#OF02$St}H^f`M6~ zWUhqVhmdHTkDScpPd<83#-DuTq=Y}mBNI6%87rv<B~Db<M&oDB#R8Q|+KyLb*xFC2 zO5U&N+T89}cK(L<%7<jyb=?yOLf!!+gUgFHv!sAAuCOYh6OWg(kfEnp$9Rc*!Q+zg z;vOf~>o=`HUMi4f?JbKrfRrX@_=M0IF+0)-)~SvYLP%%RRwp?epgBBx01Lr~WN?E* zaF%9q)4cL75ImaLWg&k`G9ETwRO{^Bz*#VoT*DxD7Rb0lZUaaw1m-g;h|%mweWY*Y za)9d*y}=i9bIpz9b6b`ryODZ6+UB1*o?F`<CaF<YVRKDfdU@-==6c;m^N;@-A`0a5 z=>?om51WsB^o{a)f#W%!XC!HEFrVurpS#;x(d`+M&lE!(cKGEq$s-rpjg(}*!!P>^ z{*j8mX#eDL>}m+Z4!~q2@Hd<<#kGn(T2?RnO4|P~nWpN;5kB^r`<Y=R^)bvmCt2Va zpPb=)S+K8F>@Au1x<<FIPZOs4pbj|PJsd=JFo5IvNamp?sn!7zpbYaQpWQT{+53@< z{P}!;9v8mA<`b;zw>h5kd0CR$gE#SVlg|*z=P9hErJEcUlFyBXIP8e<B*}vg$($?6 z3T$1_HutNwTo)%O{#*Mdm*XHq7<Np!O9FrE5d0eif8$S<|4RuU&Oi1uvx2{_-Q${= zIW$?IuJy>~41upu_^t%6s-*PB_ruq)4DMEt*Lu1jfx{7`k8(zJ-pOzJf)P$rgd2Sb zs<d?Wnn8#ff%ua`3;~1;UhqzwU9=?PoJO{e!6YI^+SWV}Vr#VWM=R*<K=1g!PfIh` zBuw0{AWM5VAbNAuDMn%(7QOPVf^dQ&T<ap>I%!LqIe|D{AUZ3=AV9DrjKh1kk?iY> zz$TQ1F#)s?#;edkORvcwF8aQuqy4GlWweim9I8K(<9Gz_W0Faakr!S%344<i``&&0 z*qK7qgRtEmPY3otKb!Jp?DzPyz>MyKJ$E(py^~@W1+ecoMA5#>eKQnc#|4{4^=XpK zjOt>97%td#FcgSP*6!`+`xrw+*g?JzOkj5p!QRv??O(BP1U7ExM_V~mZ;}Lhx71+= z;dfib?9cpurFA&-EUv>o(SS*bWHFWFcx0VulG!>W&70x(vG1)cKHQ6Bk-$Deh;TH} zZ(btoJrmenL$L1@S&UHZk^uI{XIj3Slj^X6<M`O&d`V_TYw~L9<rN6__nR!=Jp<U+ z8lq_5=A=42FM&Na1pAZExehB8`(NFu4x6K`9;)XgfjZO?dac0zRbejytb1{%HhBeJ zYt`I#1>Ov5^yj`R(}P@)uw&D;y6%qh1?Bq$VWYC~^_~tJI5ur;an8^dgcv6fPb$R2 zfH1=kzp0QsLW48hQ(7bq`bD9isPyME3!ms-B%QliFAK<l3bKz2GPvXuQ5!qOa4%MU zgf?`&AgtYJ+t8<bkR%Kn(fl)w$*={8B7t~NA?^Z%k;Eq`@Zzu$S|aQSeTqPwtq`XI z0&0F<N|PcqR$fIbt+>Yvq2kpD@yIbvQSsLq(O6v>e}09}no>$vtQWwbXd{hsb+8RR z`6;)d3%;}EUb{QxSi+lNwB87On{kfi6L@!AJ~=(ylLhxo#Vu!CkN38)9fR))j4K)` zoY@gvay?C(8pCgWklzl1Te!jU+n;gEtC@TuNoXwNdZn_PABA57=F=gkX#Ty;_>n#1 zW>)L7W(@jWsEEtCh`3`PD<8_l<t$ULb7u@}N1w(6lR3caHBo|$1>irzNnIE&5yKP+ zOey{p2~4H~6OGr+Ma&SdUmu8i8W<%$qVXDHeTdh)ml&GzE7#$7_KbH}JyAj>A)_WP zx%2{A70BWp${?uW_*F)cUWd#f-u{F+-lRp@m=$&tAQxEUFy2GlxZaN=#{9SW%v^X@ zYHp8aRSUX-u?`Qc84Hlf36P---#G`N)yUUeuGxP%ephi+hfGkjMBv0A>3U6;H}Ge= zU-J|AS%vhm4%hMhnw_AVp{qcv$C74VH86b$QZz8V_>(m-JvgJR6Hlf3AazKt1Qc-q zYhb!c$YBzai!?bBvKNQ224-i8Bn?bQiR{QBt_G$ZMI<yZpPyp0+(cdxysS4lfU{gD zA&U`WG%!!|C$DB6<xkeY+|8e^2BsO5js}KGnovHZqk*aTfcx&>zqNhgpg*DS;uR7X z$@~f`ADo3Yj+(F>@*;w_yW)MgYZ4wjRZ!wqH82M9yOqr1%m214-T+7*6D^;pbxtc9 z7^>rh5Gs-<!6cJdzA$~h=CHpo?L(@QUqK-xmg#7hlmrvO8sWH`;=R|6h2Y{r=gLB` zE?Uf_kfebzkQD;CbiEZq43Jg`j0+76{WThx9DM3}?!1$E_#q7phX;4%$8bEiwgQt> zcjZKYB28Y!l~APlZ$(AwTj|RuQ;10e!{P2)mv;XjpG16cK27{-*XR(P$tOqh`4Eah zE?x6KcS+7?rXdc~z)Y1qXstd`l9{!-ob#S5RehD>4+z1}H-uptnB5ZiokQ@4n)a{w zAMOnPSpy>_^zX{ug^kg`aI(OfPnJ2u1^Wdk<3u(kgx$BUqg&TgPvp8L4Gf0|>-toV z=k@z=lT_=P2vFDkB%d*w&#oc){85NW1H<_Q>w4p8uImES!<YQ2SD)hLCZE@(O@9Za zn3SgmHr-%(<{08I4b07w2WenRC7DkHGg0u%6@Nqs{;`HIOapUB0>4KHerLhYQ~d9` zQeBg3MM~(eYj^2pG%%bjP}jP??;`MTLQf^)xs~ACsDY_{oBQpD3UZteBn=JBC4w+p z5wd*<>1bdM5r~r&;-x>@!7D8d%oCzU>ZbJ9gTAdAn32N7ThMEXIFE8c($T<l7KCy| z$Z`?V(!jjh#MLoOAr|ha>-(ix-!E_*Nw@~)E76i<E5uYlxEh!#BW1J?)4-g@aXbQ# zG|BAlophEry~FH1@uii~o&oILg(y@5la;{UJVID-u@4pO6BN6li=Xco3{jW{<^hi5 zOQo|UnHkkZ1M`m5%nxWMQn%*?u+K3>VH%jh3G9I(*jEbnY{kw7_HWd{Tql^vDCV=B zNfrq$$<xDS6c5wDRB{}T;5V6MR?eh>G5mgwW+JjUHGn-vh(a|m0}|MWhG6d@eBZ3t znE~t!Lqu8<cjh7O&Zo!oj6kFHJN#MT)4(i|u5p-R-@k)jCifbmFbzyBfqi8N_PK)n zE)-uPlVgDW+chv33+!}-{q_%F**T9@o4oi;(!iW0YMdDgGRFl;M+4Jc5C$v41ujBb z8ki41<Bq?zLhK6&7L`@BB<aX)1gnLMgoS0$qKSaN*q$WOHVsTvKuQ$kUKb=C4b0Yp zaHJxPa}m<gz%+;?+9^aXAdDo^)WEza5OrWigz<h3CT`gMhsuc^9Gk|yYWo9@HL~`g zACV6Ds--VnKRN>&yI5mv;eyS(ZLFgoq({L;4ID+IMH(H4#_<8#H=5;?Xm*+qV)Qu6 z`IGfHjg$_`y1<!NRpemQSoaz?fOEjQ@Z6Jl&Uaj9(wSG6;yIx>Oer>Ig95LZ5`P(_ zAE+1hjMAr;nZWBO{)4wJ<aq+wTOscu$d;JsD-`XO;v!*!H{Z;}TpttF%tX@ZUsVx7 z5}&PLN&EsOkw{`UVWM6JH0Vl55-!D)Lh&!9Si2ob!lTW3Bm>U*yeeiwj)UQR8Gflc zsRu3IL)1wuJk|r1F>yIpt>}Sf4&m9ss*_k_!Rn+^$!EOL2BB?m@fl{Cz))K->ZIWg z4Ae>M5R<G<BGz4XQZMG$sFSE9Db-2KDKeo>V$suidZ@}cMm0f^5Ovay5MgmWsgpJ# zv8t15O@;tru_Sa-t~zOz$r;ovkre8r_M}dN<IHkW0;NzVRm$n78a~vN7}@J6*gv?_ z1#t=uY8z*n_VlrBPp@=B>rkk`d0V>hNhqphmu>540eMD2uJeK9Gn>8{Hw93R0R3Ho z1_+R|uc)K4CYOyugJnBc(Dqcce{Vx&YvBc2LUGDQ3zoeEWaURzK#%%B@>%vtWeWj% z?^W)(<qCAB0GX56=JGqACv#3>$3m_>^Vzi)u08W1wOHWV^H>xO2a@?Lo>ni8?T1Q} zLW9zrDEz<ip%uivTes3u2*r^m9RWE|K*|(ktPdo=l4z2o83Od#a+c;%3iL+-N>p!g z8?JP(6SVK4-jPvt=~k_@6q2J;Hfkvk3CNQQGTjG~&$3S{TL{qU0(71N<qHs6N-t=U zO-sqeFp7`@gzyFDSY?D%%yRpgL(IX+2EM~AX=+#vjf0h}jh6G3P&3o7Sa}Z)wAT=O zpoEEmpe-*yZ+?aA<{>C*M4Fd(Y^9~pVM#}t)KY2$<SYd_)CZE!Y$i!F1n7JL+Eszp zZpqxZErrUOJf=`+uoqk+Xs<x~A!VD*Xf2E>gyNKqTFOBJa-D*l=mW{GA)2JJg#b0b z%#t3UK-&utTETKO4|74jowSry_`|KBf$ue$+Z|1b&`tI;Cb!pdbQB?+E?&ZCN^!&< zZNxMsz61{wgEXaFuuQ8eP@pL_(jTvee|eSMzRW%OxV^zP7fFg@{5V%^35>iGP?qLn zFoj}{p*X$|e+A}By$?@6_&)qE+gpe8oDd7r$(+vIho>KWAAY{1)2rO4{Z%&pbe)|w zf^38HvWjdtSt+UUt@{_tweS13mY>c-oAI)8C1KK4?v6Ix0vsz9v*|qxFc|=R^M>xj zzg;N%=iq(#1vVToUfxN9@uXt(7A9s&s)FEs_+lH*)E5Z#B}%=a0~cWor-CAo?rjVe z689>1e+hD~a$kxN=RW-WLE%EY$A()O<O>Ibl!J-F!R3-LNr>ZYxCOXF05TQe5CEtU zdrR`9`|#atIE&#v!Fc{%TM=JpvKTfT$)!jV;z}FN)U`r=l~O+@)U}+-2=O5yafMhR zL5>g)09Sk;z8(4rUk>uJ{)8~OjvzO9ysVCikgn998u;B+?r&b!8h|1>--rL$e7ABR ze!e7wNy*%Yzu&=_os7}yefV|M*+cHbe}E1n<6*3Q@_qQV2m=-0hyNKVn@3TAIP1ZE z_)Ri`5H^Ne+(eWBc|<H;!;)~Wr{|DlLhr-R<!+nzjP%}Jpwbhbe#k&}ae2zZ-n+*Z z&~)}4q>}q-@|P&Nlc6w>d>@{}lkpZw_FqC9CD~sQz>@;3^9}HHf1Sg{3BECU@FByC z1@BJ9+dqIO{P_<owSc#$;6)Yhy>?U^Y2Jq?7sZM7qn^Gn2Ex!27zZ!r(R4q}@I1;; zK>~XWI%k>ioomM9MU1c-8Z8lNPai_d?so;^5rMc*AwI)A1}1oNNL-3sjz(zi?v156 ztf3`8RCFN{FLqKoc8)IhB58k1cdX6D>T3EKGdJPn4j;Lq(&DG*hH6J?q@TZKC9sdM z&y5H-&&^XN&f%S)8>-i(+V53_Pk&|s7=(1(P~9jHrz^x=0)ZL345dt5?#HQ#!W{SF zw5&&rU?U_EbEyjQ#V=V=R5pvKXh{-rE=3Nd-zw0;t|U!PS<}cd<`<qz{wbp!--sMj z@5<MnxN+L3DoE@}vz2dh3p-GY)&Q&oNQivvokbn38SWH>wfG}#w8V#yKgOtNoGJ=J zj24Io6=I-31ls5{v{8PxF<vv71kmDkQQBxJrE}WoG!~rR-L0aZcE?yVnaAVG$u!O; znyG#3+<zg1udD?Z$$h09AH88kaoLY82$OUHlvhBW-+~&;!b%0n^MTlRrX6-t06io? z!xiYuAHsTmuY^>4iBt;^Vp?W!Yb8=G2uQV$U#b-%RoPwD$nHuU)OnsPiOVODsJ+U1 z`V$+3`?X$HhkjU@#5#1x=TG?^(4O&TW+N^^Mq?kz{o122k~Q!1<!0(b(huzY+8p;b z?fF#7c%^i<Nf>bK9wog2=ia3({w1&5I-Iweq-H@vOtbEQL%W=Df-qeXCi)Qa?frPC zLj)mm1!90g93&8}4>$omuIoVIJOTX@%30~C?|qMwxvvG03e~0PD-_Qt#e+l<>ZxIx z?F$gVFd-{evWq37X)^O0U9C%D%6ptr3?K@<O=>+gj6%awPYr+ad1@HZmCK}V8s4X| zqk{T2Hbpp*M1Raqm-2s_+c)Mgip9RCkt=<7&40lr%3q@M%OmKe$~(Dfpa8yZZUK&x zBCmqdOk_I^09dlO;HKeZA$dee27?4{8VcOZ$V~$UATv2Jf1yxas#JgEjPMFoN;eI~ zLNZ86KG{ea@r!m^D#~cA&4^lYxlnDVRF8s+OO(=C!-GQdE_7WYgv&XjM@9upL;+kP zI^#WGsP0v&Le2;;l_gduG)5Vh4ee-fanwHz?BC98>igJ{E8w!Bqkn+P<@}BMr&0!} zwl7UCe}NlKKV|&-4QMnvafD2rZa1f?v#%g*hTcmAcC-&6ou$bJSz|t>5L*fas<YLl z$uvkSbZJs%#b~s!F?K%L%F={~^q5Sdo>9U!G)KNOOB0y@pz(+sxs$Vo9;g?`Swk*W zlR9e{O0|S-futd44cuEZOLA<oO!lFL!M+wDDV#Mtl1I}DZTj!$FXOCX^L$Ju-QN0% zauCk#WJ1mwD8x8x@V-T7ahx@5ivodW9a7NNZnucn<)C_M2zl`aZVy*L$tAUU1xRhu zSVQw`^fPfSIqtE(Cg`l;uU}z7S;8ux;3Hp|h_ZMX#K>6#vjOZ&{n&`%HjY&6VPceU z(uX8!!v;whOWB6?qA)mXfH#K!q_c)I55W$;paU68F(en(W19J0IBOViF!RMsRfDPD zg|mi-53<@3ym-`-vxZ_yC>QDJnYc8ZH5|tjzs6a^-HE*ZpR<NY_7L`su-!N4Ex#vc z4O7-JL)^_};N<6GWxzDr<^Q>}hUTxCDISmhW6m0897t+RlKv_>*x+Sd$pNmjhVvyP z7ipGDniDyMuL>M1kvQ;aoi+655cjG;Jy9jD3UuQHlx3~JZ6g?tvxe^v(5nJp@h2bY z`<OrZsz4Kex>p6Nf#qBkScjj9Q}XFt6}Vsy&pIQqijrApi?1N>U+=78SHast@#d{f z!fT_mhGma3i%(#YEi8@$B!5{xaU_6B9{IJ-8ghi`<1~j1VY=BBXB(U~)C<QMiuV}a zhy=4PUK^b?Tp*B-Vv!(1I0cYa2#ni;vxchuS!<t*W8Ku2Wz}x>k93588pm^Mn`Dw2 zO{zL;D3tsU(EL}fL6HK^8u|!vN@opS6ZveLBA@pk;mTgJ#Fq1tkbIW!XUgMOXHTR9 ziBEDIA1Zx7l9@xLqR*Tn_-85pjv@FH3}M(+f#C`Kq7eLD1%C_0pZ5ji^q+Cou)APC zh-JUDffETk;6&lceOWdsoi*IT@qExUW|C@MH&Q3^^0tzE25LU*S10Ea72*Q4DI)V- zpQSdne<GjVQ{?l{hq<ob!5&1)b6rS2pY$~43AuXS$Z>rAw@#83SPQ^rlw*M4U#9r` zhTu;(gke_&#wYN{gy4Vp5c9vY;xB8ax>hd?f%nneQ{b36G+C;v0v`$dv(Q_Kc+Mku zRVAh8tigLg`jdj}?E?wXM>!Y3*p70HAWT<;Pd<0qNaw0RM}Zii5dQ>(3|?tn6)1g{ z3z4Dpr-8n$R|WPHCgv}+;_T*vq;pkZbv3hbnIgRNnZrg}R|W19h{F`(HbAf>z(9Ie z1r|NSTztF0mSZ?^;W%q}d~X>Y!>$V4%5gl>$4xTnF`^ziRoJUg>`kBgu}2C~=v9Hk z6W9laU}p+;KgGT?fW3Jy%XhM~hLs%0qxx%-%#7-CRp9>nSthHnla{Vh5Wt>gh{CQ4 zT%EwaGz9w?!Je+zpL{}F`rqWN;RM0#rI=;Fbgv40)m=utu&V+qIF3i~29wOzA!*(W zzpp=UWzjo;eUlJ{UKO|`fqh;G_Sg5ZoF^-G)5m_k4>d$#R|R$!Y`Q9tEy>JiEzTNl z7VK_{eMJEKojqA5;5*q_!*d+RGr<!knUx7C2@ezO`sb`na)JHZuL=|h>^Ta%^dpEv zRd|Uf5FHa*(p7={r&y*F6=b>#lFn6u@8>bX!HO`@MM&$az&wHYy3Pvdmk)JZO2=8l zpQI3Tl>T|pxAm&P?gDbIf?Vc;q;pl^11UxiMd;%qq;*x`PJ#Fo3O*T1zFVb|Nb{<| zV*+uPLOc!#m;-np`CoC?u;o460?IH?n(>cw{LRi9=G@J=H2(^2^9NLt-|Vd61i_uA zxMhs{Uv$<`xf>52_H=y{t#p5dvxbol%<s)vL+#28IBUSs_y3}^hF|D({m*F2q&G=% zy573W<U1p&oHabME7b?7L+G47ri42=z;)JeorL5fO^&3Q%pt6Sxj-UG1Jh9=PvQ_) z1JjNo5*nDpIRRz4iOqIdJq3d_FzY1bj|ef&8anYOuaq+QlQl3Kx={jG1JevjM+4If zdA3ahv!;^!*y38-$ELrBKKARKHOv&eiHg@d8Ly4b8X^L@yFz~Wu3f(yKGEo?<VFM2 z!zYAvoHg7aIXsUUKn9wr$N@s|A+^C-!(RmNZ;E$dG9K(l#B!_dGC39eKitXn)J-AZ zdnX|T=CcK74bSb&!w+d-s4XXHU}kYVx3-&2QnQm)Ckijl;{0iT5)qw@{DaOKMhbCC zXAOrY^4Tv%KI0^x-kQ(1Zzt#T)lQ~7AsUz!9LH<*21(}Az+?*k>ov9<w}jx|U<kuB zFc&58&kn)A+q8eh?@jps8D|am3wBq<ZfYXg_?<PZpy$oWlWz)V4fMV|9A*?mU{f?n zwXQo-i}dnlNIr9)v@)6ylFzw9Od1#>OVYp`oyg~i6#48U`9w6Ijv@K9H^gDi8a|^p zyyLv?ewRP(_1_5IMDg+(q|Y=zVarkdR<gYAGK66om}?UFmxth=E%>F1A0hnzn6rlQ z0^d{NSHB7PHfmtDso;LwTS4yefux~<S$Z2Itbg1}@pK<TIvSX31Y(Xt>;?!PMo^qI z++}X@AhYl{rT^d!THi0_fs7nOr!&YuAWZD5Aa}SR>1bfi7KG-<tRzOc2x)0xx(md; z3eg1+EQz!=Fat!Bbh<*Uc%62^33r*xJIm-8rh$2q<9MWhz$CLfRq8RHN^99du`dZ= zPZXk14a}$n_TUigm|#CR*Gg~a0CrbH6y~hq#~rw*=VH|QhCl5K;G%)~vtSQV?B`zd z%VfSG3e&(;C9umwuwRubTMsLZ%zUQ<`!{M}-WSYSin$&0n{d|9Nf-%rm${DKot6>& zQ~tDWaO9yH!|y=FetZSVB7r?uh(a|mw<NG*A=s0I@6TY45m}53U=KG$VH%h|f=wEj zKT9&724*M0zD}_>zv}0E)Aro1Lp3n(aU9PCubO1GU6Tf;?p7W^4p8h_!2azTm?Z-H z7AzJbj-!a>Hfms=zL$CXNI}}WAn9meE)|3-MW|oyu#uJqrnf+hQHUvkFym4>8kjqU zp6pK|iT=z&+nhDb7LX<wP6TArD^v~xl8y#uj3C^q2=iQov@|d~3&imXaWNo_B+}Ht z94HVu3egJ?X!SF;lQS>utl?_=gPb)?q95$6VVi6^K=Z$M)^Oxa+zRJorWM&=@iKUB z$xp)eLUEl^98DCz$yvj5H!>5~D&)q0wZg>pLNP)qULXp*%}XoUU+1i$uRsn{$cuyt za}xlk&4SJvwiJq7r6^z~+TyI?CLHMn+vDZ9;9{sa>PaV%!db&top>a)>ZD)mtl@qK zrj5=T-WK1V6~tsJ-=E7_tD(L>+vcp{99#>fBX^FohEpM+T9Y9JRL1b?@!?lEYsgsB zK88y#K3@$x<CG!0{ydG&Na7?upX2-uz8cn-ahpCK_9y9Bd%lPks&ho(plu2l3y%oM zb_%j`nG2G>uZA-O=ml7Sgqv~!a<&z1@YV2~pk1nHM=@H8>jqS|0*KSOGC~%ke+bCI z3ew&OlD@BoUIMflW)Ugd(@RN68*pru4hwJ1U96nX-?n)9#vDHTpZjWPoWU)nr}F=O zqg%-#EoH1<nsh3=SU^6(6eL1;(g%{huZF_~Xr=<4CqQmXp`-B0H}EOcUZ{A6uPS(X zg9L4`qV39PEwmIu3AB`7ZeRg*RFI|yu3)nbOy5_-JOO$hb_)^G3;{w*>6K_He4yJo ztpEG*)i6Z({{?mo;s2E-t+bS0erZxm*-Aj3QIP9=AnE&RsQ0*9{;og+1jubE<OU(R zrBG<Fr7RP)Jr(WWFSwN)P*~8ILMVZjQX(KL@3I1V)CZEjuZDgCRIWg03J_Y#a?I7+ z$e3cTb*w@NxA%tMrLTs?*W=c}>`VTez8Y#e@WLcF=&Pa9hTH4ggTM>!33~su6}0VQ z)H3|*O2Q;J11H;X3vjmpL>1trMSQ~t7jI~PDan)E40N&Kbf+S3j$m|Dj8b5L`s+;D zXa;>Xyk*0gdVx?ctFlEnTBsl6RL}#`wT*j(#C0=pqXao_23|yn<EtS@5+n(66JGOz zW;d6R+2O?u;h;h}Xk5trzaj~fg!q&Vw*X%WzzGU)EdbP4L#ZTB65<3K&SKas7&|D& zk;25$lBysm#Di@(Q+Ja7^~P)~#4Mri#HoxBf597FD7Y)cFD1wk;?<xC`f9icVSZl? zCnrL>V%R`8?ub7!No5@&k?gDCF!SAtuZA3hr@k6~0AtqQ!@te9gYm0<H5>vl%UJ(@ zeMUQ(R!i#bVg3ONQ1QlB!!V?5ei(@&|9M{x9k{adw&Oqj{{~x%@N_I?m(o|m*^<0W zljl<MU+=5okAhdAc*~#n<FQYMz(X@F_*Q6$^I)_N<_Iayv;ZDAmB8aNE#O@$cvXtm zi}3!7z8bE%nhP*hGkpFzWSDA?5$3C5kRbF|geg9RbbK{r2*hSsEkufk3q;@^{BkU? zeviHy&Xq=$uk2r5*NO~-7b1HI!uK<+0Q&k6(zy`%skEGV3bA26Gl5l3s}~|^Jra5$ zQkNyM-|Va5FtGD0eKj0h&TVu*E!r+pG_!aQ>~5%y1|2P|yM+-}-(ltZHm*}AT6sFY z8Xggd`xN3<fe5rw+AeO-OS|8xuLe)bvGR5+ikC4XBt#JqW(pSz5dpbfL1I3T^nEq_ zax+)VPz5Rwpnz0qYh|R`3vCs1ZvjGh?oHlW{TF>TjM@x##aF{|_)PZIF!L(Rptn5V zny-d>+{6D3z8b#2mZf$sOjj~qZcTV<-VJPYs6)5|4rxxF5`-R#&{*ptq~oh$qCk8K z+lw$!A`q<)I4$^UcwRuu6towCw&bh96N*!m;^(J8(W<Y8`-E&CC2JtE{1K^rHJI{# z2g8k&x11>ccfJ}13CAyJ{#`i#^nEqV6oBap@cO*gd^OA!lH-)*pCD<~SHnV~+C{0( z<BVGJ)$o>(G-IR};r8K-TJhDeTBsgZs`j=-DSb8kEF@Ev<dqsKQ7gV0a!R?w6)Dy2 zpb8nIw&Ib$(roH=jB5Bl=BweAVrG05#%q!5swdHCTUy?^BL(StJVBVH2(x?$=`2l- z7KoD+;v|7+eWVceYv|IXEHMF8;1fHRQu@=f8>tDLGU%(}&L{p4`)bJemZlZj^#Aa0 z`ZB&6hFp%xWI}oCz8XG!oJ`WIBG#S3X($kcyN*h0d^MC@Nev<IgA#5JxtMmPJuC;Q zO$vVs`w-=S$ydXRlvM&7x%zxHJS?2_p}n;&NQH#?d^Jp`uvUFFG*eHE)v;@<SdG+s z`FO5=Z!G>qW9%h28uNxyAna%Sr=Tn4-F{6LrX2#{j;pZ<C~VYUI0~a=xp3GN=?Ucu z9$lv=1`F$HdMC(@??z&kG!h^&vk~{_!E0g@L-@6tj`0l%@ZXB`Y@icjf<Jd~?DL|H zAE3!hT$gDy6@}HVFNdPoo6+ndG7%4>6vkmfRTP`a>^X&1&!Bu53F?btZy;GSlI_RI z#7ja2PB>7q3Zx*4jc}j1FxvAAxOydDGvJYg2+c}RUcKB{Di3@)n6z9TLzX13Qpk&G zSzbK|1&chi1!l8&iuLJcZK&ujqRH^`?iS<CC-@_6`o}rcrpsCUndKt;!bW*n@H8Cx zvhQyitho->VdruGXjZJbz&gh3+z*mP&G18mUBMhZG)RA&DKBp*odYj`_+mM0&Tct_ zH_zn^-qH+?buzGq$a*|C*mzd<0SmHkUYI>^MahbZSvViRCX-$?^t!zDH8R3S)@5Hw zy?R}85ETDIth_T=GOskyCp8tS!R%QECKu~OYSs%e6x;(Aphx{wIeFnxh%LVm#%hy# zk4St(JvD4j-%so?HJZMh(r3>xT}0%}9`KE<v!~CZ%)G1>Yi;{W!OHIEFe?u#^x?t^ zUMO`~K|L8(Zj|(wY5J{^o*taULy~waGQ6gSAq_6Jf}fipw^+_<!(H#zxGNsd+?}ks z-T4R$DiwGCmh}5;`ty<A<*ub_uFqHlk#+eROi>+=nI7>5PeT{tfy^tPK%--<bN8ay z+w3I{b4HhaCJ}#G^Fb1UpCK=69)C47pZyG`js|x6%~L4uDo|O)69yRok@lKI$ao5Y z^Kks(R^nxyBay5ZKg}dGE$GEaPds;vr$ailw<8HoW0C^Bk0LIj!4K~!8<a+T?_wgM z-=TK6(Tr(cK)K2Ncnzs&-{Ag_H$RCvY#d7BL|9V)kL}TRM_+2YeCET+n$5EjhLr4u zb}~{nuXqRnG2>UvnCH!}1{{HpP!@6aNDs&PEDcA|$nx?Z8lSZLnjw(?zQ9I*>dk-p zm%uhA!_XwkE?&++;$%$Dm5B!4ljQel^1o7YCqrQ%*$Zt7y#9hWQt>uC=*N=+BzvLd za7<(<z2%Q~h-)w5R=<Vf-50<U{*t}WrogKdym_7#&q%`aYc`uAeb-Ih0iC$r(_HPb zPH)k4x273=dM=G)G#o5511yaUyDy8;=ty2@=LW5T4`09qDAx=>eE=CMh#iUy1m^M) z`hv0<X3iCa;}zj<A3}bi839^=*he686k@DEpr7SJ;M6T~fjJuc5CLRpHLDI@1jW1_ z+#)fY;UW=z#*9nj!m30$<Tiak7*#=GG)U_xz1~W{sk#+m=xur<j1ockt0LU$L&z_z zlEK;$Mi644Kx8V!@dANPG77U*{11_F>+wC*e7^&kti!h~|9RaJjeUc_b_qdsWU+Xg zkSyX2!T%%KuNnr93~|R>m;>RhqUcz8Gp91Y8k+CDpBf-ufGMnZ#YroTfH<*8B8^Qu zV?6Qls-|(<>I<E#^z|5FwbZs$BWc8WiXd#f&LSM;L(pm15oZu$7lC+EAvy>IBvg-* zioVP&e>`3c!Saj<)5e-uC|)D|A;Vp)WG;u4*GdRHh$cE*X|hmCgF-n(`01|vOuVlZ zq3B-I2<4lpEY^==RwxJi5b_I4liFAi;!%N^tq@<|%S=EhWhj>sN)Ilg*Ngr%lvLr5 z5lS_M-~n=u$J#Z<=YP<4N;$;L7MOKwrcr=b&NA~%_l%N5*KH5^45f&5f<xDB_s3^Z zY-tgOIa<5C!}D|hOE4%j|Lq}G5=zs=h7V)k!ii|CO%S^{ubWAn$7}isFKzDfuV2i< z{1mDSX``Rs(@J#&`|C}DaJM4d?L$bX%O5KcV-;eoKsa4~nXk*o<Tb1X+4Gi`Eal^p z)wZ2sQmPWT?G<i&g5#s6DJU)!iVvXn5h;9dHz+dRq{<*Yq(i0;F(adEg{)f1s);Or zL`C-O6ci(b;u58}1Qb~Hy%F^~92|{pl-)|-g;U|b^;ImJUpd<AjWddabDou{uG=?} z;)NM&-bY_-b5*bYJ6HA5n)l|r+E~^13qnUlsP!SFQ`Kh(#0%G0Nly|8r>cXaJN3w< z(LF_POg*}DPc%K$GyS!px#6D>0gdja&tl6n$+wt}o!lMWZ8&vVXIYK+Nw7}s^0$wu z55J19bNGuMEO{Qgj^+=GSsf#J+HSi?#OAv)0wu~Y&N|VNSI}?6hf&9DIG<`PZ|Fp> zxDTO~k=8lDNeZM2`swV06@;B&7VzZP(0oxK)m4j0`_Y0U%T0)GNjVb1TNSJ9PJuKY zg^jw%r^Z`^*+TRtUe<RX*v%a)J>;b!XbwUgT}F7w%v!`0qGup&2M2?q79$^i4y9DA zZ;0$Cd-#~yTV}<GlD98d4r0ltOl3z<y<N_w=wTfq<5omsBdSS#k#KA&Dd;`;_^^(W zqKZ;bUqf*ZWS%;(N6ZR9S17cWSH@x1Wf&evwZWmlDN82c*+rBeR{H`i2OkrpoJ*C0 zcw4Y4Q$`4|W85s>Kbu-`;WV3zl?mgT*PC$uf2GR5We=6PJdZg1m+)p1S~!ZpKAwIm zPg?A*4w>kXc&h-WI0kgI5m34mWqEfNl|?))n;dO%7$#PpL;1*Nl?OyGYv%h@vW^%( z#v%?C8!PXGkA{*cGNk#sxQ>3eyK-wRRBjmG1#bjxRlF%9d&U@iLMLOQ|FLB)(*I&q zdf9Up#ulcCDIvJng4l8{&BkwHB_~tHCBs3EZAgqid@Ry?KWGewLnvT6GJ_{8gY?@l zSk+k>EXOA^$kCw;hQ{#QOFjliF@r-bgY*%Jk3o-}gswCNJ?dS(=-B8#L`i$5Mmx1y zRa!O7ml)~3!5<lq9=j9urXT_1a1VlTj!%-g;4DFyqX>WVA>@x~WQOV;C-6atJq6-? zh1g#p5(dtMI?(Y?le9>`TyVN8&L=aeFewfWQ(<(44Mi^Pf%^)=M_Aa3IPUTx<WIr^ z*?Es33}S;Uif1dtsR9uxk-PMC1vQ;_d4Cq16BOr<jAKE7HY>nMty43bQJDFH&_xm6 zxP!!D5%Q<hCKV<K@ehGmG1bcBCV@b|U5AFa3wE>U3kCQ@NMe^($-A_Ml1+%<b+#Gg z8%nyGjuMI0&~_LjL=LxLnG@VCah+_5`NS^9o(YtPe`6;q7PNW{n5^Q*yiOwp*6P$B z@#?}V5V6UAQzZ65bJigUjE})+KM4c*6yFOi>0Anqj^Vyiqrxb;y_LRF;nWEAm8}Kg zVnsO8hmb!8tIa^A1|b?wW+r+mL_2{<H1pyqWyu|1A3Lxef437Erx{ivY3a2Ut@M>L zr!dr4-XF~f_bI|9K7{;9Wl4nzLfjz`;}qf$fk-sc^q#WVEI7L;&YIiYmLAeqbQg(^ zPkp6U5Z<0*#qod-A%6-sqJf$TLQE2fTNUCgf$;a09%=NIK9VM7U*YvY>b_DqE!a`y zrI&aOP55|yi{|gd7+>6mcVD(b;V@l1euWj&)wj0L1yY<PS`2D{T%aKReIV(dCAwUI zx+~DP<;;!K7wV|U{_a2z<x*&HDx4x{Z^8yEJ>ot_OEG&;*$5@jDf$S=jS6y_4<w(f zz}J*g0DTPv2q~gKT?NSL8eEUbWuw{+mhBrs+kBZV+p=3)=pe)rp*UruKJu`D)F?=a z4<w)YNh(_i&^Q4)UxE4w5PC`(n!cG;a-<hj;SbLtvC3)*sjwktUD;4lYeQl+^_0eF zw#<svRf5$uNqi&yF%yVi<zqH>GI>NitlB6guSn5#CWDS=6c|GCW}k%pVdbzN5$|!o zj(P16AB|6`h+>Y3#xE#E9$XH1a-w5w@vxp4mv>oX<?E0n8XpYe5g;B@I#}oG^t@I) zG?LrQaFy#PH_@GFGvU)maLJIEUBs*AIfC#9MYzjFh~`geX@U}ny#?Zxf7qsWDj>K+ zfdLp^;X3q{!MY|(Z?d}RcrMuGin$H5Wx6Jz1q+s#X~fY%FG1+52up7y(HMki%afHr ztR2QoY?y2db`2m*!8V}74bCoFGPq<dcK}-Ckp|V7GHCgoq(L1ZY~7`p2Qym+gwR|F zT5cw09q~o^i*Pko5!RJa!3;t)|ALk#E`gXY5W6bGBY-dkTZ_{QDA=dJZn}6!OhAiZ z29P23cpxXB0=tV8(?z*}T&W=2`9RX2E}{aIr$8^vFy#bG&~Yq^^li*8rz(R&b{}Tg zMzB3RD%One03)R-0sXI=Yql3w9#p8qeNcf0onnf3iOs<M&s31_ZgBZYf37JOpl%BE zFn~<?+2xMw4|-o;1kNzAY$iy7-UgD$<{ak5?lp?rFjo}{H#aEMpL|e(Q7pw=)lNW) z6y$Bso$%71tDX{t9pOpA$^c|U03}LML$vQIZ8TOk5&;_@%jOp0r4C2}F&GeS^+@!} zP#%3ID@aEdBpr`Lo**2m2urSa*htGG(a{3&Z)m=yB*lQ>FXNFYxd+(@mc%j<<`YVP zB(tzW$INtgE@uvANsyjjnD{wP<uD-h5gaq!$zTQM?L7rye?^$@B1HA@v7@pGLad51 z6RR(>O#A~7MiMJ9#Vt(kGT@9OY?m2xDns0-5Qj1s3H?nv6G%HL%4rJn&2=OU0}|#C z#+^WDPx_pcWH&{a<08NzOv@7pL0m2n@4+4*HF7>6j4;?COmZIqXAs6BvV(KWs5pg% zal1nF1OygOwBEw$8K~^DvX*AH!{^YBe3T>#Cq*+pf=&>Lct4aq2QO~%`b)f}HuHMR z>MWN;<M+}EY>3xA*P)2UD{0X+#Ov1eSz2U9aU5etv7q*$B_jM)MC0XzHH1$(S>5TP zAzmi}vWbRx9lEl?INJC7sr`=j`eooy!}gf3r-9{e%kg6?q#ld4q&W*TdcpeaQx>kz z9!2J8B-*|M4*D&~So3_Ocu~gciL~e}UXro83$H%qtfE&Z+6|Aj8}Sj-U@II;OnQ~H zNKGg@F5aJ%n3O706o~v?TsI1d+fD3L{0Mzytgcx@$p|x36rucGTt_-kPDURYtJi)( z3s=$PT1(|OrBpkG)1XTi)8#4(xN0%k8CozyL`Yv0t7D<XYPi~rT03Um%gnm1ffcM3 z(1SN3hY&Laucy7N3n`&F<5&;=I2c;?5HmzalmiW@A5$dE5F88&V}@V=tE1+)SUD}{ zLD@dRRG1m!<0W9FMKi<#P7z{;=<SrkZ-yYfI^2zb0Xil@297c^A|%WXP6C^EX_%Rz zy{LRj)XY$DE$S+U%JZ^nh%bGwEYzIfWFvft?JQ_MaFQ8r<Q!DExgd$Bhp!=?q><sg z-V0i{d^!!)I||KIZ4PRykWCeLN^{ChwrjH6Lf-T<nT+~8Fj=_9#1TP41aS=L=%><A z*+R@Un@X5xHp;~%N85ZD2Io&GA1`YWp4~7_)x6`!e-vMfL$~iNU%uz7I09_-a@kU{ zCWp)vr-u}WV?akgHM<nW=_$owwQQUpZC0Zk!^Fy$Q$7u>vBeMx^+eX{MO3nmwxN>6 z<|QO*DCvX@X+SNmqu<6La@$U75V;<oY!Kn-P=iQlObLbh3?kjAhm>?ier&O!4<Czv zB^EJQnXVKoZ)66$DTDOeF!)MWWpFV*nL&;YW$^!F?@hp?Dzg9Y1c;)di3%DQBq}Pn zqR5yS&;Uj|+8_!jC<uxou7e7S3j)R{ZQBx;C@yH+Fz&cyj7u~unt)qGM8*~OD5$sr z;wbO;oKtnW?(N&j4bIHpd7q!pgSlO|>Qkpq?RBc^2EHjHSC4?XEMSfmkRJYw#b)*C z+*8(L-?DVJ>#smDv^_pO_=i6Y&N>ct*G~(fObN9fLKut9d4lMth)V?F%!YIWcXJk- zg~C~fJ<^hx1DKO$&5h>2ev8f3La0%~s%fMSO9*4JIZO}}74fJboTau<7MrMW_EFAh z%&~JI-^7Iy<2Sc#Dufl-cOdH6)k6qlv8f-+#iL3Q%cqh)sNT*&K{RV?+^@;5F|)ST zfS2%7gFozII@J2IW!5EDy`22uBXjg8&LaziSf%f4*UI}QdEY~RRq~&TDshz7g|Cgm zXpI_R7;UJrfYFAkB*ronAUT#9v>in@i<*B7cc?kXDjYY~TI4aXfwOnDg%)|q)xQur zy+5nxpX02C=T2#+_R!>#D835RUm!Or<T4MWkflvo2n_(O>&Ma@rJ$YyN|xW!T1s+i z+Q`+PwrCO4en%ma((}dTZdC|aR3M6zHnQq$ERY(7RC*wVoCPUq3jn=%C`<Eq1syLS zr&e)3rlyT@*Ppgr5o>3qZNjuPb&K+iC{EgF0sCzc=>t>|QP6_PTsO@0vykOUNm~Hu z8Ufv?pi2ehtz=E;3E)zP@|?Dk@c^coO2z|;W-1vEK4QF~5qlP;lFiCT(otD@@Soal z^v9_z^fp!L<my-Y4r4eAA34qH>!!<Es4PTrluo_P(o-06x<ZcjKnhvf6r~4%5(3&u zK^qCktt^z})U=VSKW#IF)_AH-Tg{~{R2HH*X`{+=q(I^dxxfP{<Sa-@TL36iK>ZZ7 zr-0nbLiw1QHgff+t*y|0M)pZL|KJk0oclT=sw_lt(ngi##gjST9#_aM9!MdVtCX|_ zfF=rPtbzs#2vuVcs)p&2%-C{tva*cBBm4}rE@n(x&uaowp=3{P%p9gG<6)|MU0>}? zVwi)X81EyM_*KM?vePUfzogfJwI_$X$XF5mOg?<7wdaYxu=YHTPlcf4;;J1>)S-ss zGR$EJ6qU{?8h<px2)^<Qk=0Nm5D%)7vaEnwJBKL=p;QcF7#~(q(+xf^L2pxYpIrU9 ze}8YzxWiEhB=<j>L`y=Zsq|ZcQo1;?;*1sul}mx#>OycJoMKMNeR9-dB%o~tRD(hw zpg{ofQ=mDh72Vy)0#4^iN?v^tr8A9Dh|)=_b;P3@oGXy+6!L@%iH7O!#5(k5K1<U$ z+NN_HKqj35)}dB(eVs+b3zfVDi<rhnl+yKyjc1vNx4%LbUP#JPGZB~Cl>DTk>?n+G z$DSdeCM;e`eoh6*q%+7^ln+E|xg}SBxqWm5Yw$WH?+$XZ<MK^xD4j%6@#K)zIDwQX z<dcamBz$kvML-z}nh6l66C#B$7Il%WK6O~v6g>@NLF~K)AEOCW47vIh^Eu4S*a|RF zQJZ^E0pmKNIEtZyPPS@5dMKn}g4^GP@2ZXy&{s&GBy0*mMlm6cMg2v$_bH+`%VGy} z_?AwfZphWIn_Q7*xT1czp!Hqd+b6JYIx6H54<vk7ca4BvMfyZHV*oO`327`kT@o~1 z5qUs3#-dhq1b6(6lhsF2@0{<T{3fG-j$jeW&G7<R3$Y|g<t`*z$lX>-!{O@)2(*QO z9#_y205Q^<h*GSt_61uAt`pt<UBhq8f~f7N6+OqUJy|hb74^b-q?j}oq=24dG1BwV z0Sx&VVu@ldav{+|?#NRV<LiP5R3V_76|^rvMlm5xNm~`OEQ1xXVmu{CO-ZfjZ5|hC z+AFHkMfnX%0lf{4`Og%{{NYwNC%TYmm@BBGd~4;-0=h&&TLENr6VkGD$YHFTgB0=R z-_b&d<;GZ+9)2vvveYCtAfA4SWr@amVp*!<A)Smi@eY<H8sr(vk_`dN5{>J;mZg|b zdD17AC1M%Nl3C-mmL==SV_E8#v@G!{7uUE%quT)ElJRHlOV6@>>0J0_`%*SN1P)J~ z(i6T9|9S{3d;4KF<4-x)?S8}c;r9vTo#QQ}vj-Bs4?j^r*D7eqIV{bF%@{`t?GUA1 z#WdTahwFxO1@h~0Hf?=9knr8`n}b=?a}>1pY)aee4Vy8(CA3qN_7Kx-j~s5sc&$J> zE95i}Bz!m8UqDNSS|#l$pufb75nBPN&LpaN8fj;Yv+`(CDKkbkjN;C?lGs~(4wPEN z2|Y1+TyZt-Q%=;<I%kxOr`Wa5)lcp^h*vWsF)N21%ewJ2^)NcF#^w~dhOQ*`EA3=| zpcmOZh|^Z=4g6eMn~NZ9xuu89udn)wywU1vTd|w)b7?J^OxPPeWPbhPmn6FPZl0X8 zP@0m5&+y^N`lf%K$!;vOwfi=)8`5GO-X(`=3&_&@=M2HuJ;-*OmJPwDk;hgUf_rj^ z4KW1&TBSk-8G_%V*VY&tcpj~WeFPYS>6`C175^<m@IhxFuf!1i2+8$VFa+N_j%2ci z;MfDImA|kd`1{jY<|3)L+;ImRf}fk6Ob&IbW)7>CS+(f$Sil&l|Lca}JV{QT2*{$? z<Se71Pmm#a`Tdl#zqBE^4~h8yBSY}FB|HN7W1#INSD%VvsKYkjSc}Y!enarXLU=(5 zPkRVq48h|Baj_!K6NEFw3S|hc6VCq1>CT)qgR3Az@a01I9vk9hKK9iZQimmkF$5P1 z;t@sMCkSUu70M9YUpS{KX9RQ7jHZGN!I?tXMG4z`2w@DtFGjd{e2l$$qK|h^A$|PM z8iJ4b?GKu%(8|KU!w@`WH&#!Ms;B1UW@=B$;)tv^9xRYokFq+xzyk?y2>zifOLK*S z_7qUE{I<pr+<zCQ9jLSqM!QuZV5Z_(mXM>cf9%YV?~k-;yTt<uvobEAY5~nw&_Dq> zwW<~C6WNlsVM@zjTAI3*vOXcF{T7KxTPx)GQCv58xu!7^-Vi)ZK#NdarIMX5Ak0+e zU~Fw{TmSQhV6(pT8JZMHX8fcUDhrKnoE2!A0=+H^F?TBDa1SK>wEju~4OP(ZBUu`^ zvd{{6s@Z{D{VT{<32kGgJ<c@SZv<2pqBv=z)%CstnRkR$(3u`c_-Xyx{#@%WR?yA@ zaw|*t)$w&g+e>M0k8sO*xM_X0K)yWOrtLZpB>c4gYyr(uP_cmi64Uxt7=o*I#aw>& z_J4Up@EtpGS(;pIGwz)eXjRxWl_3qm#|tE1A>}Tl6^7s~1oS;>inJj|0K`v!)(|{o z2To^&lD{2J=`=Oie>yN=IiG59wm=3cq{@Y~!Vvt*_AJfD3K|8FN#~z41a}k>A4N41 z4Q8>3tuq9_DdLS&NZl|}R_hJHR|%+#f-VBcr1Q@ig6}(oHTZHro6gQ4r=8ePeg^b5 zqXaTlA<K?;A>n(QZ3J|Xf@T23=?rHG-sVtF&6>V8HAk}`wts1jA^811jCw>-?L4S( zUDeG3Ib9(y9Y>0>@`UfI1_)>;1ziY`QA|if@WG<n_p!N8N_0<_#SZ3LV+hU`Y04GV zG_>_y-J;&C;G-0BuLlyotD7dEHVQfcAfua*hTxMVK`){Bh;Ft8V#5r<H|BD(CMfE) zAr2~}A$Xub_EX5!E~FKP;4A@siM*GD9Rd(PS$l8uhTt;M?Q9MI$6!j$h8Tjk@5G8Z zQBhC1DF0EyfS!Zwx9@ah2(=TEo^xGDD-6Nc3g~rYynuEC$S5YHA$XHLSe9!P@#(Ro zn+-7p&lYJ8Rn#pmDx@L!WPz+hmPwM1bs?=V1m_Cq2?cEekkL&@LvXL%SvTh@;+132 zLU;_p_uvL^m{8p#hW}>>c1jQRv#GNxa`n%umj8{FeN3Uv_~C=x?$@_CnWhiFT_7D4 z($ND6--jP7p!o+|X<j{=rAc;st?7n`2yLR$CNs_Upy9gVY=QJpNWKRWz8ij}7i;<} z>=KkJ_WeLg+Xfnf8-#YN((Y!O?UBRH7)u2*L?I(Qknr8;!2;S$L0b#xFEL}>FhlTJ zoiKU)^o)O#A^51_|7k<;#sj#KWZRat@%|KLH;*CsV|FW^s)pb<$e~3;Fpdqw+!yrK zmPFRIaW>ebSb$4nOYi}c<&i|zndHNoe(8HS?)l&3cTW1VH)HQL-#MW}zZ8NkTk@Tg z(O9tqv{N$LARF)MYY=C%Hr^%dBf!Rcgd=XMjd$+ylvA-c9|axK7gZ8jn@L#tz(=fj zI?Or#`$SWMA1}eDB6tzWWX^_8LVJyVkN&9TG0mCKPE3${L-DPmSQ0W$AoQmtNaK-| z3Nh(=F4KG%yu;$-+b1vhl;h}!;q$38?%4uoF*D1XyNvTJ4xeAo$J^;dfE;>1tYB^S zj6OCvEp7A3P<oJqm-xmBeKLePHr(xuYnUg~Rhe|n^UgoS=oae0t1>6=%MI-t2ik`A zsuHA2A=ITgh#-4gp%AWB!eJf)+uK?|tlfu&C{aYFAn0mqn;5#!-oa2}Qm)DzB%)+0 z=h+A)#zOGmB6cH0a>+B%YfA|}54&2V)49YGyl^P)$#g_W3ICQP;|dLbu!KjY)MV78 zCZonb%=o8p4pz>OM^G{>1P^X9kS9a+$fdb~{uUvu#YRI($s7-%uo#zQIw=W43=u@N zBF+&6dZ}_X0>}lG?$z`D>&&9D&k&-9w&c(@!B|BdwMVg8WJsV*{O&bod@2)O8pw-Y zjyaVBB&M??e@PEpjK)*3w-;m18o|H#&TQVB#Mf7U^Cg+q<n%x3PQJNeuLX2IjX<X= zsoC&n!vULescfqnIO}ke4UD2}a3~n<RS?A%D3cT4Zo-fk_qRE*y9ZLpF?&7-kOp+0 zfF>&F!(x^O8e9d{@crZNZKeEKZ@gTKm#liZ*$++Da?)gdSrh)ye@HzydybCiH_EA# zI?@rj`gQciUYxv-d)VY1AyOH22k3|>J{`pba+^Zhcp!xwbBc}vKt%#NMnTUWW_3jS zK8%jY(jkRW?k%Y2gJMQU-2I#TTkH8^SNKLzll^On1S>DW+n}k~K!+vt`Ji5BbbunT zovdjot)QC=@$5%)xNp)nRj;OWYGArD_}Ip*-#7QO`u(aurO3ANzUG-`9BvuJHCAM! zIzu4WDC8aw#NIXLh?54CC!oFx8V=C2sMjPCj*q;Gwzeqyu2+h(|M3S-cX2T)%D$6+ zuip8O*y^&?6Ver=vhJMFFVO@`i}go8N@x;Cj~)^lE#G~PiC%{arBW$1K1v~HiILID z6h!)^8_RQ?lFkL`MM>&nB=yHg!5c-{6`V9A%U-NTuW+3{u5s`6lgQFh3460F(h~g$ z^-xaPTJ|G<04QB4sLEnt7NSWO<$ThY%Qe@DAE{@Mx+;`34agXQT&a*dJP=Py)GTOw z0Tn7}FhI%S626{QuqeBN8V`KaXpiIz+&99CxlI)F+uk-cTazGCnXpcgi-FzuQ_PY@ z4Oh#8WmEb^5)o9x@u*yURSP_JfQ5s9Q=O$f;y?bFJ$$~ofM~Az+p--#wS=!PJ!{Gf zcck2c>-}vZ8oDoJo#kc~`lO;{7T{waHVfoSPLu@!?Ng;dj#0>V9!U6x?sx&US5V`j zEDf6VKiSanEz%<~xRyhszLpN3m7vD%GHM6V*xhj&e?>x?w+-oH-)zGLyBzJd6zukr zj`ZD!+q{`B_8Ng4rI7iDxLM;V*vae(0QD768wFh=pjK#=$0e!V2c|VtMC^CJ=ngce z%mrSe*=}1_&BQ&eYQF8`rpi~~XauKspc%c)+lC1}mGH2K5au&PQv|UJHCFOxoFJeP z8gy)l+KI;u)IZaqwx`b09dr~=4H|Lq2RT(8GgH-}AF+9k!HHh8M3S*8$w$3gP>0?E zYt(U~5V|Vi4iBNQ7`MPWnL--%BXR}t3Hk<6$8bR)#WW^1>Zrt{QAZUX@p7hhi6_6s zRL>v!g}T;96MRJ(_Rz~XHo+s_M1>4B%)o<>`C^OMI3mUl>^cB<&f+VoF&^r^5~BqZ z3Qe=bo9MF7cm@5$r+8xgfZ}rH%Ri7Wx*3h8qQ)2fWMA|^zDC0rT1p-V*`<+Xh0wJb zKU%j1?1t>M4o`_gxjNiK4$~IUVu)|k{NTv6mFCto*?U{vC|htF_z#~zKP*=E0{u#4 zop1>z=<>OgCQR9yJUvRHQz5;!OBcLYvfSrmJN99gE|$@9$}$KEaz>Ke2(o-IgI>|X zL88+q7dzwz3YWaNO?<q>J`5Sb9xtvF@?#)JAT*SNZ!2cqr9UTj0r(qkzI$!AIXor$ z{D@ytoHjie8cSrIXMCfDJxN?fkxM;|KIr{1{HrKuQ)m`H`^nEdsVP~XO_KEt{@ms6 z^e%=^*5aF$;w{&BdqKRhs*vwU@JvXy8VQQj_sbVgoo*pd$L2)F;H+b(_vl^h$Ra$_ zJ;;$*zaDs;AYOPBhzWM&ExOh%`|(ElXwjOt5$|A$h#D*uOnj9nt1r9c7?-+D8la_( zSp)p7%nC_nr!y%MToYHec;cy0B!4P%-*#44%OImP4rNgMK#VQwn|c>Of96w}1K_ji z0eIp;M^<N+I0vzB%}>MV^2I6$BDsWbV4j1-9J3o761{pLEHdUn{F010k2r~}NlE{d zjf=(iv752)x7Bxl@qMK64Z&^^mwa;3Y}}K7X*TX4KW#Sdc#)Hh>+!>6<InV1UzBUI zk?!rq5|}R=-(*jkjg92VX5&-L;%uzqN6yAa#Y_5ZyjCJ|vhfmjX)zo7QzV>?*=6@p z0XA7V2EDClck_c%v+_K+*{r+*KAS%Ho6X7}5pN_$S=q!-!`jCyxT%Pj(Q!r`H;B!9 zu^m^HK3_tqP0u1|>DtWfD`!G!c$l&|QgLN39On7@3;eHiZJP=El&)=?edQYn^z~x8 z&N0#H7wm^ZQP@q!1c!IE!j2_5(ETB%O@PB=hHc&J`SvITCs#T!(UyhCI%XoFuuh4& zH#KSXWwdwlUubY632{LY`KTAA5BFyBRc>hMxk-%6fy~%Hsd!)eDmTr{h?$ReWnbBW z<mK<}WnbBrpYi>32>JCU^rLl>J}@DKqzASv=|3L{l5`yD%SbwkpX-|@1NJrlXq}|L zUl2mlYYuEtr&TuwNxFbC&PYlhwj=Go4cOP!lDVzP{lQ@*UEZ@rNv~U&Dk;7!$Wl(| zLK5x|30G`WzGCb06*=WAHZNbXY59tc%U853$BHv*%i^7(vKW^=(e-#Frk)GnRDSv# zrE()mV6s%+L2}8@=kT>Bsu6P;gYS+yucWqZ-u`@w;SG`{;k?CntSI0eCg9o0SLE|h z`e{rm3+E4w#J=czeBa~x4(&UHh6&3kY>bx@A~9M0i&YGxs)J9r;ZGFbw&y>IBCbza zdqV~~vqJ`!8g%M4b}	dm9FpWf;d$I5VJ_6NUcJZO=*i5;KhPWy~;D#tc)1CW%5A z`^u*gd`DiQt;QX{Hrh%=TbTsPhv_}h>UZgrzT_+S-e}9sSMF&{MHU{4c5bx$4@f&L zV%Z68yeJnQCbTi%216cqbKgRLWLc3_zBqrrp5~_b>U|!48?ZZ8i5h5z%!lTzx1t`v z&|ESZut*<^@_hkil~uz=5H{Bnc33j(Ab(h%Gs$gDku}RAdzl-J=Ha_}48cd$ghlyw zSbS2u`r-v>Ju(g}n7kl+#yco`RKBf#V|*O6zW6or5>IqMn1TVXWzV?9_)BDMI-avC z#w(=t#SQF{e-soqWX~8Z9&xZJGG-Oo()s2|=+}OAo;Fsl-iex@K8JR(-NMm5P>KsD zVqKj^-|&sE&ZGR%wb<l;EIh)0w)*b^|MBA2B4aQVHJ4jDQP8SgsRa1|F-bSMazBb< zB)-<{L@|e>ApiG@|3}pS3-BK=UJ$`RkSrf2Q0HeUz3@L@{9mU2uVwzwD&==U5~_%w z==G&|K3YAGf@gddbP3uY{FzT5P{+TG(0xgT=$P|k_MUXvF;`Ez3Azy)jgD#5{YRSI zXpA--Es+>H<=N!^zHep*ZY{4=aY&<;Q~}t3Z+L`8zd$fi&+G6HjYh{b=-w|U3c9T0 z7zy&E2Dy!+7+^mCVKNO32cjVVXNdnR)c=_r#e(RVx&e0Z>O_GlL$Avv$k7_)AdaHg zd^O5MQO;42|C_~s7xlj}{6lFp{fg%xIi*dRq}nlSX|KG^Lt7HpfpCWqKGd9fc^@h! zlc#$0HkGoGzX|oU_<vOWSCD_X5t3qDU}H>M_Ma2NSxOkpF;-84%o-_-W6~(t8t|Hg z>ZPGNBNSJ%v^C%p3DQP`e6u$tZ5A~co`|>wp@^s+{3M}X>ud|g(+Cxf%|kI=8jUsJ z&&yO=OGvG8X-5+s+N0odqnZ8qyO5k4KDr?z6W3KsQ)UZ!Tv{W(H=UZ*j+i-`Z?kr6 zh*z|y_GV~<Os`APxX@7Z@!yb}+7$83yA%x+y*dl8xFIvH3)poZxS~&_&M#%^T)J{n zBsLlKaw00jP?XjI=q4aZB5VJ%l6}x}RF>uF72v$R<BaZ4Ccjj(ef<XRgyRa2t}#|j z^I`a)-hzGR`C4th$Gj>UM?WDR(L1ome80y!c`+$sJfbULkN$q3xCXg{4j|eccHQ|U z-G77Vqs~N%BJJyoS5l)@Fkof&j1r7$$%0<I5?wsiLRz!ILbI(CRI7$<$8E#@TC1Me zlL}7pa#`VlZ?q*tmy@J1^4}o-Gu8hz@{jQawP7nEZ@Fo}RyNZmY%LqvJ1C?#M>=tt z7FBA%mT^U-F5yz~pKRYdkbg9B(0}?~;n5vAX|uIXEbUH7v)`jM4NL>aLbc&#@qeNE zpH2SpWmt+OxMO%vg7nuQ7jP70{Wg6FbqsYBMWWX);&~hOd^kMY%;}5VDMt1b`|_tf z>L%LmPqd0|$uZ#OU}TUDKv`6yS=3pAJf=ZD>V|ZbewT^*{7?LAj3hd4jgeeE)opy3 zAQvK{3{&ky-H3HuMTN)Iv6WoMo~5Z+>4HforVcu1@-(WpJ+HM@)BFwtJw5>+OVH3C zgHD>kMPmt`izTw2IXzkPY7nCiI!S){&M+@@#d)%5$DU|7*wr0>CIguHAH{BW1EE67 z4U7muLs1K`2iZA@+y#!xvkM6&>t>aZNk^o~C}_G2kH3y3>Gi9@Jd375alqGuYa|5S z#~d$`L3TN$U}uCV7onJIh2nQ|A0&Koazv=<lr?q$oD`~xqA(tfP*d@noe{-U4I#UG zQuYTOv<C`C%#KJo7>QC=>2T%t0q!<rSyQ2!Uo#!=B8C}2m+>21KTm^b4VOlkhjwRS zs5?g*I3x>G?$AY;Vd91VWY#HH<(ck;F!IoN7*u`(dFZExOC!(rB2R=u)>Ag2WYa*K z8L^6~6iM=;d0Yb302h3@Z4SQNR)wOn^fc7mct%MK^(<>4|3EQ-wkaU$0lQ4f!z10V z8;K9=hR3`4aeO`=Z^mOZ9w~Bmwojge<$r2eoGaDm`1cuXv^}>N$K#KT_CD_FY>(G5 zrSol@Id+qQ880r7HolV*X1N3mG|jlW8N@U}EXE%Z;shZ02?C%w#J67-Ior}FSEVMb z%Ac@zgn79#H)65O-gf_nbncCvgi#BBqY!#4VZpA>?s$Ca#ti74gjM+vg9Pzwu1(l9 zAWXvEhs5|+8a^ZTF=rDR+N{Pgl($8B5m+0zPcZC*@a}1T$1Bbc8gC^r)IT%)>?2WK zr%`Q#s9g303Dk|)cR0m@*u#?S0Rik!07bWQfU=+4#mmk$fg%N_Q+DM3*C~{yK~!{q z;K!nFR&LUAnXs2`YgKfTkNtuPL~Os@l}UC*0K2=eFHv?IVq=-1`&tY_GC3nKh2yOS z&MA`pjTcPaJ=LCvG`)nmyD}f!8KdBWH#84Bh#>h9*n<3dxawrqMG<uI1wR($TV2q| z#mKv88>@?Bee5|BsEF8pUEGvp#{$@|Lty0LxyoLR1#wsIAtq21n()h=FKlXP_7QJI zBDc)v&J*@l%D&CVUOSr7T~tJDzuX`2yFtW$%Xo9yorL`lY=oA!;SgeDK-+zlKM&oH zXdP(0`0_AH)rCf;I|+7_V!!GFY~msq4bR2sMKA8axR0#JDO(BmmGE6O`~wJIQo0~B z8c!@koBceEtD^<)XV18SRt0o;f&2Q}<zX1L7n1wwDAr033<)qBs+Fd`cRsHpL<`=U zaxB)5Fanzk??hM&EbYc<#Q!$`@_<a7JsE+|LhX&uMYY>Mk~lCQgX%?Nv-h2weWMvp zwu?2cXq)J_zHhAEGyJ)z2l+a`)6hGm_CP<MMADcZ=qvugJ<xdRf!<*k?tvEZBlkcr z@gw&@PvdbzdY~(}=7QNv3(v@%TG<2j6T(lL7dyCwP(9H4tyqXTidfcJ8|n@1fd-3M zBb0e1nA(kn>4CNs0-ZaPvfs}ogzACbkc7S4(IVFGs0j<|fxa8TWiqe_TFmdb2jcIF zqocB|*E&?G`G^B8%-I^%O^C|vfo>3XU=MU*l6{sD!DXK=>>Oq1``CXofr5IV?S)M} zP_}sU^gx>l`)Md!wEV#iUb){pk#z#OQ+uEn`5pIePZ@7kZtC40mmD0X?5V{5b3M@W z!fdC^y}@)_@;yb6z#eD|k(YX)w#J*4mwF&0Zxu?7=%R6ZFZ+!XSQmjk(3AXb5V0Q+ zZ=T-G)Q70DC-~Usn?ON5&~d`1Ug9Y6=IMdfNHJfvrIkC^$KJ*S3hIH@4W~455A;1h z7J1mW3;QNzzp&lEqX)WAuzeJJ8n8&-f?;L~sJ#(7EN7j$tJ@tR%kInJYWEBNNS1Xb zPT|lRT~+XhIA21{*AOdU^e)L<(u%ID9zvo+w_TU?5iNFI9jNQdx_wL=bX~(Xxa-0$ zV3}Z6(?pT??4rNJH<VlP_4bRPb+lCts{E#Hp)}h5%P4C(FvD2dwM$Xz=w22?4-iPH zLhkiI-1XGvL0?OT9IT)d1mqq#q_ldcJ?VD*_7|~MYW8+uS~CX@iS49~8iGGWqz4pI zzYQtKLJC>;o^c{6DF9S0ppz7IxqvVmZo~@ArWhw-iI}JDFqy)Itthcsw2K~omRT1w z$#=HE#i}zX|6{yk4w3U(K#V`2gH@#l3XiX%N8%HwCNnnNceaO%%nxPTDz&InGo^#( zj=DwAtd(yogmFrk?jbb)nN%rVOAr=CbT>s53nG~brIV+6O9YKnr}`(tp9|;1Eo@?b z@95^FwZoYbN{N~3D+~7s;dUiF?;#XUG$xT|5TgV!Oc9d=fgGNSj54KwSCZT>vdp3l ze(*CrSqiFXI9gv;WnE&`bI6bRsFAge$TwbM6?BfkcMY6Y^45GMWeo&JX3WIKGHGOM zwr-|GP*tGyCP$An7<f`3gB5at2NM4Nw=)E^se<+tkW(~TalicqLVKZuP1^@sHB&$+ zZL}cfq>b8(eFbunLT>Ru!r%Y)1rh~K@2jAJ0z#hWAu~6V_QI^E^{}O&o<FUN)n(e4 z(=F*5v5&D?gYbx#Mfk)1%=%t^*=Y4+Hi7a-gpkaLG%q<6FjkREe-ah^E0Gw_ziR8~ zPrSN4|CyD+j#-yb66}r6uo&PH<{xQ8X`;^vylI+!^g3EyB+pnJj+LE_5^b&J3Hnhm z0M_zTvaR`@J!Ztp#<4#!zw?iRVwm5%h(BZUPGlvHLFBxIG+(CLJcCVSO|<Sb1E$jW z0W?hQix#3Ua**wbtf+XzXm`GjAiBf-K<jP+g_2XBYfjw<02>}@DJx67V-Pw|<=7qW z-wtB=V9g>c#}UG)RK{o#qF#Jqm^n{{pwN$7cMd&VLZ70ccahLB_Juq^6j_%^5E-f@ zI<|$=8RCSUitXCOJ5Gbky>N+<S(q$D*#CBPuo4@syVb!SBEfk4k#?ano0a&0cuY~^ z4C`(IR|#N01&jhfl{i|wrzkOE-B}Gc2xEn+VFwXn7x9&%#7(U`hrUljKdPZW+=7$v z`9RWvQR2J&!;JSti3`NZQQ`^UV*8+TR3edeB;3SS!e66>ZVybl<WmK6PKhP5ww0G- z8sIV8JU7<xkf1wRqLOQN*wL3=f^wYI1UV>%lGuWhH6Os?ZE;}6tLE8Zw9AY*dki+_ z6+YS?+wnuR9!N2Nu$H`(T}QvM#A^0czN#9k-aK_*<#wbsvqknB_-wioo+5H$AsV|s zmy#-MbkJDs5r<hl*u9!Hfv<_vdOa*_qATxWDt6Lh$8)DUz(&QH&42p5i$7BE_Mqs@ zCJ_m5=XF%s*NgW-TFlmVfOjWC5x_gY-7h`wap7esugb^cboo|5i6`mh^MO`A>OMvZ zZ;mEsn2#s&c~?D~;bjYNwDQ^$FSaVueHrh_DyxfN>u13aQ?^FN7qA9PV(l=8z&F*K zP=*dYiq4vkhJkzm6~4m?PQ#9<U#x{38&%S7x9PR64K=HO)0nSAmxVQ`<aCUz)v&)B z^U3|<e<SsO68ty6-DaKyc^liKCGYp*C<df%V3Ot8PsRVe>i;*4w|LV~+U+*$CCGRU z(tse*!s6r}CQ3yWr-GJKyZpwfE>iz9;UDFA75c1rMqA!)(~OCK7{WnmnHqdJ1uvXf zsf|BHS4j;z@A@LS;QuWgBo+;Hm*|>IbPd>R(~PbEVhMhO2LEOgif-ggPjoXmI;uU_ zi~m#9|8wx)%nq;z#Xp^M7V)lO{?O!Rr7lPgZB_z&fq2eR&m+mRX@+19%znJ02FZd8 znHBLfxhJe`*&K4h$HocOR*dFx{_r+i?!^pFOUSx0N4@~TLE6ek$gz1zc9w4T#IM*f zgM#kaF|#?x&0nX%R0?)zI|VGAT%J1nDEH4k_LbCKgg>H+DeaLug#^q#%6%itl~4@w zx|b6AcnF0PjaHr6had5vAbwO8uiKb~NGYJy^m@xsgMaCz(xwnu_k(b6Q|>*)b+^{h z(u*77B?&Q3LyV^onQuq1FV45dgAT2ZO#z5#nFQNkgB3_b$pT9exglmti1nLTy>Cn* zv<%IQCfZ>qM=g~sHdUZ6n6fi1Ok$_Uk%<n}l`O|Q&NGZ<anf^s=8E@dfP`vMHkt}W zX)XORWdNhht|Bcix}mp;UKfZ6Ppi;ZZbTx;>q0(ks`U*sSGhI><yZlW1V9`qJN*IR zc5AI(M~Zl5gOYqd@?!~7q(O2J1lNwz!h}XfTj<CEl}19DeB4w+y_aR$;8l7bs1p%& zSQ|;XepmJT0D?pdCr;N`sKvqt8AL(;cM|^(sQ-&N3T)hLqU$uh8xZ9qj6EgD1PyW+ zM{$msZ9^c6Vk$@R4Wc+o{2!+NJ4!0B9f=2&4H#-o#iRqx3$kI>RLUi1vMs0S%oJ)m z{PCy@)+6+gsDOQ`>5(lFw80P8&qUhV84^#1VzXqjJrZq%T}KPoMr<ml-``gCpV$rs zMIpY$I9j1_D>yaK4I6PAalI0@^AHM0Hs3}NqD&A26|uA}3xTrY?ZkrG2wBVGYY^hq z+$Ni?JE==rF}aMR^qWkp(>ks$tkbs8>2mrRGs{@j4LqeZzv`Q|gisjhLZ}=rz^_of zAum*Kcq<QD`<Jl=b0d%{i9{KN1?0AThX(x2gd_aa<NauQ-?psWdV>p(MrYA<HX1v% zYfdCK0Us2Kb&!t})nQ<CVSi|v`mL<-{DjjoG_fuHqfJKB7oXD=4Mx^^w6nip9?EEf zU81os=}^LPZBR|{2BjC^`lhA$jWC=VjGnt-g!^13WoECAD96<9YjG}iydvZs^fS4o zCZ3@AG3`kAYy<sl6$T(Y#il*z=9O$7t;DNj)DyDpGuTC5Hs0`BfE9XYk%YBn-8L7u zNu)vR_G>0YoVI{=z4>;Vx+gJaVqbhD#!Ybqt67vA_%=8HNl+GIQygU)HpOvHC9?MI z%N7DUS%Aj4xDFK}{k|sRnayh0Kxg+f1#P68N>RpnNMSdv&B1SW#{RH5NR|cIEol4> zt85e!`~QoK<pM%gL8vO-J)xVe#yfGyX0=K%*%eU)?4+Yi^$9f-zu6ffXs4<LSfTh` z%=AK86A!f$Pz<=xa-_;MOr(#JN3$<(I+*N?C<1oU4U!Psa|qe2Hx(h+86l>MPz<m_ z@w-?>L_(gO3~Be%QNc--t;k8fXKx+9K!ZF!Fj&45%)7^q-<UmiA|{ipnEX0c(ZdNZ z(Mrp}4MeJx-5l>Gx?$Xsl<^xxM?W=Onk{ti{z3JC7Z;&S4oPB_<vDZ_hAX4gNrh?= z%XPdPVTwc;egk3Xr-mb85*^EE?l0>Mv>)hbG;8%uhl@b@PG}Y=$B97%>LFhE4|+=( zHSyLpEK)4OsiO8y5F=DK3Bzw76#Wb%)Dyq6mhvdHyU~z2v5E|e2&d4{f>V;{qjBUC zORUAQNR<CdD0CG+4n^Bh(L|5f|J4U=Ev@yGEf<F)*n#(dEEAVr;*tkHjpDK^yYM!U zTzQ#~mksiABX*foloX(jUc@I>M&ko!BFZm%+bC-!#1eMkDCdaFJh(*TyyfH>e&nqO zkMJXJIk}r3#~~8gCmAcNLP+eWtck`?n}Y!=r8I*_WSH7du1uY;=-6CNJmdV)DxSz@ zx3y!=H-Cc`eI&zmH&?<KS6rE#xx_12$ylcm-b-yPZ%QgJo?y>~1I%>S%w*Cb2Mh9S zMeYrx6geX&l+MKL2+p6?QXVIjFf&yNI&ZK_xK(1<RAX4Qj+Njc8LnRmdbI-$<S78U z@)F@u$1Vf;OHz55c#&tmEdq;RcGD^;Aqctpd(NlR6}bnHRtYR;REW{+NL{30RwLlL zMemG*sq7WyMGCnr%aGk@y%1%ygx_;%JH&W3i&dChOOoD@_`k}qNqXQ{sK^&jrUdS0 z<8imXQ9Pd%kQ^M(QhwA8H5$)YiD!z&b7(+3bpNWX`7iUNg|>E1mN@e8c)ob^Y<}5D z_+6C$@!HgM6qtZP8({c*^Rm5js{sD&?>L`cg3U#;ehTq1&)my2Bk8wc_Hw-Ww(-dx zzK4W8M%lZv?6nPUUQf<v-Q*(=*xlXQNO>@l-}9!GV~tnMYYKqkdxOOD8^*YjhUeFi zj=b@7lE6ha9)Di{auDZr5u*HtA9d?zyu!q@r^Iuk#xpn|o<~jKpe@4JOB}RG<|^@4 zWEWZ2Asvgp<-F*r{GV2*relB!7_?1z|0I9+0REZ6fBSc<ryGfn%T)F<y@EHd-R+v_ zIn<jkuXW4jS%ROS_yY;AOG)9{_ia|N4yGvN`(Ip0z<QL^s`E^K$u~^sql8C21YNXr z)}#E0>jkmyUsh3P0>MQK$-#)>m58$&+1`LAFJiRXx+UVq)aW@4zbC>wm;Fx;)5t$9 zLQGW17e6}?J?iNsBiRniy7Ku#=&6KzT|%_bp8sqHv7aDTVfk39)@UI3$=vSm7Lq+Z zFE9yZWkeA@l<}w{I+GLy?`ms*>4DNZMgun0kK%XS0uM3Xq{hg?P}A4UK1SJdfAX@s zNT6=Sc56Jfyls>0wLL`ymwm0Uf5A$-B>glWd%g)2Eoe+>)gRz@yzTG~@n%|eIm6pS z*taTs6Ce9@6NuP;xsOV+ivrk7nxy<I`_Uh<(>c}{ZDCWr@#3r9l84KM`Sq_>7sJ6E zQ1G4R;WGzFD<1Wklt|CF^E+<A%Z)dyXIgnP@+Or1`ww3Bi4q8#)4k>;Vjr4h9~i)% zBy#Vs?7MyJ_4`}7n^N-dGk(Y04ws2H(^|{&-;Tn5XRXyqv5$SP2^1}8O3A~klkCd^ z*mYlV9$u{MuUAnXHbq<9RL@>~d8jS)Lc#8$*c*V=9na3Ldeb5V?yO&c(5TOyRHp-6 zNYJ+F8Xb2>d1u2FLU>!n*vuth+qAL8Iqi}kai}25718j$woCj0iPRPvlHr`vd@0Zm zNcce-emcSrDEpiX0nJ6ioXvVjAe$+qzY8InJNTw`QTJ@trzrd5gs^apEkl_uAzFCa z98akXLhL4ps}%9#cdCick>CYEEwsF_E%d>H=&y)Nfxzs5htjkV8mp+Jkybpx1EJEd z;gXmMmy*)&Go!KEa(?^{kJZ!3U#T7d!$KRCp(<-Cu@jhbTt9>|R04~ww5^+PjAc9t zM(K^j%BFIR72|n!TrnveH($7YmHWiEl#&F`ZDBix+~b)mOIp~oBV4*;n<h0z-a5a$ z%Rgs%cV2Df9nRc}Dh@u6G&GvIiRm(%ABJCjU!WEGXyN@$_>n#1MqbwEl`*XEVu`qd zlZb=%v5G+)xPo<>=-3er+t_`$VKN(d6U)d$=3K}hVXrQRQ^c4e!A!@W62WwFFwuDJ z9K0Er=$(%V`BVr>azx|RB>KR_fjz{~R5)uDerL~kkC!LPC?#an#37d+2v&(;@pk1< z)DZkCr<aL#Z3iayCgwQf7inWr_^tpsz#50~9_q&Nerz%3zfIFt;tHy!HpreDgzFb; z_uz`rfJ{n41~I;44qU4cuQ^<^cO!mR@~d`j5t=oEn+#Hp*JLI7{Xyqzeuq5E;Xl^y z8a`jM9oA;(DA3oVX=PqlVDbqmD=<Cykyl{4aYR`c?nU`QD=>NDa2h-Ca!9VY3>Ft! zfyoh<zU;y)Fn^Pmv;xy!UUp>{cLgScUL;pw+Oh|VaxLA8kjVORPc9Q!moHl-F3aI! zR$$)YM;<9H;zwSAd5It06__T3bXH&}rOCyIFe@+<KIXbG;AdMG27H4$hA*zTB=gH{ z|5BDqSjmZAU4{4iPnP%l*C{+)S3$aIaRtU8-};C}d`OWG0m%)Gl@qzneq{xQ@;Ir4 zFoW}LMd*me5D}q0q+0pqS3+`_j&ey}&=J&&#A|=FN?4086+u{+hc#DL0^Qfy+zO0A zP7vh%io734s|4m^1&02b6_^}6>Ui#Ix&>NRVA$P_kY?ql^Ls9BBaBxwlf^Y5lB6Na zITLo%_;;fu70mL)(?tT)3JkluV_k}8{T?I-$MZ8kIx8?Ho|TdnwLe(Z)qa&4&od@) z(D9?&C5}8qS1#VnSY7sEUMu{O${!iPKi&ikT7fA{@_PjE_crApYjDyR{{AK8=M@-9 zp?6m94s6T{414p9`DB>WL)dpK`)*<v)V6o?`u5#9uW1E_-TireDZl6O`*`D3^O^#n z_~uGH1sYF5Ks-GqFs;CFJpR1iIvG#<H1W)lGW`}7#Y9(ceUX};S9de%37Ahl&hL0k zf1h~stiTKs{&~tjFMxlR2^h2jb99n_SO9<3hg>JNRQ{I4=cN_Vq&KhKp_^HOVQ;>? z*75xhf`1b0RHB|IKL@^*D=;_xlVz+`$T=QJh!vP)g>b17_VN(ItiWUoB3}_rpV`JM z)C$ZDSw>omB`MKF6~ec61?B(|;wgoUaUo$=U{)<-U7n|eon1nx6_`f_v9BUN`c%jF z3o*W*>lTvW6_`b`h_hm)RmSZ=xGONX?jo&y&<f0Ce#b5F`No@_z0;cIx$kibXDItn zAG?nP3S5ENImzB8fW4Kldn)_0PrPz}va^*tbp_^Se#a{?&xtqFs>=$@KO}G8MLCfI za<z|LW&#DRz?_j}pA^78LD-indoQs6<O<AKVeX;KcbAhck}ELp<VmX+v;y-izvCAC zG2_kVA+5j|d0#~_5nWvBV_z(R0#{&0CfUaZu>X+a`*&q`@v%FbK(tEY_B^z@lPPRk zFJIk-ljm81xkuPrD|`OOUY*P}fr3_G?&o*h6WkWSK3v$(V4+TQayr<5eg)=e!H!mJ z4vDN=sgm~^G`9lNPnL1cQpl?xIgl_bFd0JVu7sFN2(<!J`z2TWFR=<H3OXDJezFTK zDQo2R1uqNlCL+w%@EfrRty_WVCXkaAG8cygbQvei3e1<1j4n!;;u1owz}zc{4<L(Z zqBjsm6Cqb%Y6NksB7Xe<9XIU$JIan7KJ;>w{eg=$vJRmi5gd!iT0&1aesn4(cCm)o zyt(VTtf{3Rw2p#97TCN+gEZQ49V=T-^G00O$1c3GvkWd~9jB2Wc^#*L{9&=qx93$C za?onL_BI!QVu&uuE+&}^ooh5{&#N2aHVLt{hS-`y;FGN+O(v}m)QNaz(Wi!mz-L~P zmw5V-M+h=Uk#+C4AVen#@ex*vMC|J*1de;D5OX|2RIv~#yMJ|w2%4COo3pW+^}Zqt zMTk0S(6ClQV!I*ACB%aoViOi3L6h@HCNAeoRI(7V9Sr-+@JpAIx<S&Q<s?=fuLG5H z;0n%KSqFM%du~4MauTmt@N&|0iD#Ty4MN%A<TGZfV5lsZ<)rZr2FppS@FsORi9~mo zlX|ecW;uycl6E<%kzOX3lUVh%pB_tP{6<%TA_2=u2Ox&hI$BOz3(vZoRAV9pgw>K< zlX91nmYbLnnl+MUIjIdTCuIUfi$H0XlV-{8r)u8Rlx*2+$=SQN11loDZ_&Tnc!?=b zpV=b1Vi}64qI~;p>A)wkb&*}Bt-S<tvqENjAcZWZr^ihLTKN{2?g0uKDIjNFQA=q} zO&huT({{Lswf<9^wrr-^Lkqsy1&KryCv7xf$rQ+Q3R(0nDab+!S@$Vv3jozf+RjtZ zGy$2N*f_L;rlErOlQ}!FV*$sWdGA^?$DVnUTFiIsc{GxS)2X}{PqP=>_5-y^u6}I} z68WF_#A<Wy(iTbzQ5<d3&g#tsa<)P)^FRt`QJ55M27u-@a!J`$K|KYO%$e34>3&UU z?_e3J220V{zWk1x$pIyW^ys9GO3Kv&DOX6P2U5toPf1$<=nw%Np`hahgp$$&tH`FL z<e?dbOA%a9bTG4@6`>_&IsMEoX5(Z%pJ5h1)w~Rijg`C_E&D66%uK&x72Vj;9z&!} zh{=YaHD9@2`X=Yi)mW$zZQin^g_1&>B^_;2Nx5Di{S<Pn2U5slrf4$&6cNy`SZ)z% zHW83pQYfvdZ3?;iYr(NXdsu1DzuiJfA&QeWDk+-_WUN9i^gs%$DNIV*0zeDiU`=;c z&^`h}DQHCTFbCu_q@*mzA1(#;e69%_(P_{8vZU);`xukc>+%5u_7^YXJ*C)Uk1}G4 z5+8zxi9w1|9z>>56~$$5N3G^xiCJ8}%sKhEJ;62yK1*W!v9s7K7}7+MmZsCM<n!?K zj?cqihQ3nI!_yBw55Im(dmf%WVn8~H{k=w#!Ky?4=sf%j;!lrqPu_}0CV6z6omT|e z2A9Y>&AOA7k_z8zud`k|VU0`5%sX#ES&6LP;xXkYcUS9f0eeZtEcw6!ZUTT$-q3mY zU$$g9QjT(eXx)KH^g2iw<;oZ&LOdhBiu~u{@3QV3x<o=BtD(1&&=<2WG#7Mk<7^4y zo`)YUP8jXm^YAyq#W@eZEGJlrb=KYLU|W$OPbDaCWF_7r9#fP!#kyO-g#!5aeXGQy z0Z=6l67MNW%(w2WhAV_|yD~NtA+{1<DN0<I&8aJ5{q(v?LXXtYufNGj;QLs}LPtuh zmmsbZpB5)aiAN$nJ`bOPda@nr6apR$H#v?WXI>InU6U@kRG;v%8~ow=mdM&zUh-M? z^@spL$2e!%gU-V*6K~1$@bgW$21NgSDx<~o@U)j4M+H*O!#|G-BQ@pzH!@N_8MO&% z&76mS4?deFz*9sn>%n>WwbFtR8_g|FB8r22lr3J(nsAP%=a6Os&%<BK)wb8oQhV26 z8B1i^mZFQxhc4uNkufT8W&d8h=VAp=yf?iL?@ojwK<asTc2DKqCA<cWex{En30UQ6 z;OYE2yUR`ZRzB)2juze|<wblvk<YtfsTtn-*SK-(ro6SUQEr4h4^LMVC&!Pv`@&g6 z(rLKefw9E`j&Ng*@M?-sA-*{VZ9GZdoom|T`Am2jD_W98#U4WQ*Y64<CWtE((MAy5 zIV2B7Hlh%2N7WNs6{st#Z|)u{IuMC3rIJ6s99_;u()^ZMPjj%Eb`zki*HIyl$r-*l zzWu4m4|j9Zk5UNcziTzn|J4?B=-%8!ecBu$OjAOphfp|js;59wHuw?e2;vY$yts&k zz|5%}sZ1X3$F7Ou9QrAT@9DH@BRm+zMo1&(h!pgTUoxVY)kH6FD3bm-ha!j3Z&he< zE@_i}RyXh)^Q*pT{lbh4J`p*x&egBoapROxT_CY#^tq*6!Zy>SeFjz%5>Q6#oIxGw zcajhm;*XTkyFG-$k!Fd;*=goS^b*8Xia1FSzA`!$MTtLy8Lys13TSq^C}ngy`E$zX zR92jx-L0gbcE(sOXLsfE+R0*SKc(#54!}p&{Db69l8zVOv8uSap&4b;#CsCjbe}#O z5gNn7ixqN=2Vy^{?TC{GbhUtbD5$-Fd|K_1)M^jWY7tya$@EXHM5{$Ut>$~RI#aaD zqu*Gy%&z2ux<rB<6BXmBRY=ULqd&33aK1K?mDe645ZoAr$L;Wl4~CTBhU3^<(b%VQ zzIIo%WKI2Rex*7j^}wF5&2dlDPRBP8akN`18{K<nmn_0HIMWug`tMm{^KkJil!q4L zn-cq53+lHH6~bsGlzRwau8R9t0}Ihv5d#F#a)aYr$JM(iAlDHhR|6JjrJ}BV87V7t zZsedPR5wH?330QAc!fd)-qbMN)&)eguLK*V!DdKA$$J4PA~%Fd?>-u0B!$rPr}n0X zK`2;yQ^QW4n;M4Za+>s-h7YNf&!oDINf9>r(4XW6M7^eg-(ub)`u-hjUZR>07f}2a z{JO9rf?6t_glt|kXa4DQmjUc5Nq#{AcL0DPdvr|NYZ~$;NKAvAfgrf1p~#Jlu4y0# zjJRbt{*e-Du!ic%5#h^JX|HJ*B|-8uNCrp5-@DUPQADF{L{y5;lThDa;Yw7pXue5N z+RGZQk|57$kXsNWTKMQNe~QR~Q$$xb%#={mG}Or)5pE$%j!vkJGFLWaP~+k(|J0XJ z8)YW-`FNCBgZIjY_TC06kK;GXKeMEPYW>jU_?Nko=BnUT^H6BC;|S<F{o{&GLRgA* zFVXQ>4<XFZWU-7fZ&bvtf@ry=kc%(^hbHA#jb;@##+OgFFf`#NJtm!K!YsnpH=R1y z3{9j1z={VxfCW5FA!VJ;xvU|NvPmy%7(}^*X#pI~Wer@}+Lq;5Z*BPwEj0Eua7lAn z!@^AJR%pIDpP$TS4NG4@XOe#}U)CU!+s=e8YakbMS;K>MWRqTwX`Ecv&>abaRI4Zr z=CX#(>!={~I=!CD!!RszNp8+WQ0p~T-}F8GOdd;)CwRTae_6xf-(f&m#!Ei_%Np9^ zmE}Pkx~zf40Q*KS8*jLbTcIb2B>ALK>o!{4Sj*NeN^ZEUq20gtvW97>pYfvhWGqFK zTwI6N|1WV_!^l5aE*7c^Lj5H!YiPj1Hd!5M;j)Ii$fF#jr*FlDxUAtE4zVGZHN2Dz z`G1!+*e`<bS&Q28SGug>))!bHuIAEk@>gA@!8Es;{MRpQXeUB(d-QL+tl?ptM)X|P za2q?gmo-cmmptT9BkeoDy*=#0M+MH3m)P)WFKZaiF78o*ItrCMDv-|}D8p+6w}&w3 zsK6X?=>!*ZRA5tn<Sl)4k6<*;M+JW7NB5{e6+${k1y<o_a+iFVqXH$5bFXs%Mp4r1 z?D8B6!G>Sf@atpD`xGN$;Vs5z+kL!NUe+*MkTVoH1xSWlF17?v$|D<kS;I<+VIPg5 zvk2Yfs<RcBHQXV*57DEG5?;q22<!4%d09h=Ag@v6B|uswFt?e@8eUjS#XbFH4R`Q+ zE^XHvuVy7xFHzW8;@?!`U-t}><h!h4hy+f1S;K+Jc)F*F=h;WO{M_@3Rox8%@vK~9 z(&Jsuo<JKC8~Gh?Dt%eJb+fC&wA?gY`2CcBKmh+*6ENtg!1yHpv;h9Ek4X8)&|I>9 z@jsxaf6rwNzYF^+WnV~a-z5r-t64W`FKd{??|Gx?{l=^2bputRM6WL-o}DzFEdt^h zCxO#m)(}a?(<e<llO>*iU=AX>nq8fmo(vN>=(2{-f1$MU2GM`=qy6fLd``Ht@Q+je z;Q{<g6ENtgz?Dh<#R2@<hdHlTV_`|;|MF?dYrTcR_kA>X7dUzj^_K3az>9*vMe$b? zUYC->UDj~MgDm4c3hC#81gu9@Itz+4lix!Kqm_{1A%r<9@Oc#r(OD6-Pua#R)KP&` zpXcx&&a;Z1jPR{JDzLGnW2Qp#T}YUt0xwH4j#I+wCmk_D9Tm7j5L+waDImD;K!9*Z z1@3x|mC-oYDq}oJ;at}6#*grT);{Q{z?1xrTlxo#H>v%yJX9#+O;C16ANza>6nIqN zxFq|i0QScZu-v)Iu6e>M_ckU_&}9wlexNjQtNuMd+Ako=QGrrnzkr#v)Wi`!_H!ms z&{2Uqlk6J<*n0?jw6Zh6{*y-qdJ40HG9Q^kx=0=s*i;0`4>~IF-73~a5jwli_|aa2 zBiE!FdFQ-jbuq}teoO)d9u>GD$-X*({pxJa!y(H4`Ejq@$C^MvM+N>SY&t5imv}3( zWser}{x0mbFIu^0`q+G5Rh+(nn0i^md*8E8i2Wu%+MYlzg4kNvcPP6z*nj@0z>b0~ zR_qs#K^?k;7w)LQw$HFm2Pve|g@idO@XkM&u!Ry%atWc13fv%wS8J{EcL2h)OJOc+ zSSR7*8vgx9NfWI*D)75N4p+#{E+ouRf#-$LP6<O?La3txlLRpr3w+X)Yzc(XM98B8 z2|--0h&LWV$NitYtl_hJxdfbze$upm9OIw9tRXI3>VJjXj=6vOvWA|*9iiMu9%c<y z(EzmcKXF;ZvpAK7PSNhJUq%saz-0~RJD9)PWerOnqRSev_5DA1S;KnTUH=El@^UCJ z&F*@8T_&Fyi5FK!Vr4x@-SMGVy)~!lvlf0$`9aGev`-(+b`3kYmo>~5mpu5%5kEJv z3$MV$<Rz`Zw3n9`v5UI`lfkj-b(zPp2a0kn8TArb#lmndYv>6VvjWqNA9<wInICxt zW-ESlS74gJa#mm{rL9|msh`Dlx3b38vC1mcg$=)~;UeJ;Qr@6cUMnwa=qkwH(Njq? z@cRRH{BGn#q2oN>(90Umlo)Q;7;Z-lP(n9Xovpa6VSC{nrM#n3d9WW*0cr8NO!kHQ zAMW6MT8qYAl(2SoQVA?)GnX~I_a!$!dG-<o_ZTHzqVOEQ=hF7L@v5_ODg3=2xRc|j z{z>AWg!uiJHJmSj(_YqaY%-oB(!_J9#FL}(<OIaCsR``cP{=DV-+e)8<+1u_{AkDO zvZL%{$(lLUHXU>BPff=|CScGC%ymhAX#jtU@CPY>5b^&#mo=0M`{$>v>_6W}vU@LU z`0jJg>$I0Oyut5z1!lhSs(Ia>N@SwfSrX5+8qc)>@mwW=X$6LYc`h)cGBq|C&xvW` zX)Ez`)p)uF#IutL9JB({M&h7x_nOZ**=9^HD=_y;omudd)z^Z1Q}y+t2^h2ja}U4c z6`orH`2B@{s`5`I{=e<AhQkD(rT8quw{ivMt6R9<<|w4@9v2c~1?GMsyz!*f;^iJf zm=%~)1QAz6ArRb*AUPqf%lz~~PQ+0f{<phne7}%4fY4=ZVQ%Cp6CpNI$Uj_2m=&1* zLRj#G)x-ps5NZV`LlDyxu|E*3iO?%BokbakDB`<Hngu7X%Urpft3u!kOe4SJmi}eq z&CY_?q2|w>$%_7Tj!oeWJ~o|`!az1~1!h8$eMSKLG+|$*?7#Wg2bw@ZD=@jj&O=S# zT)dfeby<PgMA&;O`@OroI$8Fyl{@vi%oq3__ZUwYZ&oLZp_4}?%ie&gN_xJ_!Tysg zFwY9}5@qhm@+Mbcx``lxD=-~IURr_4G~TSdv|?)H-AUPR+)27fvS0g%brHA%!}sUJ zWqn?}<-6=-MDBSo$A~V@_p!&DKtU@oL--xHrX@xM%cd2WUvB2IH&)r(_}Cpypr93) zwI5QNnEfq3dRJg>751jees0#kV+H0O!9E46j;Lb{u&rHzskooh{h~s4av@<>U<M1} zG9`R)ha*O)6_^}B6e!|WAWXXyW(8)FgeUuxXks{v(7F|vO9k?@LOQyTFe@+xLO5Ru zi*F}Q7%@Vvz^uNHvtvI+%mBh@BIF9pW+KH(SWrY6Q6NxTAI4!7>?D#el-_B7&}9wR z(+|F^VUPD|1I>T`vW6}<aI$AUWM!Ut8)R<ovW9Q3=MZBx#8?XPr!H%_O^{<0xphlI zjFS-iYlu&7Wg&R-%{NBOq1m=M?}4xK(67`_wdu(Mv_qW)xvwIxBV^%Fa}of%&HR@& zd{)ky_!l~6$?p*?L~AZ<xFM6p9w*xc7eL@Tk~Ga_4V&Unj<cM!p_etxUzWtQ^0J11 zX0W_7Nyv0}e>T#~4ZW<PY$jdSK+8$AT*8+%j6&h6F%d#R<&4)GA2#5!hRhXh@Nro0 zT@Bk~mmy#Mc{1&h#7=zP$N4AjYIs8m$9}MFN#Qv37N|~F>3th*(_FC-6Ua9(+z4dd z%`PPTT@6J7x?4d{2*{aMwBoLY+k`e)X=9j{=D0zcyBdZHWDAAt<bj00tD%E{UY>20 z^iBmSX*IU3PDN(^<?m{^Zw5CbSt@@gmfwDgFQBB*o_EJyPCHCS38W5Pkd&0ho4h53 z!g$V%QMLqtwh_=p3c6ZAZb_l7@Tn*8$<-dHuqU<hgw|bY1x#zEq!7hP8;xw=zm663 zIeKVG+s`+02AgSM_`4cz5YX)kdRRaxDLs-Ug*S9NoAv)XcQx!O^1pwtRm6%L+)NHA zDLuT}q>}PQg0*?GLS}m);qPj=LqG!*G*UorNug^HQcDWC`b)}ep{>8irY)Ok&6E_P z_)5yj0(nj$i>~*U6bh443j#p70y<AY(*%T)LT4lYr|xQ~ycVYhp6~acysP1@Mjlb* z`R{6Y*1F>?10UbcgDf~Fc*fl}m%EoEgK)pDcucuwV3KvWfGGm#rhujy&NTxi;yvY> zf&HyJovG**7slt6R*3t+fDoIBuOk0l4L`lfsVm|W8NFsn=-C>2tb~4@ePJDtj&0OQ z5cisaN5#pxX5cHhICnMdEgn*o*wMOM9h@Z+Oi&3vzmDZ!@dnG8qQtkYy9F!~Ku-nS z3xM9$aG!WjQR21Mot3y$7~kJzl{iX-7%RR~lsM43bLb`s{e*_zSweSXUq*>LNDx<v z?ZwGa;+=5u-_>v(+`M-+OiH@sq6t7XZjV10d{e%kC@=Z0hQa2!g}WN|Har|)E?M&d z7<7LI-SI$oHDsqUHu$cFY$!@Py<e|Qy{lnl0tqm8HS7zYO%3oA`S;(|uslxHw%0fO zr_WJ$TA9wG=+fTR&|fn7Z1vuoyl?nj4L?crJ1TEw+{@!T8GIj_Y36Q)dxiHJ%n_pE zJA6DYD!z})G{YM#yvvjqCEkDVu7*>t;MVj+jqv?z5MjDG1|9qL-_?*Ogzc1YtA`Ng zu7(e%u@FmPwGb^HCkWq(?M4i+{)%@s94>`)TNVG7SPMGzABb!xgm-SY3K;4kggFp7 zS4z$eir7jJ7^0VBxbgq|u7<(WH~6lGEh@NpY^+H;2&`tysQ;pc*KT6M%ePtm{&KZT z2y<6MOb}Nn;z>dH$|y}2|I&9goFVCW?pCXcZ?1Ax5ikLm<Q*i_1fZ)xCMx894<!6u z4e#H`8MC*7MhM8KRhn8Et@c1+M&DZm7w&sgr&j;LyBa3E0&(T8hI8<kdRN0mXvv!9 z#9O+n;e#^he8cZ*c;{-?+Tk!=Nqf0F@zlH<V3~Cr9GVZ`D1>%O`20$j5azCiL4ueI zyN(EPw;)<>aGJTR;dX(Zt<Wezo4c#w3<+_thS;7$w0Kv;6%wqi2K%g(BT9c)gGujO zFx*IbpP&$W{PaJ5S3{mie7DBGKgS>bu7-;QFj@htu4w75hHE9rJ{qJJL0Y`4;Z6y) z2F<o;>S~Utxw{&kk{}B-$PkXGg}WMFmQdGesGV$z(%#kZo&-5jgRGcFDQe-ahLsX( zHw{&dPyub!U+%7khfBGocmeITWW~RxqR=)symMO$YU<Ar!X-+0&O-<@G}&Dc2Pxtr zLA2ab{CDnZsG0Kr_^yV|b=0lUq<>p}GIurXc_})RYfo<Zu7=+)CzJGYz2aap5(MS) zB?;!PhLbO+g3#;vGA<AQg2_(G!%76TUU8p7e+u~@x~t(UiYm!Qtb8`w-oelylH}9e z+PXb0Zl1duD#@+IyBeA>IEch*`D&|J^>~aHu!VOV|4EF-pJ<G4$&JPmgUAuzm*YQ0 zxfFMs6<IYhxZq1x^eu?R4f+dPVKi7CE^LZ)#|jlbx=x=Mq`MyEe%>|j<ECC3t-v#j z5%<Qy_m`PB#II3*%r`;6e>c*-o_2@{f6jo|S0!scMv*Ch!LC#kSGjjNl*HbNW|uU< z$GPOgT$oUa!y_=e6<6Z4G&EEO^W{=_BTMoT>`iV-m>I>K6W(UR2ZdOJ8}#QzyZ;C! z(p@u<k(3BSqF-M<+_#jTa`nsUF~L&wH68lmu&gh>ng)YBlm!;Ebh5qE&Du~=U95p% zN;#M5I{c9`oqHKl7O#kqC~Yf5_r(qJWx<o3?{6B`9EY{_S<G6Xtk*8h$T%v|u{Sh} zoZ$}*=7LKf8l=BX6jx#pZOR@2^~G{loZfr{PoBvUJf#tw<wRf&k#+doV8ht#edlK1 zI4}Dji^~>I$in{k6>aH@hKWu;J&%a+kahEOl&@IG>a;hU;#<WkIzlA#l?HmGqCz>C zeW$_XJuAg}9-4xwqPDpz$tRaUZH2`!RvX{DVCQ=s6>R>fM(zxj{Cf5O1o_W?+*A?K zGv9!3be(<Wom9jUS>HV?a;6pK_i>EAO3}xODELCDBMS1#h;q&u?Eg6RzdQWX2Pg3% zNqj3ZIH%5q9~^9jJdZ(dv7E1sbc0%wZj?xuud&r!%!*1U-J9aSz51UH|E_e+WpiET z3aG5pW+Wo=c;uCl#DJ-&Lfnwy{y1tKV;#Ge#Qw>*#G%jV)OI3iBWoGb5uuxvvljDH zeN*XG=sN28((mosa8A@vTID7TvfIJ$JxP~w<bun?@rO%EBCAYZj-fk@CmWBZ1ic#R zj?djLqiY(UGc5^rW0J=qN}L}-WyW`u4TaV<4>B)blybPnv}p<7;wIPQ6)4&5-eEYt z`ANcI;!uY5Flx3g-V!!|UKiOa-(^zj%4R9t;B#UJ_#6VCP2XJvhnTrn%$VoRuX=2O zk5CkGzL6fcfwDH7g+|tw_t^f#omUKm{x<>}^(lw{^f~!DE7SE9UA%%pVkeb7YhuPY zL%d(1-cKR#PJ|*r>MgWsc-sl@0Of7v<4FQiZ=q#(bYw`qm5*kK3oqn4_9?7b(yGq8 zFi5`CTWHhpE*9Pm$~&KU-j&T|k%CoIwnin+c$Tw0*5O_1?p8FRPS2rsjGBW*rh%oF zVdq6LY8~l2z;pc8!0G330?yM2Gbuua*jCXX(3cO@FDRR4=5QhGr-YX#x`e`F(*iVu zXe)@7Sl<&ZUM2|Cvpgt#J5);?V2;K<fdd&@&8UM1L9s+PE|F-?aFB=|W9CX@?v_;< zw1e5F3|s(R#}(D~k@rgJI928Nd4iji0A=WxM2#{|7Q!w{c+x}Q!zhjvq)$I$CqaCS zl}b^@-vxn6G7P;{e5=TqAMrfMJiiB>tim%X3C{U=jK+R|V@6U@?O82}wRjgv48*_w zbZ6SjXgD(EI^N<OC~rBvj#V_VFY~LuY3>E!#_$Cg4A!(*$VkIU2$e0}<7L%(*;FoD zoiru)6H6fh>eLlUqt1hc@b)!U7h^mG?S`GQ<wvZU!a|fQB2N&|P#sb#>t$y6li<M+ zEYEmh%GfeiN}_@Okl_xu`LIhxjkrutrl)lB^wct@_gGq`WJ{7VRG#wlTTse$YkN0J zd0kTUV$3RKpodUcjMW(@Yp9I*5!VRfQblYg2q>i-=`u>`#z{={pg;9xmH1<nQbjKK z06D+M*cIOjXP1iU>|*bvj3lbrJyF3rOPJ~zr3+m*KN`mbBC!s*&~@_&9!p{iOVG^G z*yTO$pZgq(MxiNw5ib%hXFMi+X#3_(Kw(`5wablr&zwi)zB*rI;lYz_|H4%HITvv8 zm^<AnGn07Dl~I3vJy!@*l<?Acmk_4P?<I)dinvS=PL*Hesq$un<=pIlEG%2d+a;@P zTZT^QGQoX|<rrx}_8}Z^HBA%ZND1-0hWPF82$8vzGK1D3onVztL}Mh_l^SdT1uGm{ znSEE95c^ArV>QGL2!XcfooJ%n0nykRsU-#Trr`e8w=ise^T@=3*rPZg=XvSscKm_P z53l$Tb+Of1{qlL7)w^rl+mN)a$?8%ee14Tx?2>a`LYS;B62#q#xLy!WR{L9bs*x$J zdz#vqzIAtNXu{Oj`lip$K?10CH+2?Mo{65pbZkUdRJS2iWu0L)zE6U2YNz;PREOWf zQyD+e2TN|ptfT4oqj@<-;<VLvmxzt`qX-sJ&gH0+75O{*ZR9Y^F^kWp9P73B1kSix ztjb7v9_e@m>1q1u%!3uemtYog=U3l!ozK^_1+@BcV&4&cNA^9b@2G|Ihel#w^gX`s zaeasO9WppFZRJ|LZf<cTf^StkVrL4p;!)h7gM2EyCFm_=-6WB<C3!T93w224AZo6# zau9IQWrSWOvOa#;P6uVRgPjqg1|`-4c)cOAm(1Z~W^S2vKZWG!3x<Oj@~KeS5oB+t ztLXKy?IL3qM`A;(NQmUcmg3`7_JM8m<fD>&R8pjgtfL&6W>OVYw5C_uVP5wzGSJcn zyMj}m8i0EjStzjznvM|cj1bc`1j#mcd0S~AAWrr`6s-ED`Dals6;HLXSe-Dye7y<# z{~uCqHh)899`_@T{AE0uG}qE%9#212CQWv(6HKz1rwR~?-yj^#95h^-w5&Ok(jqr4 zn;30!7!#|=p?GAn$_-*7>zM~BW$n;@jK(`;Y^<UK9_q`Yh>-g0(pvhRarvfb>8=~s z3Ev3Xq;zd&_KcBu#F~tGeeuRM@W0+H>197YFE%gDn=-=1=EfR1HEVu|m5rc?%Z4C0 zrXewY@QB!vL`2;d39$gvo&_AC0@80IU}Z-YumX=PAioY2Fz^k3d&wi<Fcxr-6_6ex z@sX&p6H%2Wqej^+z@?KLyqhR#T-#uKJUfKDQZ{0|jz7{Ky*>{4rVyWT7~`+v20Mf^ zyYu=9A+ChDhfp}O!LxTV2(ezqkr72i1d%jwCYJ-7`^3ZXB1(pGGMJNQJ19w_BWxsw z=D?kV@FD~fb-Z{wslyTqCz^vDX+H5lh{ckaOBHdcAR=Y5iIk3@)}-c4jX!7J6HZU% z^kj~OfOe<zWdur0jgvF$AjwQ2{D1+nB<6>)lo(4WoLrNVGk(NSK|H32#{_|Ty9xzy z2bri9;Sny$S=ua~rPY_M#S0#1n_i;6EZ0<&NUWNs!)PILxCG0ZqB|w7l__zVOo`1k z+n$M?EU}=}qrv1Qe)Q|qQedo3^$}lPSdRGFWWP2N`?%?=1K=1RiPnB18uH1Q?j-99 zjjtVbQe8=zQg<84efRaMjJr>3p|0ro+SHXVM=;@NC5-YA3P;XN$q_%|UO{wF#EybU z7Shtm<*A9$j~&>G|J!gDWdW>2QaF~J>X!6?9R=l1@uGtMtPrkH!VMlm;l%Qk#P|^x z3gS>j94&}sA(e@!FK1FFqDzIdX0lDp#>}xLJ)o}WED||Gb>$`@R4d`-G2Xgjwh1^D z-;X#(5a%o63PE`5O1BVoC13octt&hpNMBblfbgz>#N|sb@oMVu@%1h0zn#M0itoOB zaT%AI>+nZP&7G$-Qw7p|uBB2SB?=ktfrQ^nbi9Bv6qF+%r!Le|lD*Y|K9ozY{swor z(4K@1R?;@_<YsCFrHv@QO3_gu=O|>d2U5sc;HejBK(B&;DM(iZ9Vj5DYH&WLrj2sf zpSIV9w)7I4wl7D!#oJdwNF<^-X`?zaT_D#h<Zch7kmX59TL9=#0YwxvOhBk9<tX|) zw1I5+Sen#=O8ntIBsQx`TxMDqGp?*JtFbPz>N@gcR<_KD)m;RuT_*1v=#S|@yh}c2 zVkezPB!N*I`Q-5)s?H>Y;~oWukY1Obi232OJN<_D39i?%L<ZhR<CAAb(Z@vN=S)W& zoDSUNMBCT`Yhql!%Nna#1uxO~00bV2z$2#*(7rm{trb@v$7QC6>NR5&ooF`AAU(K! z91R(gy^GwcSuBL_F1F?5#giODv~Y5B9h4y22;yNyTnYqNC<p+<E3OWGbAXPh!gW>y z2Xn%XSLPlpmKl~2&7ZJjPa{`Nb`U}*C44cG5@ra|<~u7vEIgKlSUkz<<{ltS!d9cg z4ahEeWkA`tTmfj1M=Pi;bzGfAtjm=-ki{|(qPYmlv1G3!_eH)hQuS6s2bT~nJg2#i zOAs>!@hcYVrQusRLKF5ab}JxZUu;-+@eeTp-KFHegPcV9W*2F?i}M6>f<pH6K*Dzy z-2}9yf<8IXq!S`xjbnbKpdq`0vJ4Bdd$20(3$}-MLqIgiZvi8Ex*Op)tgrc&Ex3KI zQq*xCl&?Ui=_0BG(pMo{dLZHZno$B;i$9XEh7(jVeC3XNAM~C^G4cX?m{>Pa(QUON z%7ECgzG`QY=1fH$>_Pcju{3?v2eQt#n?imW?#dIsuewn{#1q{-0+3Mwmc2^qqXo;g z&{*Bb3)uKrH{&Hiw<_WcAX<AP(Zhqd@C{K&R~HiIMxrx>u$2-%9p;D;>PDj71@Yzu zRvC8z!OAc<5~bE4`+_ww8*!rs&Cu|pScJveW`>!$^c}zuTIc7eo3?i$1MFU7XQb|S z28+>eua7dJy%LrkPns}dM0N9VGl&-i@$&grhzcN#CKjWMo0nQ;5COliRi<DROL2uF zj%6v5bJ8#!$Oj@vABAl0LV_-YaXS#&?s=OKe#2tEsPon1NEt>9TnN*A2SSMB1yQ4j z=|C7|@P#m`bp#PW8S}{w&Lv~QNvw>CiYNvGgC`nqVfPG{?6Y>RXp@1*K{>pYB#KLl zW_*e@L3rZ%Q1;{a;uep;<hIl%9&gz-%U7cD`)LF=Fwr&72@#FYqCwZd#E!ZAxxFa1 zW6Z!VYog}U5E1uPMB^328pu1H<da@-9hm4qAnR#hqFpZA-=hV;PU(GQqIV`XHEfCg zdMZTTu@OHuf$z~6OPakv!{`2(ebT%ivxkv68lJXnhmC%7GgrJ6DV?AB^#mGpmcEkt zbtfKu%3j4pt*mY&cy%K_bSizqmV`{qqCskMq2q$RX%UlrwUq@#elD#Y2G1E2I+Q+2 z51C(AuOM&4Y%2?){9IZ~YoP3n9x}iF_8S_w%1W-aRBk?$RD_A9b@<m1I80kWc7|rm z5D^;L$7)$=v1-mXv#cF6-^<K;>PB8*#r>=4%n&@DPGns}9vw3TJ7bkSzzoqI=|BM* z#vx?8BewR*ckL0vm?0Qo*Qhy2tb&H~2)R>Is30@M`Wqlhvu217*++mGVvr+~*9<}H z>bPzM0?;-IGGCOF`66j{a6H(!r;`uAnW2r}%rIgw<pMG<k@XhIrQa(HG$%OGh#X=& z^P3MGZ$=u~2Ni5CNRg@GSdvK!8TRX4&tmasEr&@Bpg+7yPv#r7Rmh}@E2Y`xCet;U zZ6R*@nHr4hJPH6S*O)jW5)HpWIQpsKC~X1envNnf8|C5>qb)v+!TuA92lg*)45V$F zDAeXVe*8!Inw;g1T%ONY@e7F6!xc+|EpvjI<aCqd@Ee4qpBi17<P;ynS-{J(asFtt zYyyT+jxn){MvAANS8UNlq9@PF;*^oahIL66o7do}zN`Zxq*;4uE&VnIkz2M?gUGdb zWP=F54m5}az9}PDk3nQdsv%_^5g%J@=)oi6DcHrz78|Kbv5E#3a7Pu8ej5Sb%vAvw z;E@I7*MR~Cz9}PDkAS%>V2%}#9{!BQX7TCVQ{H=)?XPz@8d+icYkKfc85^8+9O|yi zg>bSG{yESkgt6ER5X4T3xLFX+Y-qCGz->lRf!nI?7tYc%ZDIy8$J$$b^B|i4`YkqN zgm9A*I(P_SEH-(9I7Sf*2arBiJJXj?7MpIu*+e<hnA6NEwBOwF<yg+!dh9!pvDl#= zLKut9y@I$>5&w!(VyNEEK|wTYYZ-WiOCA20wKZN4b5_#Kx>bGIGWAovoI>FvbM(h_ zpJE3RM(tX8-z4vQ$gfKNQ&A<3(z@`qQ5db|kz=BQ8VeY0s7hiiLjjUwnFF??$Yx0| zP)*G_R^hm@)*_FA4V=BJEwso>uKtD4Q~R@qtH)Ule|VHz_I<U7CYMC<RiG{c8LyC; z9!Mceo3aoZ09x9QrP)J4M+?ZQMzxgW)U=VSKW*KLnD$Q;Ln%F(OiNRlC~ZV>(neOD z&kkkCO$vG8NUjWKidM*3kdn3l&}{-bN<kM0$f;GFkEv;+-1VpJXQBO$(k*G*jcIA> z7Nw0SPTFVz`*DHPC}epF*A1ICmM0}`0idx0`n!T|5s<f%HK8YHsgm&krkP5{1BqrT z84o^UyrB{MU8R!E%16>MH|W8CYP-=Nr?Sx7RHc)vU+HU3;j%FOG^_MEkrpZoQ5>aH zZ}X%;`YYrt52TQ#O;LIP=nMg^JJm|Fi-6q9LP<_d8@c+^c9zf{QQDFt+;Z;gd8j}U z#Yr1gmfZz%x<Y1nAcdR-DQOD;eRwi!dM5=PE+DtEP(G%nja>a{`&ej=W2~mu9`2U& zfE6^NIBBEGa+^Tn3VF%{DdcjMlC}WQF#_tRpfd%8sxb&nz3Gw6*m5*nOpi2<ItQFi zu`XszTF+|&;z#!6#>`>5G9IRi4axLKGl^k7>W%R}Qi)$h>?k|U67oxW9awvE$cv0- z(a+?=r&@awePQi+wH;e~xN64|b*SOE409L)MdREuM&pl07{OP5A+j231mZzeQkE4^ zYv(W}A(V<i4CBKpYP!MaCFpHx?vtxO_owydva}1zrZko74x<H~G*+OLE>5gCy#+$$ zQXthX1P8(?=9JtgM=eGI`l(R*69t_O5F-Q4L9OWS3JREfu#&f85z`ojQo1`a>inF~ zkY7gIbiUr7l%;l|5Z#@C9v09e3c3;?lg<F^P%FB=Uxj?ElJ{g0)7Xeox<0Y-JS~vT z74k(tN~eL~I6Rfwl>8(|CqL=t?Xv{5V3bwZ9RQhh1{sU;fk-X4<mxZCu@RgVXDYcL z$jOc?U}#1Z6;BRX9VU?76!Lpt7ZSd=`3<&RELDGibxElJPXokH5GjPQ=r<AM4h=tn z1+jxMe2gYgG34r3Or3~wjH0@GP~o~NvQ;BJ9Tf6;k=x&e@2U<E(EO2BF}DL`6cf@| z)J1eNRT0Bj7CV^3w{!w^L#}?^{Col@tCylS_n^Xcb&m^V6~vOfZaCEKFT;0rV+Hhp zf~EjubQ988)L+zlsv>#=;TVfr(Gg7g8|!8}Mg4GygYuh<0y=_4sP8=mvIJs@ZXR(V z(L(OFQW_3lM?j!&da*Qd1&slSk=8_%VtutQ*g|lo==LZLzbgx(wxd?`9P1BYQ8E;@ ztPd&1p!^o3fS!YlNY4r6d59&7xzUA03%MgtQ4IC&+GNT1D9#hm`3gD`AfuR&rlju< z;{@%eh>ckmH6^v8w~321pAWamdZ9Pz#-RKLrGVas#{7p1<SvC=<U*ohuAq+c)t|rb z&j~wDLHhz^bQ99Dw7uwNYelRmMCBICjj=4%Uy@>3YRX_wJpB^O5{>o5vQ))GIvH)^ z9V|;U$TOBD8v>Rk8rOL(OSqtoqUK4TSeA%oEK6pM*IJgWCy!;RU(&L~r(9g)5{+&H zj7!F!wJ$x(_N8;-m+ed0^bj~awONj_XZSw+<sqD3tB<#(=kkN8CA9@HTpvDFAWtZy zzyk^2haV)MaSB>hz|w5kjIlsy+biuJrr91nTsQplU{=sO$5{o9^gzOQ!w(DSS_O3! z(1y(z9~IgmN_!=rG-Z3_aNX!Qf&4nurfr%B622SlBA_`6$`{aIV#bKAfK+D^)jW-~ zGsanYG^vysBO69>XIx3_Ej|ZIE#jb_m^^Mg1otT?YH6J_O2$*{TIcE~cOAs5nUR>4 z!;WR$c$#_`9am#>3SC2268n{QvOmy^Y#zjEEA|F{F0IW)5VqXXL+004eMR1Ab+xV7 zP58OAmP{t>jUF<;e(_5Z-Fr9B-Uo3@RYam#8*i?-vCP)39lJS(;Gh16fYTO`rT5Pn zf*+d5cAJ(B!PCfNs|>+MbBGNw1b0db6=VorJprOvV{G7gv?c5#zz}?dBh!D&5IndS z@=6TB4J6lJ!4Uk?fh3bP1mAxFi}e>b1aBrXb7g7P5WMvKWOArerC|vEsAX0yx;z#z z2I~L1A-H!>&VoD<kVUa}?PWCd2{Hu#3mbRj=pHp<d~}a2wSOf;@Ng0l!!NU^;(y){ zys(6a67LPP-R)NUBj3`Ewa9krHw0fTgqccc?BNo^7=jNI#85>f1mO&^LK%YZ5YFbx zDP~TZ!BvnU_yi%mirs-cL1=30A%rmmZ!3uDim2O<^wDZVa2MeeDQ6OM(u}4kF@8hv zhv+}CTJr}s)=6Ui<{^YJ1m7lz=N0kOzLc2%SwnF5-~OPP3au=_wng*kKV=9$aW~fR z%A>4?m+a$~{eYPY#jI0zS#8`#AP*>Hh6fVf5d3;qmgXb{9WEfJ8nt45qsuN#%Te0e zy}2CoYD6P3-7O+1>l<<u_Pw1M^6HURK~H%g;SIsp3+M_3ohhK?^rEyC>k})4cA(OB zWLlcKm9jn|r~PIN<a^Xpsb25y#dX6dsF3AJS-bJ9h6`w<fMzS`Issv(;_SBgpEm@X z^`)24q=>#A*t3PoLc<zgWqD8*VlGk0DIQ4pY5iyc?XRHi1msp0T1QVcJCLh?1^E=A zeRhOR+pFDMs4PTr(nf~h&H}kpAy;`I;ivUWWNXP#1@#e-TUo-djxQD3#!CCXn_JGq zP3x~0$h^a?f*$ff!cXfX0=ig1CkyB=F|BWfA^6H&F_)kBC4Czy@mDqkPuhuF@ZrTa z<9^tkmU2x~Ne}*Rz|+Nv{kEq-Ix6H57t#tt@Hd^MKS52AHe?Jy{PbrH!98|h@_9<$ zghe!CNB`--l<rRKw=1@1$leNBup24MK%!x~I|1DzpwCd)C7qW7WYYQP48f~}98>bn zEMn^n!4C`MFok^3mD1UIL+~jA`mLW$=ZyfFbpAO*@YF*%EACcu0mx}5Hk6+My-lG& zMkwUxU0q1{-sZ<XEX~#mdKe&1XE;Ofk0Qw1eXX9(VnOW8rZtA(XGE0gipuk#0>*U# zUDf#l>93IYcX9i>@Lg4R0j(>t3A+IxqnMC};B7=V&nV((mc<U{T4M-a(VMgBY(=&6 zpaL2@>PDSzoc27;7RVk7d1+_2zYO2ijTF#F*eA#uX}S;~qnnV1;DbfIw=1G25F2I) z{(CO#W{{$q@*Gr1L-3vg*-Rn#x{y{Ff<M`orJ0Ak7u}oy5I<RaZ}W!WlSQ{zX!z|} zkPR^eukOgA9Hgi>yO3g9X9#{mAk<DsdaiLHtuO?S6VQVS>I;xjOh`lU7rS$U#wy~E zohU)p{??j_))gYn4vKopMTIm3_YufaWSQvZTo=*`L-5aAbHWk|+6^G1n~;X!Ek!p+ zD&o`5sN5by@QWk<&k)SZE7Wgbd4-zDWXIbYL+}f-ZDgN9oADEObi3bx<&}Uw{33xg z9c&>zJdp5x_`U+VOF>`lz|w5kjIoE%j#1jJOtU?DxNdkwFD}p>6f(pE3EvIhBcS;O zR!N%)Xv1cV_X%yH(rUMNd%$qr=qQ2oP{<??Bz!lzjex$wo<nIq_7l)wV#c^(hTtPQ zVe<G#uYZ#v_^9FkX+!X?+i@f5F$8Ceo5v9RTQ2!?48h-!LyLys>6!2q_|=v~Ruy(y z$f-{6QQ(r;5`4g9c_fi_75T8HU-}-7d;T~1Ih0ZC&DeX*=TPX-FNI*sR<!#!uxgEl z<qFXKlhFp*c(<b0&DwZZ9Y;O_Y`kL}IZ|!BbC;)_ihXih(hhE=PGs#NVdVoKvEu2_ z_5au2y8y^hR13qM-OU5Y6GFmMhR7qqknB8mvw;K>3|!O*sGz}%cbMIo-5r^oS!ZTL z!sYvo5+D&GK|!MOh?0xE35wSM3IUOzf<z38h!`GX0;mxYBG2!fsyf}(JzYK3(>3wl z|6`Kv?$cH0)TvXaPCdHnRNalf6^_0P(9b}g#1_;g%(%17zV??##h%bOqrm-!!dXQU zk$z4DZ}o`0JPC8bKk2%hX>K~L#aeLDV4LIMlW#{~0LQ0Z^6jy(7jxL^AZMHxGW@Ph zY<oK>lEpW@FPOb^+$D1f{S@Gk?F_{SzVQ;yIKd-Buv-Maoxu$=bCrp1o)7-pO7ueQ z>nii~8O&nem?C5JZSXqk5Wyx*BH{PFZ8E3OZ&NtaMS*>9t3zVTk&KB$Z4w7^66o5R zGJ_j0B{IGnFQ;=>eh<r1xMh7DJd`>_fSOF=P>`3j@p4tipE(;>+vs0&p&xx3_{o%5 zsKLL5<Nt?^|4EJymD0|}hT3e@ILZ7zr!&c>GnUaIB0x>f29(KZ_Lnx{fxf~iY=ISv zTo4cMg@PaoM;{MPGNqjOk!a^6F11Ol<RqY#S`8)zW~ab1atD>0B-is^cV-J$J_i^Z za7hlRGT5VyXpdH2g&z`d5x?xljP1&VC=X#2am*CCF<Z5Qy<{ipLArye_T(7zsxuhG zd}gz?Nz8rqi!b1(HNN{Fa}FN&;mi$k3n=;D$6b|ZJ-l=1V|Qm-`3G37$%S~~o<fL> z6c&R-1!in6M=CV<7A5i1-58N?*hG$V5jmQr>^crWL1-B#^f8;zKPND5K!Q6!H2Y$C z$lglXvEJ}zCj>IlbI*QYvbLfmH=Vx?Zuo=TGqWej2w~7uDR(F%eCw6bjUQmyyStra z)Wf+F;`WgdQt`+r$B8VqiM-E6<Y<<1jf{K<9l!}4X%l*UJjn>xeFz!hFn}u~_gk=u zIT8>uV$Hws-^v}kLTpeqzJ6`hDki*DY#B7F4ao3AczjUD@uNWyD>rRxyB4=n3D=Z# zXbx+e9K%dHDAhof4t{AQlkZJ4NxrQtM`YtY<{4)VWgP@JR=7;>cuu6(CUVa>6blg{ zUt<zG3PNv<VB8#N6B+_ScS5~JYOsCe=U{8+jl1T-dE@^39jIzdjpmKJ8sXOterM%t z=f74}DN<${BYi(ua9-K=V>~+Kkg|&s7%h)K$5kEsb1LWBRJK5aDKm96D-yvY@#IJ8 zms1%(37gWFfYLoYtB*leUpaC1FXoNAoMjENMUK@l2)v$y8~2V!IWIfFj`AFx$avwF z=oOD8dW9VTq|$=r!x=OGWs`b)4AW~?Ctg9j&g&|tqA(!Gaw2EiL^imHxGYg1q1W0N zH<N8bB_QN<m*DiQ**_b1IT{Z*)97#~0Q`+G!7S#2`OS0^%uHm2S0-5My$^Kk_JH*r z@Oa92etzNXCq94NiK|Y8YB&g$i@9on(9!UXlEGMKagF#ZuZ%nW$HD>8eRjMFZD97{ z^rbt6zOZJHS#Y7DT88dEKF?CNnLcN<Qv^SAih!Twghk+EpU&k(j<kt%xQOT*x+Ev` zJlH#~TQBdyxB;^s(a<q3(w~9OHQzMqv2<{(1RA?VXi&h|ZHTi|B)EBNq=~($g{e}( z&c`7<AL`~qHgBSd?d3!cw~72=ce!X>itQAS51|7&p{I`^seX+U3L#b2FR5)lU|1um zoz^i#TPHEme9UHMH&?FgI?r>2JviG3nvl!YoWeMp!lvC^a?v=3=-)YshoQ!DJzLI6 zfJCs<!Hyvc?sUM|d1Y;nBmCJgOF1XU*_^yFO3sXrIBYMlLL9R=1<R(e!9_vmY?xPJ zngbTF{Rr9yE{-8i0>puRVj+&T@F@Bh*TW+OuAw&<IcG6#Iv;zq_*=M&xhR7*^t>Ot zY8hg!x}0}4M8|`9wSXmJ{TQ|~b;w7-=PaC}x{`HuA6$tOCWwur#LLjx=S7zz2uJa( zWDg*p<v;lw#zN0%I20AJ5M;6N0b`vBvA|NYeh{sPe|03tTJ#_3-B$Kani_eOzgP{5 z&JTXN2VZ>Q0h|o+ESkr|Th_4Q0Qjq4IRq-gy3TMK3)Y_nE6*>$4Vr;-Pk`|~KPY7z z4A!=}+LBd!e+GkT(t=HsZ1u!An#B;47Ej<r$`imIP@dvY-VBuaQ5hJ7QwDGrrA+xD z#Cym?`59O`U{8kt8n|fVls5zFiNG{S0ZvsMexD5v9R!3QJ`6Re<IT}bk+uND6>0hi zkkzW;Ulp;zwl3puzJPBwVZQ^zD-4=9es_>5fLRX4n6`o6D&z^KL)bx=Ct}!2IIMQn z@VPwNJ|f!Fuo?iOu?#_pLx$G?XZx^7$93^Yd*6wXK0fip9@yo$_gg^t#FZbO2akVa zkH@vc<JWi;*8hW{^@+bkhi>C;+l<E*z5XjmcZes1brVz)&LbM$!`@63Z#M4s5J+hx zlK?v<^Kzcey)VW@z(L&kj}2u(knE7m@ogllH`;0s$^4JuAP{j#=1hpW?WYilbvK3| z%QzknsduoaMd)_%XTS(AB{=<Z05X$26ke?A*b{J}hF=5_FPN_)omIoX;l#&c{63GJ z+JnXZksUk7V;4khD8@Van@{5#yBHTT$S%gY9He4A239fH#dt7=@nW3Bqfs$V=FvRG z_&0ca;wHNoUx5$&b}>GVVZ0cB#vWNQKFXu0i}6;BFmIGpj90QZb&D~FiLhcEcm6t5 zU{RFEw~%yaw$>KqSK%EMWfo#?dk2TM*mE2{k#UVhxjTDWH0q+unW^Bm2{sz6y#F2$ zI2PfG;{o+|fO_7}VdIvc0cs5opC1FcSpGWzwhyqNmg<q`?Q9*ld_5p-|1>7FYVRlB z4{WdM7zt?uo%TbB*%cVP>G-v~0Xp2*vzoH$_zmzH;p>5KKp6gcSc7olDyW7y#kuMD zHE%InhK7IBHfTQ}E8rZH+q;Xv^kLUv<!>?YmY<{L#faiSu5ru1i%GGw^u{f}fjw{9 z)(14U-^O{U$IIX0o4<;em5iQ(mwj%j;bpqS%lic{Op*+!FPFXmUfxF0spK;JvKn5l zWAV|Jk6V5fd)~C|WZ-H06$sSl<#+JCUnQ5%1@W@m&pf=q*?#=2!-KF0e-5}WO<MiZ zUaMakzxt&yt6$oE^-CjHztpxG=6s<k#5V8WfBNIq?;iRJd?9=H&{x^@HFn*}u5YmG zTkQG{yISzE@!dmP*tLyaN3iQCcHNy_N3-i#b{)^Id$Q|9cAdno`>^YN?0NvZzK>mF z>^g;A4`J8C*mWwq9>K2D*>wiHwzF%3T~qAZ$*x`OdKA0PVb^2WbsoDO$F2+5^#pc3 zkzGH`t_#`qBz8T8T|dsQr^2-#WM*xD5em0IhEH4Z3A_hb+kcHu|Bg=&<I_3#bU!|Q z6Q6M8*pEhS`>pu&8+=-aPk+a!Z{X8dxNKjIPe<U>1^Dz~d^#7O2JoqjPpj~$AD^zr zr~kmG2l44te0m0-5Uu}Be42+((ABiIcj8kgK4I1AhiQFl`xJbt;1inh{!8%*+35c+ zKDFV~Z}902V6y)WeA<Ce2ZC+c{sKPD#iyt6>BIQ+7(RUppB}=eUVOq?ivA&dx&xn< z<I|1!bQwOa#iwiW>1+6O7d~B#Pmki$7x8HuJ}tqgVPH(R7x8Ide9Gd}Onmw@KAnJ1 zr{L3P@aY768p0>o&TjQzgii^4x(c7B;?sJ3f;A3S|BvwrrnRm9$MFfqHdg<3e1ZpS z;i?0FI;+K+|A}`Gy%X-M;nf0sKl8Lou3VW}$n<4$<!a|=XMV7h%~fVrdNKvL<(6ay z1`D~Fm2%I_Om=auXJ&P%TufI6`*Y>ojNaMp*3``OCDZfm)6OoJihZ%-&_H*t94qz4 z2Fs<MT&0q$#Ey#PtFivf;#{m+ie>YQ^VuAvyB7YCL;l-wY+t!FG#IPo&&ds@Pfl6Z z{Ax8fFjz&LOrcQf$y9T(Vy-V!%>$v#KxwF0#bgF@1EuoP8L?AJl}f(5kc;Ju)m$I4 zusB!lEtJl-P9BmXT9~h777`Wo^T4#6M5a*AWwJ}{G_$cxxtv)VJN(ef;f&S!)mR~4 z%*AGRVDi0rNHVGj`%0y38X3a`Z2FzX=r2aSv+2$<M|Y`Ax62$|G&?rGvyIVZa$cM( zlz_ZVKi=MMECHnZp<*_-1k|OFJsjy~^8>kJC0{DW;s^?5;#vq1hN=~)4j7VKGMMYB z=CZMJrr4K@O$7o+!QV8bi9eD@ygjvR_)SFPS1E^Nlj!=%w;Kxk>=^ukLFfjPk;Sw@ zs<J%ej3FZx8OuqTZ$JJr-C(9-LxY30{3+@9l}kWAL(yr3AHVW!gdaaT0sPqYA#To~ zX_udEvGuF)eAbL`B^=0C1~S#2{#b9RtgsML3TO&u+NMCOJSA*h6QjYOta(xjn*7P- zD`6YtPmzKqe{%g?yyWm$fDWUc*!q`XV%fF!1NjT68-aQ(m!d{Kwe&3tKXR!>;m1p- zQTe#^U}*?FU<~YHJple1&8JHb>gQ8W4<hj6D!&N)c<D4MAD14SqiyINyReJeC09A> z^QkOPm;5y8&A`E7x(owG3&z(LjuByC#fOTeLKXVJJ*9!cp(>2tO2teehHpfq7#~Z5 zJ+;Ss3yz<^aN)@xoPX-^u_1`f2Y*>H1heHk%WQpf=$h?cJ9Nzr7+vkpEOP@zH(j&( zi?rn*PCmRVy?|*NOa9|QJ3i0vJH`EwdE!0JR^e|R{GIvc!TZ8}9{jDHr_^h?K1UdT zbtH7<Qq5JWY~lnT(og{gN<}th0xSoN6Xg2b0H4bI%k|nMU0JTp>DMVz(CpXA@@x)& ziWD^Ylgp(!{3%j!^EceG79H4TEyOwqzXfEsQnStIyG^e{*AA-d5Ae9?pi$PsVyQd; z6Mnros?U|nrShUhi}-`nKTmb)wiC+q80pwRz6fcB8{Y?vA#8bcMwbT`n6lo>wTJ3` zK%YoSN7izp6Og}9bQ<AD*6Jwy_|Z}F!xCci=F0rZ@|NmzfT*ze?D1r(Q@1@=>MNrc zmOo{d8MOfYlJz1)ewF+w=rzorT)rmwQ_xfLS1GyX^;4aZ?WwRwnI&kC96O>rQ68)} zHoaN8^Wwqul;tef6RcJVoG=eRAD&7ynNL|CBk`#_u29Nz07{&3fCk7er$prT16wv9 zx{>V=<F`~8!a<+JZ)E*v{1RPl{falHU&$`B^(r~rm>$GsJxFSQkW}lJ&;t+M$a=t9 z5YpGAq5h;+xwFr0;S7t-XNQ?`SMn*_l?M1!(v|HhYws9wZQH8x9YB?WYe1poPtJF9 z_*13e;?FMUP9yb^mmpL~hprL3>_gXZeN33qb35P3$ntdCi)3UudgvLJpZ59zrQLP& zr~Q3jNssyo?XLErJ+d6BpU}P_17Ff%QP03or3&B4to>o$Ab1gslGmy6_C?d@C#EOh znrfd8*En1jc1-)gT>qdGx@L6Xq6q)c4<(6&{4{O4B6i0#cfho%9X2<~SwQMT38a^p zzA!QE$YU%il=I30rUJ`x#{RVTv!aB{4p^Ydeq!E|y=QZl!E(ZNR{0{#l&7I947Zt! zt7k14C^*xGdgJ`we6Em9XEW7|_V=q)hi<<tm`A1Ems<^)KjpybNG3G0E2$3M1x7*q z%@|x<&AaJ#>W&|R=%xp4K08@PHNFD|(VGEm_NI%O0bDA_`R%C=!IzUtwTw&F3OV?^ z(jUuLVwL_<xeCiis{NTFTyn8&uBVVG!$P7GtWskO42A{<U_o2CZwQtmRoQ10w!Db1 zDX{rYnvjFj{-u(-b~Z>3d{rT@3o#T&Y;KIp1MLrFzgViqhAO$<p#pqWD#dzA#cIAd zl!FKRdsFP}e6=4)#44G^C_DH}HB_jAWMB;jEV!DQNyMkkITmVJ43-SyQmwgD;xpQ( z9DB^v3>ca@pFH&=C*Uf->e9j7+$pDgXdu&<TL3j{iW9wkMtn-FducV7E|s&n^4uv4 z^VMo0cYHCM&lIN|!x)~LSTa2`Js)SQCGk@8l$kcip&t8Ge+eiosX~#>odOiZysXo| zn9aI55%p}!)D*Ba?ce%KmFmJAtc{yHrG3iD<$PZrq|hFNe>}$Y-dQs`fNS}dnf8gn zOb<wu@ke^3KMn~hcSnzsvrXvHlw+oLqWs|>Ncof!tP;gCjC}$o9x~+$<iO$Igq@k% z<)nrQ@m@7op%V(FOtmvLC3X_%Gm{-Eh?Bl<e=JCTK%A|_J-PRTP!Yfq6swR)(9&ZV zXYu5;IWteO8RNp?FKyXywY8Xnzye=eZ)=`VqWN4;E+%QKlb@7!zauC=n)8oxyHaPu zRoPC-qX(IuvYlepTiq_p^Mx|KM)_0GtHU4ZSE}7aeUi)9Ouxb5&qV!``7=?UBzkcZ z?Ig2CUCbPPqBK<Q0Xr~d<}s{|;MLG>W}p>{w?l0e&CoF<r-b%AQgFTUv~PC0A)7Z# zv~M-m0XGM5+W~gMre4#$IrcAZw)~TEv*n-Eo^KA8JC$QHVWPk2=x0)UJ)$mu%-}@q zXYf{}w{u1cI}y?iyIAb!$iu9CN@}my(3OW_{nVa+(d5r?KR%f>te;5}{Z>ielP2_Y zj@|8%x`b}MOqwb8Id-p0j3_+aLAxHL%*b8Y6XXM+xl_9H#Y}mr7^O&ZO_`~Ob<@vO zdh&VbpTpp&9eU@urwxCO98Ac4YHz#)2Qbs7*>pQhwBr(=9cIc)*)L_}*>rI1@Wq+J zP_Cjqr|*(yhl%>fM-d6=m)Pno1`+tqu1v=;yWfScaD*T_I2gt535a2aQ{J5>%G)WI zg!cS?kbQMJ?o2tEeui7Gn$TX?5yS`Vb!K1xKNEv(k1)N1^L#k(0aF_=LxEF3nIi0S z>VfGW_?U;&K`<i%b4Eiw_z@P@N#VOZpD4*Ksm7+l1Y>M4Q-)=>xdMKFhe=1)BvU;} z7||EY+GYH<n;nlN+70WYk@171-*FT5S*B;k?n~>rX$iN9{kvc%SiQrEJnenEu=m=w zF9}2acP%^JQ-TS>BrH5o5B9^+Q4jL<=>%~j%V`(3XG~7PTUoU7SL{yXzVo0QhNGjF zw{0H{kGB#D-S4Nt?Sz;!#|d$?^R%x$U(8qYnF4IH&+?Xx@)6fw?+~1>mVBM&RId*s zI)`!5MTA*gc$|T~Mc!-V0W4IClbD`o5m`pH_|niHTVC4xPElTk%u*<jnLU|uH9e54 z^gAE)!ttfnM=d&-w4TJ(^O<r#RMcCwb#v@VSD5a$T3n&{QcEjfK3UFRv93AM<A>-3 zFtoteQ9w1*m#${Ouf^fuL8Agr0`PlK3^oHp_pVX}PZjotcGAm^RHK5fmIh0OQr}Xp zn_BvW?4iq!0E27u70Ry33J{4erNkY+bk{|A>#>_JhhCWer#hbwy)gaH`t-tmN7tbj zW`0$J-mEbF4jp=7`p0T|_1A4Ealxa<S@7K&hGNhggok`Fo96Cr;N{UVtVB2h8-So} zz6@SKaHs}BeVIYL;bI$z1CQ8{g{+s*>gahGA$?1BnbBV@K8suq0p`Q*x9hLN4X&r* z_)?k=bvZC~6Z140`BU=aOD7^f8unU?ABT>TAzPnj8)=VlEr$4npGZN+4|aON&v6=+ zjrG9nM<2|4h*(LSOg!>Pa1d4LXKtlpM;^(8l2e((s%d?NQa7%sf%Ypl7dIKxGmn;_ zXtrZ2=tQHBt3|Q7PP*dV=|1m19h=K2@h=>}3iZ7!Y#a1ZtWx*oin%g_ZT@f?ls=kG zBS}x4e$+Iu0Gu^&w}tP8U18l@>qw2Cw*3IFMY^+#RL=3PF!S(ATdA&Ba=(o8r_?>n zr^8p6@sye`ho0H~LcA-?d`kd-;rz>pkxm*UdAPJ1jOh|C8?|D*hT%2#sSMlCe^jh8 z)Sb;UZ&p+loLCIijdwim$&4Kt6TacPv9l`t!VOiV1Yi^wZx_`KY6(n1I?L6tsAF@b z^3>kv5Zn&noDlw$_RghmZ2NXlGiB>rBGi0<x;#Vi6;Km2>7XqM%wH%v0sK%sN+fon zy(s4Lef`~~G8na>v8uK{Nb~}-YOmQtx^wMc>{Kz(!i9^_AEe(&rP#n=9%eQ9FbqvS z`y#fW=C$2Cu!R-Vigv}K7HWFz^yx8Ze`0dFl#ciAtSv-7@keV7ImF=#x~GHB1oivD z(3h>|d%$TVa~R1+lb<LR7Uzb_uv!!LP=iCsAK!pWQGa|x>;vo<WAh@^O~!SrFt#0x zW#MTCj{-g+6Yv=WT6irz>>ldv&6NWSThhZY9bR|lYP>pV+7se0KzSto!VCcG@+Z*^ zGjIz*H`D|~7`kBwhGFQ286fJ@jfa}?3PZO!a)@^|OAcWSeHb}}>DYy#8>WL7hHjXS zUKqMY?U!vI;$6+LJMA6Kkwbf^4J`WdZ4b5aBn;i=*x&Y08(Ko}8){=q7`jcdJMr1g zkps|eiv0z;&5}b?>@V=!6#E;W9qPlHww?jqrr0x}+mw17pB-wULI^p8T5zmSw`*2& z^tVgf(H{=@!|>Z2{q367l>S4!OWV<3NI8Vs5E4SZp%!9=q1&8#JgcKQ`Y=n|;aRwH zo7J3tRD4#vDg85`+mwDP&^4+LTJsC^JwISFiTcs;&QJ@->(+x%{AtWD#5+SRgf_!p zcL7#4^l8n{0Dnf?6)pJ@e*yB-rUToCgEH#qiCOy-jz4uqwdf3{2TPT7hJ8#3s1rD! zDCO6voe9mSI?HU@Q;QyY%|gFY0eKEZCx9nOZq2cyolP1qbv9|d)T!+_GhDmc8ET<^ zU3=)1o3`V>u>3Y>{L!iH05BxKO&TY3HffyDIjcGS!p<i3=R0RL$3Ap~S|F@nFFHak z_zFX}IrAPJp%yxX;J2$e<HnBW%;Um(@#f5fb<A#3xrK5h5~AE@8y$Z*?S-~uv5@w+ zy*cs?=U75RzV`k)llzA%IaqvI&V3HHPgYq!uaW&ku6}IlUogItbD_DO-`1;C(rAA{ z*}r9@Hn9$}0e+Qqnbi?=v-<0D;;GcGA4d{@0sVTWgm7`nC)K3-nKIhGXqHdibwyIX zcl~$}OaWW>6i_}6f1x&b*R^k2@^jalfKjIAx)V3OfLsUAQ`hUp_*2tU@`wH=@th(2 z>C2H8-2}2J)kCxMw&D3yW}oF-(o19Y2G7)x=r(5@kuo$N02?K8tokx>NaYsFfq=T6 z68%2zg3*ynr<wMX)3<vf4*e#LyHjSz$6ESKG7Mf?$_g+nz2Mp*x2I;u@1gkY3!M7( z)MK;r0ipS<BTywh*?v=bYvemLy+-+y`-^g&3!Jre>5ox6sLZ#T&%m5JcB47#_u?tj z^BwlMPVbz*RHzLSYJ1L`38|e3<v=eCU8DVMr+f{~U$8pB`$8xZiN2Y3O~_ea&qMah zI?T>rgy%D`Iy&;~(01e=ZvLjj?0OBY{L^<X?cJo3UUisV2cpHVq~n^?BXYT!ozDxm zFU!Tbd|<`=aCE4|WD=}q+V#Do-DrJx=r(EnNJo>_k93$_KjO%tN$c!7LT#MVZ?`%^ zIcTU$SHGTek3G7k#g=cv?0Rn{zcu~aaQrIivROVckI8DiA-ZxuvRJ2+3l>4ipNCFx ztEWka%|Eft(`h(NMAtOC?N-9<cSvRa<#La}x01drUo85N5((KJI4O8q1SNlR{vB-H zYHDfl=bwTuf3p1K^2sb|P_N9cf6<a_1iqE@Wx4Qj3ndYaa`R6?x7=z=-86sxDR}sE z+7UzZkz(8<(PeySI?k@!o=S9^vmPa3c0E-H{lu0)*}ORU-bM45wb~QNpH@Dl{o=u2 zA2i!hiJnq$HTw83m<M(2kCIKPe2vbVD9fd`e9`{s@Mr8h3l@!%zgp{>FQ$v&`7MA+ zpeM=E==fF1XRRE=@@aJZspPX(o|z@!)-ShMSDt3~aVz<(m1kH!SxzIjH@*2XE{$>Y zDU?I7y6u=&{uvK?-8hNQU8DE1K84`3kl_oCBz|{|{>yrWOz4SKD*sRpyc#cmS*{`Y zRO*vVPn1(o+v}7|sDsta<X7;gY=nZ^3%PtX@~M=U51oeik>$?IF-YvPo*7;Dq|9e6 ze?i$)x6`t`H1etBr<P7*{K)xo#_LMi+xng~yUtWApBnrr>D1=aZYPzQ)vZ6&Ulsj> zhUoe67cdQ{%%`ju#8&_vsXQ46k^2E4GyF+(8AnZ^YqZ`={O<bx0O_^puQ#MWwdHR2 ztAprC`8L|GaOj3QxT0>mDA8?_zBb8!LbwCgLdc;>-*u8^zw0>VmM}VAm*^TDXG?T< zy*-e=>jXCHE;}3QK)Aa4rPaPjd<NMVY!AZHtCw#jJ;nF2hWS&_tH+<CKgs6IyCy>& zlwG&HC4P;rTa)M-tw$2wCbe75@kba>n%z(0$e~I5Ka&3fKM%HDnbEE}?I86x&F;5w z<ZI5K#5?c4`>sT{N&Q%}ejy}&n`9rF<1a6sH2dA(k%QUqz7pLg^=l37KfuNueh$A) z+J~KN(tiJ>+3#7B9GcVrY;Ter+M6VY_9po;Yd5>k!7jJ<Ciy*RpVgdxNxRwaN{$@N zey@?}HmBd$-qj@en*DC!$ieLQ0f}yN`VZ|*+UL-2Xg>mPhMab&eRgy7A-;>|x#js^ zd3_hIA_*A0+IkTG7wm8F@)<BFR*u)@c}p+7fP6PZuMz%K<$|j}0{D~4#pw87neQMz z8_Bn-T<YXo$zKq?0RAL7HfP>2ZgyXc#BX!PN%1Dlr^n;X8F$1(9W<>!PZf_hr`?Ok zjn-F3ADT3u9#1r9+!0SSNq-Z~=?})u&VM`QmJD+cT?qYc(!6lIN%O+-Ce2%dgB?8I z%lP-<xLLn7jy|NCRNqofs&A<#)i-nVp|1I)c$4NW!J%?<^sGte8N{39_cPw4dBC{Y zb@onuYtlSbyh-yu@g~jtggfvtL_5?ZKacSy&CkHW8O^E3X8lJh$3gNq4g7@{y90-j z_WZ_dL*1q@d<6{4B)-f{yHI_foisDdbLg2-7cIGE)0Lj!;&kL@s96rdS5R@P*JsH3 zTF4A^gTCr)=CtK+s5w{WQ=V4{!Jm?zoZrDT?Do*ft>*d`6ZBXwM(qC%L66Sn)XKMz zW01l)<!h$fs^rV3eD(M;)9qFACF=>wD`+#K^u5&7@nTB8yz<iK%Z#10^}^7$P-Q;7 z@&}h`IyKed&&)7R$)C3zH2G7~^U1GPJuu|fP|251KK1xA({E7n<(1c<-oCxrhL$rZ z`SQw3n=ghKd78x5e?y<?weku5Tr`o{jK22{htDRrFLHa@0H4bI%lg*<T|56>W~Rrq z_{2g2eblm};rvPo%8oMyB|kp(!w^3{lpTIF{8z~M?h<v#==d*DYn)7{8Y|@CMDy8( zmLu5uWN7%TEI(QAMZd^U`T0<G1g7LiE;Y0K_)vEEapb)V>n~_!z6j?^=?I+GPlT(- zl!B8{K}Spegl(2Txg013ef~VPu?h0?OQD88M_<g$e<;gCu0<fNDm!ORzd$tXq;Cq| z3@iEblx7q7^G!jUKTl~kfj{3Ay!<)(Vx}KW^kBJDbG~=Bw==zn+<^^gZ`gT}`s%II zetY!?Po(q~k9t1MTe^sCmOsA~YWSn_o@Hpf<IrQ`iCoM|`yg8vwojxl6EuW!_%c&Z zlzhor5r!{A%X#g5cA2SW4!wUtdDfY;LKEQd*W~_{U%6`Vr_>Wa{S8uJVeg#$Ho1S` zm)|h_85&>M`8Bj`+M&nHV`Tf}(A$Oj*OMt%OMT_cVE<CxM#JH=$@87EUPt1y$@4uj zpD-PjuH?_roSJ1d(UGT__Jrtl8R~X9^vt#cUG2ND9dPMSz#?m@9q2OTHebtbyZ8&5 z?biG*=%N>#UnPIC-FDGykUzPeIQ<zVbB^9M`MaB(PYu45^76|cv~$V~dfMSGL(8z0 z{Q2cG6n|#wzmh*c`9Z%(Uw*r=-6TB;#h;memR&Clxs`F~nJHg~o*Db@&@<c5>N2#< z-R95G@vBuh5LP}I)}e2vf1p+WWF|B_hBlvu+*~O6l<im~J`L-Wp=IZe91YtGL(9yS z<s#c}cew<ba3{aJu%GVcFR(+S%&%Gx1M}Mey+HnK`5AJn;?OhGo;vgl>vM;h@u$O| z8U1tUnd!IM^b8#jVAC^nyr)CYaQPZK?$74W(7FeQo?-nn<Sv2uOBvdR>d-S=KT?K{ z{c`v-Ti;T<vb|hfe;{V()6ljqWjiFd<H%QF>!Udzp^-l&KXN-8g&+AVRuq1`bQ+b9 zOU?sz2f9xAo6&QnyuExinm<>$)z6=jA1|Fo`Eiw71b)198s$fp^I&?gR7q#DdEiU) z+pVn+9gLyK-ygK(-vFOVy0RP_pc``C2;12pf3()Xmo={ue0L6E=ZBoWQZBW6(Veeo ztA);b14Rllcbaycmz!z++;Yd7!BWuV&n<NuTeDi}$WM`in?I+1ni)rF>dRs-E8X0} zckgiP^`IX3m4>#yG=o34zJ%q^U7F3{&o>3Pwm9n#QoC}W3!BHz7qcPGd<>~C?i8d< zEA?3}O*gidQfu(1PC??&uD_jT#(B#8%GTJ)ul8Al8u?YHAmvxdpTD$B@~2Kg;?FJ* zL+i_w`K^%_TMwqCd-zGOk@8?ENO?s%O8#o3Wt>0%6g>Pn<-wvy?teP;n7K4a&rJI( zeFDegvDb^G47m|?@^5CIr9vN(u(_7`?J`_mU1sO~Qe9^3tu0SO?kH?}hWF2;47tU0 z_%mD{v(4zE(w^1W+dTD08vBl-rWZI;SMpb54I}cWrWeScQ@*?KJFvSyVzNB2{}7np zkmXUwi)5Jgl$CE?{-``U3~fVj=$W<89fsVvI{cZn&mD%`IokXga^tAfKiR&x8rk3} z+(zgrD~O%0(+}y0o0%78E_2J7;#sVhBhxoycNl%vnc@l9<z{$2Q%Ax~J<=<;9JE;| zv|t^;9EYW+)B$h#7&^8~pFdWJbu;XguNnOe&0ie>+WaM1#g07gVEWxX)Z3dYvl4RX zo6$#yo|$otL(fe4IP}ce3!9#yb!84cGv%SBkL>F~VE0MSE-*U53a#XaWjDiSdk>Go zPYs<0`SHw()-xo^eAUni=Eo_2GvgYYo+0<84m~sTAWFIU_G9Xmf^PdolMi(|`CuWP z{2I1r9cIcGKOn)b9^0bZ{C4h2`yn$CTt*ImyHI~zLJBT(hd;CP6di`#+dBN2X%A<f zR>_qsGYgr%Os-t*{OrsRma@6Z%t}wDfVXnbOtouO>|wEPWo&LNR?XxKg&aPy(|uvq z7oT(0m`nKZ4nAQy-4DHXg;4ZAGduOx@H)Z{L-YG~IT~^!?9ek~SG4T1Q!dKRLr6Nx z#?i^28NIjZ8QMRtl}~9sf>L1Kag!mp!eRMS7KGqWNzdK?ve!4%%WqhE4fE&jk45KC zL9b!{<bKcDxqM%LHLyXo_1Mt7zp@<s_zK9Rl8&q&8u<%FrxAYS@{7WcADsYxoN_bM zPjl!oMk3D>IP}c)dzIxV>y^EFM{O;_(NPzGl8&sOQTXwt(*QrRUPa-@myVhrr~J+I zCmeca+wV@p-#0o9?fa+vb{hV^(b;ZxT+(THA4aF4W3_Dg8UFs#Y3Tcl!=Ksu(P`*A ziOpYv8CYZOL8qa4e1|_X?TbUtaQ!fJESSTeVf&Xf+unB?I;P9cui^78I+KR$o1uO2 zc79Wa>zkot$Q=F*>x-dd#~l95e7_$m=9UcRdaAi>tS3{+#g4*xD4da+&L*Tvg)9R3 zBEQ8MkbtYrhvEIZord?vb{d-BwexFeUAIlo@Vr~6;d!@CL-Rg%ehsf%>@>W;xYN)) zlAT{e^9>F?!**%5;eLRjW4xXGn*IJf%kVg8mf>;GEJNd<*pci9MqT>$Py)yCm1=G< zmW8JoJc?%?)zopGRDSW4S$#Eie5b>o*?x80u>FnCGCS{O>NrMQeumf0n>v2c;m@r7 zh#U6HYwFlSJHLjGD|G0YZ6D%>+lTmUv*W~sVSk$m!}CyycGLMaTR#$p=d}`s=b;jY zj&Y~@k%$|XpW*ehiG<nun=tHeFOf9cz9kIL%OniXdn636e@qyj_edD-uO$qxr%M>} zlVR824#V}s@O((Z(E2wgzlPfn!}B!>L&v7u`87OWlQ6W8+~LpcJZ-}8d{V;Dd4P6) z4UZQRhK_5u`7=D<l`uTtl`y<dH(}UcUBd7_-Gt%!xP;;PxP;;HR>JgnX13Y>Y0~ic zC~0^;E@{Z$KiPw1yIK33G(3Jw8uq`KG~~bDmY?DATQXsGzAkBae3Ue_|IC)3;qg(@ z@OS29(#&^AC%=a4o8j-wNyFo<q~Y;a(vZJXyF5~6#|z1n;r7Vz_%dmDJeV{*9!we< z5Ax4G6X)^!5#l~Y+`Ghmwz!|d@5??Y;C698S-hVo;F!2i74J_H@B!jJUflN)_fg`0 zn7D5})^h)r5vW{;DzA$zrg2Y=);jQ1^z|`mJcxNl@9cKuF%*C5<)pA5r<xlWtj4OP zSf)@Y^<=8KSTWa^spc2wVwr)`P_Y^-^~MHr1EuoP8L?AJl}f%F_7mlc)m&e$94jr( zm3s@Nv#pbdq=*)G2ax;R5FAUvL@LtB7yDdEWeVk7CcD&5I~x;QO%JUcF7WvI)2Zm| zD#FW8&V}Y4C$eLy&dA>(_4t+7GdIAmmL6r(J*9zQ-?vV_Be&0b`IhS;@fV=yOqt-~ z@EN(?ck$`ajojY2=xUZvT_+MYf6?b_8s{&dd>sBF&yR-Z&s}fSn;bxYw93OxFCf<e z^wjmbG5*x_l>F`AW-V+H6-Phcd>3h8qbS$IS^t9i!pevERA!&$+}6wJ-{D<)dC(|p zAtvC^kGwwBMPIMHU^j6*8(35hfB%YlDfm+s5py)gybjrXMn9+3kt31s%Q@u~eg4f$ zU+N`E`Vif}pOcQPXVLxgx#()?8OhO<pCgH$QZ-oZmE{?ET-kWO``~2PK&$QW*%5ud zGa8?D1gb1=xqYGX(a3jbdX4fY_ZK;Tyx!F*8L}$|{Pi_jF2rYG&K*9@_P-svru)nG zxO2hr^A|2W`GfOMJw7&6q(Nvlb~qaX+UZB1Cw9r-p=;JIICRbSYizpF*XuZPVD&)u z`XSk&==;f>bifuX>v>JRq<&ej!F1$dRxiWz8CWgtenUs1NqUxS$N8Bk`v}9A6MCV+ zextT`b4jnFf3FD7ucYU?OxyYu{d<Uu-$wkrQ;m>asfVOPB_@+#JtQZeX6LJHy3yC4 zx#d^o^MM`Fzq2UlvW|?g`sB#L?D)x{Yu5fbbj{i;ExQ`xT<oOb^4H}r*xEaG&cJsz zU;Ru*KQCB8w>kaBWb|_f{rQdl9Zo^ltlm?7N_I4-KbY(^+y2}9Mqg*?FJHsoafW%u z`ANgyT^xBdsr(Gj$J_iy-xuaze$n@bDd;w*|B;*(dHs$*ztQ&rE9jc#_nmj&eHW{U ztryYHNm20KoPJ2s<b19yhbGOhCZq3f_Lr~Wd0Sf_qOaF<@vGI3>Mo><-N6%Y#9t!1 zAEbu)3+n4R{541K6Vd%Ex$^DsYqlNJD(`H%61+;ru}=o}kGb+4g1?~Rw(Vyk@h^}c z)R#hLpgWrx$iomxkI(4-hr-K|`G?n=6teX(`g%?mpAOyT^y3Zee{=DxrJwHd51bga z^B;Ykr;AUAZgb`_5=|N>COVokJ~FV+&|khy8Yd>A?@RONH~RiG7u^QxgO<Uu^|$k1 zW54sokn`o?&Q}Ht!BSAp?;6;r*HAfCmkz?mZ>=I?Bl(c?+K_Laf;Z!Kc}L&>*I2$Y zeSsZZhd;CZN8S2UMg9VM61sGl)&;akq39UkhiikHAzgkr9W_H#esRO&6Nhed`Y-Y5 z`?p;6!R9ymzAFXY=FCgS<7VrfBL}nXi%r+$cYmLA0OQg3xjE%mg;oD_ln=A&&iF1K zegB)24$#)B&oV!njgcdFv-+pxS6)9Ag<r$#0c<%$_jBSZH;1m-@q|*o@;Vb+{{x$7 zrnzD1sap(Q5tQ`g@;AYsf?mV?$?|jSr@FC)EIZ}Ai|Ub@&%mr}l}m_xH$X3tKU<E` z_k;S^!zRra#GCZJIv(9GkG~u`%zl5d%Pso8Oa;G9>c>R)i{sC4ljb4f(a&*H@N2do z9{OCj#hG$G13NA&Z0G0H&Lz_`)4;CIwSTes*~Q>cJ6|fsDn0$V0XXZ8eh@E4$Hc)F z&T4-tJ3ZD@D#Lm>bimE$lw*mQiyk5S-1X?CkX}%_ABCgn^1x>-wdpc}W5;uh0N zf2?~cJEksIsSH(O14ET6tecNz;Hi)wgk7f)Z7}`O&cXD_3HVC^zS7Rh?EpXDE0fI! z?_mUTc6&7|!n(CZv`M!S{sLQpfc(nseTe)j<)@<8D1YqpzS!Jrf<G0#M)`B=%i?-H zL$d3$BCJDeKu>_L;0$V(XWjhi(`k?&clkBWPYs<0`H{<i@sfJQuV;6VPB1%aI&%Gs z!jG3uqx{Hnj>3<ZP91*idKO{cO0H)%y$JhBWO|zQ1kW?%?T_YEIPuvTVV$EEpK^J~ zc3G28W&Y**#P-|vl}kf|Y4!zMlQwIQ!+i(wrsVxBpjY3#RLt@#*GO+l`uxiBZJ^v7 z{bCBx(0X?*{gU~VbDII%XjZO4De22qRXXPR4N6I$Upd$8gy(QI%+Z6!=V!F^K+bIg zd}`SlPB&CZDe2boYo0FKm&9EN=~e|Lzp@<<Nf*~pE9uJmCD&hEi4-vNXX{mj_32uA z6~tda-$I#Rx!gnKw;_6s@TbZzYNu9tFarM?d*4WYRpn79zoE+m=>_oDOg~xj4&11I zvN|Ko+cj3-Xm_HX1#|2|<KKN`J{@|Ee|MGXDfPxx?_mFHU~SX2r;JX3)&<aU)r$!H z)Y55;AG!U(-KLGor<P7*{M440mV(;)G^@$|;##?D@u$?!TDe7|C(F<2uPIv?M{bRO zKM7qA9ln%0qLh~`e}|4Te<A6F=ciWQfi0YpAAdUG`KgspWBmBjQS#&Hk*W3}oS%`- zS&e`1k@c7I(GkJFnLj-<<1~$RmadXZJ2P0Wv8e_f*)qv96)rkTeU`bfS9@xiHk>}P zzvpyB*azq;hx+qTz8t$U8#LaMrPWA&>+|QEf|oyAe<SP{bjgkUHbmGr=}(UtyvXAj zJHHXmYw+bS!hS%1dWPyhl}CjAe}4RRM(|(ePmif<<nmS87rDJ`q`nC`c1Ab{Le94~ zpSXTo-wfJzurtE>5;C7uUpgb4FX2zm%s9^GFTy@bKmJk?{Gt2PGt*zD{H6?jFS6+w znon@(nYGuc2>Ydc%cIk9|IcuJ>o8p3IwGut_mf{o+_3x-tUDFi{*(T7MDT0po8JiM zQ~J|ud_A8(J;UV@!GD{~pLRRP_Kzuti*~z~G(65qMmU#E&L`<zvdfH}4<|R}bcQ20 z!~OeYg!9;Z<u==Fdy$NA-kCptX8S9tcC+>_72!N+zx<{m?0560XGVTn^#a!|Y4(}z zdK+QClAK>9fAVZW2>z7x<k5WydQN_KVR?k`7op6rEI$+UWch`lXUoq}`=~LmCXZYh zr}7+*27Zm?LgLp*DkQ#}f7Se=7+)tM_#Kn$A(c}i!oF~SdS?4sQO<Go<u7h_-Y5}a zKdLW(hWq7-gxP*{+|W7}(!aRjadkX`9}c-Zly+9Gts4HELeNon?xp$rcmzL*a{g@j zNB+L+UL1tq8t_N-4Ndzx^rBW@ncd71hpw4w;?Rp~26xf^p3Vs8xSamp{+>e%=+34$ z23x9f#R~2{bN2?E)?7UVW%WgACsgzTtwq3k8QFfZ-cm4QRF69&_=#*lPu|<#6RcN_ z%SSH%#Y^j~PSVsPq|>NA%DwL>{CMd!%8y*%qVVITQ->eBo<;BrE!Q)L9%H1Td1INL z(mu&@msd4}oL}gSFh8Tkr(7Nl@TttdT%Y8=1+EL%lmY86)nBg=l#)E;3~o>4@@g)> zK`H6;E9bg_a<l6}g!wux{gU~V<%+Atc8wljO8RnDm5zCSgHqDxSC+4{PElL3jvh2V zucxI4a&8;oQ_Ie9x}i!+Nw=0?^K?V*!$AY4<X5)iA?e~7u5?a<lD@2Gay{1F=M%yI zo0fhB@fXm?Q07-I{}B0Yh+ZT7sq%|j8ZdOR>wCQM?~Rel1NmztzpC=6li$$gQHQ_( zHT!%btlMa;d>h>76Jb4w%%`o_5!Qpq^ptwzs&^6gvDDHDs1*Tr-&HRn@KZ~tF@EHB z=zqdKpW1wB^^F{TYJ6g~L4DHVPpO}^@{dMO)>Eh7rfgvxxivm<99nJ;UrL=-%1hP{ zhmJCTA?bwYr&iv9Eu4}ce>&m$sg+M-{P@#R^5f`H;~xxUJ(AjOt@DICBYdZKrz_5* zjBwtDKfT7!EpXARKfmHCx&QV1d?K8)8$oXN&H?YhURi%-J8olZnQ}JIrLn%lHw7<$ zR1Z5M_`7q-jrNr!&9o0Tf62!81N!n8!7r&lJyUj!&bKu)Ut`NJ!oC3C{6_G<>Q8SM z_QM*fZ=}}|_J7FvR@w!*T}M6}+~?B~VZDmXr>#E`&I9$Q$C{nU-)9{D%-V;PVf{`; zIETnjeyNmMdy_J(FH!bM`R2F7aQQ}9f91<xgndK)^vv4-RD|`DzWha4Kjlx)jQuBj zkeX$-|B>o4)E^h^NGihq5?}dsnYE{>E;IE_yPeww`+WT57G<B0KfPTz?{4>Fl+zjZ zy1ZnBeLnvAG~50pBkc3><uAfMAAfp=?Qw*CK7RZ~+2`X=&#*m?;J;VqPs^U*`X$Yw zG_@DW2<y+a_>*T@Lhz@|uROXBLC?vrnf6i1pFEBUv5!VcPnMqvdb0dN&~xNx$R5<6 zpR19iJcpw(4^$($koYx{3W@LL-&q+fld;>WDCbnl^^nRb5y9_|KRvT{F=4o0nTVU| zx7qTG8`5*y$CY5}U~JqU<-Bme@{O|3$Df{={vee{lzl$F{6*MT<4-T@IK;gehfQ|F zh4LR^UyaPJLoaG|mf1D4ug0HGGu>?~?D<2Snb-%|FV>SO!@-W3;#sk|u~?~?i&d(* z!B`faX7DJU-8%v68dR-<dMLxcdk8x+D}ukJPrtW+=l_}gJF_CJuWvw48sDE%(@P7k z2>ShG<tKPnpOkcJdVLM@Q$wdgeq?*G_?*BskeD%LzPxmT*-_Jx%PR^$UOJ8PBg;7o zKVCX@_@Q>WGs1kZT+bYOjrW^mdP+Tz<sM~!MTC9zT71go(Ey*y{LA$~?!&yde@E5~ zuVh?fR&6`eK)KoVAi_FdE&WpI0j>hmoI^u7Xv{+drKB%cRq2@LHz*~2e&t*{>kqXh zYwJM-e;ZnQAm_FLKDF!&ryHuIlyqzPHBUF>KAS*$AlvbfbX$RN)A#Qrn%v&X^}uUY z1Ns<R<?p2z&{b`SUL*Xe@{3v;z@Jm!8=uG1s_#MkHIiSsKFZ}$C%>V~1L+0uC#?g{ z6bhxDOf?rP=K3<#{9-src%U>?tn$N#2TJ9oGh(NdDwRB(t{lr3tGPZrh<I_X+*>G} zZJj(MMYLFsjGogIVV!DY<=f!?okZjFzcQb;UPo9bEz?u#jZ3d1?3byf6QFeg<4sq+ zh`>)RoyPc)+oAsn`*&*j(drvH`qcP$%m(#Ii$A4))|O*5da|B6{WfI_<H)V?3FXjo zbNEu~td_hSI?DWoq!XT>T6qVya7ups>4fJ;)+eWbZ9+bQEv=(RrrL*)=k%ml#vA&M zDC;lfqa(t80DpR{fTQzQe|>;U1OC_V-$@$Mr*Lw!SJHV0_R9Jzw_7&0mMO<!qRxDY zZwg-iZ2j#pq;Is(A;S7{|N7AQhgM&D5!QqI(=()ZB)<sj>3#X@Wa<#zp4j}E8SmTr z*SQP(VU5%`JKwvo--CQMx_@Vu;rbk5{lBk18vfqX5y2m`AAhL``#b#UnJtef=hpc0 zXINiS5%#nA@)yBBu`j(@X6DDpex)LuAL7ejgmr!X^vv4-RD|<L{P{Cu|LyXKaE^#C ze-ZW<_|r2x{zygeN9@m^nf{it|I5r_hV`-!x7%ao@YP;#myB?}qF+9fv(1)6GQt8w znZIyyQx4Z9xtXnB$q45@%K5bGYlQtQ{`AcD$5Zjf_wV`g7s211KRq+`)h-W1>jrFk z&Hnx@+Y?;Bq&bu({*p;Ec0gHg<yn>x{3+?lqx%r_ocx;67bSmkd4$*>qogOx&jdYL zej(^N@-s6I47u)waVpQ@XyDgKE+l@9q(b7mHKFeQ9Yb;z<Mk-#;P~0ugyDW~!f-z| z5y8KqZ+;`3Pw7w3aQPat+f=XPhUTGcdWOf<al`W_@d$nn{K_{Tc^oV+{>T^EWH-)t zi~1aIH#?4vN8Se_^9vhz#LwZ^>^ws}f<Ja%UhXY669vD+&iS}CY{~dx<42DiwHg+S z&4Kp^z~B4cc=cWU9nvl$w&6;$vEwgjX~Sh@V@9-%hue80FCMXK_?O!*X>A(^5rIYu z-kt$}El2!=;U5Rj>{o+77hVH`2(HJ^tJ65WzY{_YJr6%mLqv(6?<6?>XOMgR)!+|@ zm*=&%eF7o?9?Ib|_<Oj6<Lx*Y0Q}Y9dD8tIL=^a2Ao{tV;`lf1$*}9=e+?oE{D~m) zKjk_8bGxhX_ke)&MqE66Roj<a+kOSn0GpTNseu2bD#!o$XcfMP|G5y6@(=h|F5~z= zAECk@gXueZa3@5h`~&{s7jpbHC|>;4$ZsUPJg@EI*0zfw3gaE4p&m^H2jri>nB${v zvR@7UMG#`6F}#I<_nTE5Z;BG{z#6>efOp@QIo_2@yen$(eh7Gnt`48xtAID|QjYhm z$X=~{eh(q;{7nZHy;I=zDDi|opU%-yo>{<qUf|sbX|rFAJh6g7J-7-YK(dH;CE$JX zGR`N;i2YP}XFGUX0Povh<9LrK<tftJ$i+HQkoVdp<OA)}L2Ed@A*DVEdi`9R5bsp@ zJL4*j_xpN$Z03Am{l6IghF!z){t4!d{c7^<sXxy{M35WeKMa3&J<9Q4#25IhhyOT4 z6!@comF(!(m>pG@mtB9Z=91^hU~&rq{}*F9{+>`4>{pXM8iw<RU);8;wQU$g5~_yy z7X$v<2^@d*fgHV-|J@w?FG3`Nk8*z)@ORAM_`gIp@mG_+D6a<~0^m;Mu`E^jf3B0$ z+o04#q4&2sdWhx!w=Rx%h*Ay$Z$B=BdVKukXil$3nJ+=_be=Di2lBDwIF5I6J^qh( z_(we)c|6Cv3S`QDHF6Z`eH9{r95KBI;ID83$BWm)JDlTTxxWQ}xqst$x3mF(znb)1 z?aoyYjg>s6I|oQT_7RT%v{F8z+)*(A6Vt5%-jYvnyfs*@@K=*AHiWFbSP4;Bnivh! zy#w$!_i+3aJhNX7zL3)q5JAZ4Wq5oz%kh%+@TPG*<o6ILqD?uD_mr}IxA}d9x9ps) ziTtM2^N%dybRSXb3E53YPfi7zThHNmC)dlz@jM?WH`K4!|C8fQ6MWUm{SXMT#ckE& zf3u*MMDu{ZnsN~Q9|jRbIUxT(U(WfcOkh}Qyk3YP@R0uzU*mYEV|N69s`M5@1c8V3 z<M3-a-g;&KM(}wp@7JKbuzp-~1IOE-#1ndUtAmF+dC+=}cUrxAaiU{43V=7~2OMue zSsw+TXY!hee69n$&)v=O9;s*de$4G2;ynd;BktvR&(*{GEyu(9fc>@G@8@{??hP;S zS5pq2_OcBkLU|zmseu2b-*Eh=v01`jJ^Y_SM1g-9;7@&?<0n7B(QEOMuxRh5KqSD$ zn3(<+z~6t|>#V)~Wd+~DuU`5;goq;ji6DxbzsT{g{47VWi+>?Rr2GT^s6TW3>prE4 ze<?(y`~!Y*!A{2iGauH(e;6VPeC)4{yM*H}|CJ_w2_jPdLG?b-{ZE$u+LKlIV<EsE zudIS-fDO7MqI=tYESCe|@0+)Cx(S_fJ=iH%)aNtcZ`D&A|IvK_z+X+diu!XuL?C%W zv_t;E@ungZ_^ZK_^l36gV!7e%(H4k4dcqq_9_y9(BHe2_u1XG=4<u1IlGB?6&+J#j z4;oIv1Uw<$sqpt<fp>5{dpwcbV-+8BfEMzxe<$bTO{M+w)bke{J9q}*|9TF`|0L)f z`_<$_*w2L!K`M_|kL7sZI!uM<N%vxiDDbxc%4xkEf8u;i{CDTs_!Ge{PWukW-%A(& z9S8qZz<=vc9RE&a6Mr@N_VB+BV9Gz>5AEdm=PUKtgFoo#^A^CrYy6u`ABVq>Cto-H z9lTGE<&O6K^D`R9NBh2DA;({>Y~MZn|EJT=qkX^ZGaUcVO1%^HX)D*adU_nsa(eG5 z>3R6s&grH=9;nBE{Vc~ny`CPQ?AGJ)MUJ=k;hN=OK}1Q9|9Bb4zeQIM*FZ#pk9z#^ zUvvDMb@8uo@KKNNnfw;hqXTuzaTG5{)T7G)|C>`e{)M`FTz2d6v-3FqZn}E>s#}k5 z`j5u(QID(Va{TGK`Je38<1<%r{DV+k@mFI9gdXn+cPO`ddOY)TPVWF^ztW?}Bc1*w z>hT^|a{RD*JpCGu*Qg#3dywNds>j8VZ!<k?RF9uLk>fY2$3Hlo<2S0u?|hEqH>$^* zE@>Pe^?3Cy9KTULKKCAu->TF*p~tUryJ?Nzn11*3(9acjRDCc9*2b<q*!>}K-z@G= zh&#rUf9Jk7ip9S`+*gbHH^hCNxZf)78^ry7aer9ce=Y7?#r;Kbe^uPy5%*EA^Yr!< z_XEWJFmZ1e_oKvpfw-R}?u*2|TigrczF6FsiTjtt{W5XCTHLP}_wS1P55@gKao;TN zPm25V;{F$L-zn}bJ9$1vi~A&TkBR#c;+_)sW5oSLasRlupCRtO;!b6QWhs7JpY7c5 zSbWBJ(t8o?f15G0l3ARa8Posy(|Pah|6U19_F<j6S3W`Sz4A!l|20|Blo;ikYz@H_ z4$U3=Q8>Y}_$W+%7v_2Cxw|u4M`_A1(*8f5a2ZB^zTgR$VaiVsKc}yEr!T{p{%1Vl zGK}eGJmE5|lm6uA-Ra9ProX=@T!u0IgFN9ftdssZlX*Xa<S)aR{{QC*mtjo*i=J>9 z)=3{oy!U%g0`E!SJqf%gf%hcvo&-D+m@sAhX~&(JXkW4Wvf-l!r@Ag5gSeCDWtSGR z=}L8|JKdcxW^-lhW96>ZR{6wz=B3kpy`^#${D`M}N&|zLat`8^^Tj?3!cXyp7ke^Q zDR_}PcyK6P%@5?#U5I+7D-1n)m5Z4|dN9*-76$kG2M-k~!k{a{KxPT}4{J}S(q%?{ zi90l3bcHS(<_%s9Nps8<?yyoNohz41W#nnKJ7}<Ub~>Me{}{H$9aaX{WtdePcWpp; zI#Wdw*Sn)sa)n%vEY0=a@M=0!?yDf`hT5RgU^QPVve1p5&}zD;P^#n*@u8Za(qOKL zA)9ML&MxPx4Cx8~pftLcN7Sv}@X}zqI5dze=X)@Cn@_N#Qaik%sB3A^xB<l7=?+D; ztn}u}Ac%5iDMnb<;woA@LQj9Doaq52!$>O>k%V74jIvr0rBLe2gJUp^vPKc5oa5nZ zTPDv-=a%Go;Udsm&M^V4N1#v!|8`j<v;n~Z<^d1EjSS2U^bE2bJtV*Z@OFp6n+06S zF~U!@>;=e!`842{bJ?MuTpD9-rPtjcnmkAdUv8t9>}Y_VQmLG+uz(%z0LVd=liBGC zsPyN1s|;aTt4Nhms({@<`YY_WrGWu<^Z<Lk+V#4UKZny^<9<C@$aC6j>3we=ECR*8 zp5Eq*BHnuY4Y=rB%u?E5zhVo;k*AIH%8vAq^Trm}W_ovahEwMjv?Xngu2kV11?xDg zEo~h(VEx-ki{_X6tRL=|D=yBLOGWFk{j8ROekkW$&kzW$KbJxCc}&{+432DCtsPTf zU3Lc6)_-a+-`g|LZ9TnToAu&(Ff1Bg%~hZ(f~ZQx^hZx#khZ=#Y;pChB?AQx{j8M< z*LrezCc8M-W9=9PE~EO2nSq@3#C`(XdS)1wJ);Dr0K8U*D%K6Hxxq@l0AwpeJw3Tf z#kyqTAk-sN|H~(W)5LD5{*c^6tF@;;*K-y{OIyoYD%Mji)qJ&(vmR)*T6(Q7!JA*V zSZzt`n=J+F#+HQj-!0b077KuNE!O&$HtXi)!>l&zny=yYEm*?aX1%<1*s#3yGYGrl zf);q%3{P)-6Np$3-+|XF?g!bl5WDFC>mMzQad^6|)f!%~E@~}Xm$oMJ))lRJ>#A1k z+SWGfHdvL_X5G6Pug^S&*S8<X>orf{^$SlT$-K3p)w%~FKM!D=_2sR2{mLI9Xf$k5 z92}~qnfQLuR<X9UL0blOCRa$KpO$nsSLrF|nbEXfYZK*Qz10ToVWzy)`oTn2U6NVr zM-#Kwk0<t8f1C&c?&Ac1y?3!YjSju6r}oAZHz3-xdsj<UXjLfSFMGFHf7pgh<}&4; z{&c>C?nbN~ZK&XgV{L;NTmFt5-~KwpYek2DnX<KJIMjoDrQf=GI9L63!`rMIVFgf| zb=j|A#NE=H&q3pDeSbLQ#@aF*q)^Icsu}B{;oX@EnA~4L{Cl2ggZP`D#_QIv!&m;6 zfn24Z=^1;#`Csb`BdVpr5?HvUTmjdN09I}oJ`7~jn;9xpt*^j~?Y9E<STH{6J}_W| zX<nVbF|x;cWMtM_F{(S)moIWzyt;R;nB|Z6OyaSv2PPGA#lC94wRI9p7_(%(FsW$0 zJZTUbh*Gv<t(y#jNn1BgUcxGe_2A^C{Ndrr=kSNeCR?ox@urbU>-Ldx>jxv-tX1D1 z4w>8WW6a!=gmvFYYZJV^_aS`y)X(v4$$D}mo{3^TG79n!+K|H{NLzm$35L+RV3O5R z9JJmV*_Ro#zBmd9{sK|&`VFGyK{;~Od<9&SLanl{8I`uKm?W6Edlbp%zEKbhOsBO8 z(AWG4(bumS0oUih1Rr8rdaNf$v65Z}N%4p;j)LlMy#XbE#VUvbHs;dZmT>8xKTZ_G z^W)FqZ`SW=wK6;L{oRDsuvYE9I8)ANz$t2l$GK~))ym98+InWUDxA{^Ju1j@rBqmK zy}esDKaj4Vp{-&E?up4(3!VvM{cSfU&DVEpv;O{F<aZ;kuxkNpapCUP)05k*OYTM( z)6Vpyt?PF$<cm3$9)dp^V~r^1SZP{c--CNDt(Lg<awV~z9$o6Lf)PxkS<aQA(RqF} zV=e;<(hYsHvqZ#YV;1KC%vYDDtqaB=>-iq2oc2ph*t&O&HGBZ<*+8z-x_6IK3Ru{K z733F3_vDz7`^M;kwRUuywE_8VWnoY6A;MnUqmb*ZT5s(ECalMLagUyYwPTMq>!n99 z<4^Cv>klp(3D-ZZfzN9g=gXrZ&SgOEn(OfWt9Rh_nIB;&Qd&PcGtiyQSpN+%Zv6?q zP4$$@(A-pWS?jUU2?uxrVqE$NV&C{WURPWS-|1SQEUi~Zv-)AZ0Wt3W(<lhL_|e_r zdi^?B>C}?Vf#n`RnPa&R6`==$dT4!b472G_XNCCg9Mfj~;#Xq;@wV+_;rhMRu>7^v zQzT4=Z;ufrVx2eEQxYuvy0LB6uWs855~m_#uh))6ci7;bw_LGqhA8J>FcFg3@&mlS z_1B5R(k#~VldU$;jEeR6SnxJsy*Qb-#&_&fwO-o?gjVHB*^M0_W<acejs*pUUJBF0 zcY*NDH|z~0?}w|<=Ot<DJL8s+o;^OUZ*U1mT@MW~qNS}3<G^C}SeK8tTDUZSI*zgP z=(slPxx10x(?11zQ1!X){Bc~#dI`er*o<#e)<4E2tTzFE{3=-J)gnX+3!X0-4`%Ng z$dmQfw_rg8bPBE>Z#@mE5TRSgm#jM=()WLi!71yW@d@hzfbV*hMd!>sHr{#y-rc)? zUm*0r%Xr;#$$k)@RaemWH^(of?A<Vd@^tY8mZ$CTf|I#w0?X626WXl%uG$ZX+<Oxe zAy)33P_piYur=Ssw<+tV6B5>=0N=7~e}F}vem}u_4&FU^-T{Dr!G*9$1M>9B1nb5< ztu`X`l|4%-Yt5cK(X01liLTqT&ARr60|DvAC-M5due}ehKYR?Y+g^o5A>8zwleQk) z^Bl^{vc38S&*4S&-*!<ww<pWi#=R(8uksY$fD|q~{~(}u?N<+yvbB1zlJ&K{pa8y( zZ&TLVy%N@S0AIQdVUevn_OkARclW#$1N;~Naxlx*PxrD`PITn+TOjlYh;-qlQy8J` zK<KXkfBAld1);b1vd)_bCi$HyKxpk<?}zKdPvLdjbJO9v1Fk@^RL)s9O~kI3bvwj< zm4)qO*JaORyyb9(ax7cFomd(`>nEDNKS1oYEXGzIgSFo~Czi?sFnqRd+}mnp4fvY9 zQLpo?51h5G-W$eH-C&c~L2I$>kC?!EcD)0x0^@<bizVKf_!;YmSeqg4Miy)13y87t zPk3Fo4X@X;>mBU6fn9&dt{d6)VRqfju3NTEAGY)y>(WWkd4LyIE1Dte=1HtE`|hMl zkF^1Uwz0Ucvg@+#n8F&kaz(bbOu~+W^(4ew$HLaL>t=S{#;z}KpWe!Q3tyScdsAs> zudFqbbNRmh?h;s>tDz~{$>J`55$UgH*X!X5?J0Jl?wZU}*$DCOU|}2C^$B);ie0y| z>o#`X!LB>uYPCtm=*oSH-PX7F5ei%xf{qDnq=%9KlY9L>EQMS5fiidrd05V_tJ!r8 zT!lhISN6euJ`2~U!QjD8)yMXMA;1%WwU)(P_A<tV_b=l69q|4kcmrz2-$SQl<-XW> zvv&JNsODh9d7GNH?${ShxAm)iS;LNP8}wSfv>!H+Fb0Ae#?8I8X<raYU(R}DU+DNT z;!iN*V8GMX3;QyY44BISqp!aNBM|_0?hBW90AVXb*v76q*mWmIW+boPZ?UxwhB3?j zj6APk*VXL0hF#ae6}vkRLcE6|-p0RSyocCzGrK+kS8G%}ZLQcpk+#0Pe===dwm&rF z-`Kw+ZLQtEGi_bB|E#oi^Zs3F>%02{KMZTxD@bQ8yRK)~jqJLaUAMC94!G`^GH2q5 zb!Q&;_X)orvEzd`9s1nfkL~mGF>Cf%-TLj8E8*|iVLdkvUq1Yi)_?5&`__MEUR-+P z@UM(mee^HKZ5Y08#B*aGZM&-V_Lf_AdwSfOgYRhhUdvO5J~I5#mTBMH^Y2rByWjdT z8^%07_Rpgp8Ts7EuOIRBzTf-gFaI>`%EyOYciXUME+4l1JFRQ48TQ>zJ{rHiYyIp= z-`exdF~1)1t&d*z#bICl;;=gpK0ki`ob%_be*d4xyffyvBQ8Jbmh*<)eBQ9Drd$|b zIcMdZo2Ohe{>rg_@5Ou`eoM=WXS~5E!37@&aBu4{>y+bGvz6c&e+FD0gk^B}{9o{Q zhy>%iL-4O1F7QM6B)G^h;=eebhus3<h)*y)GJH%Ie+VN!!QTV;F#IUE+iooE0fb?x z^VT^3UWoCtco9Da69D(e;7`u)ZV&<Ucd{pc(;-2`9fAw;M=-v_{L%hpgpofP#{3=h z5srTiJR?5A@W}9K|1!deFT;p`?nxZ~A$Uf7g5i<j(>`W|5nqN8zc9%0{|3*9PcS?( zeA>s1FyhNF;!i%0<L}qP@d+k;+Q&@zGK~0dtm62`34DSHpY|~mz6>M&!f$Z=g1{%3 z@M#}2;ma`N|63gYa^hdWgirgJ315a0|F-Km{*MGc!Gurym<eBo5&zihIsUT(pJ2kL z{mg_f!-$``f#Z*akJVUy1QR~(YbJadM*O#L<oHJle1ZvIPVXdmDZ_|=(9InG;{u;x z!haU@27d@6z6>M&FsRrVwpid3jPJ1i^uQnf5Jr3%M*OV6$34rKe}XYS;?q7_gb`nc z5r6D@PWv8#PcY%r{%69MVZ{H+cRBta1U|upPy3(=pWwG4ehhe`U#!gyAMJtv-2?w8 zz=w^ttm<rT&n^=15&?fxz~>71CIK%K@ZADlF5sUFc!hwG-z;9lkHG}M{dW*QE5Uoi zRE3}YPv61ivmC;)d<aH*hrr(uyvHBHSUxh0^4)SL54&366HNHDznk!781Zkvo8#Xl z@Chb-+UHI9GK}~)zRdBT75D@bKJD`+d>Kak%V7T~hP@;32_}45A5VgpGK~1gOy~If z!E6G`k6^;5eclKoz6>M&DKk0#e1T6e;nO~E!k1yh-@1_F_X&K037__P6F$M`L;M)< zM89u%VBCKhqd>Ud?}4B8z^{AY$uQX=<0m}uLJyqxz~_13Z+hU{J@A7b8235L=?{ZE z1l5-}Aii8*;xPT<*Ppl@Hd`RAs~{Z9n_zs0^@aAqBaG!O!&qMVPjUPW0-s>Qr~UAR zFT+9n{|@NM{7-_u6!QNOPk(6Dr+NApKsfSGFr`oX=P7*|M*eqXIR0${pJ2kLee{Gc z!-#(@WCFt;7x)AdKJBL`d>Kakr*a(sZGlfP;m7d-euOW>h(D%}<G+7*o_~S~pZ3=i zz6>M&U1xFpe-row6F%*)Cwv)3{52JhUl8~N6F%*;Cwv)3{PyJ>|8jv(FyW{0LCU`j zBYyULj(?xPCz$YQzdgby!9|7<|B4GZ{>uWNV8W+;_k>UIm_6L}@kkH6&;y_4fiLjD z*LvW4J@D^5@IO58UeGqjP*CER^uV9+z$Fj-We@yc9{4^F{HzBaHpZR)`#kU*5BzBl zyx0SO#RK08Fpj6P9lZZ>AHr?mTj0Zdy!D8H*9iEx0$wNJKOzh~U#!{R_y@$7?avXg ztr+dkejmQnHQuazo$JqK5RUeTVA3D*uR!`E!>E7rpo5HIHw%1%3IAk#fFIsae`Of) zF9CysVGjs=g7F>N?`iOdKZFsV;AbIz3<JdPZ4Zp`!L->w2HTKj?K{pbpVI(F`P}&- zw|q7T{vL#Iln=p35BVei4G1HDGK~3q={iwA1wO%qPktN-UxpF?KQ?guiLgBl(<hkl z$)5w^%P`{q;3ph^j=(3F@X4<O;ma`M_dU$<vjU%B!YBU@gfGL0f6%Wu{+9$k!GuqK z9tdBC5x@E*$G=VB6HNF6P>1kG_%e+6&pgfXw+MWK37`Bv5WWl}{;kh){C^63f(f7e zKM=kQBmSi?aQp*cUI)vMV8SOq5QHzoh=1do9RDK%pJ2i#KM;g3!-&6PR11^MIRc+x z!Y4lvgfGL0e|M7OUnlShCVcV(LHII^_!obN<8K!D1QR~_fgpStM*OMJLC3JS1U|up zPktZ>UxpF?7kQ396~3;a{0Sy}@&iHmGK~1Q-NEtC6!-)aKKX$ld>Kak<cc=N|0M#S zV8SOq5QHzoS$rve_$b@+9|1iXeg|N`{^hTJ!_%+A_d(1*!AKA77x{}o_$0W<F!DdV zbvWaHoxmrU@X22U;ma`MZ`q&YZxQ$e6F&KkAbc4{{I_Ot{5II&i~JKz_~bW&@ClAX z{21hkemx$z=z*7d;N>3p5)b?h5By&qc)bTk{({Q$Zip|J=Nka~mFLZ;a(NWtJ1EM7 zV5E=bNq#R7#`2V5l;`~d|4M;RFyWK`3&JP(euy6fn)LgV2X2FeViXAXqzC@E2VUZV zulB$jJ@B(0cr0v!lhd2+fwLZXr3b#v1OM6szvY472cL)K^o|AiFz9n{?9`hd|2V{# z%XbC9SiX08`Ww%EhL`W(Asow>V0dKZOa4R<#`2Y6EZ?WI9DlEUIX=OJPyR#*UxpDs z1%3fBEFtg-CVcWMLijR__>X^?<DVk%2_}5<D?<1(jQHCh<@kAlPcY%{H6NIRAK}X| z;=eV11Pfas@Chb-@+(64GK~1&KbYfxOW+es_~ciF@MReBk2;Fu|5)G?O!(wigz#k; z@sC}^@wW<mf_3p1Eav#Fu%-a@hhV}dzaj{q1Q!{`^tW8d@nZs?V8SQAB7{%yQ4l|d z1tWeR0~p6UYeoIYAPn_o-YmWPG6eDE`hqJbu)cW5FZX?!^E(OFOkjQqCVt6p3Gpk# znBRLZ=lGohpJ2i#e-DH&!-&7n*E#-a0-s>QC%+GbFT;p`<VKEP5%>fX{w?#lKnY)l z5&y|yBbmNmEbs{?{F^=aGK}~ae30YcB=89)eDeE%@JVoyVZ^`oRF40Ez$cjS$?pT< z%P`^}F~IR(5cmWWKKXqhd>KakB&`3!u+{^3`4g;*Kj#LH|9*i_FyWKm2ZS;IGK}f> z-^KBd6ZixZKKU;pe1gw__^kcVtPg__U#<_=0gUzGZcqDh;r*PS39wQK>jS~W5BWbK zeq<Q)bL~$#eq7)aO!%_?qda67@!xuw<DVk%2_}45{}Eq?5r4v~9KR^=2_}45{}Eq? z5&xbJ?!N(7N@4y9Cj6V{yX%t-BmQU4=J?kMe1ZvI*8h{>r3@qfg)2Dzy#k+L!k6_Q z@nsnC$9{|BKO^u7CVW}{5nqN8fAYN?{~du(ur7Y=_Z<IVSR#h<Bbe}I{m1lW7}H<) z7mk07z$cjSTVY-we+VN!!HXb%3<Jck1Tbqagntu^pT&##od@CX1Ndeb7vk$H1-wzf zw*fpB0%$$O4-jsHh+=)iLjtDxw=Dvu`M0eCruny*5r+1R)<e7@V4BYx1B=@*oZ7ns z5tjOg?E<FuZvlmi`oD<6MScqi!+alouRK@4^u6+80n_)&D+Ns7D{mGseXsnXfa!bX z!vd!H#HRor2XnIIXXbeUlfRjl5e9kE{9ap(!!%!b0K$;}elfo}OTdEy{)C86^Lw8Y zFwI9?C19Fg*d$<@FZjEFY5aWf!90DM&pAQBG(R#VV481PCt#Yt*(6|^&-=50X?|?) zDV#pdcO5NYnt$sNFwN&(Bw(7KS}$Ol?|NLo_WZ^BIenUsm@QzMU+5Pwjn~%*n8v?9 zK^Ww{M9BAb5l-Xt!w=!~X}tX@0n>Q#d;!z=?<RzS-ZDXNvw)Wi_|F1fE#LzV<?+`D z_-FyI6>vttmgxUoDBu$Xe1m`&3i#&&K1IN<3wV)$ryR!9J5#_P6>z_R%K{!0@EQRx z5%9eNUMAo_3V4NpM;^}UuNLrBgoio(;o}5M<AJPzsek<i0aJf{oq(zTf1iM9Jok)% zX?$i)74j76PevHhr}0;ZfN4B)l7MM^G$3FaZ(Sf@>W{1yF!hf%3Yhvke-N<Uf1AeB zr~cUc1Wf(wV+2h7<<AJ1`oI4vVCqj^CSdBHeow&E-+frX)Ly(GU}`@{9l`mb_UKRn zQ~P$JfT_LA37Gmn=L?wnGwTrE4SWC#dEYI<slW1D0aN?`ih!v<G2sK8AL^eRAz=Fc ze7u0^dvZU*klwr$AOEZn@InE9N5rS^cMpm1Q$+ZmL^yrl96g<<Pv1-15eE9FiufN9 z@R<Vc7jVCTmkYQm;I#r?Cg8ge2K}S&k+^UfVfwx~;YbeC_tK*fhV<76{6zv@C*UOl zUN7J^0^Tg(I|RH<z`qjk%L0B;z&iyzVg^sIP1u{m1w3BBCkS||fO`-I{^|SlN&(aN z?%M@S-_L&|VEP_!&E)B&1ikkOc%Fdg2zZfz7YX<b0apclrhr!?yoY6x|F$bd_%^ZL z@?M02Us~VwM-je5gj?-AoYoIc6)>$w{Fs1gec*oznASV46ELm6{DpvNJ>csCruCJv zxJd6?yuWp#fNA|#Ucj`T>>>fv`nKByOzZ6)7ci}#dqcpq9`K+9Pmk93Ef6rR7wbkC z^zBt4k1q;%r+~jLU@O7v+YbcXCg4W|924*#1bn7|-xTmN0Z&Zw^wtYFCEz;*e6oNy z3OFy|c}brB1r#pewE{jw=<@~vPZjVl5Qg%n^<UcrOzW}6r#L?;5&uwxAwI45nlHk; zMEL0fo+IEP5uesqT`FK&uXLM$Y5mjV0;cs;ZwZ*zckR;wefeSIE&Kr+)^vbTzsXNw z2f`3Q>yeKZ;af$2_XGi3;`{c;1RN9a83Jw>aG!wZ3AilaQw02f1bn7|R|t4ez+Xie z_!*qQ`TaV;0FGiAfXnwh@WUSXSr7cC2cFdFrZ>X_pWuQ2-2<0A@Ny4)l?T4l13%`0 zU+}<hd*BJP-25KmfxA5L$2@S}126NyS9svtJ@BI*_$3cKvdhh1jKd?Tybklg(>-v? z1JCim3q0^gJ@9E9Zl&~c9=PIx&-cJrc;M?j@DDujCJ+1@54_C-zwUusW;1!&{Eqd& z`+49)J#fMU&*iW!@87jRTMB=_hrg%c?+@^|75<)qKU|yr9Q-{Gf4HIh1^D|D{Na}B z?eO;^{JjK!FT>xT;qNc-_gDDa0e^pkzgOT7HdkA(!rwpO?=|?tZPq*C@1OAZ2K>DV ze{aFx+wk`e{Jjf*u!Y~kBYIlkuND5<;BPqmjetK~?>!3sc7wm&;cpN48x4Q(n}>h@ zf5}hGnt56UwtUVkWco6>a<%ibGe1~@4f8W`lP}zIOELq4h1|?axo0NZ%{a3<REEvI zgZ;U3Zbt9y_B#08L-|71MdgDZ&774x0rurrT%@x3vVQ_IN>=)#^FMS_I&Fa`4cJnZ z7XD9WBvLctU0t&+@^LUD-Wi`&hacS2$1)>%XfU0Pbb2QISEYpcNprUjVyic9zUJ(> zJT~+u3%W72BPMkzCUhg}#!KXNW9mk%C<)r`GSUNT$w-mPI+Va=g{s^nQd*Jx2>JN> zP$nllY6PT3J~vb(xEm0kP_K6ppD5&R#3zXSkFX820pY0a7Wbe8`@*X;5*-~~1cRp= zgrQn94@)9E-a#-Ak9QKx@KZ?}X5p!1Jwt#7Enh^xA>4h)Ozsz?Ikq4mF>Ved=P<H2 z6A+;kQgOK#afhirp19))a>4<LZ<z2&;v2?x<8!Yh!WBuqXxveWIu?31afb@GEbf=& zqQ(6d8VwI}*0mkm9h>vb_Fwx2$UCzA!o?nKPY~bP?MIY{(5`J?G`6$Z9pZSNala>L zGw!!YAer^Zfcb6lA?@~B6Ws2j#uhS5K^bQ<S4HRpq<MA2FC|_v?8KQ*633wph(Qr# zyR-?HLGq8YYceUPCS{afv&?!N@t}HQL9=WJMPzM!-B@vOq@zPE?jH-fF1D8)*jVmM zNsfb_cYGsd-Trsfx%5ON$2>Yjh3g*Qs7z2n5hSli0R+%%f;yNgV{NH0yQaWICvM=I z!Ix~7yGv4psnY|eEIs}dZHG?2G?}vy?!zS@oH<bN4Hy0~e8U`XQNF>@<M-2g;fcyW zOmZ^eAHjA!;Tuf;s(b^{FN0dZ7^)V7@O$M;SGdCR4HMq6(ssQE_Zc(dvu8oCXa0<M zDmf$3o`jl;&nbLP@#hYFhB!Pw>39}#5_N`1X!^-L6CaW_&nDKU!>u9rbH%(;p@Ted zJPN+7Kr-I<WG<ZdZpT>QQ^kel_LAiaawCS85vz}-;;s^vl$<OvX+#NLnuMDZ^7~_F z*Ebe8+d|z1FH2hSz;9OFc)~4L-FVDvS8yyX)-Y0CzO<Oq;Hbb{gGv6tf-}IQOCG}% z(LEl$xRWMDT#x59C{|UOcwz=p_4o`6jB9&uQ~5DdaBkyyyqqbblbP^%i>u$mBSdb; zM5SS#%yw}_wbS&et>}P@T<&>_pZVtU3Pq0ZDcHL4J%w90zM${8hSOlij?7)gp$l7d zj|xtI=n<R%(IYqoqDOENM33M!h#tX-5IurZA$kPoL7_|E_NTbZ%HEZtT=I4Rl{<F! zQCZWHvnpHEwXr3adWu-!ov%JAhy?zy)D(REWT~T5zlXQRZmyYAD&C6(kKU>@<ybh? zOD(<+E%3lqhYrM0)4;aE@w_D*Ybnxm$A!Kh_}&VL3UvlOaoMi7>PO`xC_k}b(m;<~ zdIgYT+Jn)9i7{tlb+f=?EmmgI_FtC%?9jkq6`hpMh$nFVJsG-MF4|SKktHNmLhg)} z34IA0*$5YbB;(p}m$l@<<hIh=$8v{)zeP7yLMtVF6Lo?;c!FE>un3lr`?_>fmSfZ; z>k9Nw+8srmyeGu=*$IyQK>5+3-i%~24*7O8B-P$EBiWIt_sOVs{BioOQW2Jrq$1o+ zFB8d9KNYDBcc};uCfA?d@^XhtW#tL*mXkNwE(snWxb;<$+88y-%INN{UoEmvW+n96 zqEB^%who`(RYlJdl8T-?W@gzr$FJyX!(Gzg!Q?5`TlDTwsSG>;-lF#g+eOa<1h>9L zUmK$)SsA^?F!|uK2}FTp57l9&0zLJTQQ~N}o7fs_km|JD2bAEE5dFCV%vb;o7Suab z>`50&rL%@$3V^-@*L(xknFbLq^Z9pTzqu5(?V{GLCIev3YTkjK*S@nqP&Ms?mv@>c z%?>nxvS4?qHMa}Pp3q~Z$ory-`4;_|6DoQ}&ONIlPsg|?Aw1(Ax8<R68{@kN`$MwB zaYMsi8Y+6mn09X5{ED8j-edxsDX2g67c|38ETE(EU@pDp$0JXXE=&MvWe4JEOpl1^ zq`K2Fy3<bBv#m=EBT2@`lTXjsH&Dmy35q67Y+z$SV?U4XyV?=Tf*jw(n4AVyLaTkq z<B$XW`PXH~BUX2O_rMK3$G<nwMKku^KsW7HjsNKbT~T3NgF;tNrzS*afaY|eYSC-D zU_Md2<4V?!H$IwmMscp}(s0z<j&O!3wB*f<6A(Pebuv*i#IPH-nh+1k+HjX0stxw$ zr8b7tKXwJ;H>aS~S-4N?n&Uu6iab?9t5F9}up`BquDUJ7nvfbDt&JfSt6!i;5<XEB zjQNPsg<LB}9_)-IgpTspnnNu|x^A=@>3V`$CfMhD_O%*Kc&NoF&_S#H_-|rqLD13# zmZJJoHMITq8V=?93^|f|p$DF_<eNpdzG2rbV(=^y2@;McYMAvTsG9!SeQyzkbI4fW zA_~vqCdDcvZ!FC<OL{Ay)TM}h5p}h}Q2NqQTc@M0@JQo1Df}ovs8G@>bv9biSe~o5 zkT_rwuisL1)OIf~e({)j)rzQIyzD-=uvdG@y8d!`?X=aa$K6Z@EJd%k5}Tjv2w$p{ zB9>N{>%=j*PF<aSiKnuXDdi&baLdG9YoOm-9L$fUg!(A04EJ9gtX@eDb6tw_G2L|0 z2-Yqy4p@eccF{JS5`*rg$L>T#w7SdAYgdX3Ox9E6i@WQsHm|>Q-Ch}Ad-7|V4u%!` zki@zMX;p%>RzX_9AgybVRy#;*Af%NMu&#lhN~=Dc+Z7@o%Pj{u2Xaeq*<u^}C~m(1 zaR|2*<T`#^elH)q?S3y#+?HP2M{P^*oHMqim+r&0RRMUawiM<*PTLhA&e8U~qXV?% z*K~5W`yD$n+x?24mF@G6ACm0~kWR<;z8A-0yIwozVN0*=bFTS8*nT0-3D|z2Sn7Rj z=G{K--KI%rUi;y(!>;)$*Zg>EI@g*Gw1yE7JINaF><DXofG!(bq$3|%jf-~D_G#4& zVjU+oIDivFr8nYyYUhnOm|A*)CsK0|7F{!ABg4!BN#X2FR1v{Bb(-NbyTPO4H)}X& bn!jdqbNpF)O($@(IQ%SW_m?XWv1R>Vp^c$M literal 0 HcmV?d00001 diff --git a/HySoP/src/Unstable/LEGI/example/src/CMakeLists.txt b/HySoP/src/Unstable/LEGI/example/src/CMakeLists.txt new file mode 100644 index 000000000..e12c5b539 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/example/src/CMakeLists.txt @@ -0,0 +1,45 @@ +set(EXECUTABLE_OUTPUT_PATH "${EXAMPLE_EXE_DIR}") +include_directories(${CMAKE_Fortran_MODULE_DIRECTORY}) + +# ===== Example and benchmark about advection equation and the particular solver ===== +set(EXECUTABLE_OUTPUT_PATH "${EXAMPLE_EXE_DIR}/advec") +# --- Simple turning sphere --- +set(EXAMPLE_NAME turn_sphere) + # Test file + list(APPEND ${EXAMPLE_NAME}_SRC "advec/${EXAMPLE_NAME}.f90") + list(APPEND ${EXAMPLE_NAME}_SRC "../../test/src/test_common.f90") + list(APPEND ${EXAMPLE_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/input_output/vtkxml.f90") + # General environment and utilities (mesh, io, ...) + file(GLOB ${EXAMPLE_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/layout/cart*.f90 ) + if(${EXAMPLE_NAME}_LIB) + list(APPEND ${EXAMPLE_NAME}_SRC ${${EXAMPLE_NAME}_LIB}) + endif() + # Particular solver + file(GLOB ${EXAMPLE_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/particle/*.f90) + if(${EXAMPLE_NAME}_LIB) + list(APPEND ${EXAMPLE_NAME}_SRC ${${EXAMPLE_NAME}_LIB}) + endif() +add_executable(${EXAMPLE_NAME} ${${EXAMPLE_NAME}_SRC}) +target_link_libraries(${EXAMPLE_NAME} ${LIBS}) + +# --- Case test with shear --- +# In this example, velocity radial component vanishes and as scalar is initialized with cylindric symetry, it stays constant. +# It allow to compare solver with large time step (eg cfl number bigger than one) +set(EXAMPLE_NAME shear_tag) + # Test file + list(APPEND ${EXAMPLE_NAME}_SRC "advec/${EXAMPLE_NAME}.f90") + list(APPEND ${EXAMPLE_NAME}_SRC "../../test/src/test_common.f90") + list(APPEND ${EXAMPLE_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/input_output/vtkxml.f90") + # General environment and utilities (mesh, io, ...) + file(GLOB ${EXAMPLE_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/layout/cart*.f90 ) + if(${EXAMPLE_NAME}_LIB) + list(APPEND ${EXAMPLE_NAME}_SRC ${${EXAMPLE_NAME}_LIB}) + endif() + # Particular solver + file(GLOB ${EXAMPLE_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/particle/*.f90) + if(${EXAMPLE_NAME}_LIB) + list(APPEND ${EXAMPLE_NAME}_SRC ${${EXAMPLE_NAME}_LIB}) + endif() +add_executable(${EXAMPLE_NAME} ${${EXAMPLE_NAME}_SRC}) +target_link_libraries(${EXAMPLE_NAME} ${LIBS}) + diff --git a/HySoP/src/Unstable/LEGI/example/src/advec/shear_tag.f90 b/HySoP/src/Unstable/LEGI/example/src/advec/shear_tag.f90 new file mode 100644 index 000000000..4451438c6 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/example/src/advec/shear_tag.f90 @@ -0,0 +1,161 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : advec_sheartag +! +! DESCRIPTION: +!> This program provide a numerical illustration of an adveciton problem: a +!! velocity field with radial shear. This test illustrate the effect of +!corrected remeshing formula. +!! +!! @details +!! This example could be used as a benchmark (to determine optimisation +!! efficiency or parallel scalability). The velocity field is choosen to ensure +!! That the solver will imply tag and thus corrected remeshing formula. It is a +!! Typical test cases to evaluate efficiency of such a formula in context of large +!! Cfl number (eg 3 or more). +!! Note that the analyti solution is known and could be check. +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program advec_sheartag + + ! External Library + use mpi + ! Scales code + use cart_topology + use advec + use vtkxml + ! Test procedures + use test_common + + implicit none + + logical, parameter :: output = .false. ! Do you want output for + ! vizualisation purpose ? + real(WP), parameter :: M_PI = ACOS(-1.0) ! Pi value + real(WP),parameter :: period = 1 + + logical :: success = .true. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc,nb_procZ ! number of processus + + character(str_short) :: order='p_02' ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: Vx, Vy, VZ ! the flow + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + integer :: i,j,k ! mesh indice + real(WP) :: T_step ! time where output are done + real(WP) :: T_end ! final time + real(WP) :: T ! current time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + integer :: tag_num,tag_err ! identifiant for io + integer :: tag_sol ! identifiant for io + real(WP) :: rx, ry, rr + integer, parameter :: N_mesh=400 ! number of mesh + + ! ===== Initialisation of parallel context ===== + + ! Set the verbosity + verbose_test = .true. + verbose_more = .true. + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! ===== Cut the domain along y and initialize the topology ===== + nb_procZ = 1 + if (mod(N_mesh, nb_proc)/=0) stop 'wrong number of processes : it have to divide 100' + call cart_create((/ nb_proc, nb_procZ /), ierr) + + ! ===== Create mesh ===== + call discretisation_create(N_mesh,N_mesh,20,dble(2),dble(2),dble(0.5)) + call set_group_size(5) + call advec_init(order) + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! ===== Field allocation ===== + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vx(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vz(N_proc(1), N_proc(2), N_proc(3))) + + ! ===== Initialization ==== + Vx = 0.0 + Vy = 0.0 + Vz = 0.0 + do k = 1, N_proc(3) + do j = 1, N_proc(2) + ry = ((j-1+coord(2)*N_proc(2))*d_sc(2)) - length(2)/2.0 + do i = 1, N_proc(1) + rx = ((i-1+coord(1)*N_proc(1))*d_sc(1))-length(1)/2.0 + rr = (rx**2+ry**2) + if (rr<1) then + scal3D(i,j,k) = (1-rr)**6 + else + scal3D(i,j,k) = 0 + end if + Vx(i,j,k) = cos(3*M_PI*sqrt(rr)/2)*(-ry) + Vy(i,j,k) = cos(3*M_PI*sqrt(rr)/2)*(rx) + end do + end do + end do + good_scal = scal3D + T = 0.0 + dt = 3*min(d_sc(1),d_sc(2)) + T_step = 0.0 + T_end = 0.8 + call test_substatus('cfl=3 and dt', dt, cart_rank) + + ! === Create output context and solve initial state ===== + if (output) then + call vtkxml_init_all(9, nb_proc_dim, length, cart_rank, coord,'./adv_res/') + call vtkxml_init_field(trim(order)//'_tag_num', tag_num) + call vtkxml_init_field(trim(order)//'_tag_err', tag_err) + call vtkxml_init_field(trim(order)//'_tag_sol', tag_sol) + call vtkxml_write(tag_sol, good_scal) + end if + + + ! ===== Solve equation ==== + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('tag, t', T, cart_rank) + if (output) call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + if (output) then + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call vtkxml_finish() + end if + call test_substatus ('time', (T+dt), cart_rank) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - with tag', success, cart_rank) + + + ! --- Free memory --- + deallocate(scal3D) + deallocate(good_scal) + deallocate(Vx) + deallocate(Vy) + deallocate(Vz) + + success = .not.success + + call mpi_finalize(ierr) + +end program advec_sheartag diff --git a/HySoP/src/Unstable/LEGI/example/src/advec/turn_sphere.f90 b/HySoP/src/Unstable/LEGI/example/src/advec/turn_sphere.f90 new file mode 100644 index 000000000..d87c3c985 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/example/src/advec/turn_sphere.f90 @@ -0,0 +1,186 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : advec_turnsphere +! +! DESCRIPTION: +!> This program provide a numerical illustration of an adveciton problem: a +!! turning sphere. +!! +!! @details +!! This example could be used as a benchmark (to determine optimisation +!! efficiency or parallel scalability) +!! Note that the analyti solution is known and could be check. +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program advec_turnsphere + + ! External Library + use mpi + ! Scales code + use advec + use cart_topology + use vtkxml + ! Test procedures + use test_common + + implicit none + + real(WP), parameter :: M_PI = ACOS(-1.0) ! Pi value + logical, parameter :: output = .true. ! Do you want output for + ! vizualisation purpose ? + real(WP),parameter :: period = 1 + integer, parameter :: mesh_size = 160 + + logical :: success = .true. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc,nb_procZ ! number of processus + + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: Vx, Vy, Vz ! the flow + integer :: i,j,k ! mesh indice + real(WP) :: rx, ry, rz, rr ! distance**2 to the mesh center + real(WP) :: rayon ! rayon of the initial scalar sphere + real(WP) :: T ! time + real(WP) :: T_end ! final time + real(WP) :: T_ite ! time corresponding to output + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + real(WP), dimension(:, :, :), allocatable :: good_velo ! temp field + integer :: tag_rot ! tag for visualisation context + integer :: tag_sol ! tag for visualisation context + real(WP) :: times, time1, time2 ! to evaluate computation time. + + ! ===== Initialisation of parallel context ===== + + ! Set the verbosity + verbose_test = .true. + verbose_more = .true. + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + nb_procZ = 1 + if ((mod(nb_proc,5)==0).and.(mod(mesh_size, nb_proc/5)==0)) then + nb_procZ = 5 + nb_proc = nb_proc/5 + else if ((mod(nb_proc,2)==0).and.(mod(mesh_size, nb_proc/2)==0)) then + nb_procZ = 2 + nb_proc = nb_proc/2 + else + if (mod(mesh_size, nb_proc)/=0) then + if(cart_rank==0) write(*,'(a,x,i0)') 'wrong number of processes : it have to divide', mesh_size + stop + end if + end if + + ! ===== Create mesh ==== + call cart_create((/ nb_proc, nb_procZ /), ierr) + call set_group_size(5) + call discretisation_create(mesh_size,mesh_size,mesh_size,dble(1),dble(1),dble(1)) + call test_substatus('group size', group_size(1,1), cart_rank) + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! ===== Initialize the particular solver ===== + call advec_init('p_O2') + + ! ===== Field allocation ===== + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vx(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vz(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_velo(N_proc(1), N_proc(2), N_proc(3))) + + ! ===== Initialization ==== + ! -- Scalar -- + scal3D = 0. + rayon = (minval(N*d_sc)/10.0)**2 + do k = 1, N_proc(3) + rz = (d_sc(3)*(k + coord(3)*N_proc(3) - 3.0*N(3)/5.0))**2 + do j = 1, N_proc(2) + ry = (d_sc(2)*(j + coord(2)*N_proc(2)- 3.0*N(2)/5.0))**2 + do i = 1, N_proc(1) + rx = (d_sc(1)*(i - 3.0*N(1)/5.0))**2 + rr = rx + ry + rz + if (rr < rayon) scal3D(i,j,k) = (1 - rr/rayon)**1 + end do + end do + end do + good_scal = scal3D + ! -- Velocity -- + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + Vx(i,j,k)=(2*M_PI/period)*(length(2)/2.0-((j+coord(2)*N_proc(2))*d_sc(2))) + Vy(i,j,k)=(2*M_PI/period)*(((i+coord(1)*N_proc(1))*d_sc(1))-length(1)/2.0) + end do + end do + end do + Vz = 0.0 + + + + ! ===== Initialize output context ==== + if (output) then + call vtkxml_init_all(2, nb_proc_dim, length, cart_rank, coord,'./adv_res/') + call vtkxml_init_field('turning', tag_rot) + call vtkxml_init_field('turn_sol', tag_sol) + call vtkxml_write(tag_rot, scal3D, 'turning') + end if + + + ! ===== Compute the numerical solution ===== + dt = 0.02 + T = 0 + T_end = 2*period + T_ite = 0 + times = 0 + do while (T<=T_end - dt) + call cpu_time(time1) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + call cpu_time(time2) + times=times+(time2-time1) + if (T>T_ite) then + T_ite = T_ite + T_end/10 + call test_substatus ('time', T, cart_rank) + if (output) call vtkxml_write(tag_rot, scal3D, 'turning') + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + if (output) then + call vtkxml_write(tag_rot, scal3D, 'turning') + call vtkxml_write(tag_sol, good_scal) + call vtkxml_finish() + end if + + call test_check_success(scal3D, good_scal, success, cart_rank) +print*, 'times = ', times + call test_substatus('computational time', times, cart_rank) + call test_substatus('turning sphere', success, cart_rank) + + + ! --- Free memory --- + deallocate(scal3D) + deallocate(good_scal) + deallocate(Vx) + deallocate(Vy) + deallocate(Vz) + + success = .not.success + + + call mpi_finalize(ierr) + +end program advec_turnsphere diff --git a/HySoP/src/Unstable/LEGI/test/src/CMakeLists.txt b/HySoP/src/Unstable/LEGI/test/src/CMakeLists.txt new file mode 100644 index 000000000..f72a850e4 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/CMakeLists.txt @@ -0,0 +1,53 @@ +set(EXECUTABLE_OUTPUT_PATH "${TEST_EXE_DIR}") +include_directories(${CMAKE_Fortran_MODULE_DIRECTORY}) + +# ===== Test the parallel topology and how it interact with the "global" datalayout (used in the spectral code) ===== +set(TEST_NAME Test_topo) + file(GLOB ${TEST_NAME}_FILES ${TEST_NAME}/*.f90) + if(${TEST_NAME}_FILES) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_FILES}) + endif() + list(APPEND ${TEST_NAME}_SRC "test_common.f90") + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_topology.f90") +add_executable(${TEST_NAME} ${${TEST_NAME}_SRC}) +target_link_libraries(${TEST_NAME} ${LIBS}) + +# ===== Test the parallel output ===== +set(TEST_NAME Test_io) + file(GLOB ${TEST_NAME}_FILES ${TEST_NAME}/*.f90) + if(${TEST_NAME}_FILES) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_FILES}) + endif() + list(APPEND ${TEST_NAME}_SRC "test_common.f90") + # Tested procedures + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_topology.f90") + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_mesh.f90") + file(GLOB ${TEST_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/output/*.f90) + if(${TEST_NAME}_LIB) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_LIB}) + endif() +add_executable(${TEST_NAME} ${${TEST_NAME}_SRC}) +target_link_libraries(${TEST_NAME} ${LIBS}) + +# ===== Test the advection and the particular solver ===== +set(TEST_NAME Test_advec) + # Test file + file(GLOB ${TEST_NAME}_FILES ${TEST_NAME}/*.f90) + if(${TEST_NAME}_FILES) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_FILES}) + endif() + list(APPEND ${TEST_NAME}_SRC "test_common.f90") + # General environment and utilities (mesh, io, ...) + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_topology.f90") + list(APPEND ${TEST_NAME}_SRC "${${EXE_NAME}_SRCDIRS}/cart_mesh.f90") + file(GLOB ${TEST_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/output/*.f90) + if(${TEST_NAME}_LIB) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_LIB}) + endif() + # Tested solver + file(GLOB ${TEST_NAME}_LIB ${${EXE_NAME}_SRCDIRS}/particle/*.f90) + if(${TEST_NAME}_LIB) + list(APPEND ${TEST_NAME}_SRC ${${TEST_NAME}_LIB}) + endif() +add_executable(${TEST_NAME} ${${TEST_NAME}_SRC}) +target_link_libraries(${TEST_NAME} ${LIBS}) diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux.f90 new file mode 100644 index 000000000..b2a738cae --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux.f90 @@ -0,0 +1,775 @@ +!> @addtogroup part_test +!! @{ + +!------------------------------------------------------------------------------ +! +! MODULE: test_advection +! +! DESCRIPTION: +!> Validation test for advection method. +!! +!! @details +!! This module provide different test to validate the transport solver. +!! All these test are unit test : they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular solver +!! The following test are included : +!! A - Validate the particular method, step by step +!! 1 -> Test the procedure "AC_obtain_senders" from advec_common +!! 2 -> Validate the redistribution the buffer during the remeshing (XXX todo) +!! 3 -> Validate the remeshing of untagged particles +!! 4 -> Validate the remeshing of tagged particles (XXX todo) +!! B - Validate an advection solver (XXX todo) +!! 1 -> advec a ball with a constant velocity +!! 2 -> advec a ball with a spheric velocity field (the ball turns) +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module advec_aux + + use string + use precision + implicit none + + real(WP), private :: epsilon_error = 1e-4 ! Error tolerance + + + ! Public procedures + + ! ===== Test for the particles solver ===== + ! Public function + public :: test_part_remesh_no_tag + public :: test_part_advec_1D + public :: test_part_advec_3D + public :: test_advecY + + + ! ===== Generic test for an advection solver ===== + + ! Private procedure + +contains + +!> Particles method: validation of the remeshing of untagged particles +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @param[in] order_opt = optional parameter to choose the remeshing formula +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_remesh_no_tag (init_scal, order_opt) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + character(len=*), intent(in), optional :: order_opt ! space order of the solveur + + character(len=17) :: initialisation ! to choose how to initialise the scalar field + character(len=str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scalar ! the scalar field + real(WP), dimension(:,:,:), allocatable :: p_pos_adim, p_SC ! the adimensionned particles position and the scalar they advect + logical, dimension(:,:,:), allocatable :: bl_type, bl_tag ! type and tag of each particle bloc + real(WP) :: velocity ! constant velocity of the flux + integer :: nb_proc ! number of processes + integer :: ierr ! mpi error code + integer :: i,j,k ! mesh indice + integer, dimension(2) :: ind_group ! indice of the current group of line + integer :: T_step ! time + integer :: T_end ! final time + real(WP), dimension(:,:,:), allocatable :: good_scal ! analytic solution + real(WP), dimension(3) :: translat ! to compute analytic solution + + ! Initialize the particular solver + order = 'p_O2' + if (present(order_opt)) order = trim(order_opt) + call advec_init(order) + + allocate(scalar(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(p_pos_adim(N_proc(2),1,1)) + allocate(p_SC(N_proc(2),1,1)) + allocate(bl_type(1+N_proc(2)/bl_size,1,1)) + allocate(bl_tag((N_proc(2)/bl_size),1,1)) + + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'constant' + end if + success = .true. + + !call cart_create((/ 1, nb_proc, 1 /), ierr) + !call mesh_default() + + ! Choose a velocity + velocity = N(2)/11.*d_sc(2) + T_step = 1 + T_end = 1 + T_end = T_step + translat = 0 + translat(2) = - velocity*T_step + translat = translat/d_sc + + ! Initialise the scalar field + call scal_init(initialisation, scalar, good_scal, translat) + call test_substatus('initialisation', success, cart_rank) + + ! Choose to test remeshing for centered/left and tagged/untagged particles + bl_type = .true. + bl_tag = .false. + + ! Advec it with a particular method + do k = begin_proc(3), end_proc(3) + ind_group(2) = 0 + !k = begin_proc(3) + ind_group(1) = 0 + ind_group(2) = ind_group(2) + 1 + do i = begin_proc(1), end_proc(1) + !i = begin_proc(1) + ind_group(1) = ind_group(1) + 1 + ! Initialise the particles + p_SC(:,1,1) = scalar(i,:,k) + !scalar(i,:,k)=0 + do j = begin_proc(2), end_proc(2) + p_pos_adim(j,1,1) = j + end do +! do T_step = 1, 11 + ! Advection + p_pos_adim = p_pos_adim + T_step*velocity/d_sc(2) + ! Remeshing + allocate(send_group_min(1,1)) + allocate(send_group_max(1,1)) + if (order == 'p_O4') then + call Yremesh_O4(ind_group, (/1,1/), p_pos_adim, bl_type, bl_tag, i, k, scalar) + else if (order == 'p_M6') then + call Yremesh_Mprime6(ind_group, (/1,1/), p_pos_adim, i, k, scalar) + else + call Yremesh_O2_group(ind_group, (/1,1/), p_pos_adim, bl_type, bl_tag, i, k, scalar) + end if + deallocate(send_group_min) + deallocate(send_group_max) +! end do + end do + end do + + ! Check the final scalar field + call test_check_success(scalar, good_scal, success, cart_rank) + + deallocate(scalar) + deallocate(p_pos_adim) + deallocate(p_SC) + deallocate(bl_type) + deallocate(bl_tag) + + success = .not.success + +end function test_part_remesh_no_tag + + +!> Particles method: validation of the advection along each direction +!! individually with particle method - no tag case. +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @param[in] shift = global translation of indices (optional) +!! @param[in] order_opt = optional parameter to choose the remeshing formula +!! @return error = test error (= false if the code pass the test) (= not success) +!! @details +!! These tests are devoted to validate the advection solver based on particle +!! method. They can be used for other advection solvers too. Their specificity +!! is to test each configuration that could be encoutered in the order 2 solver +!! based on particle method. Therefore they test all cases without tag (and there- +!! fore corrected remeshing formula) for order 2 (or order 4) solver. +function test_part_advec_1D(init_scal, shift, order_opt) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecX + use advecY + use advecZ + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + integer, intent(in), optional :: shift + character(len=*), intent(in), optional :: order_opt ! space order of the solveur + + character(str_short) :: initialisation ! to choose how to initialise the fields + integer :: shift_bis ! shift effectly used in the test + character(str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: velo ! the flow + real(WP), dimension(:, :, :), allocatable :: Vx, Vy, VZ ! the flow + integer :: i,j,k ! mesh indice + real(WP) :: T_step ! time where output are done + real(WP) :: T_end ! final time + real(WP) :: T ! current time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + integer :: direction ! current direction + integer :: tag_io,tag_er ! identifiant for io + integer :: tag_sol ! identifiant for io + + ! -- Mesh init -- + call discretisation_create(80,80,80,dble(1),dble(1),dble(1)) + + ! -- Allocation -- + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(velo(N_proc(1), N_proc(2), N_proc(3))) + + ! -- Initialisation -- + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'center' + end if + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + success = .true. + dt = 0.1 + + call test_substatus('shift', shift_bis, cart_rank) + + ! Initialize the particular solver + order = 'p_O2' + if (present(order_opt)) order = order_opt + call advec_init(order) + + ! ===== Test along X ===== + ! Initialise the velocity, the scalar field and compute the theoritical solution + direction = 1 + call test_substatus('direction', direction, cart_rank) + call scal_velo_init_part(init_scal, dt, shift_bis, scal3D, velo, direction, good_scal) + call test_substatus('initialisation', success, cart_rank) + + ! Advec it with a particular method + call advecX_calc(dt, velo, scal3D, order) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('advection along X', success, cart_rank) + + + ! ===== Test along Y ===== + ! Initialise the velocity, the scalar field and compute the theoritical solution + direction = 2 + call test_substatus('direction', direction, cart_rank) + call scal_velo_init_part(init_scal, dt, shift_bis, scal3D, velo, direction, good_scal) + call test_substatus('initialisation', success, cart_rank) + + ! Advec it with a particular method + call advecY_calc(dt, velo, scal3D, order) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('advection along Y', success, cart_rank) + + + ! ===== Test along Z ===== + ! Initialise the velocity, the scalar field and compute the theoritical solution + direction = 3 + call test_substatus('direction', direction, cart_rank) + call scal_velo_init_part(init_scal, dt, shift_bis, scal3D, velo, direction, good_scal) + call test_substatus('initialisation', success, cart_rank) + + ! Advec it with a particular method + call advecZ_calc(dt, velo, scal3D, order) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('advection along Z', success, cart_rank) + + + + deallocate(scal3D) + deallocate(good_scal) + deallocate(velo) + + success = .not.success + +end function test_part_advec_1D + + +!> Particles method: validation of the advection in 3D cases. +!! @param[in] order = optional parameter to choose between order 2 +!! or order 4 particle method. +!! @param[in] shift = global translation of indices (optional) +!! @return error = test error (= false if the code pass the test) (= not success) +!! @details +!! This tests are devoted to validate the advection solver based on particle +!! method on 3D cases. They can be used for other advection solvers too. Their specificity +!! is to test each configuration that could be encoutered in the order 2 and order 4 +!! solver based on particle method. Supposing the 1D tests (test_part_advec_1D) have been +!! passed successful, then passed this test means the solver does not contain +!! error anymore. +function test_part_advec_3D(shift, order) result(success) + + ! Library + use mpi + ! Scales code + use advec + use cart_topology + use vtkxml + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: order + integer, intent(in), optional :: shift + + character(str_short) :: initialisation ! to choose how to initialise the fields + integer :: shift_bis ! shift effectly used in the test + character(str_short) :: order_bis ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: velo ! the flow + real(WP), dimension(:, :, :), allocatable :: Vx, Vy, VZ ! the flow + integer :: i,j,k ! mesh indice + real(WP) :: T_step ! time where output are done + real(WP) :: T_end ! final time + real(WP) :: T ! current time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + integer :: direction ! current direction + integer :: tag_num,tag_err ! identifiant for io + integer :: tag_sol ! identifiant for io + real(WP) :: rx, ry, rz, rr + + + ! -- Parameters initialisation -- + call discretisation_create(80,80,80,dble(1),dble(1),dble(1)) + call set_group_size(10) + if(present(order)) then + order_bis = order + else + order_bis = 'p_O2' + end if + ! Initialize the particular solver + call advec_init(order_bis) + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, cart_rank) + success = .true. + T_end = 1.0 + + ! -- Allocation -- + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(velo(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vx(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vz(N_proc(1), N_proc(2), N_proc(3))) + + ! Initialize output context + call vtkxml_init_all(9, nb_proc_dim, length, cart_rank, coord,'./adv_res/') + + ! -- Fields initialisation -- + ! ===== 3D velocity ===== + ! Initialise the velocity, the scalar field and compute the theoritical solution + dt = 1 + call scal_velo_init_part('center', dt, shift_bis, scal3D, velo, 1, good_scal) + dt = 0.1 + good_scal = scal3D + velo = 1 + call test_substatus('Start test : X,Y,Z,3D,tag', cart_rank) + + + ! === Velocity along X === + T = 0.0 + T_step = 0.0 + Vx = velo + Vy = 0 + Vz = 0 + call vtkxml_init_field(trim(order_bis)//'_X_num', tag_num) + call vtkxml_init_field(trim(order_bis)//'_X_err', tag_err) + call vtkxml_init_field(trim(order_bis)//'_X_sol', tag_sol) + call vtkxml_write(tag_sol, good_scal) + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('X, t', T, cart_rank) + call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call test_substatus ('X, t', (T+dt), cart_rank) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - V along X', success, cart_rank) + + ! === Velocity along Y === + T = 0.0 + T_step = 0.0 + Vx = 0 + Vy = velo + Vz = 0 + call vtkxml_init_field(trim(order_bis)//'_Y_num', tag_num) + call vtkxml_init_field(trim(order_bis)//'_Y_err', tag_err) + scal3D = good_scal + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('Y, t', T, cart_rank) + call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - V along Y', success, cart_rank) + + ! === Velocity along Z === + T = 0.0 + T_step = 0.0 + Vx = 0 + Vy = 0 + Vz = velo + dt = 0.1 + T_end = 1 + scal3D = good_scal + call vtkxml_init_field(trim(order_bis)//'_Z_num', tag_num) + call vtkxml_init_field(trim(order_bis)//'_Z_err', tag_err) + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('Z, t', T, cart_rank) + call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - V along Z', success, cart_rank) + + ! === 3D Velocity === + call test_substatus('3D test - 3D velocity', cart_rank) + T = 0.0 + T_step = 0.0 + Vx = 2*velo + Vy = velo + Vz = 3*velo + call vtkxml_init_field(trim(order_bis)//'_3Dnum', tag_num) + call vtkxml_init_field(trim(order_bis)//'_3Derr', tag_err) + scal3D = good_scal + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('3D, t', T, cart_rank) + call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - 3D velo', success, cart_rank) + + ! --- Free memory --- + call vtkxml_finish() + deallocate(Vx) + deallocate(Vy) + deallocate(Vz) + deallocate(scal3D) + deallocate(good_scal) + deallocate(velo) + + ! === Case with corrected remeshing formula === + call discretisation_create(400,400,16,dble(2),dble(2),dble(0.5)) + call set_group_size(40) + call advec_init(order_bis) + ! -- Allocation -- + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vx(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vz(N_proc(1), N_proc(2), N_proc(3))) + ! Initialize output context + call vtkxml_init_all(9, nb_proc_dim, length, cart_rank, coord,'./adv_res/') + call vtkxml_init_field(trim(order_bis)//'_tag_num', tag_num) + call vtkxml_init_field(trim(order_bis)//'_tag_err', tag_err) + call vtkxml_init_field(trim(order_bis)//'_tag_sol', tag_sol) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + ry = ((j-1+coord(2)*N_proc(2))*d_sc(2)) - length(2)/2.0 + do i = 1, N_proc(1) + rx = ((i-1+coord(1)*N_proc(1))*d_sc(1))-length(1)/2.0 + rr = (rx**2+ry**2) + if (rr<1) then + scal3D(i,j,k) = (1-rr)**6 + else + scal3D(i,j,k) = 0 + end if + Vx(i,j,k) = cos(3*M_PI*sqrt(rr)/2)*(-ry) + Vy(i,j,k) = cos(3*M_PI*sqrt(rr)/2)*(rx) + end do + end do + end do + good_scal = scal3D + call vtkxml_write(tag_sol, good_scal) + Vz = 0.0 + T = 0.0 + dt = 3*min(d_sc(1),d_sc(2)) + T_step = 0.0 + T_end = 0.8 + call test_substatus('cfl=3 and dt', dt, cart_rank) + do while(T< (T_end - dt)) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_step) then + T_step = T_step + period/10 + call test_substatus ('tag, t', T, cart_rank) + call vtkxml_write(tag_num, scal3D) + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_num, scal3D) + call vtkxml_write(tag_err, scal3D-good_scal) + call test_substatus ('time', (T+dt), cart_rank) + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('3D test - with tag', success, cart_rank) + + + call discretisation_default() + call advec_init(order_bis) + + ! --- Free memory --- + call vtkxml_finish() + + success = .not.success + +end function test_part_advec_3D + + + +!> Test devoted to validate advection solver along one direction +!! @param[in] init_scal = optional parameter to initialise the scalar fied to +!! a constant one or to a sphere shape +!! @return error = test error (= false if the code pass the test) (= not success) +function test_advecY(init_scal) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advecY + use cart_topology + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + character(len=*), intent(in), optional :: init_scal + + character(len=17) :: initialisation ! to choose how to initialise the scalar field + character(len=str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: Vy ! the flow + real(WP) :: velocity ! constant velocity of the flux + integer :: ierr ! mpi error code + integer :: i,j,k ! mesh indice + integer :: T_step ! time + integer :: T_end ! final time + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + real(WP), dimension(3) :: translat ! to compute analytic solution + + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + + if(present(init_scal)) then + initialisation = init_scal + else + initialisation = 'constant' + end if + success = .true. + + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + + + ! Initialise the velocity + velocity = N(2)/11*d_sc(2) + Vy = velocity + T_end = 1 + dt = 0.1 + translat = 0 + translat(2) = - velocity*T_end + translat = translat/d_sc + + ! Initialise the scalar field + call scal_init(initialisation, scal3D, good_scal, translat) + call test_substatus('initialisation', success, cart_rank) + + ! Advec it with a particular method + dt = 1 + call advecY_calc(dt, Vy, scal3D, 'p_O2') + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('advec along Y', success, cart_rank) + + + ! --- Free memory --- + deallocate(scal3D) + deallocate(good_scal) + deallocate(Vy) + + success = .not.success + +end function test_advecY + + +!> Test devoted to validate the 3D advection solver +!! @return error = test error (= false if the code pass the test) (= not success) +function test_advec_rot() result(success) + + ! Library + use mpi + ! Scales code + use advec + use cart_topology + use vtkxml + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + + character(len=17) :: init ! to choose how to initialise the scalar field + character(len=str_short) :: order ! space order of the solveur + real(WP), dimension(:, :, :), allocatable :: scal3D ! the scalar field + real(WP), dimension(:, :, :), allocatable :: VX, Vy, Vz ! the flow + real(WP) :: velocity ! constant velocity of the flux + integer :: ierr ! mpi error code + integer :: i,j,k ! mesh indice + real(WP) :: T ! time + real(WP) :: T_end ! final time + real(WP) :: T_ite ! time corresponding to output + real(WP) :: dt ! time step + real(WP), dimension(:, :, :), allocatable :: good_scal ! analytic solution + real(WP), dimension(:, :, :), allocatable :: good_velo ! temp field + real(WP), dimension(:), allocatable :: pos_adim ! temp field + real(WP), dimension(3) :: translat ! to compute analytic solution + integer :: tag_rot ! tag for visualisation context + integer :: tag_sol ! tag for visualisation context + + + allocate(scal3D(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_scal(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vx(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vy(N_proc(1), N_proc(2), N_proc(3))) + allocate(Vz(N_proc(1), N_proc(2), N_proc(3))) + allocate(good_velo(N_proc(1), N_proc(2), N_proc(3))) + + init = '2D_rot' + success = .true. + ! Initialize output context + call vtkxml_init_all(2, nb_proc_dim, length, cart_rank, coord,'./adv_res/') + + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order) + call vtkxml_init_field('turning', tag_rot) + call vtkxml_init_field('turn_sol', tag_sol) + + + ! Initialise the velocity + call scal_init(init, scal3D, good_scal) + period = 1 + dt = 0.02 + allocate(pos_adim(N_proc(1))) + pos_adim = 1 + call velo_init(init, Vx, 1, pos_adim, good_velo) + call velo_init(init, Vy, 2, pos_adim, good_velo) + call velo_init(init, Vz, 3, pos_adim, good_velo) + call vtkxml_write(tag_rot, scal3D, 'turning') + call test_substatus('initialisation', success, cart_rank) + + ! Advec it with a particular method + T = 0 + T_end = 4*period + T_ite = 0 + do while (T<=T_end - dt) + call advec_step(dt, Vx, Vy, Vz, scal3D) + T = T + dt + if (T>T_ite) then + T_ite = T_ite + T_end/30 + call test_substatus ('time', T, cart_rank) + call vtkxml_write(tag_rot, scal3D, 'turning') + end if + end do + if (T<T_end) then + dt = T_end - T + call advec_step(dt, Vx, Vy, Vz, scal3D) + end if + call vtkxml_write(tag_rot, scal3D, 'turning') + call vtkxml_write(tag_sol, good_scal) + + call test_check_success(scal3D, good_scal, success, cart_rank) + call test_substatus('turning sphere', success, cart_rank) + + + ! --- Free memory --- + call vtkxml_finish() + deallocate(scal3D) + deallocate(good_scal) + deallocate(Vx) + deallocate(Vy) + deallocate(Vz) + + success = .not.success + +end function test_advec_rot + +end module advec_aux + +!> @} diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_common.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_common.f90 new file mode 100644 index 000000000..e4c09026a --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_common.f90 @@ -0,0 +1,892 @@ +!> @addtogroup part_test +!! @{ + +!------------------------------------------------------------------------------ +! +! MODULE: test_part_common +! +! DESCRIPTION: +!> This module provides tests to validate the particular solver. It is +!! more precisly focused on testing the "common part" (advec_common) used for each +!! directions. +!! +!! @author +!! Jean-Baptiste Lagaert, LEGI +!! +!! @details +!! This module is devoted to validate all the procedure from "advec_common". All the +!! tests are unit tests: they return a logical value to check if the code version pass +!! it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular +!! solver +!! This module provide the following test: +!! - Validate the particular method, step by step +!! - Test the procedure "AC_obtain_senders" from advec_common +!! - Validate the redistribution the buffer during the remeshing +!! - Validate the redistribution the buffer during the remeshing - +!! debug version : only one processus contains non-zero field. +!! - Validate the remeshing of untagged particles +!! - Validate the velocity interpolation (the RK2 scheme use the +!! velocity at midlle point to advec particles). +!! - Validate how type (left or center) and tag are computing for a +!! single line +!! - Validate how type (left or center) and tag are computing for a +!! group of line +!! +! +!------------------------------------------------------------------------------ + +module advec_aux_common + + use string + use precision + implicit none + + + + ! ===== Test for the particles solver ===== + ! Public function + public :: test_part_AC_velo_determine_com + !public :: test_part_AC_bufferToScalar + !public :: test_part_AC_bufferToScalar_Deb + !public :: test_part_AC_interpol_velocity + public :: test_part_AC_type_and_block_O2_group + + + + +contains + + +!!> Particles method: validation of the procedure "AC_bufferToScalar". +!!! @return success = test success (= false if the code pass the test) +!!! @param[in] shift = global translation of indices (optional) +!!! @details +!!! Test the procedure "AC_obtain_senders" wich send local buffer use for remeshing +!!! to the right processes. This procedure belong to "advec_common". +!function test_part_AC_bufferToScalar(shift) result(success) +! +! ! Library +! use mpi +! ! Scale code +! use advec +! use advec_common ! Some porcedure common to advection along all directions +! use advec_variables ! contains info about solver parameters and others. +! use cart_topology +! ! Test procdure +! use test_common +! +! integer, intent(in), optional :: shift +! logical :: success +! +! integer :: shift_bis ! global translation of indices +! character(str_short) :: order ! order of the particles solver +! integer :: j_min, j_max ! input argument of the tested procedure +! real(WP), dimension(:), allocatable :: send_buffer ! the buffer to redistribute +! real(WP), dimension(:), allocatable :: scal1D ! the scalar field +! integer :: direction ! direction (2 if along Y, 3=along Z) +! real(WP) :: good_scal ! theoritical value of scal1D +! integer, dimension(2) :: ind_group ! indice of current group of lines +! integer, dimension(2) :: rece_proc ! minimal and maximal gap between my coordinate and the one from which +! ! I will receive data +! integer :: proc_min ! smaller gap between me and the processes to where I send data +! integer :: proc_max ! smaller gap between me and the processes to where I send data +! +! ! Some initialisation +! success = .true. +! ind_group = 1 +! if (present(shift)) then +! shift_bis = shift +! else +! shift_bis = 0 +! end if +! call test_substatus('shift', shift_bis, cart_rank) +! +! ! Initialize the particular solver +! order = 'p_O2' +! call advec_init(order, verbosity=.false.) +! +! do direction = 1, 3 +! if (nb_proc_dim(direction)>1) then +! call test_substatus('direction', direction, cart_rank) +! good_scal = modulo(coord(direction)-shift_bis, nb_proc_dim(direction)) +! +! ! Test 1 - unrealistic case with no communication +! ! Initialize the buffer to remesh +! call AC_set_part_bound_size(0) +! j_min = 1 + shift_bis*N_proc(direction) +! j_max = N_proc(direction)*(shift_bis+1) +! allocate (send_buffer(j_min:j_max)) +! allocate (scal1D(1:N_proc(direction))) +! send_buffer = coord(direction) +! scal1D = 0.0 +! ! Let's go ! +! ! Determine the communication needed : who will communicate whit who? +! call AC_obtain_senders_line(j_min, j_max, direction, ind_group, proc_min, proc_max, rece_proc) +! ! And then distribute buffer along the processus +! call AC_bufferToScalar(direction, ind_group, j_min, j_max, proc_min, proc_max, rece_proc, send_buffer, scal1D) +! ! Check the success +! call test_check_success(scal1D, good_scal, success, cart_rank) +! deallocate (send_buffer) +! deallocate (scal1D) +! call test_substatus('just me', success, cart_rank) +! +! ! I communicate with my two neighbors +! call advec_init(order, verbosity=.false.) +! j_min = shift_bis*N_proc(direction) +! j_max = (1+shift_bis)*N_proc(direction) -1+2*bl_bound_size +! allocate (send_buffer(j_min:j_max)) +! allocate (scal1D(1:N_proc(direction))) +! send_buffer = coord(direction) +! send_buffer(j_min) = modulo(coord(direction)-1, nb_proc_dim(direction))/2.0 +! send_buffer(j_min+1) = send_buffer(j_min+1)/2. +! send_buffer(j_max) = modulo(coord(direction)+1, nb_proc_dim(direction))/2.0 +! send_buffer(j_max-1) = send_buffer(j_max-1)/2. +! scal1D = 0.0 +! ! Determine the communication needed : who will communicate whit who? +! call AC_obtain_senders_line(j_min, j_max, direction, ind_group, proc_min, proc_max, rece_proc) +! ! And then distribute buffer along the processus +! call AC_bufferToScalar(direction, ind_group, j_min, j_max, proc_min, proc_max, rece_proc, send_buffer, scal1D) +! ! Check the success +! call test_check_success(scal1D, good_scal, success, cart_rank) +! deallocate (send_buffer) +! deallocate (scal1D) +! call test_substatus('me and my neighbors', success, cart_rank) +! else +! call test_substatus('only one proc along direction, no test', cart_rank) +! end if +! end do +! +! success = .not.success +! +!end function test_part_AC_bufferToScalar +! +! +! +!!> Particles method: validation of the procedure "AC_bufferToScalar" +!!! @return success = test success (= false if the code pass the test) +!!! @param[in] shift = global translation of indices (optional) +!!! @param[in] rank = rank of the processus which will contains non-zero field. +!!! @details +!!! Debugging version : only one processus contains non zero field to remesh. +!!! Each processus communicate with its two neibor. A shift could be add. +!function test_part_AC_bufferToScalar_Deb(rank, shift) result(success) +! +! ! Library +! use mpi +! ! Scale code +! use advec +! use advec_common ! Some porcedure common to advection along all directions +! use advec_variables ! contains info about solver parameters and others. +! use cart_topology +! ! Test procdure +! use test_common +! +! integer, intent(in) :: rank +! integer, intent(in), optional :: shift +! logical :: success +! +! integer :: ierr ! mpi error code +! integer :: shift_bis ! global translation of indices +! character(str_short) :: order ! order of the particles solver +! integer :: j_min, j_max ! input argument of the tested procedure +! real(WP), dimension(:), allocatable :: send_buffer ! the buffer to redistribute +! real(WP), dimension(:), allocatable :: scal1D ! the scalar field +! real(WP), dimension(:), allocatable :: good_scal ! theoritical value of scal1D +! integer :: direction ! direction (2 if along Y, 3=along Z) +! integer, dimension(3) :: mycoord ! my coordonates in the mpi topology +! integer :: rank_shift ! rank of processus of rank = rank+shift +! integer, dimension(2) :: ind_group ! indice of current group of lines +! integer, dimension(2) :: rece_proc ! minimal and maximal gap between my coordinate and the one from which +! ! I will receive data +! integer :: proc_min ! smaller gap between me and the processes to where I send data +! integer :: proc_max ! smaller gap between me and the processes to where I send data +! +! ! Some initialisation +! success = .true. +! ind_group = 1 +! if (present(shift)) then +! shift_bis = shift +! else +! shift_bis = 0 +! end if +! call test_substatus('shift', shift_bis, cart_rank) +! call test_substatus('rank tested', rank, cart_rank) +! +! ! Initialize the particular solver +! order = 'p_O2' +! call advec_init(order, verbosity=.false.) +! +! do direction = 1, 3 +! call test_substatus('direction', direction, cart_rank) +! if (nb_proc_dim(direction)>1) then +! ! Initialise the solver environnement and the field +! call advec_init(order, verbosity=.false.) +! j_min = shift_bis*N_proc(direction) +! j_max = (1+shift_bis)*N_proc(direction) -1+2*bl_bound_size +! allocate (send_buffer(j_min:j_max)) +! allocate (scal1D(1:N_proc(direction))) +! send_buffer = 0 +! if (cart_rank == rank) then +! send_buffer = 2 +! send_buffer(j_min) = 1 +! send_buffer(j_max) = 3 +! end if +! scal1D = 0.0 +! +! ! -- Compute the analytic solution -- +! allocate (good_scal(1:N_proc(direction))) +! good_scal = 0.0 +! ! For the processus wich correspond to me after the shift +! call mpi_cart_coords(cart_comm, rank, 3, mycoord, ierr) +! mycoord(direction) = mycoord(direction) + shift_bis +! call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) +! if (cart_rank==rank_shift) good_scal = 2 +! ! For the next processus in the current direction +! mycoord(direction) = mycoord(direction) + 1 +! call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) +! if (cart_rank==rank_shift) good_scal(1) = 3 +! ! For the previous processus in the current direction +! mycoord(direction) = mycoord(direction) -2 +! call mpi_cart_rank(cart_comm, mycoord, rank_shift, ierr) +! if (cart_rank==rank_shift) good_scal(N_proc(direction)) = 1 +! +! ! -- Compute the numerical solution -- +! ! Determine the communication needed : who will communicate whit who? +! call AC_obtain_senders_line(j_min, j_max, direction, ind_group, proc_min, proc_max, rece_proc) +! ! And then distribute buffer along the processus +! call AC_bufferToScalar(direction, ind_group, j_min, j_max, proc_min, proc_max, rece_proc, send_buffer, scal1D) +! ! Check the success +! call test_check_success(scal1D, good_scal, success, cart_rank) +! deallocate (send_buffer) +! deallocate (scal1D) +! deallocate (good_scal) +! call test_substatus('me and my neighbors', success, cart_rank) +! else +! call test_substatus('only one proc along direction, no test', cart_rank) +! end if +! end do +! +! success = .not.success +! +! +!end function test_part_AC_bufferToScalar_Deb + + +!> Particles method: validation of the procedure "AC_velocity_determine_communication" wich determine +!! who will comunicate with who during the remeshing +!! @return success = test success (= false if the code pass the test) +!! @param[in] shift = global translation of indices (optional) +function test_part_AC_velo_determine_com(shift) result(success) + + ! Library + use mpi + ! Scale code + use advec + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + use cart_topology + ! Test procdure + use test_common + + integer, intent(in), optional :: shift + logical :: success + ! Be aware : during this function, success = true if everything is right, but we return not success = error + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + integer :: ierr ! mpi error code + integer , dimension(5,5) :: rece_ind_min ! minimal indice of mesh involved in remeshing particles (of my local subdomains) + integer , dimension(5,5) :: rece_ind_max ! maximal indice of mesh involved in remeshing particles (of my local subdomains) + integer, dimension(5,5,2) :: rece_gap ! distance between me and processus wich send me information + integer, dimension(2 , 2) :: send_gap ! distance between me and processus to wich I send information + integer, dimension(2) :: rece_gap_abs ! min (resp max) value of rece_gap(:,:,i) with i=1 (resp 2) + integer, dimension(:), allocatable :: rece_rank ! rank of processus from which I receive data + integer, dimension(2 , 2) :: send_theoric ! theoritical value of send_gap + integer, dimension(2) :: ind_group ! indice of current group of lines + integer :: direction ! current direction (alonG X, Y or Z) + integer, dimension(:,:), allocatable :: cartography ! cartography(proc_gap) contains the set of the lines indice in the block for wich the + ! current processus requiers data from proc_gap and for each of these lines the range + ! of mesh points from where it requiers the velocity values. + integer, dimension(:,:), allocatable :: carto_th ! theoritical value of cartography + integer :: max_size + integer :: proc_gap ! gap between two different mpi processus + integer, dimension(2) :: gs ! group size + + + ! Some initialisation + success = .true. + ind_group = 1 + gs = (/5,5/) + direction = 3 + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + call test_substatus('shift', shift_bis, cart_rank) + + ! Initialize the particular solver + order = 'p_O2' + call advec_init(order, verbosity=.false.) + call test_substatus('initialisation solveur', success, cart_rank) + + ! ===== Each line of the group is initialized considering it second indice ===== + ! -- First line communcate just with myself (ie it host processus) -- + ! Init the indice range for each lines. + rece_ind_min(:,1) = 1 + shift_bis*N_proc(direction) + rece_ind_max(:,1) = N_proc(direction)*(shift_bis+1) + ! -- Second line communicate with me and the previous processus -- + rece_ind_min(:,2) = shift_bis*N_proc(direction) + rece_ind_max(:,2) = (1+shift_bis)*N_proc(direction) + ! -- Third line communicate with me and my two neighbors -- + rece_ind_min(:,3) = shift_bis*N_proc(direction) + rece_ind_max(:,3) = (1+shift_bis)*N_proc(direction) + 1 + ! -- Fourth line communicate with me and the next processus -- + rece_ind_min(:,4) = shift_bis*N_proc(direction) + 1 + rece_ind_max(:,4) = (1+shift_bis)*N_proc(direction) + 1 + ! -- And for the fith line it depend of it firts indice inside the group -- + rece_ind_min(:,5) = 1 + shift_bis*N_proc(direction) + rece_ind_min(3,5) = shift_bis*N_proc(direction) + rece_ind_max(:,5) = (1+shift_bis)*N_proc(direction) + 1 + rece_ind_max(2,5) = (1+shift_bis)*N_proc(direction) + + ! Compute the associated processus + rece_gap(:,:,1) = floor(real(rece_ind_min-1)/N_proc(direction)) + rece_gap(:,:,2) = floor(real(rece_ind_max-1)/N_proc(direction)) + rece_gap_abs(1) = minval(rece_gap(:,:,1)) + rece_gap_abs(2) = maxval(rece_gap(:,:,2)) + allocate(rece_rank(rece_gap_abs(1):rece_gap_abs(2))) + max_size = 2 + gs(2)*(2+3*gs(1)) + allocate(cartography(max_size,rece_gap_abs(1):rece_gap_abs(2))) + + + ! -- And launch the test -- + cartography = -1 + call AC_velocity_determine_communication(direction, ind_group, gs, send_gap, & + & rece_gap, rece_gap_abs, rece_rank, cartography) + + ! -- Check result -- + ! send_gap + send_theoric(1,:) = (/-1-shift_bis,1-shift_bis/) + send_theoric(2,:) = 25 + call test_check_success(send_gap, send_theoric, success, cart_rank) + call test_substatus('send_gap', success, cart_rank) + ! cartography + allocate(carto_th(max_size, rece_gap_abs(1):rece_gap_abs(2))) + carto_th = -1 + if (rece_rank(-1+shift_bis) /= D_rank(direction)) then + carto_th(1:13,-1+shift_bis)= (/0,13,0,2,2,0,2,1,5,1,5,3,3/) + else + carto_th(1:7,-1+shift_bis)= (/0,7,0,0,0,0,0/) + end if + if (rece_rank(shift_bis) /= D_rank(direction)) then + carto_th(1:17,shift_bis)= (/0,17,2,2,2,2,2,1,5,1,5,1,5,1,5,1,5/) + else + carto_th(1:7,shift_bis)= (/0,7,0,0,0,0,0/) + end if + if (rece_rank(1+shift_bis) /= D_rank(direction)) then + carto_th(1:15,1+shift_bis)= (/0,15,0,0,2,2,4,1,5,1,5,1,1,3,5/) + else + carto_th(1:7,1+shift_bis)= (/0,7,0,0,0,0,0/) + end if + call test_check_success(cartography, carto_th, success, cart_rank) + call test_substatus('cartography', success, cart_rank) + +! ! -- For the fourth: Contraction / extention -- +! if (modulo(nb_proc_dim(direction),2)==0) then +! if (modulo(D_rank(direction),2)== 0) then +! ! Contraction +! j_min = 1 + shift_bis*N_proc(direction) +! j_max = (1+shift_bis)*N_proc(direction) +! send_begin = 0 +! send_end = 0 +! else +! ! Dilatation +! j_min = +1 - 2*bl_bound_size + shift_bis*N_proc(direction) +! j_max = (1+shift_bis)*N_proc(direction) + 2*bl_bound_size +! send_begin = -1 +! send_end = 1 +! end if + + deallocate(rece_rank) + deallocate(cartography) + deallocate(carto_th) + + success = .not.success + +end function test_part_AC_velo_determine_com + + +!> Particles method: validation of the velocity interpolation +!! @return success = test success (= false if the code pass the test) +!! @param[in] direction = 1 for along X, 2 for along Y, 3 for along Z +!! @param[in] shift = global translation of indice +function test_part_AC_velo_compute_group(direction, shift) result(success) + + ! External Library + use mpi + ! Scales code + use cart_topology + use advec_common + ! Test procedures + use advec_aux_init + use test_common + + logical :: success + integer, intent(in) :: direction, shift + + integer :: ind,ind1,ind2! indices + integer :: nn, clock ! to generate random number + integer, dimension(:), allocatable :: seed ! to generate random number + real(WP), dimension(N_proc(direction), 5, 5) :: p_pos ! location where the velocity is interpolated + real(WP), dimension(N_proc(direction)) :: r ! random numbers to initialise p_pos + real(WP), dimension(N_proc(direction),5,5) :: velo ! velocity field + real(WP), dimension(N_proc(direction),5,5) :: good_velo ! analytic interpolation of velocity field in particles position + real(WP) :: dt ! time step + integer :: T ! for solver iteration + integer, dimension(2) :: gs ! group size + + ! Initialisation + success = .true. + call test_substatus('test velocity interpolation', cart_rank) + call test_substatus('shift', shift, cart_rank) + ! To generate random number + call RANDOM_SEED(size = nn) + allocate(seed(nn)) + call SYSTEM_CLOCK(COUNT=clock) + seed = clock + 37 * (/ (ind - 1, ind = 1, nn) /) + call RANDOM_SEED(PUT = seed) + deallocate(seed) + ! Position where the velocity will be interpolated + CALL RANDOM_NUMBER(r) + do ind = 1, N_proc(direction) + p_pos(ind,:,:) = (ind+shift) + end do + gs = group_size(direction,:) + call test_check_success((/5,5/),gs, success, cart_rank) + call test_substatus('group is 5', success, cart_rank) + if (success) then + + ! ===== Init particle positions ===== + ! -- First column : particle are inside current and previous processes -- + p_pos(:,1,1) = p_pos(:,1,1) - 3 + r*d_sc(direction) + p_pos(:,2,1) = p_pos(:,2,1) - 3 + p_pos(:,3,1) = p_pos(:,3,1) - 2 + r*d_sc(direction) + p_pos(:,4,1) = p_pos(:,4,1) - 2 + p_pos(:,5,1) = p_pos(:,5,1) - 1 + r*d_sc(direction) + ! -- Second and third column : they are on the current processus and my two neighbors -- + p_pos(:,:,2) = p_pos(:,:,1) + 1 + p_pos(:,:,3) = p_pos(:,:,1) + 2 + ! -- Fourth column: paritcles are on the current and th next processes -- + p_pos(:,:,4) = p_pos(:,:,1) + 3 + + + ! ===== First test: constant velocity ===== + do ind2 = 1, 5 + do ind1 = 1, 5 + call particle_velo_init('constant', velo(:,ind1,ind2), direction, p_pos(:,ind1,ind2), good_velo(:,ind1,ind2)) + end do + end do + dt = 0.0 + call AC_particle_velocity(dt, direction, gs, (/1,1/), p_pos, velo) + ! Check result + call test_check_success(velo, good_velo, success, cart_rank) + call test_substatus('constant velocity', success, cart_rank) + + ! ===== Second test: unconstant velocity ===== + do ind2 = 1, 5 + do ind1 = 1, 5 + call particle_velo_init('translation_field', velo(:,ind1,ind2), direction, & + & p_pos(:,ind1,ind2), good_velo(:,ind1,ind2)) + end do + end do + call AC_particle_velocity(dt, direction, gs, (/1,1/), p_pos, velo) + ! Check result + call test_check_success(velo, good_velo, success, cart_rank) + call test_substatus('unconstant velocity', success, cart_rank) + end if + + ! Return not success + success = .not. success + +end function test_part_AC_velo_compute_group + + +!> Particle method: validation of particle tag and block type determination for +!! a group of line +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_AC_type_and_block_O2_group() result(success) + + ! Library + use mpi + ! Scales code + use advec + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + use cart_topology + ! Test procedures + use test_common + + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + + logical, dimension(:,:,:), allocatable :: bl_type ! correct (analytic) type of block + logical, dimension(:,:,:), allocatable :: bl_tag ! correct (analytic) tag of block + logical, dimension(:,:,:), allocatable :: good_type ! correct (analytic) type of block + logical, dimension(:,:,:), allocatable :: good_tag ! correct (analytic) tag of block + integer :: direction ! direction (2 if along Y, 3=along Z) + real(WP) :: dt, cfl ! time step and CFL number + real(WP), dimension(:,:,:), allocatable :: p_V ! particle velocity (used to tag particles) + integer :: ind, ind2 ! indice of the current particle + integer :: ind_bl ! indice of the current block + real(WP) :: lambda_min ! minimum courant number on a block + integer :: ind_tag_bl ! indice of the first tagged block in the test + integer :: ind_tag_p ! indice of particle corresponding to the velocity + ! variation wich induce a tag of the block ind_tag_bl + integer :: ind_tag_bl2 ! indice of the second tagged block in the test + integer :: ind_tag_p2 ! indice of particle wich induce a tag of the block ind_tag_bl2 + + + ! Initialisation of context (solver, ...) + success = .true. + order ='p_O2' + call set_group_size(5) + call advec_init(order, verbosity=.false.) + direction = 3 + + ! Allocation + allocate(bl_type(bl_nb(direction)+1,group_size(direction,1),group_size(direction,2))) + allocate(good_type(bl_nb(direction)+1,group_size(direction,1),group_size(direction,2))) + allocate(bl_tag(bl_nb(direction),group_size(direction,1),group_size(direction,2))) + allocate(good_tag(bl_nb(direction),group_size(direction,1),group_size(direction,2))) + allocate(p_V(N_proc(direction),group_size(direction,1),group_size(direction,2))) + + ! Initialize of the different parameter and field + dt = 1 + cfl = dt/d_sc(direction) + p_V = 0 + + ! Test case = nothing on line of indice different from (2,3) + ! On that line, first part of block are left one, and second part are center. + ! Due to periodic condition, there is also 2 tag, one for each type switch + ! (left => center, and center => left). + ! Update dt in order to create "chock" without broke the stability condition + dt = 0.8*d_sc(direction)/sqrt(2*1.2*bl_size) + cfl = dt/d_sc(direction) + good_type = .false. + good_tag = .false. + ind_tag_bl = (nb_proc_dim(direction)*bl_nb(direction)/3) - (bl_nb(direction)*coord(direction)) + ind_tag_p = (ind_tag_bl-1)*bl_size + bl_size/2 + 1 + ind_tag_p2 = floor((0.3/0.8)*(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p) + ind_tag_p) + ind_tag_p2 = ind_tag_p2 + 1 + ind_tag_bl2 = (ind_tag_p2 - 1 - bl_size/2)/bl_size + 1 + if (modulo(ind_tag_p2-1-bl_size/2, bl_size)==0) ind_tag_bl2 = ind_tag_bl2 -1 + if (ind_tag_bl <=bl_nb(direction)) then + if (ind_tag_bl>=1) then + ! Tag the right block transition + good_tag(ind_tag_bl, 2, 3) = .true. + else + ! Change the velocity for the first half block + lambda_min = max(0,shift_bis) + 10 + do ind = 1, bl_size/2 + p_V(ind, 2, 3) = 0.8*(1.0-float(ind-ind_tag_p) & + & /(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind+1<ind_tag_p2) good_type(1, 2, 3) = .true. + end if + ! Update velocity and block type + do ind_bl = max(2, ind_tag_bl+1), bl_nb(direction) + lambda_min = max(0,shift_bis) + 10 + do ind = 1, bl_size + ind2 = ind+((ind_bl-2)*bl_size)+bl_size/2 ! the first block is only a half block + p_V(ind2, 2, 3) = 0.8*(1.-float(ind2-ind_tag_p) & + &/(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind2+1<ind_tag_p2) good_type(ind_bl, 2, 3) = .true. + end do + ! For the last half block + lambda_min = max(0,shift_bis) + 10 + ind_bl = bl_nb(direction) + 1 + do ind = 1, bl_size/2 + ind2 = ind+((ind_bl-2)*bl_size)+bl_size/2 ! the first block is only a half block + p_V(ind2, 2 , 3) = 0.8*(1.-float(ind2-ind_tag_p) & + & /(N(direction)-N_proc(direction)*coord(direction)-ind_tag_p))/cfl + end do + if (ind2+bl_size/2+1<ind_tag_p2) good_type(ind_bl, 2, 3) = .true. + end if + if ((ind_tag_bl2 <= bl_nb(direction)).and.(ind_tag_bl2>0)) good_tag(ind_tag_bl2, 2, 3) = .true. + call AC_type_and_block(dt, direction, group_size(direction,:), (/1,1/), p_V, bl_type, bl_tag) + + + call test_check_success(bl_tag, good_tag, success, cart_rank) + call test_substatus('test 3 - two tag ', success, cart_rank) + call test_check_success(bl_type, good_type, success, cart_rank) + call test_substatus('test 3 - center at first, then left', success, cart_rank) + + + ! Deallocation + deallocate(bl_type) + deallocate(good_type) + deallocate(bl_tag) + deallocate(good_tag) + deallocate(p_V) + + success = .not. success + +end function test_part_AC_type_and_block_O2_group + + +! ============================================================ +! ========== Test about remeshing ========== +! ============================================================ + +!> Particle method: validation of computation of remeshing range for a group of line +!! @param[in] shift = global translation of indice +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_AC_remesh_range() result(success) + + ! Library + use mpi + ! Scales code + use advec + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + use cart_topology + ! Test procedures + use test_common + use advec_aux_init + + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + + logical, dimension(:,:,:), allocatable :: bl_type ! type of block + logical, dimension(:,:,:), allocatable :: bl_tag ! tag of block + integer :: direction ! direction (2 if along Y, 3=along Z) + real(WP), dimension(:,:,:), allocatable :: p_pos_adim ! particle position + integer, dimension(:,:), allocatable :: send_min ! first mesh where particles are remeshed + integer, dimension(:,:), allocatable :: good_send_min! theoritical first mesh where particles are remeshed + integer, dimension(:,:), allocatable :: send_max ! last mesh where particles are remeshed + integer, dimension(:,:), allocatable :: good_send_max! theoritical last mesh where particles are remeshed + integer, dimension(:,:,:), allocatable :: send_gap ! distance between me and processus wich send me information + integer, dimension(2) :: send_gap_abs ! min (resp max) value of rece_gap(:,:,i) with i=1 (resp 2) + integer, dimension(2) :: gs ! group size + integer, dimension(2) :: ind_group ! group indice + + + ! Initialisation of context (solver, ...) + success = .true. + direction = 2 + shift_bis = 0.0 + ind_group = (/1,1/) + call set_group_size(5) + gs = group_size(direction,:) + + ! Allocation + allocate(bl_type(bl_nb(direction)+1,group_size(direction,1),group_size(direction,2))) + allocate(bl_tag(bl_nb(direction),group_size(direction,1),group_size(direction,2))) + allocate(p_pos_adim(N_proc(direction),group_size(direction,1),group_size(direction,2))) + allocate(send_min(group_size(direction,1),group_size(direction,2))) + allocate(send_max(group_size(direction,1),group_size(direction,2))) + allocate(good_send_min(group_size(direction,1),group_size(direction,2))) + allocate(good_send_max(group_size(direction,1),group_size(direction,2))) + allocate(send_gap(group_size(direction,1),group_size(direction,2),2)) + + ! ----- Initialisation ----- + bl_type = .true. + bl_tag = .false. + call pos_gp_init(direction, gs, shift_bis, p_pos_adim, bl_type) + + ! ----- Lambda 2 corrected ----- + order ='p_O2' + ! Init solver + call advec_init(order, verbosity=.false.) + ! Test procedure + call AC_remesh_range(bl_type, p_pos_adim, direction, send_min, send_max, send_gap, send_gap_abs) + ! Compute theoric value + where (bl_type(1,:,:)) + ! First particle is a centered one + send_min = nint(p_pos_adim(1,:,:))-1 + elsewhere + ! First particle is a left one + send_min = floor(p_pos_adim(1,:,:))-1 + end where + where (bl_type(N_proc(direction)/bl_size +1,:,:)) + ! Last particle is a centered one + send_max = nint(p_pos_adim(N_proc(direction),:,:))+1 + elsewhere + ! Last particle is a left one + send_max = floor(p_pos_adim(N_proc(direction),:,:))+1 + end where + ! Check results + call test_check_success(send_min, good_send_min, success, cart_rank) + call test_check_success(send_max, good_send_max, success, cart_rank) + call test_substatus('remesh range - order 2 ', success, cart_rank) + + ! ----- Lambda 4 corrected ----- + order ='p_O4' + ! Init solver + call advec_init(order, verbosity=.false.) + ! Test procedure + call AC_remesh_range(bl_type, p_pos_adim, direction, send_min, send_max, send_gap, send_gap_abs) + ! Compute theoric value + where (bl_type(1,:,:)) + ! First particle is a centered one + send_min = nint(p_pos_adim(1,:,:))-2 + elsewhere + ! First particle is a left one + send_min = floor(p_pos_adim(1,:,:))-2 + end where + where (bl_type(N_proc(direction)/bl_size +1,:,:)) + ! Last particle is a centered one + send_max = nint(p_pos_adim(N_proc(direction),:,:))+2 + elsewhere + ! Last particle is a left one + send_max = floor(p_pos_adim(N_proc(direction),:,:))+2 + end where + ! Check results + call test_check_success(send_min, good_send_min, success, cart_rank) + call test_check_success(send_max, good_send_max, success, cart_rank) + call test_substatus('remesh range - order 4 ', success, cart_rank) + + ! ----- M'6 ----- + order ='p_O2' + ! Init solver + call advec_init(order, verbosity=.false.) + ! Test procedure + call AC_remesh_range(bl_type, p_pos_adim, direction, send_min, send_max, send_gap, send_gap_abs) + ! Compute theoric value + send_min = nint(p_pos_adim(1,:,:))-2 + send_max = floor(p_pos_adim(N_proc(direction),:,:))+3 + ! Check results + call test_check_success(send_min, good_send_min, success, cart_rank) + call test_check_success(send_max, good_send_max, success, cart_rank) + call test_substatus('remesh range - Mprime 6 ', success, cart_rank) +! call AC_remesh_determine_communication(direction, gs, ind_group, rece_gap, send_gap, send_gap_abs, send_rank, cartography) + + + ! Free memory + deallocate(bl_type) + deallocate(bl_tag) + deallocate(p_pos_adim) + deallocate(send_min) + deallocate(send_max) + deallocate(good_send_min) + deallocate(good_send_max) + deallocate(send_gap) + + success = .not. success + +end function test_part_AC_remesh_range + + +!> Particle method: validation of computation of remeshing range for a group of line +!! @return error = test error (= false if the code pass the test) (= not success) +function test_part_AC_remesh_determine_communication(shift) result(success) + + ! Library + use mpi + ! Scales code + use advec + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + use cart_topology + ! Test procedures + use test_common + use advec_aux_init + + integer, intent(in), optional :: shift + logical :: success + + integer :: shift_bis ! global translation of indices + character(str_short) :: order ! order of the particles solver + + logical, dimension(:,:,:), allocatable :: bl_type ! type of block + logical, dimension(:,:,:), allocatable :: bl_tag ! tag of block + integer :: direction ! direction (2 if along Y, 3=along Z) + real(WP), dimension(:,:,:), allocatable :: p_pos_adim ! particle position + integer, dimension(:,:), allocatable :: send_min ! first mesh where particles are remeshed + integer, dimension(:,:), allocatable :: send_max ! last mesh where particles are remeshed + integer, dimension(:,:,:), allocatable :: send_gap ! distance between me and processus wich send me information + integer, dimension(2) :: send_gap_abs ! min (resp max) value of rece_gap(:,:,i) with i=1 (resp 2) + integer, dimension(2 , 2) :: rece_gap ! distance between me and processus to wich I send information + integer, dimension(2) :: gs ! group size + integer, dimension(2) :: ind_group ! group indice + integer :: max_size ! maximal size of cartography(:,proc_gap) + integer, dimension(:,:), allocatable :: cartography ! cartography(proc_gap) contains the set of the lines indice in the block to wich the + ! current processus will send data during remeshing and for each of these lines the range + ! of mesh points from where it requiers the velocity values. + integer, dimension(:), allocatable :: send_rank ! rank of processus to wich I send information + + + ! Initialisation of context (solver, ...) + success = .true. + direction = 2 + shift_bis = 0.0 + ind_group = (/1,1/) + call set_group_size(5) + gs = group_size(direction,:) + if (present(shift)) then + shift_bis = shift + else + shift_bis = 0 + end if + + + ! Allocation + allocate(bl_type(bl_nb(direction)+1,group_size(direction,1),group_size(direction,2))) + allocate(bl_tag(bl_nb(direction),group_size(direction,1),group_size(direction,2))) + allocate(p_pos_adim(N_proc(direction),group_size(direction,1),group_size(direction,2))) + allocate(send_min(group_size(direction,1),group_size(direction,2))) + allocate(send_max(group_size(direction,1),group_size(direction,2))) + allocate(send_gap(group_size(direction,1),group_size(direction,2),2)) + + ! ----- Initialisation ----- + bl_type = .true. + bl_tag = .false. + call pos_gp_init(direction, gs, shift_bis, p_pos_adim, bl_type) + + ! ===== Test method ===== + ! -- Init solver -- + order ='p_O2' + call advec_init(order, verbosity=.false.) + ! -- Compute range -- + call AC_remesh_range(bl_type, p_pos_adim, direction, send_min, send_max, send_gap, send_gap_abs) + ! -- Allocation -- + max_size = 2 + gs(2)*(2+3*gs(1)) + allocate(cartography(max_size,send_gap_abs(1):send_gap_abs(2))) + allocate(send_rank(send_gap_abs(1):send_gap_abs(2))) + ! -- Test the target procedure: determine which processes communicate together -- + call AC_remesh_determine_communication(direction, gs, ind_group, rece_gap, send_gap, send_gap_abs, send_rank, cartography) + + ! -- Compute theoritical results + + ! -- Check results -- + !call test_check_success(send_min, good_send_min, success, cart_rank) + !call test_check_success(send_max, good_send_max, success, cart_rank) + !call test_substatus('remesh range - order 2 ', success, cart_rank) + + + ! -- Free memory -- + deallocate(bl_type) + deallocate(bl_tag) + deallocate(p_pos_adim) + deallocate(send_min) + deallocate(send_max) + deallocate(send_gap) + deallocate(cartography) + deallocate(send_rank) + + success = .not. success + +end function test_part_AC_remesh_determine_communication + +end module advec_aux_common +!> @} diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_init.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_init.f90 new file mode 100644 index 000000000..9747a839c --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_aux_init.f90 @@ -0,0 +1,529 @@ +!> @addtogroup part_test +!! @{ + +!------------------------------------------------------------------------------ +! +! MODULE: test_advection_init +! +! DESCRIPTION: +!> Initialisation procedure for advection test (and solver based on particle method). +!! +!! @details +!! This module provide different initialisation setup in order to test the transport solver. +!! +!! The following initialisation are included : +!! 1 -> Constant field for both scalar and velocity +!! 2 -> 2D-rotation of a sphere +!! 3 -> scalar(i,j,k) = i/Nx + 10* j/Ny + 100*k/Nz with periodic boundary condition +!! 4 -> velocity(i,j,k) = i/Nx + 10* j/Ny + 100*k/Nz with periodic boundary condition +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module advec_aux_init + + use string + use precision + implicit none + + ! ===== Initialisation for advection test ===== + ! Public function + public :: velo_init + public :: particle_velo_init + public :: scal_init + public :: scal_velo_init_part + ! Private function + private :: compute_velo_tag + + ! ===== Setup parameter ===== + ! Public variables + !> Period for rotation cases + real(WP), public :: period = 1 + ! Private variable + !> Pi value + real(WP), parameter :: M_PI = ACOS(-1.0) + + + + +contains + +!> Initialisation of the scalar field for the different tests. +!! @param[in] init = parameter to initialise the scalar fied to a constant one or to a sphere shape +!! @param[in] translat = optional argument, translat the field, in order to obtain analytic solution for non zero velocity in test case +!! "translation field" +!! @param[out] scalar = scalar field +!! @param[out] good_scal = analytic solution +subroutine scal_init(init, scalar, good_scal, translat) + + use test_common + use cart_topology + + character(len=*), intent(in) :: init + real(WP), dimension(:,:,:), intent(out) :: scalar + real(WP), dimension(:,:,:), intent(out) :: good_scal + real(WP), dimension(3), intent(in), optional :: translat + + real(WP) :: rr, rx, ry, rz, rayon + real(WP) :: dist + integer :: i, j, k + + + select case(init) + case('constant') + call test_substatus('constant scal', cart_rank) + scalar = 1. + good_scal = 1. + case('2D_rot') + call test_substatus('uncentred sphere', cart_rank) + scalar = 0. + rayon = (minval(N*d_sc)/10.0)**2 + do k = 1, N_proc(3) + rz = (d_sc(3)*(k + coord(3)*N_proc(3) - 3.0*N(3)/5.0))**2 + do j = 1, N_proc(2) + ry = (d_sc(2)*(j + coord(2)*N_proc(2)- 3.0*N(2)/5.0))**2 + do i = 1, N_proc(1) + rx = (d_sc(1)*(i - 3.0*N(1)/5.0))**2 + rr = rx + ry + rz + if (rr < rayon) scalar(i,j,k) = (1 - rr/rayon)**4 + end do + end do + end do + good_scal = scalar + case('translation_field') + call test_substatus('translation field', cart_rank) + if (present(translat)) then + call test_substatus('translation on X', translat(1), cart_rank) + call test_substatus('translation on Y', translat(2), cart_rank) + call test_substatus('translation on Z', translat(3), cart_rank) + else + call test_substatus('velocity = zero ', cart_rank) + end if + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + dist = (float(i-1+coord(1)*N_proc(1))/N(1)) + scalar(i,j,k) = cos((dist-0.5)*2*M_PI) + dist = (float(j-1+coord(2)*N_proc(2))/N(2)) + scalar(i,j,k) = scalar(i,j,k)*cos((dist-0.5)*2*M_PI) + dist = (float(k-1+coord(3)*N_proc(3))/N(3)) + scalar(i,j,k) = scalar(i,j,k)*cos((dist-0.5)*2*M_PI) + if (present(translat)) then + ! Only periodic condition + dist = (i+translat(1)-1+coord(1)*N_proc(1))*d_sc(1) ! distance au bord x = 0 + dist = modulo(dist, length(1)) ! on utilise la periodicite + ! In other case, as the velocity is a linear function of the position, the analytic velocity + ! is the same that the interpolate one + good_scal(i,j,k) = cos((dist-0.5)*2*M_PI) + dist = (j+translat(2)-1+coord(2)*N_proc(2))*d_sc(2) + dist = modulo(dist, length(2)) + good_scal(i,j,k) = good_scal(i,j,k) * cos((dist-0.5)*2*M_PI) + dist = (k+translat(3)-1+coord(3)*N_proc(3))*d_sc(3) + dist = modulo(dist, length(3)) + good_scal(i,j,k) = good_scal(i,j,k) * cos((dist-0.5)*2*M_PI) + else + good_scal(i,j,k) = scalar(i,j,k) + end if + end do + end do + end do + case default + scalar = 1. + good_scal = 1. + end select + +end subroutine scal_init + + + +!> Initialisation of the velocity field to test its interpolation +!! @param[in] init = parameter to initialise the scalar fied to a constant one or to a sphere shape +!! @param[out] velo = velocity field along one direction +!! @param[in] direction = current direction (along X,Y or Z-axis) +!! @param[in] p_pos_adim = adimensionned particles postion (location where the velocity will be interpolated) +!! @param[in,out] good_velo = analytic interpolation of the velocity field (on location p_pos) +subroutine velo_init(init, velo, direction, p_pos_adim, good_velo) + + use test_common + use cart_topology + + character(len=*), intent(in) :: init + real(WP), dimension(:,:,:), intent(inout) :: velo + real(WP), dimension(:), intent(in) :: p_pos_adim + integer, intent(in) :: direction + real(WP), dimension(:,:,:), intent(inout) :: good_velo + + real(WP) :: dist ! distance from original position for translation case + integer :: i, j, k ! mesh indices + integer :: ierr ! mpi error code + + + select case(init) + case('constant') + velo = 1. + good_velo = 1. + case('2D_rot') + select case(direction) + case(1) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=(2*M_PI/period)*(length(2)/2.0-((j+coord(2)*N_proc(2))*d_sc(2))) + good_velo(i,j,k)=(2*M_PI/period)*(length(2)/2.0-((j+coord(2)*N_proc(2))*d_sc(2))) + end do + end do + end do + case(2) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=(2*M_PI/period)*(((i+coord(1)*N_proc(1))*d_sc(1))-length(1)/2.0) + good_velo(i,j,k)=(2*M_PI/period)*(((i+coord(1)*N_proc(1))*d_sc(1))-length(1)/2.0) + end do + end do + end do + case(3) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k)=0 + good_velo(i,j,k)=0 + end do + end do + end do + case default + call test_substatus(' XXX error : wrong direction =', direction, cart_rank) + stop + end select + case('translation_field') + select case(direction) + case(1) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(1) .eqv. .true.) then + dist = (p_pos_adim(i)-1+coord(1)*N_proc(1))*d_sc(1) ! distance au bord x = 0 + dist = modulo(dist, length(1)) ! on utilise la periodicite + ! If dist belong to (length - dx, length) then with have to interpolate + ! the velocity between postion (length-dx) and 0 (due to periodicity boundary condition) + if (dist>length(1)-d_sc(1)) dist = (length(1)-dist)*(length(1)-d_sc(1))/d_sc(1) + ! In other case, as the velocity is a linear function of the position, the analytic velocity + ! is the same that the interpolate one + good_velo(i,j,k) = dist/length(1) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + else + call test_substatus(' boundary along X condition not implemented ', cart_rank) + end if + end do + end do + end do + case(2) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(2) .eqv. .true.) then + dist = (p_pos_adim(j)-1+coord(2)*N_proc(2))*d_sc(2) + dist = modulo(dist, length(2)) + ! See direction 1 for explaination + if (dist>length(2)-d_sc(2)) dist = (length(2)-dist)*(length(2)-d_sc(2))/d_sc(2) + good_velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(dist)/length(2) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + else + call test_substatus(' boundary along X condition not implemented ', cart_rank) + end if + end do + end do + end do + case(3) + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*(float(k-1+coord(3)*N_proc(3))/N(3)) + if (periods(3) .eqv. .true.) then + dist = (p_pos_adim(k)-1+coord(3)*N_proc(3))*d_sc(3) + dist = modulo(dist, length(3)) + ! See direction 1 for explaination + if (dist>length(3)-d_sc(3)) dist = (length(3)-dist)*(length(3)-d_sc(3))/d_sc(3) + good_velo(i,j,k) = (float(i-1)/N(1)) & + & + 10*(float(j-1+coord(2)*N_proc(2))/N(2)) & + & + 100*dist/length(3) + else + call test_substatus(' boundary along X condition not implemented ', cart_rank) + end if + end do + end do + end do + case default + call test_substatus(' XXX error : wrong direction =', direction, cart_rank) + stop + end select + case default + velo = 1. + good_velo = 1. + end select + + +end subroutine velo_init + + +!> Initialisation of particle velocity field to test its interpolation +!! @param[in] init = parameter to initialise the scalar fied to a constant one or to a sphere shape +!! @param[out] velo = initial particles velocity +!! @param[in] direction = current direction (along X,Y or Z-axis) +!! @param[in] p_pos_adim = adimensionned particles postion (location where the velocity will be interpolated) +!! @param[in,out] good_velo = analytic interpolation of the velocity field (on location p_pos) +subroutine particle_velo_init(init, velo, direction, p_pos_adim, good_velo) + + use test_common + use cart_topology + + character(len=*), intent(in) :: init + real(WP), dimension(:), intent(inout) :: velo + real(WP), dimension(:), intent(in) :: p_pos_adim + integer, intent(in) :: direction + real(WP), dimension(:), intent(inout) :: good_velo + + real(WP) :: dist ! distance from original position for translation case + integer :: ind ! particle indice + + + select case(init) + case('constant') + velo = 1. + good_velo = 1. + case('translation_field') + do ind = 1, size(velo) + velo(ind) = (float(ind-1+coord(direction)*N_proc(direction))/N(direction)) + if (periods(direction) .eqv. .true.) then + dist = (p_pos_adim(ind)-1+coord(direction)*N_proc(direction))*d_sc(direction) + dist = modulo(dist, length(direction)) + ! See direction 1 for explaination + if (dist>length(direction)-d_sc(direction)) & + & dist = (length(direction)-dist)*(length(direction)-d_sc(direction))/d_sc(direction) + good_velo(ind) = dist/length(direction) + else + call test_substatus(' boundary condition not implemented ', cart_rank) + end if + end do + case default + velo = 1. + good_velo = 1. + end select + +end subroutine particle_velo_init + + +!> Initialisation of paticles and velocity field to provide setups to test advection +!! @param[in] init = parameter used to choose between the different setup +!! @param[in,out] dt = time step (used to compute solution) +!! @param[in] shift = global translation of indices (optional) +!! @param[out] scal3D = scalar field +!! @param[out] velo = velocity field along one direction +!! @param[in] direction = current direction (along X,Y or Z-axis) +!! @param[out] good_scal = analytic solution of the advection problem +subroutine scal_velo_init_part(init, dt, shift, scal3D, velo, direction, good_scal) + + ! Scales code + use cart_topology + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + ! Test procedures + use test_common + + character(len=*), intent(in) :: init + real(WP), intent(inout) :: dt + integer, intent(in) :: shift + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: velo + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: scal3D + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)), intent(out) :: good_scal + integer, intent(in) :: direction + + integer :: i, j, k ! mesh indices + real(WP) :: cfl ! ratio between time and space steps + real(WP) :: t ! some time indication + real(WP) :: dt_bis ! time step used to compute trajectories + ! with a numerical integration + real(WP) :: sX, sY, sZ ! some temp variable + real(WP), dimension(3) :: vect_dir ! some temp variable + + + cfl = dt/d_sc(direction) + + + ! -- Initialize velocity and compute some trajectories -- + select case(init) + case('left') + ! -- Test case 1 : only left block, no tag -- + velo = (shift+0.3)/cfl + scal3D = -dt*velo + call test_substatus('particle- no tag, only left block', cart_rank) + + case('tag') + ! Update dt in order to create "chock" without broke the stability condition + dt = 0.8*d_sc(direction)/sqrt(2*1.2*bl_size) + cfl = dt/d_sc(direction) + ! Compute trajectories + scal3D = 0.0 + do k = 1, N_proc(3) + do j = 1, N_proc(2) + do i = 1, N_proc(1) + velo(i,j,k) = compute_velo_tag(dble(j), shift, cfl, direction) + dt_bis = min(0.01_WP, dt/10) + t = 0 + do while(t <= dt-dt_bis) + scal3D(i,j,k) = scal3D(i,j,k) & + &- dt_bis*compute_velo_tag(j+scal3D(i,j,k), shift, cfl, direction)/d_sc(direction) + t = t + dt_bis + end do + dt_bis = dt - t + scal3D(i,j,k) = scal3D(i,j,k) & + &- dt_bis*compute_velo_tag(j+scal3D(i,j,k), shift, cfl, direction)/d_sc(direction) + end do + end do + end do + call test_substatus('particle- 2 tag, left and center', cart_rank) + + case default ! default = 'center' + ! Test case 2 : only center block, no tag + velo = (shift+0.8)/cfl + scal3D = -dt*velo + call test_substatus('particle- no tag, only center block', cart_rank) + end select + + ! -- Compute solution of the advection problem + vect_dir = 0 + vect_dir(direction) = 1 + do k = 1, N_proc(3) + sZ = (k-1+(coord(3)*N_proc(3)))*d_sc(3) + do j = 1, N_proc(2) + sY = (j-1+(coord(2)*N_proc(2)))*d_sc(2) + do i = 1, N_proc(1) + sX = (i-1+(coord(1)*N_proc(1)))*d_sc(1) + good_scal(i,j,k) = cos(2*M_PI*(sZ+vect_dir(3)*scal3D(i,j,k))/length(3)) + good_scal(i,j,k) = good_scal(i,j,k)*cos(2*M_PI*(sY+vect_dir(2)*scal3D(i,j,k))/length(2)) + !good_scal(i,j,k) = good_scal(i,j,k)*cos(3*2*M_PI*(sY+vect_dir(2)*scal3D(i,j,k))/length(2)) + good_scal(i,j,k) = good_scal(i,j,k)*cos(2*M_PI*(sX+vect_dir(1)*scal3D(i,j,k))/length(1)) + !good_scal(i,j,k) = good_scal(i,j,k)*cos(5*2*M_PI*(sX+vect_dir(1)*scal3D(i,j,k))/length(1)) + scal3D(i,j,k) = cos(2*M_PI*sZ/length(3)) + scal3D(i,j,k) = scal3D(i,j,k)*cos(2*M_PI*sY/length(2)) + !scal3D(i,j,k) = scal3D(i,j,k)*cos(3*2*M_PI*sY/length(2)) + scal3D(i,j,k) = scal3D(i,j,k)*cos(2*M_PI*sX/length(1)) + !scal3D(i,j,k) = scal3D(i,j,k)*cos(5*2*M_PI*sX/length(1)) + end do + end do + end do + +end subroutine scal_velo_init_part + +!> Compute a velocity field wich produce 2 tagged block during an advection step +!! with the solver based on particle method +!! @param[in] pos = relative position along current direction +!! @param[in] shift = shift (in number of mesh) +!! @param[in] cfl = time step/space step +!! @param[in] direction = current direction +!! @return res = velocity field +function compute_velo_tag(pos, shift, cfl, direction) result(res) + + ! Topology + use cart_topology + ! Solver information + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + ! Test tools + use test_common + + real(WP), intent(in) :: pos, cfl + integer, intent(in) :: shift, direction + real(WP) :: res + real(WP) :: pos_abs ! absolute position (i,j,k are relative position in the current processus) + integer :: ind_tag_bl, ind_tag_p + + ind_tag_bl = (nb_proc_dim(direction)*(N(direction)/bl_size)/3)! - (bl_number(direction)*coord(direction)) + ind_tag_p = (ind_tag_bl-1)*bl_size + bl_size/2 + 1 + + pos_abs = pos + coord(direction)*N_proc(direction) + + res = shift/cfl + if ((pos_abs >= ind_tag_p).and.(pos_abs < N(direction))) then + res = res + 0.8*(1.0-(pos_abs-ind_tag_p)/(N(direction)-ind_tag_p))/cfl + end if + +end function compute_velo_tag + + +!> Initialisation of particle position for a group +!! @param[in] direction = current direction +!! @param[in] gs = group_size +!! @param[in] shift = shift (in number of mesh) +!! @param[out] p_pos = scalar field +!! @param[out] bl_type = bloc type (left/center), optional +subroutine pos_gp_init(direction, gs, shift, p_pos, bl_type) + + ! Topology + use cart_topology + ! Solver information + use advec_common ! Some porcedure common to advection along all directions + use advec_variables ! contains info about solver parameters and others. + ! Test tools + use test_common + + integer, intent(in) :: shift, direction + integer, dimension(2), intent(in) :: gs + real(WP), dimension(N_proc(direction), gs(1), gs(2)), intent(out) :: p_pos + logical, dimension(bl_nb(direction)+1, gs(1), gs(2)), intent(inout), optional :: bl_type + + integer :: ind, ind2 ! some indice (line coordiante, particle indice) + + ! ===== Each line of the group is initialized considering it second indice ===== + ind2 = 1 + do while(ind2<=gs(2)) + ! Init are done with a cycle of five + select case(modulo(ind2,5)) + case(1) + do ind = 1, N_proc(direction) + p_pos(ind,:,ind2) = ind - 2.1 + shift*N_proc(direction) + end do + if(present(bl_type)) bl_type(:,:,ind2) = .true. + case(2) + do ind = 1, N_proc(direction) + p_pos(ind,:,ind2) = ind - 1.1 + shift*N_proc(direction) + end do + if(present(bl_type)) bl_type(:,:,ind2) = .true. + case(3) + do ind = 1, N_proc(direction) + p_pos(ind,:,ind2) = ind + shift*N_proc(direction) + end do + if(present(bl_type)) bl_type(:,:,ind2) = .false. + case(4) + do ind = 1, N_proc(direction) + p_pos(ind,:,ind2) = ind + 1.1 + shift*N_proc(direction) + end do + if(present(bl_type)) bl_type(:,:,ind2) = .false. + case default + do ind = 1, N_proc(direction) + p_pos(ind,:,ind2) = ind + 2.1 + shift*N_proc(direction) + end do + if(present(bl_type)) bl_type(:,:,ind2) = .false. + end select + + ind2 = ind2 +1 + end do + +end subroutine pos_gp_init + + +end module advec_aux_init +!> @} diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_main.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_main.f90 new file mode 100644 index 000000000..795eae187 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_advec/advec_main.f90 @@ -0,0 +1,213 @@ +!> @addtogroup part_test +!! @{ + +!------------------------------------------------------------------------------ +! +! PROGRAM : advec_main +! +! DESCRIPTION: +!> This program use the function implemented in the module advec_aux to +!! test the advection solver. +!! +!! @author +!! Jean-Baptiste Lagaert, LEGI +! +!> @details +!! All these test are unit test: they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! All the "test_part_*" function are devoted to validate the particular +!! solver +!! +!! The following test are included: +!! - Validate the particular method, step by step +!! - Test the procedure "AC_obtain_senders" from advec_common +!! - Validate the redistribution the buffer during the remeshing +!! - Validate the redistribution the buffer during the remeshing - +!! debug version : only one processus contains non-zero field. +!! - Validate the remeshing of untagged particles +!! - Validate the velocity interpolation (the RK2 scheme use the +!! velocity at midlle point to advec particles). +!! - Validate how type (left or center) and tag are computing for a +!! single line +!! - Validate how type (left or center) and tag are computing for a +!! group of line +!! - Validate an advection solver (in advec_aux) +!! - advec a ball with a constant velocity +!! - advec a ball with a spheric velocity field (the ball turns) +!! - Advection with radial shear. This test also validate the remeshing +!! of tagged particles. +!! +! +!------------------------------------------------------------------------------ + +program advec_main + + ! External Library + use mpi + ! Scales code + use cart_topology + ! Test procedures + use test_common + use advec_aux + use advec_aux_common + use advec_aux_common_line + + implicit none + + logical :: error = .false. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc,nb_procZ ! number of processus + integer :: i ! some boucle indice + integer :: direction ! along X (1), Y (2) or Z (3) + + ! ===== Initialisation ===== + + ! Set the verbosity + verbose_test = .true. + verbose_more = .false. + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + nb_procZ = 1 + if ((mod(nb_proc,5)==0).and.(mod(default_size, nb_proc/5)==0)) then + nb_procZ = 5 + nb_proc = nb_proc/5 + else if ((mod(nb_proc,2)==0).and.(mod(default_size, nb_proc/2)==0)) then + nb_procZ = 2 + nb_proc = nb_proc/2 + else + if (mod(default_size, nb_proc)/=0) stop 'wrong number of processes : it have to divide 100' + end if + call cart_create((/ nb_proc, nb_procZ /), ierr) + call discretisation_default() + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! ===== Test about procedures involved in remeshing process ===== + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('particle method - remeshing', rank_world) + + ! Does it well compute who communicate with who during remeshing ? + error = test_part_AC_obtain_senders() + call test_status(error, 'obtain_senders sans shift', rank_world) + error = test_part_AC_obtain_senders(1) + call test_status(error, 'obtain_senders avec shift', rank_world) + error = test_part_AC_obtain_senders(3*nb_proc_dim(2)+2) + call test_status(error, 'obtain_senders avec large shift', rank_world) + + ! The remeshing are done in a buffer. Is it well re-distribuate on processes ? + do i = 0, min(4, nb_proc-1) + error = test_part_AC_bufferToScalar_Deb(i) + call test_status(error, 'bufferToScalar deb, no shift, rank =', i, rank_world) + error = test_part_AC_bufferToScalar_Deb(i,1) + call test_status(error, 'bufferToScalar deb,shift; rank =', i, rank_world) + end do + error = test_part_AC_bufferToScalar() + call test_status(error, 'bufferToScalar sans shift', rank_world) + error = test_part_AC_bufferToScalar(1) + call test_status(error, 'bufferToScalar avec shift', rank_world) + error = test_part_AC_bufferToScalar(3*nb_proc_dim(2)+2) + call test_status(error, 'bufferToScalar avec large shift', rank_world) + + ! Test remeshing of untagged particles + error = test_part_remesh_no_tag() + call test_status(error, 'remeshing of cst field advected a cst v', rank_world) + error = test_part_remesh_no_tag('translation_field') + call test_status(error, 'remeshing of uncst field advected a cst v', rank_world) + error = test_part_remesh_no_tag(order_opt='p_O4') + call test_status(error, 'O4: remeshing of cst field advected a cst v', rank_world) + error = test_part_remesh_no_tag('translation_field', order_opt='p_O4') + call test_status(error, 'O4: remeshing of uncst field advected a cst v', rank_world) + error = test_part_remesh_no_tag(order_opt='p_M6') + call test_status(error, 'Mprime 6: remeshing of cst field advected a cst v', rank_world) + error = test_part_remesh_no_tag('translation_field', order_opt='p_M6') + call test_status(error, 'Mprime 6: remeshing of uncst field advected a cst v', rank_world) + + + ! ===== Test about procedures involved in computation of particles advection ===== + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('particle: velocity interpolation', rank_world) + + ! Test auxiliary procedures + error = test_part_AC_obtain_recevers() + call test_status(error, 'AC_obtain_recevers', rank_world) + + ! Test velocity interpolation + error = test_part_AC_interpol_velocity(2, 0) + call test_status(error, 'velocity interpolation, no shift', rank_world) + error = test_part_AC_interpol_velocity(2, 1) + call test_status(error, 'velocity interpolation, shift', rank_world) + + ! Test group variants + call test_title('particle: velocity interpolation (group)', rank_world) + call set_group_size(5) + error = test_part_AC_velo_determine_com(0) + call test_status(error, 'velocity: communication', rank_world) + error = test_part_AC_velo_determine_com(1) + call test_status(error, 'velocity: communication, shift', rank_world) + do direction = 1, 3 + error = test_part_AC_velo_compute_group(direction,0) + call test_status(error, 'velocity: interpol', direction, rank_world) + end do + + ! ===== Test others ===== + call test_title('particle method - tag and bloc type', rank_world) + call mpi_barrier(MPI_COMM_WORLD, ierr) + error = test_part_AC_type_and_block_O2() + call test_status(error, 'determine block type and tag particles', rank_world) + error = test_part_AC_type_and_block_O2_group() + call test_status(error, 'block and type for a group of line', rank_world) + + ! ===== Test solvers ===== + + ! Test devoted to solver based on particles method + call test_title('particle method - advection test', rank_world) + error = test_part_advec_1D() + call test_status(error, 'advection - center block, no tag', rank_world) + error = test_part_advec_1D('left') + call test_status(error, 'advection - left block, no tag', rank_world) + verbose_more = .true. + error = test_part_advec_3D() + call test_status(error, 'advection - 3D tests', rank_world) + verbose_more = .false. + + ! Idem for order 4 (corrected lambda 4) + call test_title('particle method - advection test', rank_world) + error = test_part_advec_1D(order_opt='p_O4') + call test_status(error, 'advection - center block, no tag', rank_world) + error = test_part_advec_1D('left', order_opt='p_O4') + call test_status(error, 'advection - left block, no tag', rank_world) + verbose_more = .true. + error = test_part_advec_3D(order='p_O4') + call test_status(error, 'advection - 3D tests', rank_world) + verbose_more = .false. + + ! Idem for order M'6 remeshing formula + call test_title('particle method - advection test', rank_world) + error = test_part_advec_1D(order_opt='p_M6') + call test_status(error, 'advection - center block, no tag', rank_world) + error = test_part_advec_1D('left', order_opt='p_M6') + call test_status(error, 'advection - left block, no tag', rank_world) + verbose_more = .true. + error = test_part_advec_3D(order='p_M6') + call test_status(error, 'advection - 3D tests', rank_world) + verbose_more = .false. + + ! Generic test +! call mpi_barrier(MPI_COMM_WORLD, ierr) +! call test_title('generic advection test', rank_world) +! error = test_advec_rot() +! call test_status(error, 'turning sphere', rank_world) + + + call mpi_finalize(ierr) + +end program advec_main + +!> @} diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_io/io_aux.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_io/io_aux.f90 new file mode 100644 index 000000000..12bfa054b --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_io/io_aux.f90 @@ -0,0 +1,98 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : io_main +! +! DESCRIPTION: +!> This files contains binary test on io procedures. +!! +!! @details +!! All these test are unit test : they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! This first version test only the output at vtk xml format in parallel context. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module io_aux + + implicit none + + public :: test_io_output + + +contains + +function test_io_output() result(success) + + ! External Library + use mpi + ! Scales code + use cart_topology + use cart_mesh + use parallel_io_bin + ! Test procedures + use test_common + + implicit none + + logical :: success ! logical result + real(WP), dimension(N_proc(1),N_proc(2),N_proc(3)) :: field ! constant field used in this test + integer :: tag_cst ! tag for constant field used in this test + integer :: tagX,tagY,tagZ ! tag for unconstant fields used in this test + integer :: i ! some boucle indice + + + success = .true. + + ! Initialize output context + call parallel_io_init_all(4, nb_proc_dim, length, myrank, coord, './io_res/') + call test_substatus('general context intialization', success, myrank) + + call parallel_io_init_field('cst', tag_cst) + call parallel_io_init_field('X', tagX) + call parallel_io_init_field('Y', tagY) + call parallel_io_init_field('Z', tagZ) + call test_substatus('fields context intialization', success, myrank) + + ! Make some output + field = 1.0 + call parallel_write(tag_cst, field, 'cst') + field = 2.0 + call parallel_write(tag_cst, field, 'cst') + call test_substatus('constant output', success, myrank) + + do i = 1, N_proc(1) + field(i,:,:) = i+coord(1)*N_proc(1) + end do + call parallel_write(tag_cst, field, 'X') + field = 2*field + call parallel_write(tag_cst, field, 'X') + call test_substatus('X output', success, myrank) + + do i = 1, N_proc(2) + field(:,i,:) = i+coord(2)*N_proc(2) + end do + call parallel_write(tag_cst, field, 'Y') + call test_substatus('Y output', success, myrank) + + do i = 1, N_proc(3) + field(:,:,i) = i+coord(3)*N_proc(3) + end do + call parallel_write(tag_cst, field, 'Z') + call test_substatus('Z output', success, myrank) + + + ! Free memory + call parallel_io_finish() + + ! The main programm want receive a signal corresponding to error rather than success + success = .not. success + +end function test_io_output + +end module io_aux diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_io/io_main.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_io/io_main.f90 new file mode 100644 index 000000000..45c63c1ff --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_io/io_main.f90 @@ -0,0 +1,78 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : io_main +! +! DESCRIPTION: +!> This program use the function implemented in the module io_aux to +!! test the io routines. +!! +!! @details +!! All these test are unit test : they return a logical value to check if +!! the code version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! This first version test only the output at vtk xml format in parallel context. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program io_main + + ! External Library + use mpi + ! Scales code + use cart_topology + use parallel_io_bin + ! Test procedures + use test_common + use io_aux + + implicit none + + logical :: error = .false. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc,nb_procZ ! number of processus + integer :: i ! some boucle indice + + ! ===== Initialisation ===== + + ! Set the verbosity + verbose_test = .true. + verbose_more = .true. + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + nb_procZ = 1 + if ((mod(nb_proc,5)==0).and.(mod(100, nb_proc/5)==0)) then + nb_procZ = 5 + nb_proc = nb_proc/5 + else if ((mod(nb_proc,2)==0).and.(mod(100, nb_proc/2)==0)) then + nb_procZ = 2 + nb_proc = nb_proc/2 + else + if (mod(100, nb_proc)/=0) stop 'wrong number of processes : it have to divide 100' + end if + call cart_create((/ nb_proc, nb_procZ /), ierr) + call discretisation_default() + call mpi_barrier(MPI_COMM_WORLD, ierr) + + + ! ===== Test about io procedures ===== + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_title('io - parallel vtk xml', rank_world) + error = test_io_output() + call test_status(error, 'write output', rank_world) + !error = test_io_input() + !call test_status(error, 'write input', rank_world) + + call mpi_finalize(ierr) + +end program io_main + diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux.f90 new file mode 100644 index 000000000..a3e19682a --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux.f90 @@ -0,0 +1,274 @@ +!------------------------------------------------------------------------------ +! +! MODULE: topo_aux +! +! DESCRIPTION: +!> This module provides different tests to validate the topology and the +!! interface with the different data structures. +!! +!! @details +!! Different automatic test are developped in order to check the mesh creation +!! and the interface between the two data structures (the one used for the +!! particular method and the one from the spectral part). +!! All these test are unit test : they return a logical value to check if +!! the ierr version pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! +!! The following test are included : +!! 1 -> Initialise the topology, check the number of processes and +!! the communicators. +!! 2 -> Check the periodicity. +!! 3 -> Check if the subgrid on each processus have the good size +! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module topo_aux + + use mpi + use cart_topology + use string + use precision + implicit none + + real(WP), private :: epsilon_success = 1e-4 ! Error tolerance + + + ! Public procedures + + ! ===== Test the topology ===== + ! Public function + public :: test_topo_init + public :: test_topo_perio + public :: test_topo_submesh + + + + +contains + +!> Test the topology initialisation +!! @return success = logical success (= false if the ierr pass the test) +!! @details +!! Test the cartesian topology : check the number of processes and the +!! communicators. +function test_topo_init() result(success) + + use test_common + + logical :: success ! success status + + integer :: ierr ! mpi success ierr + integer :: nb_proc ! total number of processus + integer :: nb_Y, nb_Z ! actual number of processus in each direction + integer, dimension(2) :: dims ! wanted number of processus in Y and Z direction + + success = .true. + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + + ! Cut the domain along Y and initialize the toppology + dims = (/ nb_proc, 1 /) + call cart_create(dims, ierr) + + ! Check the number of process in each communicator + call mpi_comm_size(Y_comm, nb_Y, ierr) + if (nb_Y /= nb_proc) then + call test_substatus('number of processes in Y_comm', nb_Y, myrank) + call test_substatus('and it must be', nb_proc, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + + call mpi_comm_size(Z_comm, nb_Z, ierr) + if (nb_Z /= 1) then + call test_substatus('number of processes in Z_comm', nb_Z, myrank) + call test_substatus('and it must be', 1, myrank) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + + ! Compare it with the one saved in cart_topo + if (nb_Y /= nb_proc_dim(2)) then + call test_substatus('number of processes in Y_comm', nb_Y, myrank) + call test_substatus('and the solver beleave it is', nb_proc_dim(2), myrank) + success = .false. + end if + if (nb_Z /= nb_proc_dim(3)) then + call test_substatus('number of processes in Y_comm', nb_Z, myrank) + call test_substatus('and the solver beleave it is', nb_proc_dim(3), myrank) + success = .false. + end if + + ! Return error = not succes + success = .not. success + +end function test_topo_init + +!> Check if it provide the right cartesian structure with a good periodicity +!! @return success = logical success (= false if the ierr pass the test) +function test_topo_perio() result(success) + + use test_common + + logical :: success ! success status + + integer :: ierr ! mpi success ierr + integer :: rankP, rankN ! rank of previous and next (for shift) + integer :: nb_Y, nb_Z ! number of processus in each direction + integer, dimension(2) :: dims ! number of processus in Y and Z direction + integer, dimension(3) :: coord_bis ! coordonate of another processus + integer :: new_coord ! theoritical coordinate + + success = .true. + + ! Get the size + call mpi_comm_size(Y_comm, nb_Y, ierr) + call mpi_comm_size(Z_comm, nb_Z, ierr) + + ! Shift along Y + ! Positive shift + call mpi_cart_shift(cart_comm, 2-1, 1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y-1 on rank', myrank, printer) + call test_substatus('theoritical Y-1', new_coord, printer) + call test_substatus('computed Y-1', coord_bis(2), printer) +call test_substatus('X', coord_bis(1), printer) +call test_substatus('Z', coord_bis(3), printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+1 on rank', myrank, printer) + success = .false. + end if + ! Negative shift + call mpi_cart_shift(cart_comm, 2-1, -1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y-(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('topo and periodicity along Y', success, myrank) + + ! Shift along Z + ! Positive shift + call mpi_cart_shift(cart_comm, 3-1, 1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(3)-1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z-1 on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(3)+1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z+1 on rank', myrank, printer) + success = .false. + end if + ! Negative shift + call mpi_cart_shift(cart_comm, 3-1, -1, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(3)-1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z+(-1) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(3)+1, nb_Z) + if ((coord_bis(3) /=(new_coord)).OR.(coord_bis(2)/=coord(2)) ) then + call test_substatus('wrong Z-(-1)) on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('topo and periodicity along Z', success, myrank) + + ! Big shift + call mpi_cart_coords(cart_comm, myrank, 3, coord, ierr) + call mpi_cart_shift(cart_comm, 2-1, 1+2*Nb_Y, rankP, rankN, ierr) + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankP, 3, coord_bis, ierr) + new_coord = modulo(coord(2)-1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y- on rank', myrank, printer) + call test_substatus('theoritical Y-', new_coord, printer) + call test_substatus('computed Y-', coord_bis(2), printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call mpi_cart_coords(cart_comm, rankN, 3, coord_bis, ierr) + new_coord = modulo(coord(2)+1, nb_Y) + if ((coord_bis(2) /=(new_coord)).OR.(coord_bis(3)/=coord(3)) ) then + call test_substatus('wrong Y+ on rank', myrank, printer) + success = .false. + end if + call mpi_barrier(MPI_COMM_WORLD, ierr) + call test_substatus('huge shift along Y', success, myrank) + + ! Return error = not success + success = .not.success + +end function test_topo_perio + + +!> Test the construction of subdomain and the mesh size in each processus +!! @return success = logical success (= false if the ierr pass the test) +!! @details +!! Check if the subgrid on each processus have the good size +function test_topo_submesh() result(success) + + use test_common + + logical :: success + integer :: ierr ! mpi success code + + success = .true. + + call discretisation_default() + + ! Check the number of mesh + if (N_proc(1)/= 100) then + call test_substatus('local number of mesh along X', N_proc(1), myrank) + success = .false. + end if + if (N_proc(2)/= 100/nb_proc_dim(2)) then + call test_substatus('local number of mesh along Y', N_proc(2), myrank) + success = .false. + end if + if (N_proc(3)/= 100/nb_proc_dim(3)) then + call test_substatus('local number of mesh along Z', N_proc(3), myrank) + success = .false. + end if + + ! Return error = not success + success = .not.success + + call mpi_barrier(MPI_COMM_WORLD, ierr) + +end function test_topo_submesh + + +end module topo_aux diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux_interface.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux_interface.f90 new file mode 100644 index 000000000..a5e499172 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_aux_interface.f90 @@ -0,0 +1,72 @@ +!------------------------------------------------------------------------------ +! +! MODULE: topo_aux_interface +! DESCRIPTION: +!> This module provides different tests to validate the interface with the different +!! data structures. +!! +!! @details +!! Different automatic test are developped in order to check the interface between the +!! two data structures (the one used for the particular method and the one from the +!! spectral part). All these test are unit test : they return a logical value to check +!! if the library pass it or not. +!! +!! That is all these test are logical function, they return true if the result +!! is the right one and false otherwise. +!! +!! The following test are included : +!! 1 -> Test the interface between the data structure in the advection solver +!! based on particular method and the one used in the +!! pseudo-spectral method. +!! X -> TODO check the output wich could be done directly from this +!! format. +! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module topo_aux_interface + + use cart_topology + use precision + + implicit none + + ! ===== Test the topology ===== + ! Public function + public :: test_topo_coupling + +contains + +!> Test the communication between the pseudo-spectral and particles method. +!! @return success = logical success (= false if the ierr pass the test) +!! @details +!! Some advection-diffusion law on scalar field are solved by mixed numerical +!! method. In such a case, the advection part are solved with a particular +!! solver (with time order 2 and space-order of 2 or 4) and the diffusion part +!! are compute with a pseudo-spectral solver. The operator splitting is a +!! Strang splitting. All these method are provided in a parrallel +!! implemention. The data distribution used in the pseudo-spectral solver is +!! described in the module "datalayout" and the one used in the parrticle +!! solver is described in cart_topology. Of course, to avoid useless +!! communication and ensure efficient implementation, these data distribution +!! are supposed to be the same between the storage of field in the real space +!! described in "datalayout" and the one described in "cart_topology". This +!! function are provided to test it and check if the procedure provided in the +!! different solver are compatible. +function test_topo_coupling() result(success) + + use cart_topology + + logical :: success + + success = .true. + + + success = .not. success + +end function test_topo_coupling + +end module topo_aux_interface diff --git a/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_main.f90 b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_main.f90 new file mode 100644 index 000000000..440ad2b60 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/Test_topo/topo_main.f90 @@ -0,0 +1,60 @@ +!------------------------------------------------------------------------------ +! +! PROGRAM : topo_main +! +! DESCRIPTION: +!> Test the cartesian topology and all the associated variable. +!! test the advection solver. +!! This program perform all the test include in "topo_aux". This module provide +!! unit test, ie logical function wich return a logical error. +!! There is a verbosity parameter to decide to print on screen the status of +!! result of each test (and sub-test) or not. +!! +!! See topo_aux for a list of available test. +!! +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +program topo_main + + use mpi + use topo_aux + use topo_aux_interface + use test_common + + implicit none + + logical :: error = .true. ! logical error + integer :: ierr ! mpi error code + integer :: rank_world ! processus rank on "MPI_COMM_WORLD" + integer :: nb_proc ! number of processus + + ! Set the verbosity + verbose_test = .true. + verbose_more = .true. + + ! Initialise mpi + call mpi_init(ierr) + call mpi_comm_size(MPI_COMM_WORLD, nb_proc, ierr) + call mpi_comm_rank(MPI_COMM_WORLD, rank_world, ierr) + call mpi_test_substatus(ierr, error, 'mpi initialization', rank_world) + + ! Initialize the topology and test is + error=test_topo_init() + call test_status(error, '(mpi) topology initialisation', rank_world) + + ! Initialize the topology and test is + error=test_topo_perio() + call test_status(error, 'periodicity', rank_world) + + ! Initialize the topology and test is + error=test_topo_submesh() + call test_status(error, 'subdomain size', rank_world) + + call mpi_finalize(ierr) + +end program topo_main + diff --git a/HySoP/src/Unstable/LEGI/test/src/test_common.f90 b/HySoP/src/Unstable/LEGI/test/src/test_common.f90 new file mode 100644 index 000000000..f2ffd7678 --- /dev/null +++ b/HySoP/src/Unstable/LEGI/test/src/test_common.f90 @@ -0,0 +1,536 @@ +!------------------------------------------------------------------------------ +! +! MODULE: test_advection +! +! DESCRIPTION: +!> This module provide different tools useful to perform test. +! +!> @author +!! Jean-Baptiste Lagaert, LEGI +! +!------------------------------------------------------------------------------ + +module test_common + + use string + use precision + + implicit none + + ! ===== Public variables ===== + !> To print some status message during the test + logical :: verbose_test = .true. + !> More verbosity ! + logical :: verbose_more = .true. + !> To choose wich processes lead the screen output + integer :: printer = 0 + + ! ===== Public procedure ===== + ! - To print some information about the test (verbosity case) + public :: test_title + public :: test_status + public :: mpi_test_substatus + public :: test_substatus + public :: test_check_success + + ! ===== Private procedure ===== + private :: test_status_M + private :: test_status_MI + private :: test_substatus_M + private :: test_substatus_MI + private :: test_substatus_MR + private :: test_substatus_ML + private :: test_substatus_M3I + private :: test_check_success_S + private :: test_check_success_F + private :: test_check_success_F2 + private :: test_check_success_F3 + private :: test_check_success_FI + private :: test_check_success_FL + private :: test_check_success_F3L + + + ! ===== Private variables ===== + !> Error tolerance + real(WP), private :: epsilon_success = 1e-4 + + ! ===== Interface ===== + interface test_status + module procedure test_status_M, test_status_MI + end interface test_status + + interface test_substatus + module procedure test_substatus_M, test_substatus_MI, test_substatus_MR & + & , test_substatus_ML, test_substatus_M3I + end interface test_substatus + + interface test_check_success + module procedure test_check_success_S, test_check_success_F, & + & test_check_success_F2, test_check_success_F3, test_check_success_FI, & + & test_check_success_F2I, test_check_success_FL, test_check_success_F3L + end interface test_check_success + + + +contains + +!> Diffuse the error status and print the test status +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_title(message, rank) + + use cart_topology + + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + character(len=40) :: mess_bis ! message copy + + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(A1,1X,A40)')'#', mess_bis + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_title + + +!> Diffuse the error status and print the test status +!! @param[in, out] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_status_M(error, message, rank) + + use mpi + use cart_topology + + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + character(len=40) :: mess_bis ! message copy + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(error .eqv. .true.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) error=.true. + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(5X,A2,2X,A40,X,A2,L2)')'->', mess_bis, '=', .not.error + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_status_M + + +!> Diffuse the error status and print the test status +!! @param[in, out] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] message_int = integer added to the information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_status_MI(error, message, message_int , rank) + + use mpi + use cart_topology + + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank, message_int + + character(len=37) :: mess_bis ! message copy + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(error .eqv. .true.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) error=.true. + + if((verbose_test).and.(rank==printer)) then + mess_bis = message + write(*,'(5X,A2,2X,A37,X,I2,X,A2,L2)')'->', mess_bis, message_int, '=', .not.error + if((verbose_more).and.(rank==printer)) print*,'' + end if + +end subroutine test_status_MI + + +!> Use a mpi error code to update the test status and print it +!! @param[in] ierr = mpi error code +!! @param[in] error = logical equal true if there is an error +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine mpi_test_substatus(ierr, error, message, rank) + + use mpi + + integer, intent(in) :: ierr + logical, intent(inout) :: error + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + if (ierr /= MPI_SUCCESS) then + error = .false. + end if + + call test_substatus(message, error, rank) + error = .not. error + +end subroutine mpi_test_substatus + +!> Print a sub-status message +!! @param[in] message = information message +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_M(message, rank) + + character(len =*), intent(in) :: message + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40)')'+', message + end if + +end subroutine test_substatus_M + + +!> Print a sub-status message and a integer +!! @param[in] message = information message +!! @param[in] i = integer to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_MI(message, i, rank) + + character(len =*), intent(in) :: message + integer, intent(in) :: i + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,I5)')'+', message, '=', i + end if + +end subroutine test_substatus_MI + + +!> Print a sub-status message and a integer +!! @param[in] message = information message +!! @param[in] i = integer table of dimension 3 to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_M3I(message, i, rank) + + character(len =*), intent(in) :: message + integer, dimension(3), intent(in) :: i + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,I3,X,A1,X,I3,X,A1,X,I3)')'+',message,'=',i(1),',',i(2),',',i(3) + end if + +end subroutine test_substatus_M3I + + +!> Print a sub-status message and a real +!! @param[in] message = information message +!! @param[in] r = real to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_MR(message, r, rank) + + use precision + + character(len=* ), intent(in) :: message + real(WP), intent(in) :: r + integer, intent(in) :: rank + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,F8.5)')'+', message, '=', r + end if + +end subroutine test_substatus_MR + + +!> Print a sub-status message and a logical (after sending its value if false) +!! @param[in] message = information message +!! @param[in,out] l = logical to print +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_substatus_ML(message, l, rank) + + use precision + use mpi + use cart_topology + + character(len =*), intent(in) :: message + logical, intent(inout) :: l + integer, intent(in) :: rank + integer :: error_int = 0 + integer :: error_red = 0 + integer :: ierr ! mpi error code + + if(l .eqv. .false.) error_int = 1 + call mpi_allreduce(error_int, error_red, 1, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr) + if(error_red==1) l=.false. + + if((verbose_more).and.(rank==printer)) then + write(*,'(10X,A2,2X,A40,X,A1,X,L5)')'+', message, '=', l + end if + +end subroutine test_substatus_ML + + + +!> Check if the numerical success stay under a threshold - constant theoritical +!! solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_S(scal1D, good_scal, success, rank) + + use precision + use cart_topology + + real(WP), intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + integer :: success_inf ! norm L_inf of the success + + success_inf = maxval(scal1D - good_scal) + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', rank) + call test_substatus('max scal0D', maxval(scal1D), rank) + call test_substatus('min scal0D', minval(scal1D), rank) + call test_substatus('and it must be', good_scal, rank) + end if + +end subroutine test_check_success_S + + +!> Check if two integer 1-dimensionnal table are equal. +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_FI(scal1D, good_scal, success, rank) + + use precision + use cart_topology + + integer, dimension(:),intent(in) :: good_scal ! theoritical value of scal1D + integer, dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + integer :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal1D - good_scal)) + + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', rank) + call test_substatus('max scal1D', maxval(scal1D), rank) + call test_substatus('min scal1D', minval(scal1D), rank) + call test_substatus('max solution', maxval(good_scal), rank) + end if + +end subroutine test_check_success_FI + + +!> Check if two integer 2-dimensionnal table are equal. +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_F2I(array2D, good_array, success, rank) + + use precision + use cart_topology + + integer, dimension(:,:), intent(in) :: good_array ! theoritical value of array2D + integer, dimension(:,:), intent(in) :: array2D ! the computed value + logical, intent(inout) :: success + integer, intent(in) :: rank + + integer :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(array2D - good_array)) + + if (success_inf>=0.5) then ! As we consider integer, this error is enough + success = .false. + call test_substatus('XXX error', rank) + call test_substatus('max array2D', maxval(array2D), rank) + call test_substatus('min array2D', minval(array2D), rank) + call test_substatus('max solution', maxval(good_array), rank) + end if + +end subroutine test_check_success_F2I + + +!> Check if the numerical success stay under a threshold - 1D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal1D = numerical value of the scalar (1D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_F(scal1D, good_scal, success, rank) + + use precision + use cart_topology + + real(WP), dimension(:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:),intent(in) :: scal1D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + real(WP) :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal1D - good_scal)) + + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', rank) + call test_substatus('max scal1D', maxval(scal1D), rank) + call test_substatus('min scal1D', minval(scal1D), rank) + call test_substatus('max solution', maxval(good_scal), rank) + call test_substatus('min solution', minval(good_scal), rank) + end if + +end subroutine test_check_success_F + + +!> Check if the numerical success stay under a threshold - 2D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal2D = numerical value of the scalar (2D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_F2(scal2D, good_scal, success, rank) + + use precision + use cart_topology + + real(WP), dimension(:,:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:,:),intent(in) :: scal2D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + real(WP) :: success_inf ! norm L_inf of the success + + success_inf = maxval(abs(scal2D - good_scal)) + if (success_inf>=epsilon_success) then + success = .false. + call test_substatus('XXX error', rank) + call test_substatus('max scal2D', maxval(scal2D), rank) + call test_substatus('min scal2D', minval(scal2D), rank) + call test_substatus('max solution', maxval(good_scal), rank) + call test_substatus('min solution', minval(good_scal), rank) + end if + +end subroutine test_check_success_F2 + + +!> Check if the numerical success stay under a threshold - 3D space-dependant analytic solution +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal3D = numerical value of the scalar (3D) +!! @param[in] good_scal = theoritical value of the scalar +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_F3(scal3D, good_scal, success, rank) + + use precision + use cart_topology + use mpi + + real(WP), dimension(:,:,:),intent(in) :: good_scal ! theoritical value of scal1D + real(WP), dimension(:,:,:),intent(in) :: scal3D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + real(WP) :: success_inf ! norm L_inf of the success + real(WP) :: success_inf_gl ! norm L_inf of the success + integer :: ierr ! mpi error code + +integer, dimension(3) :: temp + + success_inf = maxval(abs(scal3D - good_scal)) + success_inf_gl=success_inf + call mpi_reduce(success_inf, success_inf_gl, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, ierr) + if (success_inf_gl>=epsilon_success) success = .false. + call test_substatus('norm inf of error', success_inf_gl, rank) + + if (success_inf>=epsilon_success) then + call test_substatus('XXX error', rank) + temp = minloc(scal3D - good_scal) + call test_substatus('error min in', temp, rank) + call test_substatus('scal3D', scal3D(temp(1), temp(2), temp(3)), rank) + call test_substatus('sol', good_scal(temp(1), temp(2), temp(3)), rank) + temp = maxloc(scal3D - good_scal) + call test_substatus('error max in', temp, rank) + call test_substatus('scal3D', scal3D(temp(1), temp(2), temp(3)), rank) + call test_substatus('sol', good_scal(temp(1), temp(2), temp(3)), rank) + end if + +end subroutine test_check_success_F3 + + +!> Check if two 1D logical field are identical or not +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal3D = numerical value of the logical field (1D) +!! @param[in] good_scal = theoritical value +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_FL(scal3D, good_scal, success, rank) + + use precision + use cart_topology + use mpi + + logical, dimension(:),intent(in) :: good_scal ! theoritical value of scal1D + logical, dimension(:),intent(in) :: scal3D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + logical :: success_inf ! local error + logical :: success_inf_gl ! global error + integer :: ierr ! mpi error code + + + success_inf = all(scal3D .eqv. good_scal) + success_inf_gl=success_inf + call mpi_reduce(success_inf, success_inf_gl, 1, MPI_LOGICAL, MPI_LAND, 0, MPI_COMM_WORLD, ierr) + + success = success_inf_gl + +end subroutine test_check_success_FL + + +!> Check if two 3D logical field are identical or not +!! @param[in,out] success = test success (= false if the code pass the test) +!! @param[in] scal3D = numerical value of the logical field (3D) +!! @param[in] good_scal = theoritical value +!! @param[in] rank = mpi rank to avoid to print message for each processes (usefull if there is a lot of them) +subroutine test_check_success_F3L(scal3D, good_scal, success, rank) + + use precision + use cart_topology + use mpi + + logical, dimension(:,:,:),intent(in) :: good_scal ! theoritical value of scal1D + logical, dimension(:,:,:),intent(in) :: scal3D ! the computed scalar field + logical, intent(inout) :: success + integer, intent(in) :: rank + + logical :: success_inf ! local error + logical :: success_inf_gl ! global error + integer :: ierr ! mpi error code + + + success_inf = all(scal3D .eqv. good_scal) + success_inf_gl=success_inf + call mpi_reduce(success_inf, success_inf_gl, 1, MPI_LOGICAL, MPI_LAND, 0, MPI_COMM_WORLD, ierr) + + success = success_inf_gl + +end subroutine test_check_success_F3L + + +end module test_common diff --git a/HySoP/src/Unstable/Plouhmans.f90 b/HySoP/src/Unstable/Plouhmans.f90 new file mode 100644 index 000000000..30be1c638 --- /dev/null +++ b/HySoP/src/Unstable/Plouhmans.f90 @@ -0,0 +1,132 @@ +!> Temp modules for ppm_client +module ppmExample + + use ppm_module_init + use ppm_module_data, only : ppm_kind_double + use ppm_module_finalize + + ! use client_io + use client_data, only: mk, dime + ! Physical domain and grid + use Domain + ! Fields on the grid + use Fields, only: init_fields, velocity, vorticity + ! Topology + use client_topology, only: init_topo, topo + ! Multigrid solver + !use Solver, only : init_multigrid, solve_poisson + + use mpi + use WrapFort + + implicit none + + include "ppm_numerics.h" + + integer, private :: info + +contains + + subroutine init_client() + + integer :: prec,tol + ! MPI comm + integer :: comm + ! debug mode + integer :: debug + ! error status + integer :: info + !====================== + ! Init ppm + !====================== + prec = ppm_kind_double ! Defined in ppm_param.h + comm = MPI_COMM_WORLD ! + debug = 2 + tol = -10 + info = -1 + call ppm_init(dime,prec,tol,comm,debug,info) + + !====================== + ! Read and broadcast + ! some parameters + !====================== + ! call read_data() + + !====================== + ! Geometry and grid + !====================== + call init_geometry() + call init_grid() + + !====================== + ! Creates the topology + !====================== + call init_topo(domain_minCoords, domain_maxCoords, domain_bc, domain_ghostsize, grid_resolution) + + !====================== + ! Fields allocation + !====================== + call init_fields(domain_ghostsize, topo) + + !====================== + ! Init solver + !====================== +! call init_multigrid(topo%ID, mesh%ID, domain_ghostsize, domain_bc) + + !====================== + ! Init Physics + !====================== + velocity = 0.0_mk + vorticity = 0.0_mk + + !====================== + ! Init Particles + !====================== + + print *, "end of parmes:ppm:init_client" + + end subroutine init_client + + subroutine main_client() bind(c,name='plouhmans') + + ! Multigrid parameters ... + print *, 'run ppm simulation ...' + ! init ppm ... + call init_client() + +! call solve_poisson(topo%ID, stream_function, vorticity) + + call ppm_finalize(info) + print *, 'end ppm simulation' + end subroutine main_client + + subroutine read_data() + + ! Set precision +! mpi_prec = MPI_DOUBLE_PRECISION + +!!$ ! Read input parameters on proc 0 +!!$ if(rank == 0) call readparams() +!!$ +!!$ +!!$ call MPI_BCast(runtag,256,MPI_CHARACTER,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(iruntag,1,MPI_INTEGER,0,MPI_COMM_WORLD,info) +!!$ !----------------------------------------------------------------------------! +!!$ ! MPI Broadcasts ... +!!$ !----------------------------------------------------------------------------! +!!$ call MPI_BCast(nx,dime,MPI_INTEGER,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(min_physg,dime,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(max_physg,dime,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(dt,1,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(dt_max,1,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(tend,1,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(itend,1,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call MPI_BCast(nu,1,mpi_prec,0,MPI_COMM_WORLD,info) +!!$ call mpi_bcast(verbose,1,mpi_logical,0,mpi_comm_world,info) +!!$ call mpi_bcast(maxlev,1,mpi_integer,0,mpi_comm_world,info) + + + + end subroutine read_data + +end module ppmexample diff --git a/HySoP/src/Unstable/SetsIndicators.f90 b/HySoP/src/Unstable/SetsIndicators.f90 new file mode 100755 index 000000000..6f38e3916 --- /dev/null +++ b/HySoP/src/Unstable/SetsIndicators.f90 @@ -0,0 +1,516 @@ +!> Penalization stuff (init chi, penalize vorticity) +!! Note : drag/lift are also computed with penalize routines. +module SetsIndicators + + use client_data + use VectorCalculus + !use client_topology, only : nsublist + use mpi,only:MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD + use Domain + implicit none + + private + + public :: init_obstacles,compute_control_box,compute_test,nocaForces,laplacian,chi_sphere,chi_boundary,chi_box,& + getMemoryForIndicators + + ! Indicators functions + ! The top and bottom (z axis) boundaries + integer, dimension(:,:), pointer :: chi_boundary=>NULL() + ! The sphere + integer, dimension(:,:), pointer :: chi_sphere=>NULL() + + ! Axes z is south-north, x down to upstream and y east-west + !> control volume function + integer, dimension(:,:), pointer :: chi_box => NULL() + !> north boundary ind. func (ie zmax) + integer, dimension(:,:), pointer :: chi_north => NULL() + !> south boundary ind. func (ie zmin) + integer, dimension(:,:), pointer :: chi_south => NULL() + !> east boundary ind. func (ie ymin) + integer, dimension(:,:), pointer :: chi_east => NULL() + !> west boundary ind. func (ie ymax) + integer, dimension(:,:), pointer :: chi_west => NULL() + !> upstream boundary ind. func (ie xmax) + integer, dimension(:,:), pointer :: chi_up => NULL() ! upstream + !> downstream boundary ind. func (ie xmin) + integer, dimension(:,:), pointer :: chi_down => NULL() ! downstream + !> + integer,parameter :: Down=1,Up=2,West=3,East=4,South=5,North=6 + !> Normal to each face of the control volume + real(mk),dimension(dime,2*dime) :: normal + !> A buffer for force on control volume, used to save force value on previous time step + real(mk),dimension(dime)::bufferForce + !> normalisation factor used to compute the drag in the Noca's way + real(mk) :: coef + real(mk),parameter :: uinf=1.0 + + ! temp to avoid ppm dependence + integer, parameter :: nsublist = 1 + + +contains + + !> compute chi functions for penalization at the boundaries to enforce dirichlet conditions on zmin and zmax + subroutine init_obstacles(resolution,step,lower,upper,center,radius,layer,coordMin) + !> Number of points in each dir + integer, dimension(dime), intent(in) :: resolution + !> Grid steps sizes + real(mk), dimension(dime), intent(in) :: step + !> Dimensions of the boundary layers + real(mk), dimension(dime), intent(in) :: upper,lower + !> position of the center of the sphere + real(mk),dimension(dime),intent(in):: center + !> Radius of the sphere + real(mk),intent(in) :: radius + !> Boundary layer thickness + real(mk), intent(in) :: layer + !> Coordinates of the lowest point of the local domain + real(mk),dimension(dime),intent(in) :: coordMin + + integer, dimension(:,:), allocatable :: tmp_boundary,tmp_sphere + integer::istat,i,j,k + real(mk),dimension(dime) :: coords + real(mk) :: dist + integer :: sizeMaxChi,count_boundary,count_sphere + real :: layerMin,layerMax + sizeMaxChi = product(resolution) + allocate(tmp_boundary(dime,sizeMaxChi),stat=istat) + allocate(tmp_sphere(dime,sizeMaxChi),stat=istat) + + layerMin = lower(c_Z) + layer + layerMax = upper(c_Z) - layer + + if(istat.ne.0) stop 'Chi-boundaries function allocation error.' + count_boundary=0 + count_sphere =0 + do k=1,resolution(c_Z) + coords(c_Z)=coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y) + coords(c_Y)=coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X) + coords(c_X)=coordMin(c_X) + (i-1)*step(c_X) + if( (coords(c_Z)>layerMax).or.(coords(c_Z)<layerMin)) then + count_boundary=count_boundary+1 + tmp_boundary(c_X,count_boundary)=i + tmp_boundary(c_Y,count_boundary)=j + tmp_boundary(c_Z,count_boundary)=k + end if + dist = dot_product(coords-center,coords-center) - radius**2 + if(dist <=0.0) then ! We are on or in the sphere ... + count_sphere=count_sphere+1 + tmp_sphere(c_X,count_sphere)=i + tmp_sphere(c_Y,count_sphere)=j + tmp_sphere(c_Z,count_sphere)=k + end if + end do + end do + end do + allocate(chi_boundary(dime,count_boundary)) + chi_boundary=tmp_boundary(:,1:count_boundary) + allocate(chi_sphere(dime,count_sphere)) + chi_sphere=tmp_sphere(:,1:count_sphere) + + deallocate(tmp_boundary,tmp_sphere) + + end subroutine init_obstacles + + !> Compute indicator functions for the control box (including a sphere ...) + ! This routine must fill all chi functions in + !> \param box_min coordinate of the lower point of the box + !> \param boxMax coordinate of the upper point of the box + !! We suppose (require) that boxMin+boxMax corresponds to grid points ... + subroutine compute_control_box(resolution,step,boxMin,boxMax,center,radius,coordMin) + !> Number of points in each dir (1st index) for each sub (2nd index) + integer, dimension(dime),intent(in) :: resolution + !> Grid steps sizes + real(mk), dimension(dime), intent(in) :: step + !> lower point of the box + real(mk),dimension(dime),intent(in) :: boxMin + !> upper point of the box + real(mk),dimension(dime),intent(in) :: boxMax + !> position of the center of the sphere + real(mk),dimension(dime),intent(in):: center + !> radius of the sphere + real(mk),intent(in) :: radius + !> Lower point of the domain + real(mk),dimension(dime),intent(in) :: coordMin + + logical,dimension(dime) :: isMinIn,isMaxIn + real(mk),dimension(dime) :: coordMax,coords + + integer, dimension(2*dime) :: ind + integer, dimension(2*dime) :: nbPoints + ! Size (number of points in each dir) of the control volume + integer(kind=8), dimension(dime) :: boxDim + real(mk) :: coord,dist + integer :: count,i,j,k,direction,count_box + integer(kind=8) :: nbPointsBox + integer,dimension(:,:),allocatable :: tmp_box + + !> radius of the sphere + real(mk) :: radiusBis + + ! Add an assert to check that the sphere radius is shorter thant the box size ... + radiusBis=radius!-step(c_Z) + ! First compute normals to the box boundaries + normal(:,:)=0.0 + normal(c_X,Up)=1.0 + normal(c_X,Down)=-1.0 + normal(c_Y,West)=-1.0 + normal(c_Y,East)=1.0 + normal(c_Z,North)=1.0 + normal(c_Z,South)=-1.0 + ! Coordinates of the upper point + coordMax(:)=coordMin(:)+(resolution(:)-1)*step(:) + ! First : check if box boundaries are in the current domain + isMaxIn=.False. + isMinIn=.False. + where(coordMin <= boxMin) isMinIn=.True. ! Lower boundaries + where(coordMax >= boxMax) isMaxIn=.True. ! Upper boundaries + + !! Look for local indices corresponding to the box boundaries (i.e. x,y,z = boxMin() and boxMax()) + ! index order: Down,Up,West,East,South,North + ind=0 ! + where(isMinIn(:).and.isMaxIn(:)) + ind(1:2*dime:2)=1 + ind(2:2*dime:2)=1 + end where + where((.not.isMinIn(:)).and.(isMaxIn(:))) + ind(1:2*dime:2)=1 + ind(2:2*dime:2)=1 + end where + where((isMinIn(:)).and.(.not.isMaxIn(:))) + ind(1:2*dime:2)=1 + ind(2:2*dime:2)=resolution(:) + end where + + do direction=1,dime + do k=1,resolution(direction) + coord=coordMin(direction)+(k-1)*step(direction) + if(isMinIn(direction)) then + if(coord<boxMin(direction)) ind(2*direction-1)=k+1 + end if + if(isMaxIn(direction)) then + if(coord<boxMax(direction)) then + ind(2*direction)=k+1 + else + exit + end if + end if + end do + end do + ! ind now contains the number of the points that are on the box boundary, in each direction, in the following order : + ! ind(Down Up West East South North) + + ! Remove last point to integrate properly ... + ind(2:2*dime:2)=ind(2:2*dime:2)-1 + + ! Count the number of points on each face and inside the domain + nbPoints=0 + if(isMinIn(1)) nbPoints(Down)=(ind(East)-ind(West)+1)*(ind(North)-ind(South)+1) + if(isMaxIn(1)) nbPoints(Up)=(ind(East)-ind(West)+1)*(ind(North)-ind(South)+1) + if(isMinIn(3)) nbPoints(South)=(ind(East)-ind(West)+1)*(ind(Up)-ind(Down)+1) + if(isMaxIn(3)) nbPoints(North)=(ind(East)-ind(West)+1)*(ind(Up)-ind(Down)+1) + if(isMinIn(2)) nbPoints(East)=(ind(Up)-ind(Down)+1)*(ind(North)-ind(South)+1) + if(isMaxIn(2)) nbPoints(West)=(ind(Up)-ind(Down)+1)*(ind(North)-ind(South)+1) + + boxDim(c_X)=ind(Up)-ind(Down)+1 + boxDim(c_Y)=ind(East)-ind(West)+1 + boxDim(c_Z)=ind(North)-ind(South)+1 + nbPointsBox = boxDim(c_X)*boxDim(c_Y)*boxDim(c_Z) + + allocate(tmp_box(dime,nbPointsBox)) + allocate(chi_up(dime,nbPoints(Up)),chi_down(dime,nbPoints(Down)),chi_east(dime,nbPoints(East)),chi_west(dime,nbPoints(West))) + allocate(chi_south(dime,nbPoints(South)),chi_north(dime,nbPoints(North))) + count_box=0 + + if(all(boxDim>0)) then + do k=ind(South),ind(North) + coords(c_Z) = coordMin(c_Z)+(k-1)*step(c_Z) + do j=ind(West),ind(East) + coords(c_Y) = coordMin(c_Y)+(j-1)*step(c_Y) + do i=ind(Down),ind(Up) + coords(c_X) = coordMin(c_X)+(i-1)*step(c_X) + dist = dot_product(coords-center,coords-center) - radiusBis**2 + if(dist >=0.0) then ! We are on or outside the sphere ... + count_box = count_box+1 + tmp_box(c_X,count_box)=i + tmp_box(c_Y,count_box)=j + tmp_box(c_Z,count_box)=k + end if + end do + end do + end do + end if + allocate(chi_box(dime,count_box)) + chi_box=tmp_box(:,1:count_box) + + deallocate(tmp_box) + if(isMinIn(3)) then ! South boundary + count=1 + chi_south(3,:)=ind(South) + do j=ind(West),ind(East) + do i=ind(Down),ind(Up) + chi_south(1,count)=i + chi_south(2,count)=j + count=count+1 + end do + end do + end if + if(isMinIn(2)) then ! East boundary + count=1 + chi_east(2,:)=ind(East)+1 + do k=ind(South),ind(North) + do i=ind(Down),ind(Up) + chi_east(1,count)=i + chi_east(3,count)=k + count=count+1 + end do + end do + end if + if(isMinIn(1)) then ! Downstream boundary is in the domain + count=1 + chi_down(1,:)=ind(Down) + do k=ind(South),ind(North) + do j=ind(West),ind(East) + chi_down(2,count)=j + chi_down(3,count)=k + count=count+1 + end do + end do + end if + + if(isMaxIn(3)) then ! North boundary is in the domain + count=1 + chi_north(3,:)=ind(North)+1 + do j=ind(West),ind(East) + do i=ind(Down),ind(Up) + chi_north(1,count)=i + chi_north(2,count)=j + count=count+1 + end do + end do + end if + if(isMaxIn(2)) then ! West boundary is in the domain + count=1 + chi_west(2,:)=ind(West) + do k=ind(South),ind(North) + do i=ind(Down),ind(Up) + chi_west(1,count)=i + chi_west(3,count)=k + count=count+1 + end do + end do + end if + if(isMaxIn(1)) then ! Upstream boundary is in the domain + count=1 + chi_up(1,:)=ind(Up)+1 + do k=ind(South),ind(North) + do j=ind(West),ind(East) + chi_up(2,count)=j + chi_up(3,count)=k + count=count+1 + end do + end do + end if + + bufferForce = 0.0 + ! Compute coef used to calculate the drag in the Nocas's way + coef = 2./(uinf**2*pi*radius**2) + + end subroutine compute_control_box + + + !> Set input field to one on the control volume boundaries and to zero elsewhere + subroutine compute_test(testfield,chi) + real(mk), dimension(:,:,:),pointer:: testfield + integer,dimension(:,:),pointer ::chi + integer :: k + do k=1,size(chi,2) + testfield(chi(1,k),chi(2,k),chi(3,k)) = 1.0 + end do + end subroutine compute_test + + !> Computation of the drag according to "method B" presented in + !! Noca99 or Plouhmans, 2002, Journal of Computational Physics + subroutine nocaForces(force,velo,vort,nu,coordMin,step,dt,dvol) + + !> The force to be computed + real(mk), dimension(dime),intent(inout) :: force + !! velocity and vorticity fields, intent(in) + real(mk), dimension(:,:,:,:,:),pointer :: velo,vort + !> viscosity + real(mk),intent(in)::nu + !! Coordinates of the lowest point in the domain + real(mk),dimension(dime),intent(in):: coordMin + !! mesh step sizes + real(mk),dimension(dime),intent(in)::step + !> Time step + real(mk),intent(in)::dt + !> element. vol + real(mk),intent(in) ::dvol + ! Surface element + real(mk) :: dsurf + real(mk),dimension(dime)::localForce + integer :: info + localForce=0.0 + force=0.0 + + ! Downstream and upstream surface + dsurf=step(c_Y)*step(c_Z) + call integrateOnSurface(localForce,velo,vort,chi_down,normal(:,Down),c_X,nu,dsurf,coordMin,step) + call integrateOnSurface(localForce,velo,vort,chi_up,normal(:,Up),c_X,nu,dsurf,coordMin,step) + ! East and West + dsurf=step(c_X)*step(c_Z) + call integrateOnSurface(localForce,velo,vort,chi_east,normal(:,East),c_Y,nu,dsurf,coordMin,step) + call integrateOnSurface(localForce,velo,vort,chi_west,normal(:,West),c_Y,nu,dsurf,coordMin,step) + ! North and south + dsurf=step(c_Y)*step(c_X) + call integrateOnSurface(localForce,velo,vort,chi_south,normal(:,South),c_Z,nu,dsurf,coordMin,step) + call integrateOnSurface(localForce,velo,vort,chi_north,normal(:,North),c_Z,nu,dsurf,coordMin,step) + ! over the volume ... + call integrateOnBox(localForce,vort,chi_box,dvol,dt,coordMin,step) + + localForce=localForce*coef + !write(*,'(a,3f10.5)') ' drag local: ', localForce + call MPI_Reduce(localForce,force,dime,MPI_DOUBLE_PRECISION,MPI_SUM,0,MPI_COMM_WORLD,info) + + end subroutine nocaForces + + !> Return -1/(dime-1)*d/dt int_over_control_box coord X vorticity + subroutine integrateOnBox(force,vort,chi,dvol,dt,coordMin,step) + !! The force to be computed + real(mk), dimension(dime),intent(inout) :: force + !! vorticity fields, intent(in) + real(mk), dimension(:,:,:,:,:),pointer :: vort + !! Indicator function of the box + integer, dimension(:,:), pointer :: chi + !! Element of volume + real(mk),intent(in)::dvol + !> Time step + real(mk),intent(in)::dt + !! Coordinates of the lowest point in the domain + real(mk),dimension(dime),intent(in):: coordMin + !! mesh step sizes + real(mk),dimension(dime),intent(in)::step + + ! coordinates of the current point + real(mk),dimension(dime) :: coords,int1 + ! local indices + integer :: i,j,k,ind + real(mk)::fact + fact = -dvol/((dime-1)*dt) + int1=0.0 + !! For all points in the box ... + do ind=1,size(chi,2) + i=chi(1,ind) + j=chi(2,ind) + k=chi(3,ind) + ! coordinates of the current point + coords = coordMin + (chi(:,ind)-1)*step + !! part1 of the force + int1=int1+cross_prod(coords,vort(:,i,j,k,nsublist)) + end do + force = force + fact*(int1-bufferForce) + bufferForce = int1 ! Save for next time step ... + end subroutine integrateOnBox + + !> Compute integrals on surface to calculate forces acting on the body. + !! See (2.1) of Noca 1999 or (52) of Plouhmans 2002 + !! Integrals on the sphere are neglected. + subroutine integrateOnSurface(force,velo,vort,chi,NormalVec,direction,nu,dsurf,coordMin,step) + !! The force to be computed + real(mk), dimension(dime),intent(inout) :: force + !! velocity and vorticity fields, intent(in) + real(mk), dimension(:,:,:,:,:),pointer :: velo,vort + !! Indicator function of the considered face, intent(in) + integer, dimension(:,:), pointer :: chi + !! Normal to the considered face (dir : to the outside of the volume) + real(mk), dimension(dime),intent(in) :: NormalVec + !! index of the non-null coordinate in normal, must be c_X,c_Y or c_Z + integer,intent(in) :: direction + !! viscosity + real(mk),intent(in)::nu + !! Element of surface + real(mk),intent(in)::dsurf + !! Coordinates of the lowest point in the domain + real(mk),dimension(dime),intent(in):: coordMin + !! mesh step sizes + real(mk),dimension(dime),intent(in)::step + + !! Some local values ... + real(mk) :: u_u,n_u,n_w,fact + integer :: i,j,k,ind + !! local coordinates + real(mk), dimension(dime) :: coords + real(mk), dimension(dime) :: int1,int2,nDivT,diff_dir,buffer + + fact = 1./(dime-1) + ! For each point of the current plane ... + int1=0.0 + int2=0.0 + diff_dir=0.0 + do ind=1,size(chi,2) + i=chi(1,ind) + j=chi(2,ind) + k=chi(3,ind) + !! part1 = 1/2(velocity.velocity)n - (n.velocity)velocity - 1/(dime-1)((n.velocity)(coord X vorticity) + (n.vorticity)(coord X velocity) + ! 0.5*velocity.velocity + u_u=dot_product(velo(:,i,j,k,nsublist),velo(:,i,j,k,nsublist)) + ! normal.velocity + n_u=dot_product(velo(:,i,j,k,nsublist),NormalVec(:)) + ! normal.vorticity + n_w=dot_product(vort(:,i,j,k,nsublist),NormalVec(:)) + ! coordinates of the current point + coords = coordMin + (chi(:,ind)-1)*step + !! part1 of the force + int1=int1+0.5*u_u*NormalVec(:)-n_u*velo(:,i,j,k,nsublist)& + - fact*n_u*cross_prod(coords,vort(:,i,j,k,nsublist))& + + fact*n_w*cross_prod(coords,velo(:,i,j,k,nsublist)) + + !! part 2 of the force, the one concerning T = nu(nabla u + nabla uT) + !! Considering that the box is a parallepiped, each normal is equal to something like 1 0 0 + !! and the integral simplifies in : + !! n.T = nabla velocity_dir + d/ddir velocity, dir being the dir of the normal, + !! n X nabla.T = function(laplacian of the velocity components) + nDivT = 0.0 ! n X nabla.T + + if(direction==c_X) then ! face = Down or Up, d/dx + diff_dir = diffX(velo,i,j,k,step(direction),nsublist) + nDivT(2) = -laplacian(velo,c_Z,i,j,k,step,nsublist) ! Laplacian of velocity_y + nDivT(3) = laplacian(velo,c_Y,i,j,k,step,nsublist) ! Laplacian of velocity_z + else if(direction==c_Y) then ! face = East or West, d/dy + diff_dir = diffY(velo,i,j,k,step(direction),nsublist) + nDivT(3)=-laplacian(velo,c_X,i,j,k,step,nsublist) ! Laplacian of velocity_x + nDivT(1)=laplacian(velo,c_Z,i,j,k,step,nsublist) ! Laplacian of velocity_z + else if(direction==c_Z) then ! face = North or South, d/dz + diff_dir = diffZ(velo,i,j,k,step(direction),nsublist) + nDivT(2)=laplacian(velo,c_X,i,j,k,step,nsublist) ! Laplacian of velocity_x + nDivT(1)=-laplacian(velo,c_Y,i,j,k,step,nsublist) ! Laplacian of velocity_y + end if + buffer=nabla(velo,direction,i,j,k,step,nsublist) + diff_dir + fact*cross_prod(coords,nDivT) + buffer=NormalVec(direction)*nu*buffer + int2=int2+buffer + + end do + + ! Product with element of surface and sum to the total (input) force + force = force+(int1+int2)*dsurf + end subroutine integrateOnSurface + + !> get memory allocated for indicator sets + function getMemoryForIndicators() + real(mk) :: getMemoryForIndicators + + getMemoryForIndicators = sizeof(chi_boundary)+sizeof(chi_sphere)+sizeof(chi_box)+sizeof(chi_north)& + + sizeof(chi_west)+sizeof(chi_east)+sizeof(chi_south)+sizeof(chi_up)+sizeof(chi_down) + getMemoryForIndicators = getMemoryForIndicators*1e-6 + if(verbose) then + write(*,'(a,i3,a,f10.4,a)') & + '[',rank,'] memory used for indicator sets:', getMemoryForIndicators, ' MB.' + end if + + end function getMemoryForIndicators + +end module SetsIndicators diff --git a/HySoP/src/Unstable/TestFunctions.f90 b/HySoP/src/Unstable/TestFunctions.f90 new file mode 100755 index 000000000..2013ff527 --- /dev/null +++ b/HySoP/src/Unstable/TestFunctions.f90 @@ -0,0 +1,380 @@ +!> Functions used to compute fields values on the grid, for specific pre-defined cases. +module testsFunctions + + use client_data + implicit none + + real(mk) :: xref + integer :: np +contains + + !> Computes the analytical values for stream function, velocity and vorticity such that + !> \f{eqnarray*}{ rhs_{ex} &=& -\omega_{ex} = \Delta\psi_{ex} \\ vel_{ex} &=& \nabla \times \psi_{ex} \f} + !> \f{eqnarray*}{\nabla.\psi_{ex} &=& \nabla.\omega_{ex} = \nabla.vel_{ex} = 0.0 \\\nabla\times vel_{ex} &=& \omega_{ex} \f} + !> (see maple file) + subroutine poisson_analytic(resolution,step,coordMin,rhs_ex,vel_ex,psi_ex) + + !> the local resolution + integer, dimension(dime),intent(in) :: resolution + !> size of mesh step in each dir + real(mk), dimension(dime),intent(in) :: step + !> Coordinates of the local minimum point + real(mk),dimension(dime),intent(in) :: coordMin + ! rhs function values on the grid (i.e. -omega_ex) + real(mk), dimension(:,:,:,:), pointer :: rhs_ex + ! velocity function values on the grid + real(mk), dimension(:,:,:,:), pointer :: vel_ex + ! Stream function values on the grid + real(mk), dimension(:,:,:,:), pointer :: psi_ex + + + real(mk) :: x,y,z,cx,cy,cz,c2x,c2y,c2z,sx,sy,sz,s2x,s2y,s2z + integer :: i,j,k + real(mk) :: pi + + pi = 4.0*atan(1.0_mk) + + do k=1,resolution(c_Z) + z = coordMin(c_Z) + (k-1)*step(c_Z) + cz=cos(pi*z) + c2z=cos(2.*pi*z) + sz=sin(pi*z) + s2z=sin(2.*pi*z) + do j=1,resolution(c_Y) + y = coordMin(c_Y) + (j-1)*step(c_Y) + cy=cos(pi*y) + c2y=cos(2.*pi*y) + sy=sin(pi*y) + s2y=sin(2.*pi*y) + do i=1,resolution(c_X) + x = coordMin(c_X) + (i-1)*step(c_X) + cx=cos(pi*x) + c2x=cos(2.*pi*x) + sx=sin(pi*x) + s2x=sin(2.*pi*x) + + rhs_ex(1,i,j,k) = 8.*s2y*pi**2*s2z + rhs_ex(2,i,j,k) = 8.*s2x*pi**2*s2z + rhs_ex(3,i,j,k)= 8.*s2x*pi**2*s2y + + vel_ex(1,i,j,k) = 2.*s2x*pi*(c2y - c2z) + vel_ex(2,i,j,k) = 2.*s2y*pi*(c2z - c2x) + vel_ex(3,i,j,k) = 2.*s2z*pi*(c2x - c2y) + + psi_ex(1,i,j,k) = sy*sz + psi_ex(2,i,j,k) = sx*sz + psi_ex(3,i,j,k) = sx*sy + + end do + end do + end do + end subroutine poisson_analytic + + !> Init vorticity field on a grid, such that : + !> \f$ \omega(x,y,z) = \left[\begin{array}{c} 0 \\ -3z/(Lz^2) \\ 0 \end{array}\right]\f$ + subroutine init_vorticity(vorticity,resolution,step,coordMin,lower,upper) + + !> vorticity field + real(mk), dimension(:,:,:,:), pointer :: vorticity + !> the local mesh resolution + integer,dimension(dime),intent(in) :: resolution + !> size of mesh step in each dir + real(mk), dimension(dime),intent(in) :: step + !> Coordinates of the minimal point of the local domain + real(mk),dimension(dime),intent(in) :: coordMin + !> boundaries of the domain + real(mk),dimension(dime),intent(in):: upper,lower + integer :: i,j,k + real(mk) :: x,z,physicalDomainSize_Z + real(mk) :: coef + + physicalDomainSize_Z = (upper(c_Z)- lower(c_Z))/2. + vorticity = 0.0 + coef = -3./(physicalDomainSize_Z)**2 + + do k=1,resolution(c_Z) + z = coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y) + !y = coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X) + x = coordMin(c_X) + (i-1)*step(c_X) + !if( (z < upper(c_Z)).and.(z>lower(c_Z))) then + vorticity(c_Y,i,j,k) = cos(2.*pi*z)!)coef*z + !endif + end do + end do + end do + + + end subroutine init_vorticity + + !> Computes the analytical values for stream function, velocity and vorticity such that + !> \f{eqnarray*}{ rhs_{ex} &=& -\omega_{ex} = \Delta\psi_{ex} \\ vel_{ex} &=& \nabla \times \psi_{ex} \f} + !> \f{eqnarray*}{\nabla.\psi_{ex} &=& \nabla.\omega_{ex} = \nabla.vel_{ex} = 0.0 \\\nabla\times vel_{ex} &=& \omega_{ex} \f} + !> (see maple file) + subroutine rhs_analytic(resolution,step,coordMin,rhs_ex,velocity,vorticity,nu) + !> the local mesh resolution + integer,dimension(dime),intent(in) :: resolution + !> size of mesh step in each dir + real(mk), dimension(dime),intent(in) :: step + !> Coordinates of the minimal point of the local domain + real(mk),dimension(dime),intent(in) :: coordMin + ! rhs function values on the grid (i.e. -omega_ex) + real(mk), dimension(:,:,:,:), pointer :: rhs_ex,velocity,vorticity + !> viscosity + real(mk),intent(in) :: nu + + real(mk) :: x,y,z,cx,cy,cz,c2x,c2y,c2z,sx,sy,sz,s2x,s2y,s2z + integer :: i,j,k + + do k=1,resolution(c_Z) + z = coordMin(c_Z) + (k-1)*step(c_Z) + cz=cos(pi*z) + c2z=cos(2.*pi*z) + sz=sin(pi*z) + s2z=sin(2.*pi*z) + do j=1,resolution(c_Y) + y = coordMin(c_Y) + (j-1)*step(c_Y) + cy=cos(pi*y) + c2y=cos(2.*pi*y) + sy=sin(pi*y) + s2y=sin(2.*pi*y) + do i=1,resolution(c_X) + x = coordMin(c_X) + (i-1)*step(c_X) + cx=cos(pi*x) + c2x=cos(2.*pi*x) + sx=sin(pi*x) + s2x=sin(2.*pi*x) + + rhs_ex(1,i,j,k) = 32.*s2y*pi**4*s2z*(-2.*nu+c2x*c2y-c2x*c2z) + rhs_ex(2,i,j,k) = -32.*s2x*pi**4*s2z*(2.*nu-c2y*c2z+c2x*c2y) + rhs_ex(3,i,j,k) = 32.*s2x*pi**4*s2y*(-2.*nu+c2x*c2z-c2z*c2y) + + vorticity(1,i,j,k) = 8.*s2y*pi**2*s2z + vorticity(2,i,j,k) = 8.*s2x*pi**2*s2z + vorticity(3,i,j,k)= 8.*s2x*pi**2*s2y + + velocity(1,i,j,k) = 2.*s2x*pi*(c2y - c2z) + velocity(2,i,j,k) = 2.*s2y*pi*(c2z - c2x) + velocity(3,i,j,k) = 2.*s2z*pi*(c2x - c2y) + + + end do + end do + end do + end subroutine rhs_analytic + !> Test purpose function, + !> computes \f$ \omega(x,y,z) = \left[\begin{array}{c} 0 \\ 0 \\ 0.1 \end{array}\right]\f$ + !> and \f$ velocity(x,y,z) = \left[\begin{array}{c} 0 \\ 0 \\ 2.0 \end{array}\right]\f$ + subroutine test_particles(vorticity,velocity,resolution,step,coordMin) + + !> vorticity field + real(mk), dimension(:,:,:,:), pointer :: vorticity ,velocity + !> the local resolution + integer, dimension(dime),intent(in) :: resolution + !> size of mesh step in each dir + real(mk), dimension(dime),intent(in) :: step + !> Coordinates of the local minimum point + real(mk),dimension(dime),intent(in) :: coordMin + + integer :: i,j,k,l + real(mk) :: pi,x,y,z + + pi = 4.0*atan(1.0_mk) + vorticity = 0. + velocity = 0. + do k=1,resolution(c_Z) + z = coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y) + y = coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X) + x = coordMin(c_X) + (i-1)*step(c_X) + if( (x .eq.10*step(c_X)).and.(y.eq.0).and.(z.eq.xref)) then + do l=1,np + vorticity(3,i,j,k+l-1) = 0.1; + velocity(3,i,j,k+l-1) = 2.0 + enddo + endif + end do + end do + end do + xref = xref + step(c_Z) + !np = np +1 + end subroutine test_particles + + !> Test purpose function, + !> computes \f$ \omega(x,y,z) = \left[\begin{array}{c} cos(x) \\ cos(x) \\ cos(x) \end{array}\right]\f$ + subroutine test_vorticity(vorticity,resolution,step,coordMin,lower,upper) + ! vorticity field + real(mk), dimension(:,:,:,:), pointer :: vorticity + !> the local resolution + integer, dimension(dime),intent(in) :: resolution + !> size of mesh step in each dir + real(mk), dimension(dime),intent(in) :: step + !> Coordinates of the local minimum point + real(mk),dimension(dime),intent(in) :: coordMin + !> Boundaries coordinates + real(mk),dimension(dime),intent(in):: upper, lower + + integer :: i,j,k + real(mk) :: pi,x,y,z,physicalDomainSize_Z + real(mk) :: coef + + physicalDomainSize_Z = (upper(3)- lower(3))/2. + pi = 4.0*atan(1.0_mk) + vorticity = 0.0 + coef = -3./(physicalDomainSize_Z)**2 + do k=1,resolution(c_Z) + z = coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y) + y = coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X) + x = coordMin(c_X) + (i-1)*step(c_X) + vorticity(:,i,j,k) = cos(x) + end do + end do + end do + end subroutine test_vorticity + + + !> Compute flow through x = xmin surface, for the following stream function : + !> \f$ \psi(x,y,z) = \left[\begin{array}{c} 0 \\-U_{inf}z(1 - \frac{R^2}{z^2+x^2}) \\ 0 \end{array}\right] \f$ + !> i.e. + !> \f[ flowRate_{theo} = \left[ -U_{inf}length_y(z - \frac{R^2z}{z^2+x^2})\right]_{lower_z}^{upper_z}\f] + function requiredFlowRate3D(radius,length,lower,upper,uinf) + + !> sphere radius + real(mk),intent(in) :: radius + !> domain dimensions + real(mk),dimension(dime),intent(in) :: length + !> physical domain lower point + real(mk),dimension(dime),intent(in)::lower + !> physical domain upper point + real(mk),dimension(dime),intent(in)::upper + !> velocity inf + real(mk),intent(in) :: uinf + !> required flow rate + real(mk) :: requiredFlowRate3D + + real(mk) :: dom + ! position of the surface for flow rate computation + real(mk)::xPos + + xPos = lower(c_X) + dom = upper(c_Z)**2+xPos**2 + if(abs(dom) < epsilon(dom)) then ! if dom == 0 + requiredFlowRate3D = upper(c_Z) + else + requiredFlowRate3D = upper(c_Z)*(1.-radius**2/dom) + end if + dom = lower(c_Z)**2+xPos**2 + if(abs(dom) < epsilon(dom)) then + requiredFlowRate3D = requiredFlowRate3D - lower(c_Z) + else + requiredFlowRate3D = requiredFlowRate3D - lower(c_Z)*(1. - radius**2/dom) + end if + requiredFlowRate3D = requiredFlowRate3D * uinf *length(c_Y) + return + end function requiredFlowRate3D + + !> Compute flow through x = xmin surface, for the following stream function : + !> \f$ \psi(x,y,z) = \left[\begin{array}{c} 0 \\-U_{inf}z(1 - \frac{R^2}{z^2+x^2}) \\ 0 \end{array}\right] \f$ + !> i.e. + !> \f[ flowRate_{theo} = \left[ -U_{inf}length_y(z - \frac{R^2z}{z^2+x^2})\right]_{lower_z}^{upper_z}\f] + function requiredFlowRate2D(radius,lower,upper,uinf) + + !> sphere radius + real(mk),intent(in) :: radius + !> physical domain lower point + real(mk),dimension(dime),intent(in)::lower + !> physical domain upper point + real(mk),dimension(dime),intent(in)::upper + !> velocity inf + real(mk),intent(in) :: uinf + !> required flow rate + real(mk) :: requiredFlowRate2D + + real(mk) :: dom + ! position of the surface for flow rate computation + real(mk)::xPos + + xPos = lower(c_X) + dom = upper(c_Y)**2+xPos**2 + if(abs(dom) < epsilon(dom)) then ! if dom == 0 + requiredFlowRate2D = upper(c_Y) + else + requiredFlowRate2D = upper(c_Y)*(1.-radius**2/dom) + end if + dom = lower(c_Y)**2+xPos**2 + if(abs(dom) < epsilon(dom)) then + requiredFlowRate2D = requiredFlowRate2D - lower(c_Y) + else + requiredFlowRate2D = requiredFlowRate2D - lower(c_Y)*(1. - radius**2/dom) + end if + requiredFlowRate2D = requiredFlowRate2D * uinf + return + end function requiredFlowRate2D + + + subroutine Gaussian2D(field,resolution,step,coordMin,center) + + !> Field initialized with a Gaussian + real(mk), dimension(:,:,:), pointer :: field + !> Space step + real(mk), dimension(dime) :: step + !> local resolution + integer, dimension(dime) :: resolution + !> Coordinates of the lowest point in the current subdomain + real(mk),dimension(dime),intent(in) :: coordMin + !> + real(mk), dimension(dime),intent(in) :: center + + real(mk), parameter :: sigma = 0.2 + real(mk) :: expo + real(mk),dimension(dime) :: coord + integer :: i,j + + field = 0.0 + do j = 1,resolution(c_Y) + coord(c_Y) = coordMin(c_Y)+(j-1)*step(c_Y)-center(c_Y) + do i = 1, resolution(c_X) + coord(c_X) = coordMin(c_X) + (i-1)*step(c_X)-center(c_X) + expo=dot_product(coord,coord)*0.5/sigma**2 + field(i,j,:) = exp(-expo) + end do + end do + + end subroutine Gaussian2D + + subroutine Gaussian1D(field,resolution,step,coordMin,dir,shift) + + !> Field initialized with a Gaussian + real(mk), dimension(:,:,:), pointer :: field + !> Space step + real(mk), dimension(dime) :: step + !> local resolution + integer, dimension(dime) :: resolution + !> Coordinates of the lowest point in the current subdomain + real(mk),dimension(dime),intent(in) :: coordMin + !> + real(mk), intent(in) :: shift + !> Advection direction + integer, intent(in) :: dir + + real(mk), parameter :: sigma = 0.2 + real(mk) :: coord,coeff + integer :: i + + !coord(c_Y) = coordMin(c_Y) + (j-1)*step(c_Y) + coeff = 1./(sigma*sqrt(2.*pi)) + print * ,"shift",shift + field = 0. + do i = 1, resolution(dir) + coord = coordMin(dir) + (i-1)*step(dir)-shift + field(i,:,1) = coeff*exp(-0.5*(coord/sigma)**2.) + end do + + end subroutine Gaussian1D + + +end module testsFunctions diff --git a/HySoP/src/Unstable/callPPM.f90 b/HySoP/src/Unstable/callPPM.f90 new file mode 100644 index 000000000..d93422534 --- /dev/null +++ b/HySoP/src/Unstable/callPPM.f90 @@ -0,0 +1,98 @@ +!> temp module to call and test ppm functions. +module testPPM + + !------------------------------------------------------------------------- + ! Modules + !------------------------------------------------------------------------- +!!$ USE ppm_module_map +!!$ USE ppm_module_topo +!!$ USE ppm_module_loadbal +!!$ USE ppm_module_neighlist +!!$ USE ppm_module_ode +!!$ USE ppm_module_user_util +!!$ USE pse_global +!!$ USE pse_module_io +!!$ USE pse_module_comp + + use ppm_module_init + use ppm_module_substart + use ppm_module_substop + use ppm_module_finalize + use ppm_module_data + use mpi + + implicit none + +contains + + subroutine mult(A,x,sizeA) + real, dimension(:) :: A + real :: x + integer :: sizeA,j + + real*8, dimension(sizeA) :: B + + x = 3 + print *, "otot" + print *, A(1) + print *, "titi" + + do j=1,sizeA + B(j) =j + !! do i=1,sizeA + !! print *, A(i,j) +!!$ A(i,j) = x*A(i,j) + !!print *, A(j) + !!print *,'toto', B(j) + !!end do + end do + end subroutine mult + + subroutine init() + + real(8) :: t0 + integer :: info,size + integer :: ndim, tolexp, comm, debug, ppm_log_unit + integer, parameter :: MK = KIND(1.0D0) + + ndim = 3 + tolexp = -15 + comm = MPI_COMM_WORLD + debug = 2 + ppm_log_unit = 99 + + call MPI_Init(info) + if(info.ne.0) then + write(*,*) 'FAILED TO INITIALIZE MPI. ABORTING!' + end if + call MPI_COMM_SIZE(comm,size,info) + + ! PPM init. + !! This will: + !! - init the stdout, stderr, stdlog outputs + !! - check if MPI has been properly initialized + !! - fill comm, ppm_rank, ppm_nb_procs ... and MPI/ppm related values + !! - check and set dimension of the problem, precision and tolerance + !! - set MPI_PREC --> ppm_mpi_kind + !! - init proc speed array (ppm_proc_speed) + !! - reset topology counter + call ppm_init(ndim,MK,tolexp,comm,debug,info,ppm_log_unit,98,97) + + print *, "debug ", debug, " module debug", ppm_debug + + !! Display ... + call substart('testPPM',t0,info) + + !! Warning : display elapsed time since t0. + call substop ('testPPM', t0, info) + + !! Finalize + !! - deallocate lots of arrays ... + !! - call ppm_mesh_finalize --> deallocate mesh structures + call ppm_finalize(info) + + call MPI_FINALIZE(info) + + end subroutine init +end module testPPM + diff --git a/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp b/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp new file mode 100644 index 000000000..919a18e57 --- /dev/null +++ b/HySoP/src/interfaces/Fortran2Cpp/WrapC.hpp @@ -0,0 +1,10 @@ +#ifndef CWRAPPER_HPP +#define CWRAPPER_HPP + +typedef struct { + int length; + double* elements; +} C2FPtr; + + +#endif diff --git a/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 b/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 new file mode 100644 index 000000000..7748dd0c4 --- /dev/null +++ b/HySoP/src/interfaces/Fortran2Cpp/WrapFortran.f90 @@ -0,0 +1,35 @@ +module WrapFort + + use iso_c_binding + + implicit none + + public aliasF2C + + real(kind=8) :: ref + integer, parameter :: real_kind = kind(ref) + + !> A structure to bind C and fortran pointers + type, bind(C), public :: C2FPtr + integer (c_int) :: length + type (c_ptr) :: elements + end type C2FPtr + + logical, parameter :: NDEBUG = .TRUE. + +contains + + subroutine aliasF2C(vectorC, vectorF, length) + type(c_ptr),intent(inout) :: vectorC + integer(c_int), intent(out) :: length + real(kind=real_kind), pointer, dimension(:) :: vectorF + + if(.not.associated(vectorF) ) then + stop 'Error, input Fortran vector is not associated' + end if + length = size(vectorF) + vectorC = c_loc(vectorF(1)) + + end subroutine aliasF2C + +end module WrapFort diff --git a/HySoP/src/interfaces/ppm/ppm_wrapper.hpp b/HySoP/src/interfaces/ppm/ppm_wrapper.hpp new file mode 100644 index 000000000..85181449f --- /dev/null +++ b/HySoP/src/interfaces/ppm/ppm_wrapper.hpp @@ -0,0 +1,104 @@ +/** \file ppm_wrapper.hpp Interfaces to ppm (fortran) routines + */ +#ifndef PPMWRAPPER_HPP +#define PPMWRAPPER_HPP +#include"F2CMangle.hpp" +#include<mpi.h> +#include <cstring> + +/** Namespace for ppm functions and subroutines */ + +namespace PPM +{ + + extern "C" { + + //F2C_GLOBAL(pass,PASS); + // Init and close ppm + void F2C_MODULE(ppm_module_init,ppm_init, PPM_MODULE_INIT,PPM_INIT)(int*, int*,int*,int*,int*,int*,int*,int*,int*); + void F2C_MODULE(ppm_module_finalize, ppm_finalize,PPM_MODULE_FINALIZE,PPM_FINALIZE)(int&); + // Display functions + void F2C_MODULE(charfunctions, start, CHARFUNCTIONS, START)(double*,int*,char*,int ); + void F2C_MODULE(charfunctions, stop, CHARFUNCTIONS, stop)(double*,int*,char*,int ); + + void F2C_MODULE(testppm,mult,TESTPPM,MULT)(double*,double*,int*); + + // Topologies + // void F2C_MODULE(ppm_module_mktopo, ppm_mktopo, PPM_MODULE_MKTOPO,PPM_MKTOPO)(int*, double*, int*, + + void F2C_MODULE(modtest, cas1, MODTEST,CAS1)(double*); + void F2C_MODULE(modtest, cas2, MODTEST,CAS2)(double*); + void F2C_MODULE(modtest, cas3, MODTEST,CAS3)(double*); + void F2C_MODULE(modtest, cas4, MODTEST,CAS4)(double*); + void F2C_MODULE(modtest, cas5, MODTEST,CAS5)(double*); + void F2C_MODULE(modtest, cas6, MODTEST,CAS6)(double*); + void F2C_MODULE(modtest, application3, MODTEST,APPLICATION3)(); + // int F2C_MODULE(ppm_module_data,ppm_debug, PPM_MODULE_DATA,PPM_DEBUG); + } + + + /** A static class to call wrapped ppm functions */ + class wrapper + { + + static int _info; + + public : + + /** PPM initialization + \param problem dimension + \param precision for real numbers + \param exp tolerance + \param MPI comm + \param debug mode value + \param error status + \param log unit value for io + \param stderr unit value + \param stdout unit value + */ + static void init(int ndim, int MK,int tolexp, MPI::Intracomm& comm, int debug, int* info, int ppm_log_unit, int err, int out) + { + MPI_Fint Fcomm = MPI_Comm_c2f(comm); + F2C_MODULE(ppm_module_init,ppm_init, PPM_MODULE_INIT,PPM_INIT)(&ndim,&MK,&tolexp,&Fcomm,&debug,info,&ppm_log_unit,&err,&out); + } + + /** Terminates ppm library + \param[in,out] error status + */ + static void finalize(int& info) + { + F2C_MODULE(ppm_module_finalize, ppm_finalize,PPM_MODULE_FINALIZE,PPM_FINALIZE)(info); + } + + /** Wrapper to ppm substart function + @param[in] caller name + @param[in,out] cpu time when this function is called + @param[in] error status + */ + static void substart(std::string& msg, double* t0, int* info) + { + size_t size = msg.size()+1; + char * msgF = new char[size]; + strncpy(msgF, msg.c_str(),size); + F2C_MODULE(charfunctions, start, CHARFUNCTIONS, START)(t0,info,msgF,strlen(msgF)); + } + + /** Wrapper to ppm substopt function + @param[in] caller name + @param[in] cpu time when substart for this function has been called + @param[in] error status + */ + static void substop(std::string& msg, double* t0, int* info) + { + size_t size = msg.size()+1; + char * msgF = new char[size]; + strncpy(msgF, msg.c_str(),size); + F2C_MODULE(charfunctions, stop, CHARFUNCTIONS, STOP)(t0,info,msgF,strlen(msgF)); + } + + }; + +} + + +#endif diff --git a/HySoP/src/interfaces/ppm/wrap_ppm_topologies.f95 b/HySoP/src/interfaces/ppm/wrap_ppm_topologies.f95 new file mode 100644 index 000000000..a13e7dc1f --- /dev/null +++ b/HySoP/src/interfaces/ppm/wrap_ppm_topologies.f95 @@ -0,0 +1,54 @@ +!> Fortran 2003 interface to ppm routines related to topologies +module wrap_ppm_topologies + + use ppm_module_mktopo + use WrapFort + use ppm_module_data + + implicit none + +contains + + !> Purely geometry-based decompositions + subroutine create_topology_geom(dimPb, topoid, decomp, minPhys, maxPhys, bc, ghostsize) bind(C, name='createTopoG') + + integer(kind=c_int), intent(in) :: dimPb + integer(kind=c_int), intent(inout) :: topoid + integer(kind=c_int), intent(inout) :: decomp + !integer(kind=c_int), intent(in) :: assig + type(c_Ptr), intent(in), VALUE :: minPhys + type(c_Ptr), intent(in), VALUE :: maxPhys + type(c_Ptr), intent(in), VALUE :: bc + real(kind=real_kind), intent(in) :: ghostsize ! ghostsize is a real in ppm subroutine ... strange ... +! type(c_ptr), intent(inout) :: costPerProc + + + ! Local vars + integer :: info + ! integer :: nbProcs = 3 ! TODO : input arg + integer :: assig = ppm_param_assign_internal + real(kind=real_kind), pointer, dimension(:) :: cost => NULL() + real(kind=real_kind), pointer, dimension(:) ::min_phys => NULL(), max_phys => NULL() + integer, pointer, dimension(:) :: bcdef => NULL() + ! Wrap C pointers + call c_f_pointer (minPhys, min_phys, (/dimPb/)) + call c_f_pointer(maxPhys, max_phys, (/dimPb/)) + call c_f_pointer(bc, bcdef, (/dimPb/)) + decomp = ppm_param_decomp_cuboid + + ! If cost is already allocated + ! if(c_associated(costPerProc)) then + ! call c_f_pointer(costPerProc, cost, (/nbProcs/)) + ! end if + + ! We skip optional vars for the moment ... + call ppm_topo_mkgeom_d(topoid, decomp,assig, min_phys, max_phys, bcdef, ghostsize, cost, info) + + !call aliasF2C(costPerProc, cost, nbProcs) + + print *, "topoid ", topoid + + end subroutine create_topology_geom + + +end module wrap_ppm_topologies diff --git a/HySoP/src/ppmInterface/CMakeLists.txt b/HySoP/src/ppmInterface/CMakeLists.txt new file mode 100755 index 000000000..158812ec4 --- /dev/null +++ b/HySoP/src/ppmInterface/CMakeLists.txt @@ -0,0 +1,21 @@ + +find_package(PPMCore 1.2 REQUIRED) +include_directories(${PPMCore_INCLUDE_DIRS}) +set(LIBS ${LIBS} ${PPMCore_LIBRARY}) +if(VERBOSE_MODE) + message(STATUS "Found PPM version ${PPMCore_VERSION}: ${PPMCore_LIBRARY}") + message(STATUS "PPM headers location: ${PPMCore_INCLUDE_DIRS}") +endif(VERBOSE_MODE) + +# --- PPM Numerics --- +if(WITH_PPMNumerics) + find_package(PPMNumerics 1.2 REQUIRED) + include_directories(${PPMNumerics_INCLUDE_DIRS}) + set(LIBS ${LIBS} ${PPMNumerics_LIBRARY}) + if(VERBOSE_MODE) + message(STATUS "Found PPMNumerics version ${PPMNUmerics_VERSION}: ${PPMNumerics_LIBRARY}") + message(STATUS "PPMNumerics header location: ${PPMNumerics_INCLUDE_DIRS}") + endif(VERBOSE_MODE) +endif() + + diff --git a/HySoP/src/ppmInterface/Fields.f90 b/HySoP/src/ppmInterface/Fields.f90 new file mode 100755 index 000000000..31a752427 --- /dev/null +++ b/HySoP/src/ppmInterface/Fields.f90 @@ -0,0 +1,143 @@ +!> Declaration, allocation of all the fields on the grid. +module Fields + + use client_data + use mpi + use PPMFields + + implicit none + + !> Velocity + real(mk), dimension(:,:,:,:), pointer :: velocity => NULL() + !> Vorticity + real(mk), dimension(:,:,:,:), pointer :: vorticity =>NULL() + !> Vorticity (a scalar in the 2D case) + real(mk), dimension(:,:,:), pointer :: vorticity2D =>NULL() + !> Stream function - Test purpose. Useless if ppm fft solver works as it is supposed to ... + ! real(mk), dimension(:,:,:,:,:), pointer :: stream_function =>NULL() + !> rhs of vorticity eq (i.e. stretch + diffusion terms) + real(mk), dimension(:,:,:,:), pointer :: rhs =>NULL() + real(mk), dimension(:,:,:), pointer :: gauss =>NULL() + !> + !real(mk), dimension(:,:,:,:,:), pointer :: vel_ex => NULL() + !> Scalar on the grid, test purpose for chi functions + real(mk),dimension(:,:,:),pointer::testFunc=>NULL() + !> Scalar on the grid + real(mk),dimension(:,:,:),pointer::scalar=>NULL() + +contains + + !> Fields allocation. + !! Warning : ghostpoints must be included in field (i.e. size = "real size" + 2*number of ghostpoints) + subroutine initFields(resolution,ghostsize) + + !> Required resolution for the fields (without ghosts) + integer, dimension(dime), intent(in) :: resolution + !> number of ghost points in each direction (ghost(c_X) = 2 means resolution(c_X)+ 4 points for the field) + integer, dimension(:),pointer:: ghostsize + + integer::istat + ! Lower and upper bounds for fields + integer, dimension(dime) :: ldl, ldu + ! nsublist from ppm topo. Assumed to be equal to 1 see Topology.f90 + + ldl = 1 - ghostsize + ldu = resolution + ghostsize + + + if(dime==2) then + call initPPMFields2D(resolution,ghostsize) + velocity => PPMvelocity2D + vorticity2D => PPMvorticity2D + scalar => PPMscalar2D + allocate(gauss(ldl(c_X):ldu(c_X),ldl(c_Y):ldu(c_Y),1), stat = istat) + allocate(rhs(dime,ldl(c_X):ldu(c_X),ldl(c_Y):ldu(c_Y),1), stat = istat) + + else if(dime == 3) then + call initPPMFields3D(resolution,ghostsize) + velocity => PPMvelocity3D(:,:,:,:,1) + vorticity => PPMvorticity3D(:,:,:,:,1) + rhs => PPMrhs3D(:,:,:,:,1) + allocate(gauss(ldl(c_X):ldu(c_X),ldl(c_Y):ldu(c_Y),ldl(c_Z):ldu(c_Z)), stat = istat) + end if + + allocate(testFunc(resolution(c_X),resolution(c_Y),resolution(c_Z))) + + +!!$ ! Velocity ... +!!$ allocate(velocity(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist),stat = istat) +!!$ if(istat.ne.0) stop 'Field allocation error for velocity' +!!$ ! Vorticity +!!$ allocate(vorticity(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) +!!$ if(istat.ne.0) stop 'Field allocation error for vorticity' +!!$ ! rhs +!!$ allocate(rhs(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) + +!!$ if(istat.ne.0) stop 'Field allocation error for rhs' +!!$ +!!$ !allocate(stream_function(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) +!!$ !if(istat.ne.0) stop 'stream_function allocation error for rhs' + +!! allocate(testFunc(ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3)), stat = istat) + !! if(istat.ne.0) stop 'Field allocation error for testFunc' + ! Scalar + !allocate(scalar(ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) + !if(istat.ne.0) stop 'Field allocation error for scalar' + end subroutine initFields + + !> compute the size of the memory used to save fields + function getMemoryUsedForFields() + real(mk) :: getMemoryUsedForFields + getMemoryUsedForFields = sizeof(velocity)+sizeof(vorticity)+sizeof(rhs)+sizeof(testfunc)+sizeof(scalar) + getMemoryUsedForFields = getMemoryUsedForFields*1.e-6 + if(verbose) then + write(*,'(a,i3,a,f10.4,a)') & + '[',rank,'] Fields have been initialized. Memory used :', getMemoryUsedForFields, ' MB.' + end if + end function getMemoryUsedForFields + + !> Shift the velocity x component according to a required flow rate + !> \f[ velocity_x = velocity_x + shift \f] + !> with + !> \f[shift = \frac{reqFlowRate-currentFlowRate}{S_x} \f] + !> \f$S_x\f$ being the surface where x=xmin (incoming flow) + subroutine shiftVelocityX(reqFlowRate,step,resolution,surf,coordMin,lower) + !> Required flow rate + real(mk), intent(in) :: reqFlowRate + !> Grid step + real(mk), dimension(dime), intent(in) :: step + !> local resolution + integer,dimension(dime),intent(in) :: resolution + !> Area of the surface for integration + real(mk) ,intent(in) :: surf + !> Coordinates of the minimal point of the current domain + real(mk),dimension(dime),intent(in) :: coordMin + !> lower bound of the physical domain + real(mk),dimension(dime),intent(in) :: lower + + real(mk) :: localShift,globalShift + integer :: info + localShift = 0 + + ! We compute the current flow rate through surface x = xmin, for the x component of the velocity : + ! FlowRate = sum(surf x=xmin)( velocity(c_X) ) * step(c_Z)*step(c_Y) + ! And use this value to shift the velocity(c_X) to have : + ! RequiredFlowRate = FlowRate + Surf(x=xmin)*globalShift + + ! Step 1 : compute flowRate + if(abs(coordMin(c_X)-lower(c_X)) <= 2.*epsilon(globalShift) ) then + ! Compute mean value of the velocity through a face ortho. to x dir. + ! Warning: ghost points must be excluded + localShift = sum(velocity(c_X,1,1:resolution(c_Y)-1,1:resolution(c_Z)-1)) + end if + ! Step 2 : reduction over all mpi processus ... + call MPI_ALLReduce(localShift,globalShift,1,MPI_DOUBLE_PRECISION,MPI_SUM,MPI_COMM_WORLD,info) + ! Step 3 : set global shift + globalShift = (reqFlowRate-globalShift*step(c_Y)*step(c_Z))/surf + + ! Step 4 : update velocity(c_X) + velocity(c_X,:,:,:) = velocity(c_X,:,:,:) + globalShift + + end subroutine shiftVelocityX + +end module Fields diff --git a/HySoP/src/ppmInterface/PPMFields.f90 b/HySoP/src/ppmInterface/PPMFields.f90 new file mode 100755 index 000000000..bb2e45920 --- /dev/null +++ b/HySoP/src/ppmInterface/PPMFields.f90 @@ -0,0 +1,80 @@ +!> Declaration, allocation of all the fields on the grid. +module PPMFields + + use client_data + use client_topology, only: nsublist + + implicit none + + !> Velocity 3D (PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: PPMvelocity3D => NULL() + !> Velocity 2D (PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: PPMvelocity2D => NULL() + !> Vorticity 3D (PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: PPMvorticity3D => NULL() + !> Vorticity 2D (PPM-style storage) + real(mk), dimension(:,:,:), pointer :: PPMvorticity2D => NULL() + !> RHS 3D (PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: PPMrhs3D => NULL() + !> A Scalar on a 3D grid (PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: PPMscalar3D => NULL() + !> A Scalar on a 2D grid (PPM-style storage) + real(mk), dimension(:,:,:), pointer :: PPMscalar2D => NULL() + +contains + + !> Fields allocation. + !! Warning : ghostpoints must be included in field (i.e. size = "real size" + 2*number of ghostpoints) + subroutine initPPMFields3D(resolution,ghostsize) + + !> Required resolution for the fields (without ghosts) + integer, dimension(dime), intent(in) :: resolution + !> number of ghost points in each direction (ghost(c_X) = 2 means resolution(c_X)+ 4 points for the field) + integer, dimension(:),pointer:: ghostsize + + integer::istat + ! Lower and upper bounds for fields + integer, dimension(dime) :: ldl, ldu + ! nsublist from ppm topo. Assumed to be equal to 1 see Topology.f90 + + ldl = 1 - ghostsize + ldu = resolution + ghostsize + ! Velocity ... + allocate(PPMvelocity3D(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist),stat = istat) + if(istat.ne.0) stop 'Field allocation error for velocity (PPM)' + ! Vorticity + allocate(PPMvorticity3D(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) + if(istat.ne.0) stop 'Field allocation error for vorticity (PPM))' + ! rhs + allocate(PPMrhs3D(dime,ldl(1):ldu(1),ldl(2):ldu(2),ldl(3):ldu(3),nsublist), stat = istat) + if(istat.ne.0) stop 'Field allocation error for rhs (PPM))' + + end subroutine initPPMFields3D + + subroutine initPPMFields2D(resolution,ghostsize) + + !> Required resolution for the fields (without ghosts) + integer, dimension(dime), intent(in) :: resolution + !> number of ghost points in each direction (ghost(c_X) = 2 means resolution(c_X)+ 4 points for the field) + integer, dimension(:),pointer:: ghostsize + + integer::istat + ! Lower and upper bounds for fields + integer, dimension(dime) :: ldl, ldu + ! nsublist from ppm topo. Assumed to be equal to 1 see Topology.f90 + + ldl = 1 - ghostsize + ldu = resolution + ghostsize + ! Velocity ... + allocate(PPMvelocity2D(dime,ldl(1):ldu(1),ldl(2):ldu(2),1),stat = istat) + if(istat.ne.0) stop 'Field allocation error for velocity (PPM)' + ! Vorticity (a sacalar in 2D) + allocate(PPMvorticity2D(ldl(1):ldu(1),ldl(2):ldu(2),1), stat = istat) + if(istat.ne.0) stop 'Field allocation error for vorticity (PPM))' + ! Scalar + allocate(PPMscalar2D(ldl(1):ldu(1),ldl(2):ldu(2),1), stat = istat) + if(istat.ne.0) stop 'Field allocation error for scalar (PPM))' + + end subroutine initPPMFields2D + +end module PPMFields diff --git a/HySoP/src/ppmInterface/Particles.f90 b/HySoP/src/ppmInterface/Particles.f90 new file mode 100755 index 000000000..1b7b12b5f --- /dev/null +++ b/HySoP/src/ppmInterface/Particles.f90 @@ -0,0 +1,1445 @@ +!> Functions dealing with particles : +!> - initialisation, creation +!> - remesh and interpolation +!> - integration (push) +module Particles + + use ppm_module_rmsh, only : ppm_rmsh_create_part,ppm_interp_m2p, ppm_interp_p2m !, ppm_rmsh_remesh + use ppm_module_map_field_ghost, only:ppm_map_field_ghost_get!, ppm_map_field_ghost_put + use ppm_module_map_field, only : ppm_map_field_push,ppm_map_field_send,ppm_map_field_pop + use ppm_module_impose_part_bc + use client_data + use ppm_module_data, only : ppm_param_rmsh_kernel_mp4 + use ppm_module_map_part + use ppm_module_util_dbg + + implicit none + + private + + public initNSSolver_particles,getMemoryUsedForParticles,ScalarSolver_particles,init_parts,& + countAndCreateParticles, countAndUpdateParticles,PPMupdateParticles3D, PPMupdateParticles2D,& + freeParticles,createParticlesEverywhere,npart,RK4_2D,Ppmremesh2d,RK2_2D,PPMupdateParticles2DScalar,& + RK2_2DScalar,PPMremesh2DScalar,remesh2D,createParticlesEverywhereScalar,RK4_2Dscalar + + !> cutoff values (threshold for vorticity values for which particles are created) + real(mk), dimension(2) :: cutoff + !> Current number of particles + integer :: npart + !> Particles positions + real(mk), dimension(:,:), pointer :: xp=>NULL() + !> Particles strength (ie var carried by part, vorticity indeed) + real(mk), dimension(:,:), pointer :: omp=>NULL() + !> Particle velocities + real(mk), dimension(:,:), pointer :: velop=>NULL() + !> Particles RHS term + real(mk), dimension(:,:), pointer :: rhsp => NULL() + !> Particles scalar term + real(mk), dimension(:), pointer :: scalar_p => NULL() + !> Backup vector for RK schemes + real(mk), dimension(:,:), pointer :: buffer=>NULL(),buffer2=>NULL(),buffer3=>NULL() + + !> Size of buffer, i.e. more or less number of particles at the previous time step + integer :: buffer_size + !> Kernel for remesh ... + integer :: kernel + +contains + + subroutine ScalarSolver_particles(scalar,velocity,dt,topoid,meshid,ghostsize,resetpos,step,coordMin,resolution) + + !> Vorticity field, on the grid + real(mk),dimension(:,:,:),pointer :: scalar + !> Velocity field, on the grid + real(mk),dimension(:,:,:,:),pointer :: velocity + !> Current time step + real(mk),intent(in) :: dt + !> Current topo id + integer, intent(in) :: topoid + !> Current mesh id + integer, intent(in) :: meshid + !> Number of ghost points + integer, dimension(:),pointer:: ghostsize + !> bool to reset (or not) particles positions + logical, intent(in) :: resetpos + real(mk),dimension(dim3),intent(in) :: coordMin,step + integer, dimension(dim3),intent(in) :: resolution + !> Error status + integer :: dir + + do dir=1,dime + !call ppm_rmsh_create_part(topoid,meshid,xp,npart,scalar_p,scalar,cutoff,info,resetpos,& + ! field_wp=velocity,wp=velop,lda2=dime) + call reset_parts(scalar,resolution,coordMin,step) + write(*,'(a,i5,a,i8)') '[',rank,'] initialisation with ', npart,' particles' + ! Integrate + call push_split_particles(dir,dt,topoid,topoid,ghostsize,velocity,coordMin,step) + ! Remesh + call remesh_split_mp6(scalar,dir,step,coordMin) + + if(dir == c_X) then + scalar(-ghostsize(c_X)+1:ghostsize(c_X)+1,:,:) = scalar(-ghostsize(c_X)+1:ghostsize(c_X)+1,:,:) & + + scalar(resolution(c_X)-ghostsize(c_X):resolution(c_X)+ghostsize(c_X),:,:) + scalar(resolution(c_X)-ghostsize(c_X):resolution(c_X)+ghostsize(c_X),:,:) = scalar(-ghostsize(c_X)& + +1:ghostsize(c_X)+1,:,:) + else if(dir == c_Y) then + scalar(:,-ghostsize(c_Y)+1:ghostsize(c_Y)+1,:) = scalar(:,-ghostsize(c_Y)+1:ghostsize(c_Y)+1,:) & + + scalar(:,resolution(c_Y)-ghostsize(c_Y):resolution(c_Y)+ghostsize(c_Y),:) + scalar(:,resolution(c_Y)-ghostsize(c_Y):resolution(c_Y)+ghostsize(c_Y),:) = scalar(:,-ghostsize(c_Y)& + +1:ghostsize(c_Y)+1,:) + else + scalar(:,:,-ghostsize(c_Z)+1:ghostsize(c_Z)+1) = scalar(:,:,-ghostsize(c_Z)+1:ghostsize(c_Z)+1) & + + scalar(:,:,resolution(c_Z)-ghostsize(c_Z):resolution(c_Z)+ghostsize(c_Z)) + scalar(:,:,resolution(c_Z)-ghostsize(c_Z):resolution(c_Z)+ghostsize(c_Z)) = scalar(:,:,-ghostsize(c_Z)& + +1:ghostsize(c_Z)+1) + end if + end do + ! Ghost values for vorticity +!!$ call ppm_map_field_ghost_get(topoid,meshid,ghostsize,info) +!!$ call ppm_map_field_push(topoid,meshid,scalar,info) +!!$ call ppm_map_field_send(info) +!!$ call ppm_map_field_pop(topoid,meshid,scalar,ghostsize,info) + + end subroutine ScalarSolver_particles + + subroutine init_parts(scalar,velocity,resolution,coordMin,step) + real(mk),dimension(:,:,:), pointer :: scalar + real(mk),dimension(:,:,:,:),pointer :: velocity + real(mk),dimension(dim3),intent(in)::coordMin,step + integer, dimension(dim3),intent(in)::resolution + + integer :: i,j,k,current_part + real(mk),dimension(dim3) :: coord + + current_part = 1 + npart = product(resolution-1) + allocate(xp(dime,npart),velop(dime,npart),scalar_p(npart),buffer(dime,npart)) + do k=1,resolution(c_Z)-1 + coord(c_Z) = coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y)-1 + coord(c_Y) = coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X)-1 + coord(c_X) = coordMin(c_X) + (i-1)*step(c_X) + xp(:,current_part) = coord(:) + velop(:,current_part) = velocity(:,i,j,k) + scalar_p(current_part) = scalar(i,j,k) + current_part = current_part + 1 + + end do + end do + end do + + + endsubroutine init_parts + + subroutine reset_parts(scalar,resolution,coordMin,step) + + real(mk),dimension(:,:,:), pointer :: scalar + real(mk),dimension(dime),intent(in)::coordMin,step + integer, dimension(dime),intent(in)::resolution + + integer :: i,j,k,current_part + real(mk),dimension(dim3) :: coord + + current_part = 1 + do k=1,resolution(c_Z)-1 + coord(c_Z) = coordMin(c_Z) + (k-1)*step(c_Z) + do j=1,resolution(c_Y)-1 + coord(c_Y) = coordMin(c_Y) + (j-1)*step(c_Y) + do i=1,resolution(c_X)-1 + coord(c_X) = coordMin(c_X) + (i-1)*step(c_X) + xp(:,current_part) = coord(:) + scalar_p(current_part) = scalar(i,j,k) + current_part = current_part + 1 + end do + end do + end do + + endsubroutine reset_parts + + + !> Set required parameters for particles creations + subroutine initNSSolver_particles() + + ! Cutoff : lower and upper bound for cutoff, i.e. for each value of the ref. field between cutoff(1) and cutoff(2), a particle will be + ! created. + cutoff(1) = 1.d-8 + cutoff(2) = 1e9!00000 + kernel = ppm_param_rmsh_kernel_mp4 + npart = 0 + buffer_size = npart + end subroutine initNSSolver_particles + + + + !> PPM-based creation/update of particles distribution + subroutine PPMupdateParticles3D(field_on_grid,resetpos,topoid,meshid,vel) + !> The field used to create particles (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: field_on_grid + !> true to reset distribution else false + logical, intent(in) :: resetpos + !> topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer :: info + !> velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: vel + info = 0 + + ! --------> The following call will allocate memory for xp, omp and velop + ! --------> And deallocation will be handled by ppm. (?) + ! --------> Other variables carried by particles but not allocated during ppm_rmsh_create call + ! --------> is there a better way to do this, with map_push or other ppm routines? No according to Omar. + ! Call ppm func to create the particles distribution + call ppm_rmsh_create_part(topoid,meshid,xp,npart,omp,dime,field_on_grid,cutoff,info,resetpos,& + field_wp=vel,wp=velop,lda2=dime) + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + !if(associated(xp)) print *, "xp shape:", rank, " ", shape(xp), npart + ! --------> Ok, from here all vars carried by particles must have the following shape : dime,npart + !> --------> mesh to particles for velocity => done in ppm_rmsh_create_part + ! call ppm_interp_m2p(topoid, meshid, xp, npart, velop, dime, kernel, ghostsize, vel,info) + ! print *, 'End of update particles' + + end subroutine PPMupdateParticles3D + + subroutine PPMupdateParticles2DScalar(field_on_grid,resetpos,topoid,meshid,vel) + !> The field used to create particles (must be in PPM-style storage) + real(mk), dimension(:,:,:), pointer :: field_on_grid + !> true to reset distribution else false + logical, intent(in) :: resetpos + !> topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer :: info,i + !> velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + info = 0 + + ! --------> The following call will allocate memory for xp, omp and velop + ! --------> And deallocation will be handled by ppm. (?) + ! --------> Other variables carried by particles but not allocated during ppm_rmsh_create call + ! --------> is there a better way to do this, with map_push or other ppm routines? No according to Omar. + ! Call ppm func to create the particles distribution + call ppm_rmsh_create_part(topoid,meshid,xp,npart,scalar_p,field_on_grid,cutoff,info,.true.,& + field_wp=vel,wp=velop,lda2=dime) + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + open(45,file="omp") ! Output only for one process + do i = 1,npart + write(45,'(3(11e14.5))') xp(c_X,i),scalar_p(i) + end do + close(45) + + + !if(associated(xp)) print *, "xp shape:", rank, " ", shape(xp), npart + ! --------> Ok, from here all vars carried by particles must have the following shape : dime,npart + !> --------> mesh to particles for velocity => done in ppm_rmsh_create_part + ! call ppm_interp_m2p(topoid, meshid, xp, npart, velop, dime, kernel, ghostsize, vel,info) + ! print *, 'End of update particles' + + end subroutine PPMupdateParticles2DScalar + + subroutine PPMupdateParticles2D(field_on_grid,resetpos,topoid,meshid,vel) + !> The field used to create particles (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: field_on_grid + !> true to reset distribution else false + logical, intent(in) :: resetpos + !> topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer :: info + !> velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + info = 0 + + ! --------> The following call will allocate memory for xp, omp and velop + ! --------> And deallocation will be handled by ppm. (?) + ! --------> Other variables carried by particles but not allocated during ppm_rmsh_create call + ! --------> is there a better way to do this, with map_push or other ppm routines? No according to Omar. + ! Call ppm func to create the particles distribution + call ppm_rmsh_create_part(topoid,meshid,xp,npart,omp,dime,field_on_grid,cutoff,info,resetpos,& + field_wp=vel,wp=velop,lda2=dime) + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + !if(associated(xp)) print *, "xp shape:", rank, " ", shape(xp), npart + ! --------> Ok, from here all vars carried by particles must have the following shape : dime,npart + !> --------> mesh to particles for velocity => done in ppm_rmsh_create_part + ! call ppm_interp_m2p(topoid, meshid, xp, npart, velop, dime, kernel, ghostsize, vel,info) + ! print *, 'End of update particles' + + end subroutine PPMupdateParticles2D + + !> time integration + !> Advection of particles, more or less a copy of Adrien's code. + subroutine push_particles(dt,topoid,meshid,ghostsize,vel,rhs) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer:: ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: vel + ! Secondary field to be mapped to particles (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: rhs + + ! Compute new particles positions ... + ! Integrate ... ===> update omp + ! Todo: switch process between the different methods, leaded by a user-defined var? Later ... + ! call runge_kutta_2(dt,topoid,meshid,ghostsize,vel,rhs) + call RK4_3D(dt,topoid,meshid,ghostsize,vel,rhs) + end subroutine push_particles + + subroutine PPMremesh3D(topoid,meshid,ghostsize,field) + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer :: ghostsize + ! vorticity on grid, (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: field + + integer info + info = -1 + !call ppm_dbg_print_d(topoid,ghostlayer,1,1,info,xp,npart) + call ppm_interp_p2m(topoid,meshid,xp,npart,omp,dime,kernel,ghostsize,field,info) + if(info.ne.0) then + stop 'Particles: ppm remesh error ' + end if + end subroutine PPMremesh3D + + subroutine PPMremesh2D(topoid,meshid,ghostsize,field) + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer :: ghostsize + ! vorticity on grid, (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: field + + integer info + info = -1 + !call ppm_dbg_print_d(topoid,ghostlayer,1,1,info,xp,npart) + call ppm_interp_p2m(topoid,meshid,xp,npart,omp,dime,kernel,ghostsize,field,info) + if(info.ne.0) then + stop 'Particles: ppm remesh error ' + end if + end subroutine PPMremesh2D + subroutine PPMremesh2DScalar(topoid,meshid,ghostsize,field) + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer :: ghostsize + ! vorticity on grid, (must be in PPM-style storage) + real(mk), dimension(:,:,:), pointer :: field + + integer info + info = -1 + !call ppm_dbg_print_d(topoid,ghostlayer,1,1,info,xp,npart) + call ppm_interp_p2m(topoid,meshid,xp,npart,scalar_p,kernel,ghostsize,field,info) + if(info.ne.0) then + stop 'Particles: ppm remesh error ' + end if + end subroutine PPMremesh2DScalar + + !> Runge Kutta 2 for positions and 1 for vorticity + subroutine RK2_3D(dt,topoid,meshid,ghostsize,vel,rhs) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer:: ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: vel + ! Secondary field to be mapped to particles (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: rhs + + !> local loop indices + integer :: i,newNpart,k + integer :: info + + ! buffer must be of the same size as xp so if the number of particles has increased in comparison with previous step, + ! we reallocate secondary fields. + ! Note Franck : Either we allocate buffer at each time step or we reallocate only when buffer_size increase. + ! Since memory is our main problem, we allocate/deallocate at each time step, for the moment. + ! if(buffer_size.lt.npart) then + ! deallocate(buffer) + allocate(buffer(dime,npart)) + buffer_size = npart + + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+0.5*dt*velop(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + ! call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + ! if(size(rhsp,2).lt.npart) then + ! deallocate(rhsp) + allocate(rhsp(dime,npart)) + ! end if +!! print *, 'max min omp start', maxval(omp),minval(omp),maxval(rhsp),minval(rhsp) + + !! Mesh to particles for the new particles positions ... + !> for velocity + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + !> for rhs of vorticity eq. + call ppm_interp_m2p(topoid,meshid,xp,npart,rhsp,dime,kernel,ghostsize,rhs,info) + ! Update positions according to the new velocity and vorticity with new rhs + + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+dt*velop(k,i) + omp(k,i)=omp(k,i)+dt*rhsp(k,i) + end do + end do +!! print *, 'max min omp stop', maxval(omp),minval(omp), maxval(rhsp),minval(rhsp) + + ! Free memory as soon as possible ... + deallocate(buffer,rhsp) + ! Vorticity mapping ... + newNpart = 0 + + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + + end subroutine RK2_3D + + !> Runge Kutta 4 + subroutine RK4_3D(dt,topoid,meshid,ghostsize,vel,rhs) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer::ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: vel + ! Secondary field to be mapped to particles (must be in PPM-style storage) + real(mk), dimension(:,:,:,:,:), pointer :: rhs + + !> local loop indices + integer :: i, newNpart,k + real(mk) :: alpha + !> error status + integer :: info + ! buffer is used to save intermediate values for xp and omp, thus buffersize=2*npart + + allocate(buffer(dime,npart),buffer2(dime,npart),buffer3(dime,npart),rhsp(dime,npart)) + buffer_size=npart + + !> Compute current rhs on particles + call ppm_interp_m2p(topoid,meshid,xp,npart,rhsp,dime,kernel,ghostsize,rhs,info) + ! First RK stage + ! Velocity is up to date, following the call to update_particles + alpha=0.5*dt + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=velop(k,i) + buffer3(k,1)=rhsp(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + ! call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_push(buffer3,dime,npart,info) + call ppm_map_part_push(rhsp,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(rhsp,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer3,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + call ppm_interp_m2p(topoid,meshid,xp,npart,rhsp,dime,kernel,ghostsize,rhs,info) + + !! Second RK4 stage, with the updated velocity + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + buffer3(k,i)=buffer3(k,i)+2.*rhsp(k,i) + end do + end do + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_push(buffer3,dime,npart,info) + call ppm_map_part_push(rhsp,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(rhsp,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer3,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + call ppm_interp_m2p(topoid,meshid,xp,npart,rhsp,dime,kernel,ghostsize,rhs,info) + + !! Third RK4 stage + alpha=dt + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + buffer3(k,i)=buffer3(k,i)+2.*rhsp(k,i) + end do + end do + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_push(buffer3,dime,npart,info) + call ppm_map_part_push(rhsp,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(rhsp,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer3,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + call ppm_interp_m2p(topoid,meshid,xp,npart,rhsp,dime,kernel,ghostsize,rhs,info) + + !! Last RK4 stage + alpha=dt/6. + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*buffer2(k,i)+alpha*velop(k,i) + omp(k,i)=omp(k,i)+alpha*buffer3(k,i)+alpha*rhsp(k,i) + end do + end do + + ! Free memory as soon as possible ... + deallocate(buffer,buffer2,buffer3,rhsp) + ! Vorticity mapping ... + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + + end subroutine RK4_3D + + !> Runge Kutta 4, for 2D domain (i.e rhs == 0). + subroutine RK4_2D(dt,topoid,meshid,ghostsize,vel) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer::ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + + !> local loop indices + integer :: i, newNpart,k + real(mk) :: alpha + !> error status + integer :: info + ! buffer is used to save intermediate values for xp and omp, thus buffersize=2*npart + + allocate(buffer(dime,npart),buffer2(dime,npart)) + buffer_size=npart + + ! First RK stage + ! Velocity is up to date, following the call to update_particles + alpha=0.5*dt + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=velop(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + print *, "NEW", npart,newNpart + npart = newNpart + + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Second RK4 stage, with the updated velocity + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + end do + end do + call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + print *, "NEW2", npart,newNpart + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Third RK4 stage + alpha=dt + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + end do + end do + newNpart = 0 + call ppm_impose_part_bc(topoid,xp,npart,info) + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + print *, "NEW3", npart,newNpart + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Last RK4 stage + alpha=dt/6. + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*buffer2(k,i)+alpha*velop(k,i) + end do + end do + + ! Free memory as soon as possible ... + deallocate(buffer,buffer2) + ! Vorticity mapping ... + call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + print *, "NEW4", npart,newNpart + npart = newNpart + + end subroutine RK4_2D + + !> Runge Kutta 4, for 2D domain (i.e rhs == 0). + subroutine RK4_2DScalar(dt,topoid,meshid,ghostsize,vel) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer::ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + + !> local loop indices + integer :: i, newNpart,k + real(mk) :: alpha + !> error status + integer :: info + ! buffer is used to save intermediate values for xp and omp, thus buffersize=2*npart + + allocate(buffer(dime,npart),buffer2(dime,npart)) + buffer_size=npart + + ! First RK stage + ! Velocity is up to date, following the call to update_particles + alpha=0.5*dt + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=velop(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + !call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + !! Second RK4 stage, with the updated velocity + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + end do + end do +! call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Third RK4 stage + alpha=dt + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + buffer2(k,i)=buffer2(k,i)+2.*velop(k,i) + end do + end do + newNpart = 0 + !call ppm_impose_part_bc(topoid,xp,npart,info) + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_push(buffer2,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer2,dime,npart,newNpart,info) + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Last RK4 stage + alpha=dt/6. + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+alpha*buffer2(k,i)+alpha*velop(k,i) + end do + end do + + ! Scalar mapping ... + !call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + ! Free memory as soon as possible ... + deallocate(buffer,buffer2) + + end subroutine RK4_2DSCALAR + + !> Runge Kutta 4, for 2D domain (i.e rhs == 0). + subroutine RK2_2D(dt,topoid,meshid,ghostsize,vel) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer::ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + + !> local loop indices + integer :: i, newNpart,k + real(mk) :: alpha + !> error status + integer :: info + ! buffer is used to save intermediate values for xp and omp, thus buffersize=2*npart + + allocate(buffer(dime,npart)) + buffer_size=npart + + ! First RK stage + ! Velocity is up to date, following the call to update_particles + alpha=0.5*dt + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + ! call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + + !! Second RK2 stage, with the updated velocity + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+dt*velop(k,i) + end do + end do + ! Vorticity mapping ... + ! call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(omp,dime,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(omp,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + ! Free memory as soon as possible ... + deallocate(buffer) + + end subroutine RK2_2D + + !> Runge Kutta 2, for 2D domain (i.e rhs == 0). + subroutine RK2_2DScalar(dt,topoid,meshid,ghostsize,vel) + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer::ghostsize + ! velocity on grid (must be in PPM-style storage) + real(mk), dimension(:,:,:,:), pointer :: vel + + !> local loop indices + integer :: i, newNpart,k + real(mk) :: alpha + !> error status + integer :: info,np0 + ! buffer is used to save intermediate values for xp and omp, thus buffersize=2*npart + + allocate(buffer(dime,npart)) + buffer_size=npart + + np0 = npart + + ! First RK stage + ! Velocity is up to date, following the call to update_particles + alpha=0.5*dt + do i=1,npart + do k=1,dime + buffer(k,i)=xp(k,i) + xp(k,i)=buffer(k,i)+alpha*velop(k,i) + end do + end do + ! Particles positions have changed ... we must map between domains + !call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + call ppm_map_part_global(topoid,xp,npart,info) ! positions + !call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + !! Mesh to particles for the new particles positions ... + !> for velocity and rhs + call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + !! Second RK2 stage, with the updated velocity + do i=1,npart + do k=1,dime + xp(k,i)=buffer(k,i)+dt*velop(k,i) + end do + end do + ! call ppm_impose_part_bc(topoid,xp,npart,info) + newNpart = 0 + ! call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + end subroutine RK2_2DSCALAR + + !> Runge Kutta 2 for positions and 1 for vorticity + subroutine push_split_particles(dir,dt,topoid,meshid,ghostsize,vel,coordMin,step) + !> splitting direction + integer, intent(in) :: dir + !> time step + real(mk), intent(in) ::dt + ! topo and mesh ids + integer, intent(in) :: topoid + integer, intent(in) :: meshid + integer, dimension(:),pointer:: ghostsize + ! velocity on grid + real(mk), dimension(:,:,:,:), pointer :: vel + real(mk),dimension(dim3),intent(in) :: coordMin,step + !> local loop indices + integer :: i,newNpart + integer :: info + + do i=1,npart + buffer(dir,i)=xp(dir,i) + xp(dir,i)=buffer(dir,i)+0.5*dt*velop(dir,i) + end do + ! Particles positions have changed ... we must map between domains + ! call ppm_impose_part_bc(topoid,xp,npart,info) ! Useless according to doc, required according to Omar ... + newNpart = 0 + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + !call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(velop,dime,npart,info) ! velocity + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_push(buffer,dime,npart,info) + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(buffer,dime,npart,newNpart,info) + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(velop,dime,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + ! Update sizes ... + npart = newNpart + ! if(size(rhsp,2).lt.npart) then + + !> for velocity + !call ppm_interp_m2p(topoid,meshid,xp,npart,velop,dime,kernel,ghostsize,vel,info) + call mesh2particles(vel,coordMin,step,dir) + + do i=1,npart + xp(dir,i)=buffer(dir,i)+dt*velop(dir,i) + end do + + ! Vorticity mapping ... + newNpart = 0 + + call ppm_map_part_partial(topoid,xp,npart,info) ! positions + call ppm_map_part_global(topoid,xp,npart,info) ! positions + call ppm_map_part_push(scalar_p,npart,info) ! vorticity + call ppm_map_part_send(npart,newNpart,info) ! send + call ppm_map_part_pop(scalar_p,npart,newNpart,info) + call ppm_map_part_pop(xp,dime,npart,newNpart,info) + npart = newNpart + end subroutine push_split_particles + + subroutine mesh2particles(velocity,coordMin,step,dir) + + real(mk),dimension(:,:,:,:),pointer :: velocity + integer, intent(in) :: dir + real(mk),dimension(dim3),intent(in) :: step + real(mk),dimension(dim3),intent(in) :: coordMin + + real(mk) :: coord,dist + real(mk),dimension(2) :: weights + integer :: i,j + integer, dimension(2,dime) :: indGrid + + do i = 1,npart + do j = 1,2 + indGrid(j,:) = ((xp(:,i) - coordMin(:))/step(:) + epsilon(pi))+1 + enddo + indGrid(2,dir) = indGrid(1,dir) + 1 + + coord = coordMin(dir) + (indGrid(1,dir)-1)*step(dir) + dist = (xp(dir,i) - coord)/step(dir) + weights(1) = 1.-dist + weights(2) = dist + + velop(dir,i) = weights(1)*velocity(dir,indGrid(1,1),indGrid(1,2),indGrid(1,3))& + + weights(2)*velocity(dir,indGrid(2,1),indGrid(2,2),indGrid(2,3)) + end do + + end subroutine mesh2particles + + subroutine remesh_split_mp6(scalar,dir,step,coordMin) + real(mk),dimension(:,:,:), pointer :: scalar + integer, intent(in) :: dir + real(mk),dimension(dim3),intent(in) :: step + real(mk),dimension(dim3),intent(in) :: coordMin + + real(mk) :: coord,dist + real(mk),dimension(6) :: val,weights + integer :: i,j + + integer, dimension(6,dime) :: indGrid + + scalar = 0.0 + + do i = 1,npart + do j = 1,6 + indGrid(j,:) = ((xp(:,i) - coordMin(:))/step(:) + epsilon(pi))+1 + enddo + indGrid(1,dir) = indGrid(3,dir) - 2 + indGrid(2,dir) = indGrid(3,dir) - 1 + indGrid(4,dir) = indGrid(3,dir) + 1 + indGrid(5,dir) = indGrid(3,dir) + 2 + indGrid(6,dir) = indGrid(3,dir) + 3 + + coord = coordMin(dir) + (indGrid(3,dir)-1)*step(dir) + dist = (xp(dir,i) - coord)/step(dir) + weights(1) = -(dist)*(5.*(dist + 2.)-8.)*(dist - 1.)**3/24. + weights(2) = (dist)*(dist - 1.)*(25.*(dist + 1.)**3-114.*(dist + 1.)**2+153.*(dist + 1.)-48.)/24. + weights(3) = -(dist-1.)*(25.*dist**4-38.*dist**3-3.*dist**2+12.*dist+12)/12. + weights(4) = (dist)*(25.*(1. - dist)**4-38.*(1. - dist)**3-3.*(1. - dist)**2+12.*(1. - dist)+12)/12. + weights(5) = (1. - dist)*(-dist)*(25.*(2. - dist)**3-114.*(2. - dist)**2+153.*(2. - dist)-48.)/24. + weights(6) = -(1. - dist)*(5.*(3. - dist)-8.)*(-dist)**3/24. + + val(:) = scalar_p(i)*weights(:) + do j = 1, 6 + scalar(indGrid(j,c_X),indGrid(j,c_Y),indGrid(j,c_Z)) = & + scalar(indGrid(j,c_X),indGrid(j,c_Y),indGrid(j,c_Z)) + val(j) + end do + + end do + + end subroutine remesh_split_mp6 + + + !> Return the memory used to save var. attached to particles + function getMemoryUsedForParticles() + real(mk) :: getMemoryUsedForParticles + + getMemoryUsedForParticles = sizeof(xp)+sizeof(velop)+sizeof(rhsp)+sizeof(buffer)+& + sizeof(buffer2)+sizeof(buffer3) + getMemoryUsedForParticles = getMemoryUsedForParticles*1e-6 + if(verbose) then + write(*,'(a,i3,a,f10.4,a)') & + '[',rank,'] memory used for particles:', getMemoryUsedForParticles, ' MB.' + end if + + end function getMemoryUsedForParticles + + !> Create particles on the grid points where refField>cutoff. + subroutine countAndCreateParticles(refField,velocity,resolution,step,coordMin) + + !> Field (on grid) used to set particles + real(mk), dimension(:,:,:,:), pointer :: refField + !> velocity on the grid + real(mk), dimension(:,:,:,:), pointer :: velocity + !> Local resolution + integer, dimension(dim3),intent(in) :: resolution + !> Space step + real(mk), dimension(dim3),intent(in) :: step + !> Coordinates of the lowest point of the current domain + real(mk), dimension(dim3),intent(in) :: coordMin + + ! particles counter + integer :: count + ! norm of refField at each point of the grid + real(mk) :: strength + ! coordinates + real(mk), dimension(dim3) :: coord + integer, dimension(dim3) :: nbCells + + integer :: i,j,k + + nbCells = max(resolution-1,1) + + print *, "uuuu",maxval(refField) + + ! Count the number of particles within cutoff bounds. + ! Loop over grid points. We use 'max' to allow the '1 point in one direction' case + ! (i.e. to deal with 2D case in a 3D context) + ! Remark : there is no resize function in fortran so we must count first, allocate and then fill fields. + count = 0 + + print *, "str", cutoff + do k=1,nbCells(c_Z) + do j=1,nbCells(c_Y) + do i=1,nbCells(c_X) + strength = sqrt(sum(refField(:,i,j,k)**2)) + if((strength.gt.cutoff(1)).and.(strength.lt.cutoff(2))) then + count = count + 1 + end if + end do + end do + end do + + ! Allocations + allocate(xp(dime,count),omp(dime,count),velop(dime,count)) + + print *, 'nb parts ...', count, shape(xp) + + ! and set values + coord = coordMin + count = 0 + do k=1,nbCells(c_Z) + do j=1,nbCells(c_Y) + do i=1,nbCells(c_X) + strength = sqrt(sum(refField(:,i,j,k)**2)) + if((strength.gt.cutoff(1)).and.(strength.lt.cutoff(2))) then + count = count + 1 + omp(:,count) = refField(:,i,j,k) + velop(:,count) = velocity(:,i,j,k) + xp(:,count) = coord(1:dime) + end if + coord(c_X) = coord(c_X) + step(c_X) + end do + coord(c_Y) = coord(c_Y) + step(c_Y) + end do + coord(c_Z) = coord(c_Z) + step(c_X) + end do + + npart = count + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + end subroutine countAndCreateParticles + + !> Update particles on the grid points where refField>cutoff. + !! Note : There are deallocation/reallocation if the number of particles as increased. + subroutine countAndUpdateParticles(refField,velocity,resolution,step,coordMin) + + !> Field (on grid) used to set particles + real(mk), dimension(:,:,:,:), pointer :: refField + !> velocity on the grid + real(mk), dimension(:,:,:,:), pointer :: velocity + !> Local resolution + integer, dimension(dim3),intent(in) :: resolution + !> Space step + real(mk), dimension(dim3),intent(in) :: step + !> Coordinates of the lowest point of the current domain + real(mk), dimension(dim3),intent(in) :: coordMin + + ! particles counter + integer :: count + ! norm of refField at each point of the grid + real(mk) :: strength + ! coordinates + real(mk), dimension(dim3) :: coord + integer, dimension(dim3) :: nbCells + integer :: i,j,k + + nbCells = max(resolution-1,1) + + ! Count the number of particles within cutoff bounds. + ! Loop over grid points. We use 'max' to allow the '1 point in one direction' case + ! (i.e. to deal with 2D case in a 3D context) + ! Remark : there is no resize function in fortran so we must count first, allocate and then fill fields. + count = 0 + do k=1,max(resolution(c_Z)-1,1) + do j=1,max(resolution(c_Y)-1,1) + do i=1,max(resolution(c_X)-1,1) + strength = sqrt(sum(refField(:,i,j,k)**2)) + if((strength.gt.cutoff(1)).and.(strength.lt.cutoff(2))) then + count = count + 1 + end if + end do + end do + end do + + ! Check if reallocation is required + if(count > npart) then + ! Free old memory + if(associated(xp)) deallocate(xp) + if(associated(omp)) deallocate(omp) + if(associated(velop)) deallocate(velop) + + ! Allocations + allocate(xp(dime,count),omp(dime,count),velop(dime,count)) + end if + + ! and set values + coord = coordMin + count = 0 + do k=1,max(resolution(c_Z)-1,1) + do j=1,max(resolution(c_Y)-1,1) + do i=1,max(resolution(c_X)-1,1) + strength = sqrt(sum(refField(:,i,j,k)**2)) + if((strength.gt.cutoff(1)).and.(strength.lt.cutoff(2))) then + count = count + 1 + omp(:,count) = refField(:,i,j,k) + velop(:,count) = velocity(:,i,j,k) + xp(:,count) = coord + end if + coord(c_X) = coord(c_X) + step(c_X) + end do + coord(c_Y) = coord(c_Y) + step(c_Y) + end do + coord(c_Z) = coord(c_Z) + step(c_X) + end do + + npart = count + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + end subroutine countAndUpdateParticles + + !> Create particles on the grid points where refField>cutoff. + subroutine createParticlesEverywhere(refField,velocity,resolution,step,coordMin) + + !> Field (on grid) used to set particles + real(mk), dimension(:,:,:,:), pointer :: refField + !> velocity on the grid + real(mk), dimension(:,:,:,:), pointer :: velocity + !> Local resolution + integer, dimension(dim3),intent(in) :: resolution + !> Space step + real(mk), dimension(dim3),intent(in) :: step + !> Coordinates of the lowest point of the current domain + real(mk), dimension(dim3),intent(in) :: coordMin + + ! coordinates + real(mk), dimension(dim3) :: coord + integer, dimension(dim3) :: nbCells + integer :: i,j,k,count + + nbCells = max(resolution-1,1) + coord = coordMin + count = 0 + npart = product(nbCells) + ! Allocations + allocate(xp(dime,npart),omp(dime,npart),velop(dime,npart)) + do k=1,nbCells(c_Z) + do j=1,nbCells(c_Y) + do i=1,nbCells(c_X) + count = count + 1 + omp(:,count) = refField(:,i,j,k) + velop(:,count) = velocity(:,i,j,k) + xp(:,count) = coord + coord(c_X) = coord(c_X) + step(c_X) + end do + coord(c_X) = coordMin(c_X) + coord(c_Y) = coord(c_Y) + step(c_Y) + end do + coord(c_Y) = coordMin(c_Y) + coord(c_Z) = coord(c_Z) + step(c_X) + end do + + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + end subroutine createParticlesEverywhere + + !> Create particles on the grid points where refField>cutoff. + subroutine createParticlesEverywhereScalar(refField,velocity,resolution,step,coordMin) + + !> Field (on grid) used to set particles + real(mk), dimension(:,:,:), pointer :: refField + !> velocity on the grid + real(mk), dimension(:,:,:,:), pointer :: velocity + !> Local resolution + integer, dimension(dim3),intent(in) :: resolution + !> Space step + real(mk), dimension(dim3),intent(in) :: step + !> Coordinates of the lowest point of the current domain + real(mk), dimension(dim3),intent(in) :: coordMin + + ! coordinates + real(mk), dimension(dim3) :: coord + integer, dimension(dim3) :: nbCells + integer :: i,j,k,count + + nbCells = max(resolution-1,1) + coord = coordMin + count = 0 + npart = product(nbCells) + ! Allocations + allocate(xp(dime,npart),scalar_p(npart),velop(dime,npart)) + do k=1,nbCells(c_Z) + do j=1,nbCells(c_Y) + do i=1,nbCells(c_X) + count = count + 1 + scalar_p(count) = refField(i,j,k) + velop(:,count) = velocity(:,i,j,k) + xp(:,count) = coord + coord(c_X) = coord(c_X) + step(c_X) + end do + coord(c_X) = coordMin(c_X) + coord(c_Y) = coord(c_Y) + step(c_Y) + end do + coord(c_Y) = coordMin(c_Y) + coord(c_Z) = coord(c_Z) + step(c_X) + end do + + write(*,'(a,i5,a,i8,a)') '[',rank,'] initialisation with ', npart,' particles' + + open(45,file="scalp") ! Output only for one process + do i = 1,npart + write(45,'(6e14.5)') xp(c_X,i),scalar_p(i) + end do + close(45) + end subroutine createParticlesEverywhereScalar + + + !> Free all arrays carried by particles + !! useful only for tests. + ! --------> is it required to call some specific routines to clean anything related to particles, at the end of the simulation? + ! or ppm_finalize do it all? + ! According to Omar: do not use ppm "internal" routines but clean it yourself. + subroutine freeParticles() + if(associated(xp)) deallocate(xp) + if(associated(omp)) deallocate(omp) + if(associated(velop)) deallocate(velop) + if(associated(rhsp)) deallocate(rhsp) + if(associated(buffer)) deallocate(buffer) + if(associated(buffer2)) deallocate(buffer2) + if(associated(scalar_p)) deallocate(scalar_p) + npart = 0 + buffer_size = 0 + end subroutine freeParticles + + subroutine remesh2D(field,coordMin,step,resolution) + + real(mk),dimension(:,:,:),pointer :: field + real(mk),dimension(dim3),intent(in) :: coordMin + real(mk),dimension(dim3),intent(in) :: step + integer, dimension(dim3),intent(in) :: resolution + + real(mk),dimension(dime) :: invStep + !! List of grid point indices for each particle : [Left-1 Left Right Right+1] + !! Left/Right == left/right points of the grid around the particle + integer, dimension(4,dime) :: indGrid + !! current point coordinates and distance to the left boundary of the local domain + real(mk),dimension(dime) :: coord,dist + !! weights + real(mk),dimension(4,dime) :: weights + integer:: i,j + invStep = 1./step(1:dime) + do i = 1,npart + indGrid(2,:) = ((xp(:,i) - coordMin(:))*invStep(:) + epsilon(pi))+1 + indGrid(1,:) = indGrid(2,:) - 1 + indGrid(3,:) = indGrid(2,:) + 1 + indGrid(4,:) = indGrid(2,:) + 2 + !enforce periodicity + do j =1,4 + indGrid(j,:) = mod(indGrid(j,:)+resolution(1:dime),resolution(1:dime))+1 + end do + + coord = coordMin(1:dime) + (indGrid(2,:)-1)*step(1:dime) + dist = (xp(:,i) - coord)*invStep + + weights(1,:) = 0.5*dist*((1.-dist)**2) + weights(2,:) = 1.-2.5*dist**2+1.5*dist**3 + weights(3,:) = 1.-2.5*(1.-dist)**2+1.5*(1.-dist)**3 + weights(4,:) = 0.5*dist**2*(dist-1.) + + do j =1,4 + field(indGrid(j,c_X),indGrid(:,c_Y),1) = field(indGrid(j,c_X),indGrid(:,c_Y),1)& + + weights(j,c_X)*weights(:,c_Y)*scalar_p(i) + end do + + end do + + end subroutine remesh2D + + + +end module Particles diff --git a/HySoP/src/ppmInterface/Solver.f90 b/HySoP/src/ppmInterface/Solver.f90 new file mode 100755 index 000000000..532f0e514 --- /dev/null +++ b/HySoP/src/ppmInterface/Solver.f90 @@ -0,0 +1,164 @@ +!> Poisson Solver on the grid +! +! Notes Franck concerning multigrid solver : +! - the old (before jan 2012) version of this solver was bugged in ppm. I let the Parmes routines calling this solver +! in the present file for future debugs, but they are not (really not ...) usable. + +module Solver + + use client_data, only: mk, dime,rank +!!!!!!! Comment to remove ppm use ppm_module_numerics_data, only: ppm_param_eq_poisson, ppm_param_smooth_rbsor +!!!!!!! Comment to remove ppm use ppm_module_poisson, only: ppm_poisson_init, ppm_poisson_plan, ppm_poisson_grn_pois_per, ppm_poisson_solve, & +!!!!!!! Comment to remove ppm ppm_poisson_drv_curl_fd2, ppm_poisson_drv_curl_fd4, ppm_poisson_drv_none +!!!!!!! Comment to remove ppm use client_topology +!!!!!!! Comment to remove ppm use ppm_module_typedef, only : ppm_param_mesh_coarsen +!!!!!!! Comment to remove ppm use ppm_module_mesh_derive, only: ppm_mesh_derive +! use ppmljk_poisson + + !! All multigrid stuff ... + !!use ppm_module_mg_init + !!use ppm_module_mg_solv + + implicit none + + private + + public :: init_poisson_solver, solve_poisson!!!, ppm_poisson_drv_curl_fd2, ppm_poisson_drv_curl_fd4, ppm_poisson_drv_none + + type(ppm_poisson_plan),pointer :: fftwplanForppm => NULL() + + ! Interface to poisson solver initialisation. Only fft at the time + interface init_poisson_solver + module procedure init_fftw + end interface + + interface solve_poisson + module procedure solve_poisson_fftw + end interface + +contains + + !> Do not work, bug in ppm numerics ... +!!$ subroutine init_multigrid(topoid, meshid, ghostsize, bc) +!!$ +!!$ integer, intent(in) :: topoid +!!$ integer, intent(in) :: meshid +!!$ integer, dimension(:), pointer :: ghostsize +!!$ integer, dimension(:), pointer :: bc +!!$ +!!$ integer, dimension(dime,2*dime):: ibcdef +!!$ real(mk), dimension(dime,1,1,1,1):: ibcvalue +!!$ +!!$ logical :: with_w_cycles, dump_info +!!$ real(mk) :: omega +!!$ integer :: limlev ! Number of mg levels +!!$ integer :: info +!!$ +!!$ info = -1 +!!$ limlev = 2 ! Warning, limlev must cope with grid resolution ... +!!$ omega = 1.15_mk ! Relaxation param +!!$ with_w_cycles = .FALSE. +!!$ dump_info = .TRUE. +!!$ ibcvalue(:,:,:,:,:)=0.0_mk +!!$ ibcdef(1,:)=bc(:) +!!$ ibcdef(2,:)=bc(:) +!!$ ibcdef(3,:)=bc(:) +!!$ ! Initialize the solver +!!$ !! ppm_param_eq_poisson : equation type. Poisson is the only possible type ... +!!$ !! ppm_param_smooth_rbsor : Gauss Seidel, only possible type +!!$ ! Anyway, at the time the two parameters above are not used in ppm routine. +!!$ !! maxlev : number of levels in multigrid +!!$ !! +!!$ +!!$ call ppm_mg_init(topoid, ppm_param_eq_poisson,ghostsize, ppm_param_smooth_rbsor,dime,ibcdef,& +!!$ ibcvalue,meshid,limlev,with_w_cycles,dump_info,omega,info) +!!$ +!!$ if(info.ne.0) stop 'Init_multigrid failed ...' +!!$ +!!$ end subroutine init_multigrid +!!$ +!!$ !> Do not work +!!$ subroutine solve_poisson_multigrid(topoid, field, rhs) +!!$ integer, intent(in) :: topoid +!!$ real(mk), dimension(:,:,:,:,:), pointer :: field +!!$ real(mk), dimension(:,:,:,:,:), pointer :: rhs +!!$ +!!$ integer :: itera, iterf, iter1, iter2, info +!!$ real(mk) :: Eu +!!$ +!!$ itera = 3 +!!$ iterf = 3 +!!$ iter1 = 10 +!!$ iter2 = 4 +!!$ print *, 'solve ...', topoid +!!$ +!!$ ! Bug inside ... +!!$ call ppm_mg_solv(topoid, field, rhs, dime, itera, iterf, iter1, iter2, Eu, info) +!!$ +!!$ end subroutine solve_poisson_multigrid + + !> Init fftw through ppm routines + subroutine init_fftw(fieldin,fieldout,topoid,meshid,deriveValue) + + real(mk), dimension(:,:,:,:,:), pointer :: fieldin, fieldout + integer, intent(in) :: topoid, meshid + integer, intent(in), optional :: deriveValue + + ! Parameters for ppm poisson routine + integer :: info + + ! Flag to select built-in Green functions (...) + integer :: green + integer :: der + + if (present(deriveValue)) then + der = deriveValue + else + der = ppm_poisson_drv_curl_fd4 + end if + + green = ppm_poisson_grn_pois_per ! periodic boundaries + info = -1 + allocate(fftwplanForppm) + ! Call ppm routine to initialize fftw plan. + call ppm_poisson_init(topoid,meshid,fftwplanForppm,fieldin,fieldout,green,info,derive=ppm_poisson_drv_curl_fd4) + !call mypoisson_init(topoid,meshid,fftwplanForppm,fieldin,fieldout,info) + + if(info.NE.0) stop 'PPM Poisson solver init failed.' + end subroutine init_fftw + + !> Interface to ppm poisson solver with fftw + subroutine solve_poisson_fftw(fieldin,fieldout,topoid,meshid,ghostsize) + + real(mk), dimension(:,:,:,:,:), pointer :: fieldin, fieldout + integer, intent(in) :: meshid, topoid + integer, dimension(:),pointer::ghostsize + + integer :: info + ! Finite diff scheme used to compute curl + !integer :: dtype + + info = -1 + + ! Solves laplacian(fieldout) = - fieldin + call ppm_poisson_solve(topoid,meshid,fftwplanForppm,fieldin,fieldout,ghostsize,info) + !call mypoisson_solve(topoid,meshid,fftwplanForppm,fieldin,fieldout,ghostsize,info) + if(info.NE.0) stop 'PPM Poisson solver failed.' + + ! info = -1 + ! Computes fieldout = curl(fieldout) using finite differences, 2nd order (dtype = ppm_poisson_drv_curl_fd2), + ! or 4th order (dtype = ppm_poisson_drv_curl_fd4). Last one is untested according to ppm doc ... + ! According to Johannes, not needed if I set derive in poisson_init + !call ppm_poisson_fd(topoid,meshid,fieldout,fieldout,dtype,info) + !if(info.NE.0) stop 'PPM Poisson, curl computation failed.' + + end subroutine solve_poisson_fftw + + subroutine finalize_poisson_fftw() + ! TODO ... + ! In ppm nothing is done to free fftw plan or other temp. buffers. + end subroutine finalize_poisson_fftw + +end module Solver + + diff --git a/HySoP/src/ppmInterface/Topology.f90 b/HySoP/src/ppmInterface/Topology.f90 new file mode 100755 index 000000000..77147a660 --- /dev/null +++ b/HySoP/src/ppmInterface/Topology.f90 @@ -0,0 +1,225 @@ +!> Tools to create and init the topology +!! Based on ppm +module client_topology + + use ppm_module_typedef, only : ppm_t_topo + use ppm_module_mktopo + use ppm_module_topo_get + use ppm_module_mesh_define + use ppm_module_data, only : ppm_param_assign_internal,ppm_param_decomp_cartesian,ppm_topo,& + ppm_param_decomp_xpencil,ppm_param_decomp_ypencil,ppm_param_decomp_zpencil + + use client_data, only : mk,dime,dim3 + use parmesTools + + implicit none + + !> A pointer to a ppm topology + type :: topoPtr + !> pointer to ppm topo + type(ppm_t_topo), pointer :: ptr + !> id of the local mesh on the current topo (Warning : we consider only 1 mesh/topo, at the present time) + integer :: meshid + end type topoPtr + + !> A pointer to ppm topology object + type(ppm_t_topo), pointer :: topo => null() + !> Array of 1D topologies for FFTW solvers + type(topoPtr), dimension(dime) :: topo1D + !> 1D topology for FFTW solvers + type(ppm_t_topo), pointer :: topoY => NULL() + !> number of sub-domains on the current (mpi)proc. This is for ppm and should be 1 in our case. + integer :: nsublist + !> number of the current mpi proc according to ppm. May be different from rank and is required. + integer :: isubl + !> local mesh number + integer :: meshNum + + private + + public PPMinitTopo, topo, meshNum, ppm_t_topo, getPPMLocalResolution,nsublist,isubl,createTopologyY,topoY + +contains + + !> Create the topology - Based on ppm_topo_mkfield routine (interface = ppm_mktopo) + subroutine PPMinitTopo(minPos,maxPos,bc,ghostsize,resolution) + + real(mk), dimension(:),pointer :: minpos,maxpos + integer, dimension(:),pointer :: bc + integer, dimension(:),pointer :: ghostsize + integer, dimension(:),pointer :: resolution + + ! Unused parameter that must be present as an input arg ... + real(mk), dimension(:,:),pointer :: false_xp => NULL() + real(mk), dimension(:),pointer :: subcost => NULL() + integer :: false_np + integer assigning, decomposition + integer :: info, meshid, topoid + + info = -1 + topoid=0 + meshid =-1 + decomposition = ppm_param_decomp_cartesian + assigning = ppm_param_assign_internal + false_np = -1 ! Must be negative to have purely mesh-based decomposition + ! topology + ! Note FP: ghostsize are never used in mktopo for decomp_cartesian. + ! Note2 FP: struct topo as input results in failure. + + call ppm_mktopo(topoid,meshid,false_xp,false_np,decomposition,assigning,minPos(1:dime),maxPos(1:dime),bc, & + ghostsize,subcost,resolution(1:dime),info) + !decomposition = ppm_param_decomp_xy_slab + !ghostsize =0.0 + !CALL ppm_mktopo(topoid,meshid,false_xp,0,decomposition,assigning,minPos,maxPos,bc,& + ! ghostsize,subcost,resolution,info) + + !meshid2=-1 + !nmxyc=resolution + !nmxyc(1)=(resolution(1)-1)/2 +1 + !CALL ppm_mesh_define(topoid,meshid2,nmxyc,istartxyc,ndataxyc,info) + + !print *, 'iaiaaoaioaioa', ppm_topo(topoid)%t%mesh(meshid2)%nnodes + if(info.ne.0) stop 'Topology:init initialisation failed' + + ! Get the created topology ... + topo=>ppm_topo(topoid)%t + + ! We init ppm numbers for sub domains + nsublist=topo%nsublist + call parmesAssert(nsublist,1,'there are several sub-domains on the current process and that is not allowed.') + !> Number of the current process for ppm. May be different from rank. + isubl = topo%isublist(nsublist) + !! If we need nsublist > 1, every place where isubl is used should look like : + ! do isub=1,nsublist + ! isubl=topo%isublist(isub) + ! call something(...,isubl,...) + ! enddo + + ! we suppose that there is only on mesh created on each subdomain + meshNum = topo%max_meshid + call parmesAssert(meshNum,1,& + 'it seems that several meshes are defined on the current sub-domain, which may result in simulation failure.') + + print *, rank, "AAAAAAAAAAAAAA", shape(topo%mesh(meshNum)%nnodes), "nbnbnb", topo%mesh(meshNum)%nnodes + +!!$ call ppm_topo_get_meshinfo(topoid,meshid,nm,istart,ndata,maxndata,isublist,nsublist,info) +!!$ +!!$ print *, 'nm', nm +!!$ print *, 'istart', istart +!!$ print *, 'ndata', ndata +!!$ print *, 'maxndata',maxndata +!!$ print *, 'isublist', isublist +!!$ print *, 'nsublist',nsublist + ! Notes Franck: + ! nsublist is the number of subdomains for one processus (mpi proc not physical proc ...) + ! isublist[i] = global number of the subdomain i (i being the local number) + ! Warning: it seems that isublist is of size mpi-number-of proc but only the 1:nsublist elements are relevent + ! sub2proc[i] = global number of the processus on which subdomain i is attached + ! +!!$ +!! print *, '[', rank,'], subs : ', topo%nsublist, '//', shape(topo%isublist),'//', topo%isublist(1) +!!$ print *, '======================= [', rank,'] ', shape(topo%sub2proc) +!!$ print *, '======================= [', rank,'] ', topo%sub2proc +!!$ +!!$ +!!$ print *, '======================= [', rank,'] ', shape(topo%mesh(1)%nnodes) +!!$ print *, '======================= [', rank,'] ', topo%mesh(1)%nnodes +!!$ print *, '======================= [', rank,'] ', shape(topo%mesh(1)%istart) +!!$ print *, '======================= [', rank,'] ', topo%mesh(1)%Nm + + end subroutine PPMinitTopo + + !> Return the local (mpi) subdomain resolution + function getPPMLocalResolution(localTopo,meshid) + + !> topology of interest + type(ppm_t_topo), pointer :: localTopo + !> id of the mesh from which we need to get the resolution + integer, intent(in) :: meshid + integer,dimension(dim3) :: getPPMLocalResolution + + getPPMLocalResolution = 1 + getPPMLocalResolution(1:dime) = maxval(localTopo%mesh(meshid)%nnodes(:,localTopo%isublist(1:localTopo%nsublist)),2) + + end function getPPMLocalResolution + + !> 1D topologies creation, for fftw solvers + !! + subroutine create1DTopologies(minPos,maxPos,bc,resolution) + + real(mk), dimension(:),pointer :: minpos,maxpos + integer, dimension(:),pointer :: bc + integer, dimension(:),pointer :: resolution + + ! Unused parameter that must be present as an input arg ... + real(mk), dimension(:,:),pointer :: false_xp => NULL() + real(mk), dimension(:),pointer :: subcost => NULL() + integer :: false_np + integer :: assigning + integer, dimension(dim3) :: decomposition + integer :: info, meshid, topoid,i + integer,dimension(dim3), parameter :: zeros = (/0,0,0/) + + info = 0 + decomposition(c_X) = ppm_param_decomp_xpencil + decomposition(c_Y) = ppm_param_decomp_ypencil + decomposition(c_Z) = ppm_param_decomp_zpencil + assigning = ppm_param_assign_internal + false_np = 0 ! Purely mesh-based decomposition + + ! No ghosts for these topologies + + ! loop over dimensions + do i=1,dime + topoid = 0 + meshid = -1 + call ppm_mktopo(topoid,meshid,false_xp,0,decomposition(i),assigning,minpos(1:dime),maxpos(1:dime),bc,& + zeros(1:dime),subcost,resolution(1:dime),info) + topo1D(i)%ptr=>ppm_topo(topoid)%t + topo1D(i)%meshid = meshid + end do + + print *,"iijiji", topo1D(c_X)%ptr%mesh(meshid)%nnodes + + end subroutine create1DTopologies + + !> 1D topologies creation, for fftw solvers + !! + subroutine createTopologyY(topoid,meshid,minPos,maxPos,bc,resolution) + + real(mk), dimension(:),pointer :: minpos,maxpos + integer, dimension(:),pointer :: bc + integer, dimension(:),pointer :: resolution + integer, intent(inout) :: topoid + integer, intent(inout) :: meshid + + ! Unused parameter that must be present as an input arg ... + real(mk), dimension(:,:),pointer :: false_xp => NULL() + real(mk), dimension(:),pointer :: subcost => NULL() + integer :: false_np + integer :: assigning + integer :: decomposition + integer :: info + integer,dimension(dime), parameter :: zeros = (/0,0/) + + info = 0 + + decomposition = ppm_param_decomp_xpencil + assigning = ppm_param_assign_internal + false_np = 0 ! Purely mesh-based decomposition + + ! No ghosts for these topologies + ! loop over dimensions + topoid = 0 + meshid = -1 + call ppm_mktopo(topoid,meshid,false_xp,0,decomposition,assigning,minpos(1:dime),maxpos(1:dime),bc,& + zeros(1:dime),subcost,resolution(1:dime),info) + topoY=>ppm_topo(topoid)%t + + print *,rank,"iijiji", topoY%mesh(meshid)%nnodes + print *,rank,"iooooooooijiji", getPPMLocalResolution(topoY,meshid) + + end subroutine createTopologyY + + +end module client_topology diff --git a/HySoP/src/ppmInterface/callCharFunc.f90 b/HySoP/src/ppmInterface/callCharFunc.f90 new file mode 100644 index 000000000..9ba929739 --- /dev/null +++ b/HySoP/src/ppmInterface/callCharFunc.f90 @@ -0,0 +1,39 @@ +!> \file callCharFunc.f90 Wrapper to fortran functions that have a char-type input argument. + +!> \brief Module to wrap fortran functions with char arg. +module charFunctions + + use ppm_module_substart + use ppm_module_substop + + implicit none + +contains + + !> Wrapper to ppm substart function + !! @param[in,out] cpu time when this function is called + !! @param[in] error status + !! @param[in] Name of the calling-function + subroutine start(t0,info,msg) + + real(8) :: t0 + character(len=*) :: msg + integer :: info + call substart(msg,t0,info) + end subroutine start + + !> Wrapper to ppm substop function : print caller name and cpu time elasped since start call (for the same caller) + !! @param[in] cpu time, value returned during substart call + !! @param[in] error status + !! @param[in] Name of the calling-function + subroutine stop(t0,info,msg) + + real(8) :: t0 + character(len=*) :: msg + integer :: info + + call substop(msg,t0,info) + end subroutine stop + +end module charFunctions + diff --git a/HySoP/src/ppmInterface/poisson_init.f90 b/HySoP/src/ppmInterface/poisson_init.f90 new file mode 100755 index 000000000..42ad26088 --- /dev/null +++ b/HySoP/src/ppmInterface/poisson_init.f90 @@ -0,0 +1,597 @@ +module ppmljk_poisson + + use client_data + use ppm_module_poisson + use ppm_module_mktopo + use ppm_module_topo_get + use ppm_module_mesh_define + use ppm_module_map_field + use ppm_module_map_field_global + use ppm_module_map + use mpi + + implicit none + + integer,dimension(dim3), parameter :: zeros = (/0,0,0/) + + !#define __ZEROSI (/0,0,0/) + +contains + + !> Initialisation of Poisson solver (fft), based on ppm and on a copy on the + !! equivalent file in ppm + subroutine mypoisson_init(topoid,meshid,ppmpoisson,fieldin,fieldout,info) +!!! * ppm_poisson_grn_pois_per - Poisson equation, periodic boundaries +!!! +!!! [NOTE] +!!! fieldin is not preserved by this routine! +!!! fieldin and fieldout must NOT be the same fields. In-place FFTs have +!!! not been implemented. +!!! + + !> the topology id + integer, intent(in) :: topoid + !> corresponding mesh id + integer, intent(in) :: meshid + !> fftw plan interface + type(ppm_poisson_plan),intent(out) :: ppmpoisson + !> input field (i.e. rhs of poisson eq.) + !@ strictly speaking fieldin is not being used in the init routine + real(mk), dimension(:,:,:,:,:), pointer :: fieldin + !> output field + real(mk), dimension(:,:,:,:,:), pointer :: fieldout + !> error status + integer, intent(out) :: info + + !------------------------------------------------------------------------- + ! Local variables + !------------------------------------------------------------------------- + ! real(mk) :: t0 + real(mk),dimension(:,:),pointer :: xp=>NULL() !particle positions + TYPE(ppm_t_topo),pointer :: topology=>NULL() + TYPE(ppm_t_equi_mesh) :: mesh + integer ,dimension(dime) :: indl,indu + real(mk),PARAMETER :: PI=ACOS(-1.0_mk) !@ use ppm pi + real(mk) :: normfac +!!!factor for the Greens function, including FFT normalization + integer :: i,j,k + integer :: kx,ky,kz + integer :: isubl,isub + integer,dimension(dime*2) :: bcdef + integer :: assigning + integer :: decomposition + integer,SAVE :: ttopoid + integer :: tmeshid + real(mk) :: Lx2,Ly2,Lz2 + + real(mk),dimension(dime) :: tmpmin,tmpmax + integer, dimension(:),pointer :: maxndataxy=>NULL(),maxndataz=>NULL() + integer, dimension(: ), pointer :: dummynmxy=>NULL(),dummynmz=>NULL() + + !------------------------------------------------------------------------- + ! Initialise routine + !------------------------------------------------------------------------- + ! CALL substart('ppm_poisson_init',t0,info) + + ppmpoisson%case = ppm_poisson_grn_pois_per + + !------------------------------------------------------------------------- + ! Nullify pointers from the ppmpoisson plans and the fftplans + !------------------------------------------------------------------------- + NULLIFY(xp) + NULLIFY(ppmpoisson%costxy) + NULLIFY(ppmpoisson%istartxy) + NULLIFY(ppmpoisson%ndataxy) + NULLIFY(ppmpoisson%istartxyc) + NULLIFY(ppmpoisson%ndataxyc) + NULLIFY(ppmpoisson%costz) + NULLIFY(ppmpoisson%istartz) + NULLIFY(ppmpoisson%ndataz) + NULLIFY(ppmpoisson%planfxy%plan) + NULLIFY(ppmpoisson%planbxy%plan) + NULLIFY(ppmpoisson%planfz%plan) + NULLIFY(ppmpoisson%planbz%plan) + + !------------------------------------------------------------------------- + ! Get topology and mesh values of input/output + !------------------------------------------------------------------------- + call ppm_topo_get(topoid,topology,info) + mesh = topology%mesh(meshid) + + !------------------------------------------------------------------------- + ! Setup mesh sizes for intermediate meshes/topologies + !------------------------------------------------------------------------- + !size of real slabs + ppmpoisson%nmxy (1) = mesh%nm(1) + ppmpoisson%nmxy (2) = mesh%nm(2) + ppmpoisson%nmxy (3) = mesh%nm(3) + !size of complex slabs + ppmpoisson%nmxyc(1) = (mesh%nm(1)-1)/2+1 + !!ppmpoisson%nmxyc(1) = mesh%nm(1) + ppmpoisson%nmxyc(2) = mesh%nm(2) + ppmpoisson%nmxyc(3) = mesh%nm(3) + !size of complex pencils + ppmpoisson%nmz (1) = (ppmpoisson%nmxyc(1)) + ppmpoisson%nmz (2) = (ppmpoisson%nmxyc(2)) + ppmpoisson%nmz (3) = (ppmpoisson%nmxyc(3)) + !size of the fft + ppmpoisson%nmfft(1) = mesh%nm(1)-1 + ppmpoisson%nmfft(2) = mesh%nm(2)-1 + ppmpoisson%nmfft(3) = mesh%nm(3)-1 + !Inverse of the size of the domain squared + Lx2 = 1.0_mk/(topology%max_physd(1)-topology%min_physd(1))**2 + Ly2 = 1.0_mk/(topology%max_physd(2)-topology%min_physd(2))**2 + Lz2 = 1.0_mk/(topology%max_physd(3)-topology%min_physd(3))**2 + + !------------------------------------------------------------------------- + ! Create temporary derivation arrays if necessary + !------------------------------------------------------------------------- + ppmpoisson%derivatives = ppm_poisson_drv_curl_sp + + !------------------------------------------------------------------------- + ! Create spectral scaling components always. Just in case some + ! reprojection comes up + ! The conditionals need to be for not just the Poisson equation + !------------------------------------------------------------------------- + ppmpoisson%normkx = & + & 2.0_mk*PI/(topology%max_physd(1)-topology%min_physd(1)) + ppmpoisson%normky = & + & 2.0_mk*PI/(topology%max_physd(2)-topology%min_physd(2)) + ppmpoisson%normkz = & + & 2.0_mk*PI/(topology%max_physd(3)-topology%min_physd(3)) + + !------------------------------------------------------------------------- + ! Create new slab topology + !------------------------------------------------------------------------- + ttopoid = 0 + tmeshid = -1 + decomposition = ppm_param_decomp_xy_slab + assigning = ppm_param_assign_internal + bcdef = ppm_param_bcdef_periodic + tmpmin = topology%min_physd + tmpmax = topology%max_physd + + CALL ppm_mktopo(ttopoid,tmeshid,xp,0,& + & decomposition,assigning,& + & tmpmin,tmpmax,bcdef,& + & zeros,ppmpoisson%costxy,& + & ppmpoisson%nmxy,info) + + ppmpoisson%topoidxy = ttopoid + ppmpoisson%meshidxy = tmeshid + !------------------------------------------------------------------------- + ! Get additional xy-mesh information + !------------------------------------------------------------------------- + CALL ppm_topo_get_meshinfo(ppmpoisson%topoidxy,ppmpoisson%meshidxy, & + & dummynmxy,ppmpoisson%istartxy,ppmpoisson%ndataxy,maxndataxy, & + & ppmpoisson%isublistxy,ppmpoisson%nsublistxy,info) + + + !------------------------------------------------------------------------- + ! Create complex slab mesh + !------------------------------------------------------------------------- + ttopoid = ppmpoisson%topoidxy + tmeshid = -1 + CALL ppm_mesh_define(ttopoid,tmeshid,& + & ppmpoisson%nmxyc,ppmpoisson%istartxyc,ppmpoisson%ndataxyc,info) + ppmpoisson%meshidxyc = tmeshid + + + !------------------------------------------------------------------------- + ! Create new pencil topology + !------------------------------------------------------------------------- + ttopoid = 0 + tmeshid = -1 + bcdef = ppm_param_bcdef_periodic + assigning = ppm_param_assign_internal + decomposition = ppm_param_decomp_zpencil + + CALL ppm_mktopo(ttopoid,tmeshid,xp,0,& + & decomposition,assigning,& + & tmpmin,tmpmax,bcdef,& + & zeros,ppmpoisson%costz,& + & ppmpoisson%nmz,info) + + ppmpoisson%topoidz = ttopoid + ppmpoisson%meshidz = tmeshid + !------------------------------------------------------------------------- + ! Get additional z-mesh information + !------------------------------------------------------------------------- + CALL ppm_topo_get_meshinfo(ppmpoisson%topoidz,ppmpoisson%meshidz, & + & dummynmz,ppmpoisson%istartz,ppmpoisson%ndataz,maxndataz, & + & ppmpoisson%isublistz,ppmpoisson%nsublistz,info) + + !------------------------------------------------------------------------- + ! Set and get minimum and maximum indicies + !------------------------------------------------------------------------- + indl(1) = 1 + indl(2) = 1 + indl(3) = 1 + + !------------------------------------------------------------------------- + ! Allocate real xy slabs + !------------------------------------------------------------------------- + ALLOCATE(ppmpoisson%fldxyr(dime,& + & indl(1):maxndataxy(1),indl(2):maxndataxy(2),indl(3):maxndataxy(3),& + & 1:ppmpoisson%nsublistxy),stat=info) + + + !------------------------------------------------------------------------- + ! Set and get minimum and maximum indicies of COMPLEX xy slabs + !------------------------------------------------------------------------- + indl(1) = 1 + indl(2) = 1 + indl(3) = 1 + indu(1) = 0 + indu(2) = 0 + indu(3) = 0 + DO isub=1,ppmpoisson%nsublistxy + isubl = ppmpoisson%isublistxy(isub) + indu(1) = MAX(indu(1),ppmpoisson%ndataxyc(1,isubl)) + indu(2) = MAX(indu(2),ppmpoisson%ndataxyc(2,isubl)) + indu(3) = MAX(indu(3),ppmpoisson%ndataxyc(3,isubl)) + ENDDO + + + !------------------------------------------------------------------------- + ! Allocate complex xy slabs + !------------------------------------------------------------------------- + ALLOCATE(ppmpoisson%fldxyc(dime,& + & indl(1):indu(1),indl(2):indu(2),indl(3):indu(3),& + & 1:ppmpoisson%nsublistxy),stat=info) + + + !------------------------------------------------------------------------- + ! Allocate two complex z pencils + Greens fcn array !@check return vars. + !------------------------------------------------------------------------- + ALLOCATE(ppmpoisson%fldzc1(dime,& + & indl(1):maxndataz(1),indl(2):maxndataz(2),indl(3):maxndataz(3),& + & 1:ppmpoisson%nsublistz),stat=info) + + ALLOCATE(ppmpoisson%fldzc2(dime,& + & indl(1):maxndataz(1),indl(2):maxndataz(2),indl(3):maxndataz(3),& + & 1:ppmpoisson%nsublistz),stat=info) + + + !------------------------------------------------------------------------- + ! The complex Greens function is always kept on the z-pencil topology + !------------------------------------------------------------------------- + ALLOCATE(ppmpoisson%fldgrnr(& + & indl(1):maxndataz(1),indl(2):maxndataz(2),indl(3):maxndataz(3),& + & 1:ppmpoisson%nsublistz),stat=info) + + !------------------------------------------------------------------------- + ! Set up xy FFT plans + ! The inverse plan takes the returning topology since it has the full size + !------------------------------------------------------------------------- + CALL ppm_fft_forward_2d(ppmpoisson%topoidxy,ppmpoisson%meshidxy,& + & ppmpoisson%planfxy,ppmpoisson%fldxyr,& + & ppmpoisson%fldxyc,info) + + CALL ppm_fft_backward_2d(ppmpoisson%topoidxy,ppmpoisson%meshidxy,& + & ppmpoisson%planbxy,ppmpoisson%fldxyc,& + & ppmpoisson%fldxyr,info) + + + !------------------------------------------------------------------------- + ! Set up z FFT plans + !------------------------------------------------------------------------- + CALL ppm_fft_forward_1d(ppmpoisson%topoidz,ppmpoisson%meshidz,& + & ppmpoisson%planfz,ppmpoisson%fldzc1,& + & ppmpoisson%fldzc2,info) + + CALL ppm_fft_backward_1d(ppmpoisson%topoidz,ppmpoisson%meshidz,& + & ppmpoisson%planbz,ppmpoisson%fldzc2,& + & ppmpoisson%fldzc1,info) + + + !------------------------------------------------------------------------- + ! Compute Greens function. Analytic, periodic + ! + ! (d2_/dx2 + d2_/dy2 + d2_/dz2)psi = -omega => + ! -4*pi2(kx2 + ky2 + kz2)PSI = -OMEGA => + ! PSI = 1/(4*pi2)*1/(kx2 + ky2 + kz2)OMEGA + !------------------------------------------------------------------------- + ! Scaling the spectral coefficients... + ! one minus due to (i*k)^2 and another due to the Poisson equation + normfac = 1.0_mk/(4.0_mk*PI*PI * & + !and normalisation of FFTs (full domain) !vertex + & real((ppmpoisson%nmfft(1))* & + & (ppmpoisson%nmfft(2))* & + & (ppmpoisson%nmfft(3)),mk)) + DO isub=1,ppmpoisson%nsublistz + isubl=ppmpoisson%isublistz(isub) + DO k=1,ppmpoisson%ndataz(3,isubl) + DO j=1,ppmpoisson%ndataz(2,isubl) + DO i=1,ppmpoisson%ndataz(1,isubl) + kx = i-1 + (ppmpoisson%istartz(1,isubl)-1) + ky = j-1 + (ppmpoisson%istartz(2,isubl)-1) + kz = k-1 + (ppmpoisson%istartz(3,isubl)-1) + !This is a nasty way to do this but it is only done once so...: + IF (kx .GT. (ppmpoisson%nmfft(1)/2)) kx = kx-(ppmpoisson%nmfft(1)) + IF (ky .GT. (ppmpoisson%nmfft(2)/2)) ky = ky-(ppmpoisson%nmfft(2)) + IF (kz .GT. (ppmpoisson%nmfft(3)/2)) kz = kz-(ppmpoisson%nmfft(3)) + ppmpoisson%fldgrnr(i,j,k,isub) = & + & normfac/(real(kx*kx,mk)*Lx2 & + & + real(ky*ky,mk)*Ly2 & + & + real(kz*kz,mk)*Lz2) + !Take care of singularity + !This is nasty as well + IF ((kx*kx+ky*ky+kz*kz) .EQ. 0) THEN + ppmpoisson%fldgrnr(i,j,k,isub) = 0.0_mk + ENDIF + ENDDO + ENDDO + ENDDO + ENDDO + end subroutine mypoisson_init + + subroutine mypoisson_solve(topoid,meshid,ppmpoisson,fieldin,fieldout,gstw,info) + + + INTEGER, INTENT(IN) :: topoid +!!! Topology ID + INTEGER, INTENT(IN) :: meshid +!!! Mesh ID + TYPE(ppm_poisson_plan),INTENT(INOUT) :: ppmpoisson +!!! The PPM Poisson plan + REAL(mk),DIMENSION(:,:,:,:,:),POINTER :: fieldin +!!! Input data field + REAL(mk),DIMENSION(:,:,:,:,:),POINTER :: fieldout +!!! Output data field + INTEGER,DIMENSION(dime),INTENT(IN) :: gstw +!!! Ghost layer width + INTEGER, INTENT(OUT) :: info +!!! Return status, 0 upon succes + + !------------------------------------------------------------------------- + ! Local variables + !------------------------------------------------------------------------- + + REAL(mk) :: t0 + INTEGER :: isub,isubl + INTEGER :: i,j,k + INTEGER :: info2 + INTEGER :: presentcase + COMPLEX(mk) :: divomega + INTEGER :: gi,gj,gk + COMPLEX(mk) :: kx,ky,kz + COMPLEX(mk) :: phix,phiy,phiz + REAL(mk) :: normfac + + !------------------------------------------------------------------------- + ! Check if we run a different/temporary case + !------------------------------------------------------------------------- + + presentcase = ppmpoisson%case + + !----------------------------------------------------------------------- + ! Map data globally to the slabs (XY) + ! This is where the vorticity is extended and padded with 0 for free-space + !----------------------------------------------------------------------- + !Initialise + CALL ppm_map_field_global(topoid,ppmpoisson%topoidxy,meshid,ppmpoisson%meshidxy,info) + !Push the data + CALL ppm_map_field_push(topoid,meshid,fieldin,3,info) + CALL ppm_map_field_send(info) + !Retrieve + CALL ppm_map_field_pop(ppmpoisson%topoidxy,ppmpoisson%meshidxy,ppmpoisson%fldxyr,3,zeros,info) + + !----------------------------------------------------------------------- + ! Do slab FFT (XY) - use the xy topology as its extent has not been halved + !----------------------------------------------------------------------- + CALL ppm_fft_execute_2d(ppmpoisson%topoidxy,& + & ppmpoisson%meshidxy, ppmpoisson%planfxy, & + & ppmpoisson%fldxyr, ppmpoisson%fldxyc, & + & info) + + !----------------------------------------------------------------------- + ! Map to the pencils (Z) + !----------------------------------------------------------------------- + !Initialise + CALL ppm_map_field_global(& + & ppmpoisson%topoidxy, & + & ppmpoisson%topoidz, & + & ppmpoisson%meshidxyc, & + & ppmpoisson%meshidz,info) + + !Push the data + CALL ppm_map_field_push(& + & ppmpoisson%topoidxy, & + & ppmpoisson%meshidxyc,ppmpoisson%fldxyc,3,info) + !Send + CALL ppm_map_field_send(info) + + !Retrieve + CALL ppm_map_field_pop(& + & ppmpoisson%topoidz, & + & ppmpoisson%meshidz,ppmpoisson%fldzc1, & + & 3,zeros,info) + + !----------------------------------------------------------------------- + ! Do pencil FFT (Z) + !----------------------------------------------------------------------- + CALL ppm_fft_execute_1d(ppmpoisson%topoidz,& + & ppmpoisson%meshidz, ppmpoisson%planfz, & + & ppmpoisson%fldzc1, ppmpoisson%fldzc2, & + & info) + + + !----------------------------------------------------------------------- + ! Apply the periodic Greens function + !----------------------------------------------------------------------- + DO isub=1,ppmpoisson%nsublistz + isubl=ppmpoisson%isublistz(isub) + DO k=1,ppmpoisson%ndataz(3,isubl) + DO j=1,ppmpoisson%ndataz(2,isubl) + DO i=1,ppmpoisson%ndataz(1,isubl) + ppmpoisson%fldzc2(1,i,j,k,isub) = ppmpoisson%fldgrnr( i,j,k,isub)*& + & ppmpoisson%fldzc2(1,i,j,k,isub) + ppmpoisson%fldzc2(2,i,j,k,isub) = ppmpoisson%fldgrnr( i,j,k,isub)*& + & ppmpoisson%fldzc2(2,i,j,k,isub) + ppmpoisson%fldzc2(3,i,j,k,isub) = ppmpoisson%fldgrnr( i,j,k,isub)*& + & ppmpoisson%fldzc2(3,i,j,k,isub) + ENDDO + ENDDO + ENDDO + ENDDO + + + !----------------------------------------------------------------------- + ! Spectral derivatives + ! normkx, etc contains 2pi/Lx + !----------------------------------------------------------------------- + normfac = 1.0_MK/ REAL((ppmpoisson%nmfft(1))* & !vertex + & (ppmpoisson%nmfft(2))* & + & (ppmpoisson%nmfft(3)),MK) + DO isub=1,ppmpoisson%nsublistz + isubl=ppmpoisson%isublistz(isub) + DO k=1,ppmpoisson%ndataz(3,isubl) + gk = k - 1 + (ppmpoisson%istartz(3,isubl)-1) + IF (gk .GT. (ppmpoisson%nmfft(3)/2)) gk = gk-(ppmpoisson%nmfft(3)) + kz = CMPLX(0.0_MK,REAL(gk,MK),MK)*ppmpoisson%normkz + DO j=1,ppmpoisson%ndataz(2,isubl) + gj = j - 1 + (ppmpoisson%istartz(2,isubl)-1) + IF (gj .GT. (ppmpoisson%nmfft(2)/2)) gj = gj-(ppmpoisson%nmfft(2)) + ky = CMPLX(0.0_MK,REAL(gj,MK),MK)*ppmpoisson%normky + DO i=1,ppmpoisson%ndataz(1,isubl) + gi = i - 1 + (ppmpoisson%istartz(1,isubl)-1) + IF (gi .GT. (ppmpoisson%nmfft(1)/2)) gi = gi-(ppmpoisson%nmfft(1)) + kx = CMPLX(0.0_MK,REAL(gi,MK),MK)*ppmpoisson%normkx + + phix = ppmpoisson%fldzc2(1,i,j,k,isub) + phiy = ppmpoisson%fldzc2(2,i,j,k,isub) + phiz = ppmpoisson%fldzc2(3,i,j,k,isub) + + ppmpoisson%fldzc2(1,i,j,k,isub) = (ky*phiz-kz*phiy) + ppmpoisson%fldzc2(2,i,j,k,isub) = (kz*phix-kx*phiz) + ppmpoisson%fldzc2(3,i,j,k,isub) = (kx*phiy-ky*phix) + ENDDO + ENDDO + ENDDO + ENDDO + + !----------------------------------------------------------------------- + ! IFFT pencil (Z) + !----------------------------------------------------------------------- + CALL ppm_fft_execute_1d(ppmpoisson%topoidz,& + & ppmpoisson%meshidz, ppmpoisson%planbz, & + & ppmpoisson%fldzc2, ppmpoisson%fldzc1, & + & info) + + !----------------------------------------------------------------------- + ! Map back to slabs (XY) + !----------------------------------------------------------------------- + !Initialise + CALL ppm_map_field_global(& + & ppmpoisson%topoidz, & + & ppmpoisson%topoidxy, & + & ppmpoisson%meshidz, & + & ppmpoisson%meshidxyc,info) + !Push the data + CALL ppm_map_field_push(& + & ppmpoisson%topoidz, & + & ppmpoisson%meshidz,ppmpoisson%fldzc1,3,info) + + !Send + CALL ppm_map_field_send(info) + + !Retrieve + CALL ppm_map_field_pop(& + & ppmpoisson%topoidxy, & + & ppmpoisson%meshidxyc,ppmpoisson%fldxyc, & + & 3,zeros,info) + + !----------------------------------------------------------------------- + ! IFFT (XY) use the non-reduced topology + !----------------------------------------------------------------------- + CALL ppm_fft_execute_2d(ppmpoisson%topoidxy,& + & ppmpoisson%meshidxy, ppmpoisson%planbxy, & + & ppmpoisson%fldxyc, ppmpoisson%fldxyr, & + & info) + + + !----------------------------------------------------------------------- + ! Map back to standard topology (XYZ) + !----------------------------------------------------------------------- + !Initialise + CALL ppm_map_field_global(& + & ppmpoisson%topoidxy, & + & topoid, & + & ppmpoisson%meshidxy, & + & meshid,info) + !Push the data + CALL ppm_map_field_push(& + & ppmpoisson%topoidxy, & + & ppmpoisson%meshidxy,ppmpoisson%fldxyr,3,info) + + !Send + CALL ppm_map_field_send(info) + + !------------------------------------------------------------------------- + ! FINAL RETRIEVE - Here we do different things depending on the task + ! i.e. the receiver varies + !------------------------------------------------------------------------- + IF ((ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd2 .OR. & + & ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd4) ) THEN + CALL ppm_map_field_pop(& + & topoid, & + & meshid,ppmpoisson%drv_vr, & + & 3,gstw,info) + !------------------------------------------------------------------------- + ! Ghost the temporary array for derivatives (drv_vr) + !------------------------------------------------------------------------- + CALL ppm_map_field_ghost_get(topoid,meshid,gstw,info) + CALL ppm_map_field_push(topoid,meshid,ppmpoisson%drv_vr,3,info) + CALL ppm_map_field_send(info) + CALL ppm_map_field_pop(topoid,meshid,ppmpoisson%drv_vr,3,gstw,info) + + ELSE + CALL ppm_map_field_pop(& + & topoid, & + & meshid,fieldout, & + & 3,gstw,info) + ENDIF + + !------------------------------------------------------------------------- + ! Treat ghost layer to make FD stencils work + !------------------------------------------------------------------------- + IF (ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd2) THEN + CALL ppm_poisson_extrapolateghost(topoid,meshid,ppmpoisson%drv_vr,& + & 2,4,gstw,info) + ENDIF + IF (ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd4 .AND.& + & (presentcase .EQ. ppm_poisson_grn_pois_fre)) THEN + CALL ppm_poisson_extrapolateghost(topoid,meshid,ppmpoisson%drv_vr,& + & 2,4,gstw,info) + ENDIF + + !------------------------------------------------------------------------- + ! Optionally do derivatives + ! Perhaps make ppm_poisson_fd take _none as argument. Then maybe no + ! if-statement is required + !------------------------------------------------------------------------- + IF (presentcase .NE. ppm_poisson_grn_reprojec) THEN + IF (ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd2) THEN + CALL ppm_poisson_fd(topoid,meshid,ppmpoisson%drv_vr,fieldout,& + & ppm_poisson_drv_curl_fd2,info) + ENDIF + IF (ppmpoisson%derivatives .EQ. ppm_poisson_drv_curl_fd4) THEN + CALL ppm_poisson_fd(topoid,meshid,ppmpoisson%drv_vr,fieldout,& + & ppm_poisson_drv_curl_fd4,info) + ENDIF + ENDIF + + !------------------------------------------------------------------------- + ! Finally ghost the velocity/stream function field before returning it + ! Also extrapolate if freespace + !------------------------------------------------------------------------- + CALL ppm_map_field_ghost_get(topoid,meshid,gstw,info) + CALL ppm_map_field_push(topoid,meshid,fieldout,3,info) + CALL ppm_map_field_send(info) + CALL ppm_map_field_pop(topoid,meshid,fieldout,3,gstw,info) + + end subroutine mypoisson_solve + + +end module ppmljk_poisson diff --git a/HySoP/unusedOrObsolet/DiscreteTransportProblem.py b/HySoP/unusedOrObsolet/DiscreteTransportProblem.py new file mode 100644 index 000000000..438e6df5b --- /dev/null +++ b/HySoP/unusedOrObsolet/DiscreteTransportProblem.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +""" +@package Problem +Problem representation +""" +from ..Param import * +from DiscreteProblem import DiscreteProblem + + +class DiscreteTransportProblem(DiscreteProblem): + """ + Transport problem discrete representation. + """ + + def __init__(self, advection, domains=None, variables=None, operators=None): + """ + Constructor. + Create a transport problem instance. + + @param advection : Advection operator for transport problem. + @param domains : Additionals domains. + @param variables : Additionnals variables. + @param operators : Additionnals operators. + """ + DiscreteProblem.__init__(self) + ## Current simulation time + self.t = 0 + ## Advection operator for the transport problem + self.advecOp = advection + self.addOperator([self.advecOp]) + if domains != None: + self.addDomain(domains) + if variables != None: + self.addVariable(variables) + if operators != None: + self.addOperator(operators) + ## Splitting informations + self.splittingStep = None + + def step(self, dt): + [c_step[0].applyOperator(self.t, dt * c_step[1], c_step[2]) for c_step in self.operator_list] + self.t += dt + + def solve(self, T, dt): + """ + Solving method. + Solve by applying each operators. For a given splitting. + + @param T : Simulation final time. + @param dt : Simulation time step. + """ + print "\n=== Solving ===" + ite = 0 + if not self.printer is None: + while self.t < T: + self.step(dt) + ite += 1 + #print "iteration ", ite, "\t t =", self.t + self.printer.printStep() + else: + while self.t < T: + self.step(dt) + ite += 1 + #print "Iteration ", ite, "\t t =", self.t, "\t(No output mode)" + print "\n=== End Solving ===" + print "\n=== Timings ===" + c_time = 0. + q_time = 0. + s_time = 0. + c_flop = 0 + c_bytes_accessed = 0 + for op in self.operators: + op_compute_time = 0. + print "Time :", op + for i in xrange(self.domains[0].dimension): + print " - direction ", i, " :", op.compute_time[i], "s" + op_compute_time += op.compute_time[i] + print " - TOTAL ", op_compute_time, "s \t", (op.total_flop / op_compute_time) * 1e-9, "GFlop/s \t", (op.total_bytes_accessed / op_compute_time) * 1e-9, "GB/s" + c_time += op_compute_time + c_flop += op.total_flop + q_time += op.queued_time + s_time += op.submit_time + c_bytes_accessed += op.total_bytes_accessed + print "Computing time : ", c_time, "s \t", (c_flop / c_time) * 1e-9, "GFlop/s \t", (c_bytes_accessed / c_time) * 1e-9, "GB/s" + if not self.operators[0].gpu_kernel is None: + print "OpenCL queued time : ", q_time, "s" + print "OpenCL submit time : ", s_time, "s" + + def __str__(self): + """ToString method""" + s = "DiscreteTransportProblem (DiscreteProblem) : {0}\n".format(id(self)) + s += " {0} domains, {1} variables and {2} operators.\n".format(len(self.domains), len(self.variables), len(self.operators)) + s += " Domains : \n" + for d in self.domains: + s += str(d) + s += "\n Variables : \n" + for v in self.variables: + s += str(v) + s += "\n Operators : \n" + for o in self.operators: + s += str(o) + s += "\n Solver : {0}\n".format(self.solver) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : DiscreteTransportProblem" + print DiscreteTransportProblem.__doc__ diff --git a/HySoP/unusedOrObsolet/GPUParticularSolver.py b/HySoP/unusedOrObsolet/GPUParticularSolver.py new file mode 100644 index 000000000..f87f51852 --- /dev/null +++ b/HySoP/unusedOrObsolet/GPUParticularSolver.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +GPU Particular solver description. +""" +import os +import pyopencl as cl +from ..Param import * +from ParticularSolver import ParticularSolver +from ..Domain.ParticleField import ParticleField +from ..Variable.DiscreteVariable import DiscreteVariable +from ..Operator.RemeshingDOp import RemeshingDOp +from ..Operator.TagDOp import TagDOp +from ..Operator.InterpolationDOp import InterpolationDOp +from ..Operator.RemeshingDOp import RemeshingDOp + + +class GPUParticularSolver(ParticularSolver): + """ + GPU Particular solver description. + Link with differents numericals methods used. Prepare GPU side (memory, kernels, ...) + """ + def __init__(self, problem, + ODESolver, + InterpolationMethod, + RemeshingMethod, + splittingMethod='strang', + platform_id=0, device_id=0, + device_type='gpu', + src=None): + """ + Constructor. + Create a solver description. + """ + ParticularSolver.__init__(self, problem, ODESolver, InterpolationMethod, RemeshingMethod, splittingMethod) + self.parameters_initialization() + self.user_src = src + #Get platform. + self.platform = cl.get_platforms()[platform_id] + #Get device. + if device_type == 'gpu': + self.device = self.platform.get_devices(cl.device_type.GPU)[device_id] + else: + self.device = self.platform.get_devices()[device_id] + print "Running on", self.device.name, "of", self.platform.name, "platform." + #Creates GPU Context + self.ctx = cl.Context([self.device]) + #Create CommandQueue on the GPU Context + self.queue = cl.CommandQueue(self.ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) + + def parameters_initialization(self): + # Modifying domains parameters to fit with float4 or int4 opencl objects + self.gpu_shape = tuple(self.grid.elementNumber) + padding_float = np.zeros(4 - self.grid.dimension, dtype=dtype_real_gpu) + padding_uint = np.zeros(4 - self.grid.dimension, dtype=dtype_integer) + self.grid.min = np.concatenate((self.grid.min, padding_float)).astype(dtype_real_gpu) + self.grid.max = np.concatenate((self.grid.max, padding_float)).astype(dtype_real_gpu) + self.grid.length = np.concatenate((self.grid.length, padding_float)).astype(dtype_real_gpu) + self.grid.elementSize = np.concatenate((self.grid.elementSize, padding_float)).astype(dtype_real_gpu) + self.grid.elementNumber = np.concatenate((self.grid.elementNumber, padding_uint + 1)).astype(dtype_integer) + self.ppos.values.resize(self.gpu_shape, refcheck=False) + + def buffer_allocations(self): + self.gpu_used_mem = 0 + for v in self.discreteProblem.variables: + v.values = np.asarray(v.values, dtype=dtype_real_gpu) + v.gpu_mem_object = cl.Buffer(self.ctx, + cl.mem_flags.READ_WRITE, + size=v.values.nbytes + ) + self.gpu_used_mem += v.gpu_mem_object.size + print "Allocation " + v.name + " on gpu, size:", v.gpu_mem_object.size * 1e-6, 'MBytes' + + if debug > 0: + debug_size = 0 + self.discreteProblem.advecOp.debug_integer = np.zeros(debug, dtype=dtype_integer) + self.discreteProblem.advecOp.debug_integer_buffer = cl.Buffer( + self.ctx, cl.mem_flags.READ_WRITE | cl.mem_flags.COPY_HOST_PTR, + hostbuf=self.discreteProblem.advecOp.debug_integer) + debug_size += self.discreteProblem.advecOp.debug_integer_buffer.size + self.discreteProblem.advecOp.debug_float = np.zeros(debug, dtype=dtype_real_gpu) + self.discreteProblem.advecOp.debug_float_buffer = cl.Buffer( + self.ctx, cl.mem_flags.READ_WRITE | cl.mem_flags.COPY_HOST_PTR, + hostbuf=self.discreteProblem.advecOp.debug_float) + debug_size += self.discreteProblem.advecOp.debug_float_buffer.size + self.gpu_used_mem += debug_size + print "Allocation debug buffer on gpu, size:", debug_size, 'B' + + def initialize(self): + """ + Solver initialisation for a given DiscreteProblem.DiscreteProblem. + + @param discreteProblem : Problem to initialize. + """ + # OpenCL Buffer allocations + print "\n=== Device memory allocations ===" + self.buffer_allocations() + p = self.gpu_used_mem * 100 / (self.device.global_mem_size * 1.) + print "Total memory allocated on gpu :", self.gpu_used_mem * 1e-6, "MBytes (", p, " % of total available memory)" + + # Kernels creation/compilation + print "\n=== Kernel sources compiling ===" + f = open(os.path.join(os.path.split(os.path.abspath(__file__))[0], "gpu_src.cl"), 'r') + self.gpu_src = "".join(f.readlines()) + f.close() + if not self.user_src is None: + f = open(self.user_src, 'r') + self.gpu_src += "".join(f.readlines()) + f.close() + build_options = "-cl-single-precision-constant -cl-opt-disable" + build_options += " -D DIM=" + str(self.dim) + build_options += " -D DEBUG=" + str(debug) + build_options += " -D MAX_LINE_POINTS=" + str(np.max(self.grid.elementNumber)) + self.prg = cl.Program(self.ctx, self.gpu_src).build(build_options) + print self.prg.get_build_info(self.device, cl.program_build_info.LOG) + print self.prg.get_build_info(self.device, cl.program_build_info.OPTIONS) + print self.prg.get_build_info(self.device, cl.program_build_info.STATUS) + + for op in self.discreteProblem.operators: + for k in self.prg.all_kernels(): + if op.gpu_kernel_name == k.get_info(cl.kernel_info.FUNCTION_NAME): + op.gpu_kernel = self.prg + op.gpu_queue = self.queue + op.gpu_shape = self.gpu_shape + + print "\n=== Data initialization ===" + for v in self.discreteProblem.variables: + v_is_init = False + print v.name, + for i,k in enumerate(self.prg.all_kernels()): + if ('init' + v.name) == k.get_info(cl.kernel_info.FUNCTION_NAME): + print 'Initialization Kernel found ', + evt = eval("self.prg."+"init"+v.name)(self.queue, + self.gpu_shape, + None, + v.gpu_mem_object, + dtype_real_gpu(0.), + v.domain.min.astype(dtype_real_gpu), + v.domain.elementNumber.astype(dtype_integer), + v.domain.elementSize.astype(dtype_real_gpu) + ) + self.queue.finish() + print 'compute time :', (evt.profile.end - evt.profile.start) * 1e-9, 's', + v.contains_data, v_is_init = False, True + if not v_is_init: + v.init() + print '... Done' + + print "\n=== Data Transfers host->device ===" + copy_evts = [] + transfered_size = 0 + for v in self.discreteProblem.variables: + if v.contains_data: + print v.name, + if v.dimension == self.dim: + print "Memoire arrangée", + offset = 0 + evt = cl.enqueue_copy(self.queue, v.gpu_mem_object, + v.values[..., 0].ravel(), + device_offset=np.long(offset)) + copy_evts.append(evt) + offset += v.values[..., 0].nbytes + evt = cl.enqueue_copy(self.queue, v.gpu_mem_object, + v.values[..., 1].swapaxes(1, 0).ravel(), + device_offset=np.long(offset)) + copy_evts.append(evt) + if self.dim == 3: + offset += v.values[..., 1].nbytes + evt = cl.enqueue_copy(self.queue, v.gpu_mem_object, + v.values[..., 2].swapaxes(1, 0).swapaxes(2, 0).ravel(), + device_offset=np.long(offset)) + copy_evts.append(evt) + else: + print "Normal layout", + evt = cl.enqueue_copy(self.queue, v.gpu_mem_object, v.values) + copy_evts.append(evt) + print "Transfering", v.values.nbytes * 1e-6, "MBytes ..." + transfered_size += v.values.nbytes + self.queue.finish() + if len(copy_evts)>0: + t = 0. + for evt in copy_evts: + t += (evt.profile.end - evt.profile.start) + print "Transfering host -> device :", t * 1e-9, "s \t", transfered_size / t, "GB/s" + else: + print "No transfers" + + def collect_data(self): + self.queue.finish() + print "\n=== Data Transfers device->host ===" + copy_evts = [] + transfered_size = 0 + for v in self.discreteProblem.variables: + if v.contains_data: + print v.name, + if v.dimension == self.dim: + print "Memoire arrangée", + temp = np.empty(self.gpu_shape, dtype=dtype_real_gpu) + offset = 0 + evt = cl.enqueue_copy(self.queue, temp, v.gpu_mem_object, device_offset=np.long(offset)) + copy_evts.append(evt) + v.values[..., 0] = temp.reshape(self.gpu_shape) + offset += temp.nbytes + evt = cl.enqueue_copy(self.queue, temp, v.gpu_mem_object, device_offset=np.long(offset)) + copy_evts.append(evt) + v.values[..., 1] = temp.reshape(self.gpu_shape).swapaxes(1, 0) + if self.dim == 3: + offset += temp.nbytes + evt = cl.enqueue_copy(self.queue, temp, v.gpu_mem_object, device_offset=np.long(offset)) + copy_evts.append(evt) + v.values[..., 2] = temp.reshape(self.gpu_shape).swapaxes(2, 0).swapaxes(1, 0) + else: + print "Normal layout", + evt = cl.enqueue_copy(self.queue, v.values, v.gpu_mem_object) + copy_evts.append(evt) + print "Transfering", v.values.nbytes * 1e-6, "MBytes ..." + transfered_size += v.values.nbytes + self.queue.finish() + t = 0. + for evt in copy_evts: + t += (evt.profile.end - evt.profile.start) + print "Transfering device -> host :", t * 1e-9, "s \t", transfered_size / t, "GB/s" + + def terminate(self): + self.queue.finish() + + def __str__(self): + """ToString method""" + s = "GPU Particular solver " + s += "\n - ODESolver : " + str(self.ODESolver) + s += "\n - Interpolation : " + str(self.InterpolationMethod) + s += "\n - Remeshing : " + str(self.RemeshingMethod) + s += "\n - GPU informations : " + s += "\n - platform : " + self.platform.name + s += " OpenCL version: " + self.platform.version + s += "\n - device : " + self.device.name + s += " Global Memory available : " + str(self.device.global_mem_size // 1024 // 1024) + " MB ( " + str(self.device.global_mem_size) + " B)" + s += "\n Space index max : " + str(self.device.max_work_item_sizes) + s += " Max workgroup size : " + str(self.device.max_work_group_size) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : GPUParticularSolver" + print GPUParticularSolver.__doc__ diff --git a/HySoP/unusedOrObsolet/GPUParticularSolver_GLRender.py b/HySoP/unusedOrObsolet/GPUParticularSolver_GLRender.py new file mode 100644 index 000000000..24432e771 --- /dev/null +++ b/HySoP/unusedOrObsolet/GPUParticularSolver_GLRender.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +GPU Particular solver description OpenGL rendering. +""" +import os +import sys +import pyopencl as cl +from ..Param import * +from ParticularSolver import ParticularSolver +from GPUParticularSolver import GPUParticularSolver +from ..Domain.ParticleField import ParticleField +from ..Variable.DiscreteVariable import DiscreteVariable +from ..Operator.RemeshingDOp import RemeshingDOp +from ..Operator.TagDOp import TagDOp +from ..Operator.InterpolationDOp import InterpolationDOp +from ..Operator.RemeshingDOp import RemeshingDOp +from ..Operator.VolumeDOp import VolumeDOp +from OpenGL.GL import * +from OpenGL.GLU import * +from OpenGL.GLUT import * +import time + + +class GPUParticularSolver_GLRender(GPUParticularSolver): + """ + GPU Particular solver description. + Link with differents numericals methods used. Prepare GPU side (memory, kernels, ...) + """ + def __init__(self, problem, + ODESolver, + InterpolationMethod, + RemeshingMethod, + splittingMethod='strang', + platform_id=0, + device_id=0, + device_type='gpu', + dt=1., + src=None, + endTime=None): + """ + Constructor. + Create a solver description. + """ + ParticularSolver.__init__(self, problem, ODESolver, InterpolationMethod, RemeshingMethod, splittingMethod) + self.dt = dt + self.parameters_initialization() + self.user_src = src + self.endTime = endTime + if not endTime is None: + self.endTime += self.dt * 1.5 + + self.volume = DiscreteVariable(domain=self.grid, spec=self.gpu_shape[1:], name="Volume") + self.volumeDOp = VolumeDOp(self.volume, self.pscal, + np.prod(self.grid.elementSize[0:self.dim]), level=0.5) + self.discreteProblem.addOperator(self.volumeDOp) + self.discreteProblem.operator_list.append((self.volumeDOp, 1.0, 0)) + + glutInit(sys.argv) + glutInitWindowSize(self.width, self.height) + glutInitWindowPosition(0, 0) + glutCreateWindow('OpenCL/OpenGL Parmepy (' + str(np.prod(self.grid.elementNumber[0:self.grid.dimension])) + ' particles)') + + from pyopencl.tools import get_gl_sharing_context_properties + if sys.platform == "darwin": + self.ctx = cl.Context(properties=get_gl_sharing_context_properties(), + devices=[]) + else: + # Some OSs prefer clCreateContextFromType, some prefer + # clCreateContext. Try both. + try: + self.ctx = cl.Context(properties=[ + (cl.context_properties.PLATFORM, platform)] + + get_gl_sharing_context_properties()) + except: + self.ctx = cl.Context(properties=[ + (cl.context_properties.PLATFORM, platform)] + + get_gl_sharing_context_properties(), + devices=[platform.get_devices()[0]]) + self.device = self.ctx.devices[0] + self.queue = cl.CommandQueue(self.ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) + + self.points = DiscreteVariable(domain=self.parts, dimension=self.dim) + self.points.values = np.asarray(self.points.values, dtype=dtype_real_gpu) + self.vbo_points = glGenBuffers(1) + glBindBuffer(GL_ARRAY_BUFFER, self.vbo_points) + glBufferData(GL_ARRAY_BUFFER, self.points.values.nbytes, None, GL_STREAM_DRAW) + glEnableClientState(GL_VERTEX_ARRAY) + glVertexPointer(self.dim, GL_FLOAT, 0, None) + + self.pcolor = DiscreteVariable(domain=self.parts, dimension=4) + self.pcolor.values = np.asarray(self.pcolor.values, dtype=dtype_real_gpu) + self.vbo_color = glGenBuffers(1) + glBindBuffer(GL_ARRAY_BUFFER, self.vbo_color) + glBufferData(GL_ARRAY_BUFFER, self.pcolor.values.nbytes, None, GL_STREAM_DRAW) + glEnableClientState(GL_COLOR_ARRAY) + glColorPointer(4, GL_FLOAT, 0, None) + + def parameters_initialization(self): + GPUParticularSolver.parameters_initialization(self) + #mouse handling for transforming scene + self.mouse_down = False + self.mouse_old = np.array([0., 0.]) + self.rotate = np.array([0., 0., 0.]) + self.translate = -(self.grid.min + self.grid.length / 2.)[0:3] + self.initrans = np.array([0., 0., -2.]) + self.width, self.height = 800, 800 + + def buffer_allocations(self): + GPUParticularSolver.buffer_allocations(self) + # GL buffer allocation + self.points.gpu_mem_object = cl.GLBuffer(self.ctx, + cl.mem_flags.READ_WRITE, + int(self.vbo_points)) + self.gpu_used_mem += self.ppos.gpu_mem_object.size + print "Allocation points colors to render, size:", self.ppos.gpu_mem_object.size, 'B' + self.pcolor.gpu_mem_object = cl.GLBuffer(self.ctx, + cl.mem_flags.READ_WRITE, + int(self.vbo_color)) + self.gpu_used_mem += self.pscal.gpu_mem_object.size + print "Allocation particles color on gpu, size:", self.pscal.gpu_mem_object.size, 'B' + self.gl_objects = [self.points.gpu_mem_object, self.pcolor.gpu_mem_object] + +###GL CALLBACKS + def timer(self, t): + glutTimerFunc(t, self.timer, t) + glutPostRedisplay() + + def on_key(self, *args): + ESCAPE = '\033' + if args[0] == ESCAPE or args[0] == 'q': + sys.exit() + + def on_click(self, button, state, x, y): + if state == GLUT_DOWN: + self.mouse_down = True + self.button = button + else: + self.mouse_down = False + self.mouse_old[0] = x + self.mouse_old[1] = y + + def on_mouse_motion(self, x, y): + dx = x - self.mouse_old[0] + dy = y - self.mouse_old[0] + if self.mouse_down and self.button == 0: # left button + self.rotate[0] += dy * .02 + self.rotate[1] += dx * .02 + elif self.mouse_down and self.button == 2: # right button + self.translate[2] -= dy * .001 + self.mouse_old[0] = x + self.mouse_old[1] = y + ###END GL CALLBACKS + + def display(self): + if self.endTime is None or (not self.endTime is None and self.discreteProblem.t <= self.endTime): + cl.enqueue_acquire_gl_objects(self.queue, self.gl_objects) + display_step = time.time() - self.display_clock + self.display_clock = time.time() + t = time.time() + self.discreteProblem.step(self.dt) + l = list(self.gpu_shape) + splitting_dir = 1 + nb_ligne = l.pop(splitting_dir) + self.prg.colorize(self.queue, tuple(l), None, + self.pscal.gpu_mem_object, + self.pcolor.gpu_mem_object, + self.points.gpu_mem_object, + dtype_integer(splitting_dir), + dtype_integer(nb_ligne), + self.grid.min, + self.grid.elementNumber.astype(dtype_integer), + self.grid.elementSize + ) + glutSetWindowTitle("OpenCL/OpenGL Parmepy T={0:8.4f} ( {1} particles)".format( + self.discreteProblem.t, np.prod(self.grid.elementNumber[0:self.grid.dimension]))) + cl.enqueue_release_gl_objects(self.queue, self.gl_objects) + self.queue.finish() + print "Compute time :", (time.time() - t) * 1e3, "ms, \t over ", display_step * 1e3, "ms, \t", 1. / (time.time() - t), "fps" + + glFlush() + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + #handle mouse transformations + glTranslatef(self.initrans[0], self.initrans[1], self.initrans[2]) + glRotatef(self.rotate[0], 1, 0, 0) + glRotatef(self.rotate[1], 0, 1, 0) # we switched around the axis so make this rotate_z + glTranslatef(self.translate[0], self.translate[1], self.translate[2]) + + glEnable(GL_POINT_SMOOTH) + glPointSize(1) + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + glBindBuffer(GL_ARRAY_BUFFER, self.vbo_color) + glColorPointer(4, GL_FLOAT, 0, None) + glBindBuffer(GL_ARRAY_BUFFER, self.vbo_points) + glVertexPointer(self.dim, GL_FLOAT, 0, None) + + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_COLOR_ARRAY) + glDrawArrays(GL_POINTS, 0, np.prod(self.gpu_shape)) + glDisableClientState(GL_COLOR_ARRAY) + glDisableClientState(GL_VERTEX_ARRAY) + + #glDisable(GL_BLEND) + orig = np.array([0, 0, 0]) + x_one = np.array([1, 0, 0]) + y_one = np.array([0, 1, 0]) + z_one = np.array([0, 0, 1]) + glColor3f(1, 0, 0) # red + self.draw_line(orig, x_one) + glColor3f(0, 1, 0) # green + self.draw_line(orig, y_one) + glColor3f(0, 0, 1) # blue + self.draw_line(orig, z_one) + + def draw_line(self, v1, v2): + glBegin(GL_LINES) + glVertex3f(v1[0], v1[1], v1[2]) + glVertex3f(v2[0], v2[1], v2[2]) + glEnd() + + def initialize(self): + """ + Solver initialisation for a given DiscreteProblem.DiscreteProblem. + + @param discreteProblem : Problem to initialize. + """ + GPUParticularSolver.initialize(self) + + glutDisplayFunc(self.display) + glViewport(0, 0, self.width, self.height) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(np.max(self.grid.length) * 30., self.width / float(self.height), 0.1, 4.) + glMatrixMode(GL_MODELVIEW) + + #handle user input + glutKeyboardFunc(self.on_key) + glutMouseFunc(self.on_click) + glutMotionFunc(self.on_mouse_motion) + + #this will call draw every 10ms + self.display_clock = time.time() + self.display_time_step = 10 + glutTimerFunc(self.display_time_step, self.timer, self.display_time_step) + + glClearColor(1, 1, 1, 1) + glColor(0, 0, 1) + + print "\n=== Solving ===" + print "Début de la boucle GLUT. ('q' ou 'ESC' pour quiter)" + self.discreteProblem.solve = glutMainLoop() + + def __str__(self): + """ToString method""" + s = "GPU Particular solver OpenGL rendering" + s += "\n - ODESolver : " + str(self.ODESolver) + s += "\n - Interpolation : " + str(self.InterpolationMethod) + s += "\n - Remeshing : " + str(self.RemeshingMethod) + s += "\n - GPU informations : " + s += "\n - platform : " + self.platform.name + s += " OpenCL version: " + self.platform.version + s += "\n - device : " + self.device.name + s += " Global Memory available : " + str(self.device.global_mem_size // 1024 // 1024) + " MB ( " + str(self.device.global_mem_size) + " B)" + s += "\n Space index max : " + str(self.device.max_work_item_sizes) + s += " Max workgroup size : " + str(self.device.max_work_group_size) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : GPUParticularSolver_GLRender" + print GPUParticularSolver_GLRender.__doc__ diff --git a/HySoP/unusedOrObsolet/InterpolationDOp.py b/HySoP/unusedOrObsolet/InterpolationDOp.py new file mode 100644 index 000000000..de3db03b0 --- /dev/null +++ b/HySoP/unusedOrObsolet/InterpolationDOp.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +""" +@package Operator +Operator representation +""" +from ..Param import * +from DiscreteOperator import DiscreteOperator +import time + + +class InterpolationDOp(DiscreteOperator): + """ + Interpolation operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, position, velocityField, resvelo, method): + """ + Constructor. + Create a Interpolation operator on a given discrete domain. + Work on a position to interpolate velocity from a grid. + + @param position : particles positions. + @param velocityField : grid velocity. + @param resvelo DiscreteVariable.DiscreteVariable : new velocity + @param method : Numerical method. + """ + DiscreteOperator.__init__(self) + ## Particles positions. + self.ppos = position + ## Grid velocity values. + self.gvelo = velocityField + ## Particles velocity + self.resultVelocity = resvelo + self.addVariable([self.ppos, self.gvelo, self.resultVelocity]) + self.numMethod = method + self.compute_time = 0. + self.queued_time = 0. + self.submit_time = 0. + self.total_flop = 0 + + def setResultVariable(self, resvelo): + """ + Set results variables + + @param resvelo DiscreteVariable.DiscreteVariable : new velocity + """ + ## Particles velocity + self.resultVelocity = resvelo + self.addVariable([self.resultVelocity]) + + def applyOperator(self, t, dt, splittingDirection): + """ + Apply advection operator. + + @param t : current time. + @param dt : time step for advection. + @param splittingDirection : direction to advect. + """ + #for i in self.gvelo.domain.explore(): + # self.resultVelocity.values[i] = self.numMethod.interpolate(t, self.ppos.values[i], splittingDirection) + c_time = time.time() + ## ------------------- NumPy Optimisation + self.resultVelocity.values = self.numMethod.interpolate(t, self.ppos.values, splittingDirection) + ## ------------------- + self.compute_time += (time.time() - c_time) + self.total_flop += self.numMethod.nb_flop * np.prod(self.gvelo.values.shape[0:-1]) + + def __str__(self): + """ToString method""" + return "InterpolationDOp (DiscreteOperator)" + +if __name__ == "__main__": + print __doc__ + print "- Provided class : InterpolationDOp" + print InterpolationDOp.__doc__ diff --git a/HySoP/unusedOrObsolet/ParticleField.py b/HySoP/unusedOrObsolet/ParticleField.py new file mode 100644 index 000000000..9b9d57644 --- /dev/null +++ b/HySoP/unusedOrObsolet/ParticleField.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +""" +@package Domain +Physical domain representation. +""" +from ..Param import * +from DiscreteDomain import DiscreteDomain + + +class ParticleField(DiscreteDomain): + """ + Particle field. + DiscreteDomain.DiscreteDomain specialization. + """ + + def __init__(self, grid): + """ + Constructor. + Create a list of Particle from each node of a given grid. + + @param grid Grid.Grid : grid to create Particles from + """ + DiscreteDomain.__init__(self, grid.dimension) + self.elementNumber = np.copy(grid.elementNumber) + + def setPositions(self, ppos): + """ + Set positions as variable. + Change exploring method. + + @param ppos : position variable. + """ + self.positions = ppos.values + + def __str__(self): + """ + ToString method. + """ + s = "ParticleField of " + str(np.prod(self.elementNumber)) + " Particles" + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : ParticleField" + print ParticleField.__doc__ diff --git a/HySoP/unusedOrObsolet/TagDOp.py b/HySoP/unusedOrObsolet/TagDOp.py new file mode 100644 index 000000000..5b2ae2e3d --- /dev/null +++ b/HySoP/unusedOrObsolet/TagDOp.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +""" +@package Operator +Operator representation +""" +from DiscreteOperator import DiscreteOperator + +providedClass = "TagDOp" + + +class TagDOp(DiscreteOperator): + """ + Tag operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, partPositions, partVelocities, grid, resbloc, restag): + """ + Constructor. + Create a Tag operator. + Work on given particles positions and velocities to compute particles' type and tag. + + @param ppos : particles positions. + @param pvelo : particles velocities. + @param grid : underlying grid. + @param resbloc DiscreteVariable.DiscreteVariable : particles bloc type. + @param restag DiscreteVariable.DiscreteVariable : particles tag. + """ + DiscreteOperator.__init__(self) + ## Particles positions. + self.ppos = partPositions + ## Particles velocities. + self.pvelo = partVelocities + ## grid + self.grid = grid + ## Tag + self.resultTag = restag + ## Bloc + self.resultBloc = resbloc + self.addVariable([self.ppos, self.pvelo, self.resultBloc, self.resultTag]) + + def setResultVariable(self, resbloc, restag): + """ + Set results variables + + @param resbloc DiscreteVariable.DiscreteVariable : particles bloc type. + @param restag DiscreteVariable.DiscreteVariable : particles tag. + """ + ## Tag + self.resultTag = restag + ## Bloc + self.resultBloc = resbloc + self.addVariable([self.resultBloc, self.resultTag]) + + def _nint(self, x): + """ + Nearest interger function. + + @param x : real number. + @return : x nearest integer. + """ + if x > -0.5: + return int(x + 0.5) + else: + return int(x + 0.5) - 1 + + def applyOperator(self, t, dt, splittingDirection): + """ + Apply advection operator. + """ + #Used dimension + d = splittingDirection + bloc_size = 2 + for line in self.grid.explore(d): + nb_bloc = len(line) / bloc_size + d_bloc = bloc_size * self.grid.elementSize[d] + eps_bl = self.grid.elementSize[d] * 0.000000001 + cfl = dt / self.grid.elementSize[d] + max_V = self.pvelo.values[line[0]][d] + for i in line: + if max_V < self.pvelo.values[i][d]: + max_V = self.pvelo.values[i][d] + bl_nbPart = [0 for i in xrange(nb_bloc)] + bl_type = [0 for i in xrange(nb_bloc)] + bl_ind = [0 for i in xrange(nb_bloc)] + bl_final_ind = [0 for i in xrange(nb_bloc)] + bl_lambdaMin = [max_V * cfl for i in xrange(nb_bloc)] + p_ind_bl = {} + for i in line: + self.resultBloc.values[i] = 0 + self.resultTag.values[i] = -1 + # Update bloc infos + for i in line: + ind_bl = int((self.grid.points[i][d] - self.grid.min[d] + eps_bl) / d_bloc) + bl_lambdaMin[ind_bl] = min([bl_lambdaMin[ind_bl], self.pvelo.values[i][d] * cfl]) + bl_nbPart[ind_bl] += 1 + bl_final_ind[ind_bl] = i + # Compute bl_lambdaMin from next bloc + for i in xrange(nb_bloc - 1): + ind = tuple([bl_final_ind[i][dd] + 1 if dd == d else bl_final_ind[i][dd] for dd in xrange(len(line[0]))]) + bl_lambdaMin[i] = min([bl_lambdaMin[i], self.pvelo.values[ind][d] * cfl]) + # Last bloc + bl_lambdaMin[nb_bloc - 1] = min([bl_lambdaMin[nb_bloc - 1], self.pvelo.values[line[0]][d] * cfl]) + # Bloc type + for i in xrange(nb_bloc): + ind = self._nint(bl_lambdaMin[i]) + #print i, ind, bl_lambdaMin[i] + if bl_lambdaMin[i] - ind + eps_bl < 0.: + # Center bloc + #print "Centré" + bl_type[i] = 1 + bl_ind[i] = ind + 1 + else: + # Left bloc + #print "Gauche" + bl_type[i] = 0 + bl_ind[i] = ind + # Update particles results + for i in line: + ind_bl = int((self.grid.points[i][d] - self.grid.min[d] + eps_bl) / d_bloc) + p_ind_bl[i] = bl_ind[ind_bl] + self.resultBloc.values[i] = bl_type[ind_bl] + for i in xrange(len(line) - 1): + if self.resultTag.values[line[i]] == -1 and (line[i][d] < (self.resultTag.domain.elementNumber[d] - 1)) and line[i][d] > 0: + if (p_ind_bl[line[i]] != p_ind_bl[line[i + 1]]) and (self.resultBloc.values[line[i]] != self.resultBloc.values[line[i + 1]]): + # tag particle i and i+1 + print "Tag de la particule", line[i], "et", line[i + 1] + self.resultTag.values[line[i]] = 1 + self.resultTag.values[line[i + 1]] = 2 + else: + # No tag particle i + self.resultTag.values[line[i]] = 0 + if (p_ind_bl[line[0]] != p_ind_bl[line[-1]]) and (self.resultBloc.values[line[0]] != self.resultBloc.values[line[-1]]): + # tag particle 0 and -1 + print "Tag de la particule", line[0], "et", line[-1] + self.resultTag.values[line[0]] = 2 + self.resultTag.values[line[-1]] = 1 + else: + # No tag particle 0 and -1 + self.resultTag.values[line[0]] = 0 + self.resultTag.values[line[-1]] = 0 + + def __str__(self): + """ToString method""" + s = "TagDOp (DiscreteOperator) : {0} \n".format(id(self)) + s += " particles positions = {0}, particles scalar = {1}\n".format(id(self.ppos), id(self.pscal)) + s += " Variables : \n" + for v in self.variables: + s += str(id(v)) + "\n" + s += " Domains : \n" + for d in self.domains: + s += str(id(d)) + "\n" + return s + "\n" + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ diff --git a/HySoP/unusedOrObsolet/VelocityDOp.py b/HySoP/unusedOrObsolet/VelocityDOp.py new file mode 100644 index 000000000..b35a362a4 --- /dev/null +++ b/HySoP/unusedOrObsolet/VelocityDOp.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +""" +@package Operator +Operator representation +""" +from ..Param import * +from DiscreteOperator import DiscreteOperator +import time +import pyopencl as cl + +providedClass = "VelocityDOp" + + +class VelocityDOp(DiscreteOperator): + """ + Advection operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, velo_op): + """ + Constructor. + Create a Transport operator on a given continuous domain. + Work on a given scalar at a given velocity to produce scalar distribution at new positions. + + @param advec : Advection operator. + """ + DiscreteOperator.__init__(self) + self.is_splittable = False + ## Velocity. + self.velocity = velo_op.velocity.discreteVariable + ## Transported scalar. + self.formula = velo_op.formula + self.period = velo_op.period + self.addVariable([self.velocity]) + self.gpu_kernel_name = "velocity" + self.compute_time = [0., 0., 0.] + self.submit_time = 0. + self.queued_time = 0. + self.total_flop = 0 + self.total_bytes_accessed = 0 + + def applyOperator(self, t, dt, splittingDirection): + """ + Apply advection operator. + + @param t : current time. + @param dt : time step for advection. + @param splittingDirection : direction to advect. + """ + if self.gpu_kernel is None: + raise NotImplementedError("No implementation for velocity opérator on CPU.") + else: + evt = self.gpu_kernel.velocity(self.gpu_queue, tuple(self.gpu_shape), None, + self.velocity.gpu_mem_object, + dtype_real_gpu(t), dtype_real_gpu(self.period), + self.velocity.domain.min.astype(dtype_real_gpu), + self.velocity.domain.elementNumber.astype(dtype_integer), + self.velocity.domain.elementSize.astype(dtype_real_gpu) + ) + # self.gpu_queue.finish() + # cl.enqueue_copy(self.gpu_queue, self.resultPosition.values, self.resultPosition.gpu_mem_object) + # print self.resultPosition.values + self.gpu_queue.finish() + #temp_tab = np.zeros_like(self.velocity.values) + #cl.enqueue_copy(self.gpu_queue, temp_tab, self.velocity.gpu_mem_object) + #self.gpu_queue.finish() + #print temp_tab + self.queued_time += (evt.profile.submit - evt.profile.queued) * 1e-9 + self.submit_time += (evt.profile.start - evt.profile.submit) * 1e-9 + self.compute_time[splittingDirection] += (evt.profile.end - evt.profile.start) * 1e-9 + self.total_flop += 32 * np.prod(self.gpu_shape) + self.total_bytes_accessed += 4 * 2 * np.prod(self.gpu_shape) + #print "Advection:", self.compute_time * 1e-9 + + def __str__(self): + """ToString method""" + return "VelocityDOp (DiscreteOperator)" + +if __name__ == "__main__": + print __doc__ + print "- Provided class : VelocityDOp" + print VelocityDOp.__doc__ diff --git a/HySoP/unusedOrObsolet/VelocityOp.py b/HySoP/unusedOrObsolet/VelocityOp.py new file mode 100644 index 000000000..18c5ffbb5 --- /dev/null +++ b/HySoP/unusedOrObsolet/VelocityOp.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +""" +@package Operator +Operator representation +""" +from ..Param import * +from ContinuousOperator import ContinuousOperator +from VelocityDOp import VelocityDOp + + +class VelocityOp(ContinuousOperator): + """ + Velocity operator representation + """ + + def __init__(self, velocity, formula=None, period=10.): + """ + Constructor. + Create an Velocity operator from given variables velocity and scalar. + + @param velocity ContinuousVariable.ContinuousVariable : velocity variable. + @param scalar ContinuousVariable.ContinuousVariable : scalar variable. + """ + ContinuousOperator.__init__(self) + ## advection velocity variable + self.velocity = velocity + ## advected scalar variable + self.formula = formula + self.period = period + self.addVariable([self.velocity]) + + def discretize(self, spec=None): + """ + Velocity operator discretization method. + Create an VelocityDOp.VelocityDOp from given specifications. + + @param spec : discretization specifications, not used. + """ + if self.discreteOperator is None: + self.discreteOperator = VelocityDOp(self) + + def __str__(self): + """ToString method""" + s = " Velocity operator (ContinuousOperator)" + return s + "\n" + +if __name__ == "__main__": + print __doc__ + print "- Provided class : VelocityOp" + print VelocityOp.__doc__ diff --git a/HySoP/unusedOrObsolet/VolumeDOp.py b/HySoP/unusedOrObsolet/VolumeDOp.py new file mode 100644 index 000000000..f21cf0a6a --- /dev/null +++ b/HySoP/unusedOrObsolet/VolumeDOp.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +""" +@package Operator +Operator representation +""" +from ..Param import * +from DiscreteOperator import DiscreteOperator +import time +import pyopencl as cl +import pylab as pl + +providedClass = "VolumeDOp" + + +class VolumeDOp(DiscreteOperator): + """ + Advection operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, volume, pscal, pvolume, level=0.5, filename='./volume.dat'): + """ + Constructor. + Create a Transport operator on a given continuous domain. + Work on a given scalar at a given velocity to produce scalar distribution at new positions. + + @param advec : Advection operator. + """ + DiscreteOperator.__init__(self) + self.is_splittable = False + ## Volume. + self.volume = volume + self.pscal = pscal + self.pvolume = pvolume + self.addVariable([self.volume, self.pscal]) + self.level = level + self.volume_evolution = [] + self.gpu_kernel_name = "volume" + self.compute_time = [0., 0., 0.] + self.submit_time = 0. + self.queued_time = 0. + self.total_flop = 0 + self.total_bytes_accessed = 0 + self.file = open(filename, 'w', 1) + + def applyOperator(self, t, dt, splittingDirection): + """ + Apply advection operator. + + @param t : current time. + @param dt : time step for advection. + @param splittingDirection : direction to advect. + """ + if self.gpu_kernel is None: + raise NotImplementedError("No implementation for velocity opérator on CPU.") + else: + l = list(self.gpu_shape) + nb_ligne = l.pop(splittingDirection) + if debug == 0: + evt = self.gpu_kernel.volume(self.gpu_queue, tuple(l), None, + self.pscal.gpu_mem_object, + self.volume.gpu_mem_object, + dtype_real_gpu(self.level), dtype_real_gpu(self.pvolume), dtype_integer(splittingDirection), dtype_integer(nb_ligne), + self.volume.domain.min.astype(dtype_real_gpu), + self.volume.domain.length.astype(dtype_real_gpu), + self.volume.domain.elementNumber.astype(dtype_integer), + self.volume.domain.elementSize.astype(dtype_real_gpu) + ) + else: + evt = self.gpu_kernel.volume(self.gpu_queue, tuple(l), None, + self.pscal.gpu_mem_object, + self.volume.gpu_mem_object, + self.debug_float_buffer, self.debug_integer_buffer, + dtype_real_gpu(self.length), dtype_real_gpu(self.pvolume), dtype_integer(splittingDirection), dtype_integer(nb_ligne), + self.volume.domain.min.astype(dtype_real_gpu), + self.volume.domain.length.astype(dtype_real_gpu), + self.volume.domain.elementNumber.astype(dtype_integer), + self.volume.domain.elementSize.astype(dtype_real_gpu) + ) + self.gpu_queue.finish() + cl.enqueue_copy(self.gpu_queue, self.volume.values, self.volume.gpu_mem_object) + self.file.write(str(self.volume.values.sum()) + '\n') + if debug > 0: + cl.enqueue_copy(self.gpu_queue, self.debug_float, self.debug_float_buffer) + cl.enqueue_copy(self.gpu_queue, self.debug_integer, self.debug_integer_buffer) + print " :: DEBUG :: ", self.debug_float + print " :: DEBUG :: ", self.debug_integer + self.queued_time += (evt.profile.submit - evt.profile.queued) * 1e-9 + self.submit_time += (evt.profile.start - evt.profile.submit) * 1e-9 + self.compute_time[splittingDirection] += (evt.profile.end - evt.profile.start) * 1e-9 + self.total_flop += nb_ligne * np.prod(l) + self.total_bytes_accessed += nb_ligne * np.prod(l) * 4 + #print "Advection:", self.compute_time * 1e-9 + + def __str__(self): + """ToString method""" + return "VolumeDOp (DiscreteOperator)" + +if __name__ == "__main__": + print __doc__ + print "- Provided class : VolumeDOp" + print VolumeDOp.__doc__ diff --git a/HySoP/unusedOrObsolet/continuous.py b/HySoP/unusedOrObsolet/continuous.py new file mode 100644 index 000000000..9f7b5f11d --- /dev/null +++ b/HySoP/unusedOrObsolet/continuous.py @@ -0,0 +1,77 @@ +""" +@package parmepy.problem.continuous + +Abstract problem representation. +""" +from abc import ABCMeta, abstractmethod + + +class ContinuousProblem: + """ + Abstract description of continuous problem. + """ + + __metaclass__ = ABCMeta + + @abstractmethod + def __init__(self): + """ + Create an empty problem. + """ + print "CONTINUOUS PROBLEM" + ## Operators of the problem. + self.operators = [] + ## Discretization of the problem. + self.discreteProblem = None + + @abstractmethod + def discretize(self, spec=None): + """ + Abstract method. + Must be implemented by sub-class. + + @param spec : discretization specifications + """ + raise NotImplementedError("Need to override method in a subclass") + + @abstractmethod + def setSolver(self, solver): + """ + Set solver for the discrete problem. + It must have a discrete Problem. + + @param solver : solver to use. + """ + if self.discreteProblem == None: + raise NotImplementedError("Cannot set solver on a non discretized problem ") + self.discreteProblem.setSolver(solver) + + @abstractmethod + def setPrinter(self, printer): + """ + Set result printer. + It must have a discrete Problem. + + @param printer : printer to use. + """ + if self.discreteProblem == None: + raise NotImplementedError("Cannot set printer on a non discretized problem ") + self.discreteProblem.setPrinter(printer) + + @abstractmethod + def solve(self, T, dt): + """ + Solving the problem. + It must have a discrete Problem to solve. + + @param T : Simulation final time + @param dt : Simulation time step + """ + if self.discreteProblem == None: + raise NotImplementedError("Cannot solve a non discretized problem ") + self.discreteProblem.solve(T, dt) + +if __name__ == "__main__": + print __doc__ + print "- Provided class : ContinuousProblem" + print ContinuousProblem.__doc__ diff --git a/HySoP/unusedOrObsolet/cpu_data_transfer-subarray.py b/HySoP/unusedOrObsolet/cpu_data_transfer-subarray.py new file mode 100644 index 000000000..310d86314 --- /dev/null +++ b/HySoP/unusedOrObsolet/cpu_data_transfer-subarray.py @@ -0,0 +1,376 @@ +# -*- coding: utf-8 -*- +""" +@file cpu_data_transfer-subarray.py +Communicator MPI to synchronize ghost +""" + +import numpy as np +import mpi4py.MPI as MPI +import time + + +class Synchronize(object): + """ + Synchronization of ghosts values on domain + """ + + def __init__(self, topology): + """ + Constructor. + @param topology : Local topology + """ + self.topo = topology + self.total_time = 1 + ## problem le topology.mesh.resolution peut etre different du shape du field rentre + self.size= topology.mesh.resolution + + + def apply(self, *listFields): + """ + Application of synchronization at a list of Fields + @ list of Fields or one Fields. + Make the synchronization with this law : + for synchronize P1 with P2 : + if P1.rank < P2.rank + P1 send, own and after recv ghost + P2 recv ghost and send his own + else + do the reciproque + And we do that direction by direction, with a sort table of + the synchro who need. + """ +# Rappel de la correspondance direction <-> indice +# self.topo.tabSort = np.array([[self.up,0] , [self.down,1] , [self.east,2], [self.west,3], +# [self.north,4],[self.south,5]]) + self.compute_time = time.time() + self.comm = main_comm + self.count = None + + for f in listFields: +# self.size= f.data[0].shape +# print 'size array:' ,self.size, 'size topo :', self.topo.mesh.resolution +# print 'rank', self.topo.rank, 'tab',self.topo.tabSort + for i in xrange(self.topo.tabSort[:,0].shape[0]) : +# print 'rang, destinataire, orientation', self.topo.rank, self.topo.tabSort[i,0], self.topo.tabSort[i,1] + if ( self.topo.rank == self.topo.tabSort[i,0]): + # UP DOWN + if(self.topo.tabSort[i,1] == 0): + for j in xrange(self.topo.dim) : + f[j][self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] =\ + f[j][self.topo.ghosts[0]:2*self.topo.ghosts[0],:,:] + + if(self.topo.tabSort[i,1] == 1): + for j in xrange(self.topo.dim) : + f[j][0:self.topo.ghosts[0],:,:] =\ + f[j][self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:] + + # WEST EAST + if(self.topo.tabSort[i,1] == 2): + for j in xrange(self.topo.dim) : + f[j][:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] =\ + f[j][:,self.topo.ghosts[1]:2*self.topo.ghosts[1],:] + + if(self.topo.tabSort[i,1] == 3): + for j in xrange(self.topo.dim) : + f[j][:,0:self.topo.ghosts[1],:] =\ + f[j][:,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1]:self.topo.mesh.resolution[1]-self.topo.ghosts[1],:] + + # NORTH SOUTH + if(self.topo.tabSort[i,1] == 4): + for j in xrange(self.topo.dim) : + f[j][:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] =\ + f[j][:,:,self.topo.ghosts[2]:2*self.topo.ghosts[2]] + + if(self.topo.tabSort[i,1] == 5): + for j in xrange(self.topo.dim) : + f[j][:,:,0:self.topo.ghosts[2]] =\ + f[j][:,:,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]:self.topo.mesh.resolution[2]-self.topo.ghosts[2]] + else : +# if(self.topo.tabSort[i,1] == 'up'): + if(self.topo.tabSort[i,1] == 0): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'UP',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.UPsend(self.topo.tabSort[i,0], f) + else : +# print 'UP', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.UPrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'down'): + if(self.topo.tabSort[i,1] == 1): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'DOWN',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.DOWNsend(self.topo.tabSort[i,0], f) + else : +# print 'DOWN', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.DOWNrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'east'): + if(self.topo.tabSort[i,1] == 2): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'EST',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.EASTsend(self.topo.tabSort[i,0], f) + else : +# print 'EST', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.EASTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'west'): + if(self.topo.tabSort[i,1] == 3): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'WEST',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.WESTsend(self.topo.tabSort[i,0], f) + else : +# print 'WEST', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.WESTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'north'): + if(self.topo.tabSort[i,1] == 4): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'NORTH',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.NORTHsend(self.topo.tabSort[i,0], f) + else : +# print 'NORTH', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.NORTHrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'south'): + if(self.topo.tabSort[i,1] == 5): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'SOUTH',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.SOUTHsend(self.topo.tabSort[i,0], f) + else : +# print 'SOUTH', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.SOUTHrecv(self.topo.tabSort[i,0], f) + self.compute_time = time.time() - self.compute_time + self.total_time += self.compute_time + + return self.compute_time + + + def UPsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:].shape) + startsSend = np.asarray([self.topo.mesh.resolution[0]-2*self.topo.ghosts[0],0,0]) + UPtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + UPtypeSend.Create_contiguous( UPtypeSend.Get_true_extent()[1] + UPtypeSend.Get_true_extent()[0]) + UPtypeSend.Commit() + self.comm.Send([listFields[i],self.count, UPtypeSend ], dest=proc, tag=11) + UPtypeSend.Free() + startsRecv = [self.topo.mesh.resolution[0]-self.topo.ghosts[0],0,0] + UPtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + UPtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, UPtypeRecv] , source=proc, tag=11) + listFields[i][ + self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:]\ + = data[self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] + UPtypeRecv.Free() + + + def DOWNsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + self.topo.ghosts[0]:2*self.topo.ghosts[0],:,:].shape) + startsSend = np.asarray([self.topo.ghosts[0],0,0]) + DOWNtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + DOWNtypeSend.Commit() + self.comm.Send([ listFields[i], DOWNtypeSend ], dest=proc, tag=22) + DOWNtypeSend.Free() + startsRecv = [0,0,0] + DOWNtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + DOWNtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, DOWNtypeRecv], source=proc, tag=22) + listFields[i][0:self.topo.ghosts[0],:,:] = data[0:self.topo.ghosts[0],:,:] + DOWNtypeRecv.Free() + + def EASTsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1]:self.topo.mesh.resolution[1]-self.topo.ghosts[1],:].shape) + startsSend = np.asarray([0,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1],0]) + EASTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + EASTtypeSend.Commit() + self.comm.Send([ listFields[i], EASTtypeSend ], dest=proc, tag=33) + EASTtypeSend.Free() + startsRecv = [0,self.topo.mesh.resolution[1]-self.topo.ghosts[1],0] + EASTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + EASTtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, EASTtypeRecv] , source=proc, tag=33) + listFields[i][ + :,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1] ,:]\ + = data[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] + EASTtypeRecv.Free() + + def WESTsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,self.topo.ghosts[1]:2*self.topo.ghosts[1],:].shape) + startsSend = np.asarray([0,self.topo.ghosts[1],0]) + WESTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + WESTtypeSend.Commit() + self.comm.Send([ listFields[i], WESTtypeSend ], dest=proc, tag=44) + WESTtypeSend.Free() + startsRecv = [0,0,0] + WESTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + WESTtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, WESTtypeRecv], source=proc, tag=44) + listFields[i][:,0:self.topo.ghosts[1],:] = data[:,0:self.topo.ghosts[1],:] + WESTtypeRecv.Free() + + + def NORTHsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,:,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]:self.topo.mesh.resolution[2]-self.topo.ghosts[2]].shape) + startsSend = np.asarray([0,0,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]]) + NORTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + NORTHtypeSend.Commit() + self.comm.Send([listFields[i], NORTHtypeSend ], dest=proc, tag=55) + NORTHtypeSend.Free() + startsRecv = [0,0,self.topo.mesh.resolution[2]-self.topo.ghosts[2]] + NORTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + NORTHtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, NORTHtypeRecv] , source=proc, tag=55) + listFields[i][ + :,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]]\ + = data[:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] + NORTHtypeRecv.Free() + + def SOUTHsend(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,:,self.topo.ghosts[2]:2*self.topo.ghosts[2]].shape) + startsSend = np.asarray([0,0,self.topo.ghosts[2]]) + SOUTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + SOUTHtypeSend.Commit() + self.comm.Send([ listFields[i], SOUTHtypeSend ], dest=proc, tag=66) + SOUTHtypeSend.Free() + startsRecv = [0,0,0] + SOUTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + SOUTHtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, SOUTHtypeRecv], source=proc, tag=66) + listFields[i][:,:,0:self.topo.ghosts[2]] = data[:,:,0:self.topo.ghosts[2]] + SOUTHtypeRecv.Free() + + def UPrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:].shape) + startsRecv = np.asarray([self.topo.mesh.resolution[0]-self.topo.ghosts[0],0,0]) + UPtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + UPtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, UPtypeRecv], source=proc, tag=22) + UPtypeRecv.Free() + listFields[i][self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] = data[ \ + self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] + startsSend = [self.topo.mesh.resolution[0]-2*self.topo.ghosts[0],0,0] + UPtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + UPtypeSend.Commit() + self.comm.Send([listFields[i], UPtypeSend], dest=proc, tag=22) + UPtypeSend.Free() + + + def DOWNrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + 0:self.topo.ghosts[0],:,:].shape) + startsRecv = np.asarray([0,0,0]) + data=listFields[i] + DOWNtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + DOWNtypeRecv.Create_contiguous( DOWNtypeRecv.Get_true_extent()[1] + DOWNtypeRecv.Get_true_extent()[0]) + DOWNtypeRecv.Commit() + self.comm.Recv([data, self.count , DOWNtypeRecv], source = proc, tag =11) + DOWNtypeRecv.Free() + listFields[i][0:self.topo.ghosts[0],:,:] = data[0:self.topo.ghosts[0],:,:] + startsSend = [self.topo.ghosts[0],0,0] + DOWNtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + DOWNtypeSend.Commit() + self.comm.Send([listFields[i], DOWNtypeSend], dest = proc, tag =11) + DOWNtypeSend.Free() + + + def EASTrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:].shape) + startsRecv = np.asarray([0,self.topo.mesh.resolution[1]-self.topo.ghosts[1],0]) + EASTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + EASTtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, EASTtypeRecv], source=proc, tag=44) + EASTtypeRecv.Free() + listFields[i][:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] = data[ \ + :,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] + startsSend = [0,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1],0] + EASTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + EASTtypeSend.Commit() + self.comm.Send([listFields[i], EASTtypeSend], dest=proc, tag=44) + EASTtypeSend.Free() + + def WESTrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,0:self.topo.ghosts[1],:].shape) + startsRecv = np.asarray([0,0,0]) + WESTtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + WESTtypeRecv.Commit() + data=listFields[i] + self.comm.Recv([data, WESTtypeRecv], source = proc, tag =33) + WESTtypeRecv.Free() + listFields[i][:,0:self.topo.ghosts[1],:] = data[:,0:self.topo.ghosts[1],:] + startsSend = [0,self.topo.ghosts[1],0] + WESTtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + WESTtypeSend.Commit() + self.comm.Send([listFields[i], WESTtypeSend], dest = proc, tag =33) + WESTtypeSend.Free() + + def NORTHrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]].shape) + startsRecv = np.asarray([0,0,self.topo.mesh.resolution[2]-self.topo.ghosts[2]]) + NORTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + NORTHtypeRecv.Commit() + data = listFields[i] + self.comm.Recv([data, NORTHtypeRecv], source=proc, tag=66) + NORTHtypeRecv.Free() + listFields[i][:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] = data[ \ + :,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] + startsSend = [0,0,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]] + NORTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + NORTHtypeSend.Commit() + self.comm.Send([listFields[i], NORTHtypeSend], dest=proc, tag=66) + NORTHtypeSend.Free() + + def SOUTHrecv(self, proc, listFields): + for i in xrange(self.topo.dim) : + subsizes = np.asarray(listFields[i][ \ + :,:,0:self.topo.ghosts[2]].shape) + startsRecv = np.asarray([0,0,0]) + SOUTHtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=ORDERMPI) + SOUTHtypeRecv.Commit() + data=listFields[i] + self.comm.Recv([data, SOUTHtypeRecv], source = proc, tag =55) + SOUTHtypeRecv.Free() + listFields[i][:,:,0:self.topo.ghosts[2]] = data[:,:,0:self.topo.ghosts[2]] + startsSend = [0,0,self.topo.ghosts[2]] + SOUTHtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=ORDERMPI) + SOUTHtypeSend.Commit() + self.comm.Send([listFields[i], SOUTHtypeSend], dest = proc, tag =55) + SOUTHtypeSend.Free() + + + def printComputeTime(self): + self.timings_info[0] = "\"Synchronization total\"" + self.timings_info[1] = str(self.total_time) + print "Synchronization total time : ", self.total_time + print "Time of the last Synchronization iteration :", self.compute_time + + def __str__(self): + s = "Synchronize. " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Synchronize" + print Synchronize.__doc__ diff --git a/HySoP/unusedOrObsolet/cpu_data_transfer.py b/HySoP/unusedOrObsolet/cpu_data_transfer.py new file mode 100644 index 000000000..576ae0ab7 --- /dev/null +++ b/HySoP/unusedOrObsolet/cpu_data_transfer.py @@ -0,0 +1,301 @@ +# -*- coding: utf-8 -*- +""" +@file cpu_data_transfer.py +Communicator MPI to synchronize ghost +""" +from parmepy.constants import np, ORDER +from parmepy.mpi import main_comm +import time + + +class Synchronize(object): + """ + Synchronization of ghosts values on domain + """ + + def __init__(self, topology): + """ + Constructor. + @param topology : Local topology + """ + self.topo = topology + self.total_time = 1 + ## problem le topology.mesh.resolution peut etre different du shape du field rentre + self.size= topology.mesh.resolution + + def apply(self, *listFields): + """ + Application of synchronization at a list of Fields + @ list of Fields or one Fields. + Make the synchronization with this law : + for synchronize P1 with P2 : + if P1.rank < P2.rank + P1 send, own and after recv ghost + P2 recv ghost and send his own + else + do the reciproque + And we do that direction by direction, with a sort table of + the synchro who need. + """ +# Rappel de la correspondance direction <-> indice +# self.topo.tabSort = np.array([[self.up,0] , [self.down,1] , [self.east,2], [self.west,3], +# [self.north,4],[self.south,5]]) + self.compute_time = time.time() + self.comm = main_comm + self.count = None + + for f in listFields: +# self.size= f.data[0].shape +# print 'size array:' ,self.size, 'size topo :', self.topo.mesh.resolution +# print 'rank', self.topo.rank, 'tab',self.topo.tabSort + for i in xrange(self.topo.tabSort[:,0].shape[0]) : +# print 'rang, destinataire, orientation', self.topo.rank, self.topo.tabSort[i,0], self.topo.tabSort[i,1] + if ( self.topo.rank == self.topo.tabSort[i,0]): + # UP DOWN + if(self.topo.tabSort[i,1] == 0): + for j in xrange(self.topo.dim) : + f[j][self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] =\ + f[j][self.topo.ghosts[0]:2*self.topo.ghosts[0],:,:] + + if(self.topo.tabSort[i,1] == 1): + for j in xrange(self.topo.dim) : + f[j][0:self.topo.ghosts[0],:,:] =\ + f[j][self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:] + + # WEST EAST + if(self.topo.tabSort[i,1] == 2): + for j in xrange(self.topo.dim) : + f[j][:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] =\ + f[j][:,self.topo.ghosts[1]:2*self.topo.ghosts[1],:] + + if(self.topo.tabSort[i,1] == 3): + for j in xrange(self.topo.dim) : + f[j][:,0:self.topo.ghosts[1],:] =\ + f[j][:,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1]:self.topo.mesh.resolution[1]-self.topo.ghosts[1],:] + + # NORTH SOUTH + if(self.topo.tabSort[i,1] == 4): + for j in xrange(self.topo.dim) : + f[j][:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] =\ + f[j][:,:,self.topo.ghosts[2]:2*self.topo.ghosts[2]] + + if(self.topo.tabSort[i,1] == 5): + for j in xrange(self.topo.dim) : + f[j][:,:,0:self.topo.ghosts[2]] =\ + f[j][:,:,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]:self.topo.mesh.resolution[2]-self.topo.ghosts[2]] + else : +# if(self.topo.tabSort[i,1] == 'up'): + if(self.topo.tabSort[i,1] == 0): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'UP',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.UPsend(self.topo.tabSort[i,0], f) + else : +# print 'UP', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.UPrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'down'): + if(self.topo.tabSort[i,1] == 1): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'DOWN',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.DOWNsend(self.topo.tabSort[i,0], f) + else : +# print 'DOWN', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.DOWNrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'east'): + if(self.topo.tabSort[i,1] == 2): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'EST',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.EASTsend(self.topo.tabSort[i,0], f) + else : +# print 'EST', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.EASTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'west'): + if(self.topo.tabSort[i,1] == 3): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'WEST',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.WESTsend(self.topo.tabSort[i,0], f) + else : +# print 'WEST', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.WESTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'north'): + if(self.topo.tabSort[i,1] == 4): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'NORTH',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.NORTHsend(self.topo.tabSort[i,0], f) + else : +# print 'NORTH', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.NORTHrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'south'): + if(self.topo.tabSort[i,1] == 5): + if( self.topo.rank < self.topo.tabSort[i,0]) : +# print 'SOUTH',self.topo.rank,'Send to',self.topo.tabSort[i,0] + self.SOUTHsend(self.topo.tabSort[i,0], f) + else : +# print 'SOUTH', self.topo.rank,'Recv from',self.topo.tabSort[i,0] + self.SOUTHrecv(self.topo.tabSort[i,0], f) + self.compute_time = time.time() - self.compute_time + self.total_time += self.compute_time + + return self.compute_time + + + def UPsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((ghosts[0],resolution[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=11) + self.comm.Recv(data , source=proc, tag=11) + listFields[i][ + self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:]\ + = data + + + def DOWNsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((ghosts[0],resolution[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + ghosts[0]:2*ghosts[0],:,:]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=22) + self.comm.Recv(data , source=proc, tag=22) + listFields[i][0:ghosts[0],:,:] = data + + + def EASTsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], ghosts[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + :,resolution[1]-2*ghosts[1]:resolution[1]-ghosts[1],:]), order=ORDER) + + self.comm.Ssend(data, dest=proc, tag=33) + self.comm.Recv(data , source=proc, tag=33) + listFields[i][:,resolution[1]-ghosts[1]:resolution[1],:]= data + + + def WESTsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], ghosts[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + :,ghosts[1]:ghosts[1]*2,:]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=44) + self.comm.Recv(data , source=proc, tag=44) + listFields[i][:,0:ghosts[1],:]= data + + + def NORTHsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], resolution[1], ghosts[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + :,:,resolution[2]-2*ghosts[2]:resolution[2]-ghosts[2]]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=55) + self.comm.Recv(data , source=proc, tag=55) + listFields[i][:,:,resolution[2]-ghosts[2]:resolution[2]]= data + + + def SOUTHsend(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], resolution[1], ghosts[2]) , dtype=PARMES_REAL , order=ORDER) + data = np.array(np.copy(listFields[i][ \ + :,:,ghosts[2]:2*ghosts[2]]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=66) + self.comm.Recv(data , source=proc, tag=66) + listFields[i][:,:,0:ghosts[2]]= data + + + def UPrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((ghosts[0],resolution[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data, source = proc, tag =22) + listFields[i][resolution[0]-ghosts[0]:resolution[0],:,:] = data + data = np.array(np.copy(listFields[i][ \ + resolution[0]-2*ghosts[0]:resolution[0]-ghosts[0],:,:]), order=ORDER) + self.comm.Ssend(data, dest = proc, tag =22) + + + def DOWNrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((ghosts[0],resolution[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data, source = proc, tag =11) + listFields[i][0:self.topo.ghosts[0],:,:] = data + data = np.array(np.copy(listFields[i][ \ + ghosts[0]:ghosts[0]*2,:,:]), order=ORDER) + self.comm.Ssend(data, dest = proc, tag =11) + + + def EASTrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], ghosts[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data , source=proc, tag=44) + listFields[i][:,resolution[1]-ghosts[1]:resolution[1],:]= data + data = np.array(np.copy(listFields[i][ \ + :,resolution[1]-2*ghosts[1]:resolution[1]-ghosts[1],:]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=44) + + + def WESTrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], ghosts[1], resolution[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data , source=proc, tag=33) + listFields[i][:,0:ghosts[1],:]= data + data = np.array(np.copy(listFields[i][ \ + :,ghosts[1]:2*ghosts[1],:]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=33) + + + def NORTHrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], resolution[1], ghosts[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data , source=proc, tag=66) + listFields[i][:,:,resolution[2]-ghosts[2]:resolution[2]]= data + data = np.array(np.copy(listFields[i][ \ + :,:,resolution[2]-2*ghosts[2]:resolution[2]-ghosts[2]]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=66) + + + def SOUTHrecv(self, proc, listFields): + ghosts= self.topo.ghosts + resolution = self.topo.mesh.resolution + for i in xrange(self.topo.dim) : + data = np.zeros((resolution[0], resolution[1], ghosts[2]) , dtype=PARMES_REAL , order=ORDER) + self.comm.Recv(data , source=proc, tag=55) + listFields[i][:,:,0:ghosts[2]]= data + data = np.array(np.copy(listFields[i][ \ + :,:,ghosts[2]:2*ghosts[2]]), order=ORDER) + self.comm.Ssend(data, dest=proc, tag=55) + + + def printComputeTime(self): + self.timings_info[0] = "\"Synchronization total\"" + self.timings_info[1] = str(self.total_time) + print "Synchronization total time : ", self.total_time + print "Time of the last Synchronization iteration :", self.compute_time + + def __str__(self): + s = "Synchronize. " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Synchronize" + print Synchronize.__doc__ diff --git a/HySoP/unusedOrObsolet/cpu_data_transfer_S.py b/HySoP/unusedOrObsolet/cpu_data_transfer_S.py new file mode 100644 index 000000000..90b908a45 --- /dev/null +++ b/HySoP/unusedOrObsolet/cpu_data_transfer_S.py @@ -0,0 +1,307 @@ +# -*- coding: utf-8 -*- +""" +@file cpu_data_transfer_S.py +Communicator MPI to synchronize ghosts of scalar fields +""" +from parmepy.constants import np, ORDER +from parmepy.mpi import main_comm +import time + + +class SynchronizeS(object): + """ + Synchronization of ghosts values for scalar fields + """ + + def __init__(self, topology): + """ + Constructor. + @param topology : Local topology + """ + self.topo = topology + self.total_time = 0. + self.size= topology.mesh.resolution + + + def apply(self, *listFields): + """ + Application of data synchronization to a list of scalar Fields + @ list of scalar Fields + Make the synchronization with this law : + to synchronize P1 with P2 : + if P1.rank < P2.rank + P1 send its own and after recv ghost + P2 recv ghost and send its own + else + do the reciproque + This algorithm is performed orientation by orientation, + using a sorted table containing neighbours ranks and their orientation as follows : + """ +# Rappel de la correspondance direction <-> indice +# self.topo.tabSort = np.array([[self.up,0] , [self.down,1] , [self.east,2], [self.west,3], +# [self.north,4],[self.south,5]]) + self.compute_time = time.time() + self.comm = main_comm + + for f in listFields: + for i in xrange(self.topo.tabSort[:,0].shape[0]) : + if ( self.topo.rank == self.topo.tabSort[i,0]): + # UP DOWN + if(self.topo.tabSort[i,1] == 0): + f[self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] =\ + f[self.topo.ghosts[0]:2*self.topo.ghosts[0],:,:] + + if(self.topo.tabSort[i,1] == 1): + f[0:self.topo.ghosts[0],:,:] =\ + f[self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:] + + # WEST EAST + if(self.topo.tabSort[i,1] == 2): + f[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] =\ + f[:,self.topo.ghosts[1]:2*self.topo.ghosts[1],:] + + if(self.topo.tabSort[i,1] == 3): + f[:,0:self.topo.ghosts[1],:] =\ + f[:,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1]:self.topo.mesh.resolution[1]-self.topo.ghosts[1],:] + + # NORTH SOUTH + if(self.topo.tabSort[i,1] == 4): + f[:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] =\ + f[:,:,self.topo.ghosts[2]:2*self.topo.ghosts[2]] + + if(self.topo.tabSort[i,1] == 5): + f[:,:,0:self.topo.ghosts[2]] =\ + f[:,:,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]:self.topo.mesh.resolution[2]-self.topo.ghosts[2]] + else : +# if(self.topo.tabSort[i,1] == 'up'): + if(self.topo.tabSort[i,1] == 0): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.UPsend(self.topo.tabSort[i,0], f) + else : + self.UPrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'down'): + if(self.topo.tabSort[i,1] == 1): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.DOWNsend(self.topo.tabSort[i,0], f) + else : + self.DOWNrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'east'): + if(self.topo.tabSort[i,1] == 2): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.EASTsend(self.topo.tabSort[i,0], f) + else : + self.EASTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'west'): + if(self.topo.tabSort[i,1] == 3): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.WESTsend(self.topo.tabSort[i,0], f) + else : + self.WESTrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'north'): + if(self.topo.tabSort[i,1] == 4): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.NORTHsend(self.topo.tabSort[i,0], f) + else : + self.NORTHrecv(self.topo.tabSort[i,0], f) +# if(self.topo.tabSort[i,1] == 'south'): + if(self.topo.tabSort[i,1] == 5): + if( self.topo.rank < self.topo.tabSort[i,0]) : + self.SOUTHsend(self.topo.tabSort[i,0], f) + else : + self.SOUTHrecv(self.topo.tabSort[i,0], f) + self.compute_time = time.time() - self.compute_time + self.total_time += self.compute_time + + return self.compute_time + + + def UPsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + self.topo.mesh.resolution[0]-2*self.topo.ghosts[0]:self.topo.mesh.resolution[0]-self.topo.ghosts[0],:,:].shape) + startsSend = np.asarray([self.topo.mesh.resolution[0]-2*self.topo.ghosts[0],0,0]) + UPtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + UPtypeSend.Commit() + self.comm.Send([ listFields, UPtypeSend ], dest=proc, tag=77) + startsRecv = [self.topo.mesh.resolution[0]-self.topo.ghosts[0],0,0] + UPtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + UPtypeRecv.Commit() + data = listFields + self.comm.Recv([data, UPtypeRecv] , source=proc, tag=77) + listFields[self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:]\ + = data[self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:] + + def DOWNsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + self.topo.ghosts[0]:2*self.topo.ghosts[0],:,:].shape) + startsSend = np.asarray([self.topo.ghosts[0],0,0]) + DOWNtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + DOWNtypeSend.Commit() + self.comm.Send([ listFields, DOWNtypeSend ], dest=proc, tag=77) + startsRecv = [0,0,0] + DOWNtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + DOWNtypeRecv.Commit() + data = listFields + self.comm.Recv([data, DOWNtypeRecv], source=proc, tag=77) + listFields[0:self.topo.ghosts[0],:,:] = data[0:self.topo.ghosts[0],:,:] + + def EASTsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1]:self.topo.mesh.resolution[1]-self.topo.ghosts[1],:].shape) + startsSend = np.asarray([0,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1],0]) + EASTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + EASTtypeSend.Commit() + self.comm.Send([ listFields, EASTtypeSend ], dest=proc, tag=33) + startsRecv = [0,self.topo.mesh.resolution[1]-self.topo.ghosts[1],0] + EASTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + EASTtypeRecv.Commit() + data = listFields + self.comm.Recv([data, EASTtypeRecv] , source=proc, tag=33) + listFields[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1] ,:]\ + = data[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] + + def WESTsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,self.topo.ghosts[1]:2*self.topo.ghosts[1],:].shape) + startsSend = np.asarray([0,self.topo.ghosts[1],0]) + WESTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + WESTtypeSend.Commit() + self.comm.Send([ listFields, WESTtypeSend ], dest=proc, tag=33) + startsRecv = [0,0,0] + WESTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + WESTtypeRecv.Commit() + data = listFields + self.comm.Recv([data, WESTtypeRecv], source=proc, tag=33) + listFields[:,0:self.topo.ghosts[1],:] = data[:,0:self.topo.ghosts[1],:] + + def NORTHsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,:,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]:self.topo.mesh.resolution[2]-self.topo.ghosts[2]].shape) + startsSend = np.asarray([0,0,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]]) + NORTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + NORTHtypeSend.Commit() + self.comm.Send([ listFields, NORTHtypeSend ], dest=proc, tag=55) + startsRecv = [0,0,self.topo.mesh.resolution[2]-self.topo.ghosts[2]] + NORTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + NORTHtypeRecv.Commit() + data = listFields + self.comm.Recv([data, NORTHtypeRecv] , source=proc, tag=55) + listFields[:,:, self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]]\ + = data[:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] + + def SOUTHsend(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,:,self.topo.ghosts[2]:2*self.topo.ghosts[2]].shape) + startsSend = np.asarray([0,0,self.topo.ghosts[2]]) + SOUTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + SOUTHtypeSend.Commit() + self.comm.Send([ listFields, SOUTHtypeSend ], dest=proc, tag=55) + startsRecv = [0,0,0] + SOUTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + SOUTHtypeRecv.Commit() + data = listFields + self.comm.Recv([data, SOUTHtypeRecv], source=proc, tag=55) + listFields[:,:,0:self.topo.ghosts[2]] = data[:,:,0:self.topo.ghosts[2]] + + def UPrecv(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + self.topo.mesh.resolution[0]-self.topo.ghosts[0]:self.topo.mesh.resolution[0],:,:].shape) + startsRecv = np.asarray([self.topo.mesh.resolution[0]-self.topo.ghosts[0],0,0]) + UPtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + UPtypeRecv.Commit() + data = listFields + self.comm.Recv([data, UPtypeRecv], source=proc, tag=77) + listFields[self.topo.mesh.resolution[0] - + self.topo.ghosts[0]:self.topo.mesh.resolution[0], :, :] = \ + data[self.topo.mesh.resolution[0] - + self.topo.ghosts[0]:self.topo.mesh.resolution[0], :, :] + startsSend = [self.topo.mesh.resolution[0] - + 2 * self.topo.ghosts[0], 0, 0] + UPtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + UPtypeSend.Commit() + self.comm.Send([listFields, UPtypeSend], dest=proc, tag=77) + + + def DOWNrecv(self, proc, listFields): + subsizes = np.asarray(listFields[0:self.topo.ghosts[0],:,:].shape) + startsRecv = np.asarray([0,0,0]) + DOWNtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + DOWNtypeRecv.Commit() + data=listFields + self.comm.Recv([data, DOWNtypeRecv], source = proc, tag =77) + listFields[0:self.topo.ghosts[0],:,:] = data[0:self.topo.ghosts[0],:,:] + startsSend = [self.topo.ghosts[0],0,0] + DOWNtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + DOWNtypeSend.Commit() + self.comm.Send([listFields, DOWNtypeSend], dest = proc, tag =77) + + def EASTrecv(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:].shape) + startsRecv = np.asarray([0,self.topo.mesh.resolution[1]-self.topo.ghosts[1],0]) + EASTtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + EASTtypeRecv.Commit() + data = listFields + self.comm.Recv([data, EASTtypeRecv], source=proc, tag=33) + listFields[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] = \ + data[:,self.topo.mesh.resolution[1]-self.topo.ghosts[1]:self.topo.mesh.resolution[1],:] + startsSend = [0,self.topo.mesh.resolution[1]-2*self.topo.ghosts[1],0] + EASTtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + EASTtypeSend.Commit() + self.comm.Send([listFields, EASTtypeSend], dest=proc, tag=33) + + def WESTrecv(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,0:self.topo.ghosts[1],:].shape) + startsRecv = np.asarray([0,0,0]) + WESTtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + WESTtypeRecv.Commit() + data=listFields + self.comm.Recv([data, WESTtypeRecv], source = proc, tag =33) + listFields[:,0:self.topo.ghosts[1],:] = data[:,0:self.topo.ghosts[1],:] + startsSend = [0,self.topo.ghosts[1],0] + WESTtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + WESTtypeSend.Commit() + self.comm.Send([listFields, WESTtypeSend], dest = proc, tag =33) + + def NORTHrecv(self, proc, listFields): + subsizes = np.asarray(listFields[ \ + :,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]].shape) + startsRecv = np.asarray([0,0,self.topo.mesh.resolution[2]-self.topo.ghosts[2]]) + NORTHtypeRecv = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + NORTHtypeRecv.Commit() + data = listFields + self.comm.Recv([data, NORTHtypeRecv], source=proc, tag=55) + listFields[:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] = \ + data[:,:,self.topo.mesh.resolution[2]-self.topo.ghosts[2]:self.topo.mesh.resolution[2]] + startsSend = [0,0,self.topo.mesh.resolution[2]-2*self.topo.ghosts[2]] + NORTHtypeSend = MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + NORTHtypeSend.Commit() + self.comm.Send([listFields, NORTHtypeSend], dest=proc, tag=55) + + def SOUTHrecv(self, proc, listFields): + subsizes = np.asarray(listFields[:,:,0:self.topo.ghosts[2]].shape) + startsRecv = np.asarray([0,0,0]) + SOUTHtypeRecv= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsRecv, order=MPI.ORDER_F) + SOUTHtypeRecv.Commit() + data=listFields + self.comm.Recv([data, SOUTHtypeRecv], source = proc, tag =55) + listFields[:,:,0:self.topo.ghosts[2]] = data[:,:,0:self.topo.ghosts[2]] + startsSend = [0,0,self.topo.ghosts[2]] + SOUTHtypeSend= MPI.DOUBLE.Create_subarray(self.size, subsizes, startsSend, order=MPI.ORDER_F) + SOUTHtypeSend.Commit() + self.comm.Send([listFields, SOUTHtypeSend], dest = proc, tag =55) + + def printComputeTime(self): + self.timings_info[0] = "\"Synchronization total\"" + self.timings_info[1] = str(self.total_time) + print "Synchronization total time : ", self.total_time + print "Time of the last Synchronization iteration :", self.compute_time + + def __str__(self): + s = "Synchronize. " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Synchronize scalar fields" + print SynchronizeS.__doc__ diff --git a/HySoP/unusedOrObsolet/differentialOperator.py b/HySoP/unusedOrObsolet/differentialOperator.py new file mode 100755 index 000000000..7e377277e --- /dev/null +++ b/HySoP/unusedOrObsolet/differentialOperator.py @@ -0,0 +1,683 @@ +# -*- codingind utf-8 -*- +""" +@file differentialOperator.py +Discrete stretching representation +""" +import numpy as np +from parmepy.constants import np, PARMES_REAL, ORDER +from parmepy.numerics.method import NumMethod +#from parmepy.tools.cpu_data_transfer import Synchronize +from parmepy.tools.cpu_data_transfer_S import SynchronizeS + + +class DifferentialOperator(NumMethod): + """ + Operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, field1, field2, method='', choice=''): + """ + Constructor. + Create a Stretching operator on a given continuous domain. + Work on a given field2 and field1 to compute the stretching term. + + @param field1 : field n1 (vorticity). + @param field2 : field n2 (velocity or density). + @param method : name and order of the spacial discretization method. + @param choice : differential operator to discretize + """ + self.name = "Differential Operator Discretization" + self.field1 = field1 + self.field2 = field2 + self.choice = choice + self.method = method + self.compute_time = 0. + self.topology = self.field2.topology + self.meshSize = self.topology.mesh.space_step + +# def setUp(self): +# pass + + def __call__(self, synchroOp=None): + """ + Apply operator. + """ + ind0a = self.topology.mesh.local_start[0] + ind0b = self.topology.mesh.local_end[0] + 1 + ind1a = self.topology.mesh.local_start[1] + ind1b = self.topology.mesh.local_end[1] + 1 + ind2a = self.topology.mesh.local_start[2] + ind2b = self.topology.mesh.local_end[2] + 1 + ind0 = np.arange(ind0a, ind0b) + ind1 = np.arange(ind1a, ind1b) + ind2 = np.arange(ind2a, ind2b) + if self.choice.find('divWU') >= 0: + + # Ghosts synchronization +# linenb = 0 +# if (self.topology.rank == 0): +# time.sleep(2) +# print 'Bligne 1', field1[:,linenb,linenb] +# time.sleep(2) +# print 'Bligne 2', field1[linenb,:,linenb] +# time.sleep(2) +# print 'Bligne 3', field1[linenb,linenb,:] +# time.sleep(2) + +# if (self.topology.rank == 0): +# time.sleep(2) +# print 'Aligne 1', field1[:,linenb,linenb] +# time.sleep(2) +# print 'Aligne 2', field1[linenb,:,linenb] +# time.sleep(2) +# print 'Aligne 3', field1[linenb,linenb,:] +# time.sleep(2) + OpSynchronize = Synchronize(self.topology) + OpSynchronize.apply(self.field2, self.field1) + + synchroOp.apply() + if self.method.find('FD_order2') >= 0: + raise ValueError("2nd order scheme Not yet implemented") +## X components of temp and result +# temp1 = ( +# self.field1[0][ind+1, ind, ind] * +# self.field2[0][ind+1, ind, ind] - +# self.field1[0][ind-1, ind, ind] * +# self.field2[0][ind-1, ind, ind] +# ) / (2. * self.meshSize[0]) + +# temp2 = ( +# self.field1[1][ind, ind+1, ind] * +# self.field2[0][ind, ind+1, ind] - +# self.field1[1][ind, ind-1, ind] * +# self.field2[0][ind, ind-1, ind] +# ) / (2. * self.meshSize[1]) +# +# temp3 = ( +# self.field1[2][ind, ind, ind+1] * +# self.field2[0][ind, ind, ind+1] - +# self.field1[2][ind, ind, ind-1] * +# self.field2[0][ind, ind, ind-1] +# ) / (2. * self.meshSize[2]) + +# self.result[0][ind, ind]= temp1 + temp2 + temp3 + +## Y components of temp and result +# temp1 = ( +# self.field1[0][ind+1, ind, ind] * +# self.field2[1][ind+1, ind, ind] - +# self.field1[0][ind-1, ind, ind] * +# self.field2[1][ind-1, ind, ind] +# ) / (2. * self.meshSize[0]) + +# temp2 = ( +# self.field1[1][ind, ind+1, ind] * +# self.field2[1][ind, ind+1, ind] - +# self.field1[1][ind, ind-1, ind] * +# self.field2[1][ind, ind-1, ind] +# ) / (2. * self.meshSize[1]) +# +# temp3 = ( +# self.field1[2][ind, ind, ind+1] * +# self.field2[1][ind, ind, ind+1] - +# self.field1[2][ind, ind, ind-1] * +# self.field2[1][ind, ind, ind-1] +# ) / (2. * self.meshSize[2]) + +# self.result[1][ind, ind]= temp1 + temp2 + temp3 + +## Z components of temp and result +# temp1 = ( +# self.field1[0][ind+1, ind, ind] * +# self.field2[2][ind+1, ind, ind] - +# self.field1[0][ind-1, ind, ind] * +# self.field2[2][ind-1, ind, ind] +# ) / (2. * self.meshSize[0]) + +# temp2 = ( +# self.field1[1][ind, ind+1, ind] * +# self.field2[2][ind, ind+1, ind] - +# self.field1[1][ind, ind-1, ind] * +# self.field2[2][ind, ind-1, ind] +# ) / (2. * self.meshSize[1]) +# +# temp3 = ( +# self.field1[2][ind, ind, ind+1] * +# self.field2[2][ind, ind, ind+1] - +# self.field1[2][ind, ind, ind-1] * +# self.field2[2][ind, ind, ind-1] +# ) / (2. * self.meshSize[2]) + + else: +# X components of temp and result + temp1 = self.field2[0][...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[0][ind0-2, ind1a:ind1b, ind2a:ind2b] * + self.field2[0][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1, ind1a:ind1b, ind2a:ind2b] * + self.field2[0][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field1[0][ind0+1, ind1a:ind1b, ind2a:ind2b] * + self.field2[0][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field1[0][ind0+2, ind1a:ind1b, ind2a:ind2b] * + self.field2[0][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + + temp2 = self.field2[0][...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[1][ind0a:ind0b, ind1-2, ind2a:ind2b] * + self.field2[0][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field1[1][ind0a:ind0b, ind1-1, ind2a:ind2b] * + self.field2[0][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field1[1][ind0a:ind0b, ind1+1, ind2a:ind2b] * + self.field2[0][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field1[1][ind0a:ind0b, ind1+2, ind2a:ind2b] * + self.field2[0][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + + temp3 = self.field2[0][...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-2] * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-1] * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+1] * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+2] * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + +# tmp1 = np.array([temp1 + temp2 + temp3]) + tmp1 = temp1 + temp2 + temp3 + +# Y components of temp and result + temp1 = self.field2[1][...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[0][ind0-2, ind1a:ind1b, ind2a:ind2b] * + self.field2[1][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1, ind1a:ind1b, ind2a:ind2b] * + self.field2[1][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field1[0][ind0+1, ind1a:ind1b, ind2a:ind2b] * + self.field2[1][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field1[0][ind0+2, ind1a:ind1b, ind2a:ind2b] * + self.field2[1][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + + temp2 = self.field2[1][...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[1][ind0a:ind0b, ind1-2, ind2a:ind2b] * + self.field2[1][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field1[1][ind0a:ind0b, ind1-1, ind2a:ind2b] * + self.field2[1][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field1[1][ind0a:ind0b, ind1+1, ind2a:ind2b] * + self.field2[1][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field1[1][ind0a:ind0b, ind1+2, ind2a:ind2b] * + self.field2[1][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + + temp3 = self.field2[1][...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-2] * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-1] * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+1] * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+2] * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + +# tmp2 = np.array([temp1 + temp2 + temp3]) + tmp2 = temp1 + temp2 + temp3 + +# Z components of temp and result + temp1 = self.field2[2][...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[0][ind0-2, ind1a:ind1b, ind2a:ind2b] * + self.field2[2][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1, ind1a:ind1b, ind2a:ind2b] * + self.field2[2][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field1[0][ind0+1, ind1a:ind1b, ind2a:ind2b] * + self.field2[2][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field1[0][ind0+2, ind1a:ind1b, ind2a:ind2b] * + self.field2[2][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + + temp2 = self.field2[2][...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[1][ind0a:ind0b, ind1-2, ind2a:ind2b] * + self.field2[2][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field1[1][ind0a:ind0b, ind1-1, ind2a:ind2b] * + self.field2[2][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field1[1][ind0a:ind0b, ind1+1, ind2a:ind2b] * + self.field2[2][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field1[1][ind0a:ind0b, ind1+2, ind2a:ind2b] * + self.field2[2][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + + temp3 = self.field2[2][...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-2] * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2-1] * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+1] * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field1[2][ind0a:ind0b, ind1a:ind1b, ind2+2] * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + +# tmp3 = np.array([temp1 + temp2 + temp3]) + tmp3 = temp1 + temp2 + temp3 + result = np.concatenate(( + np.array(tmp1), np.array(tmp2), np.array(tmp3))) +# return result + return tmp1, tmp2, tmp3 + + elif self.choice.find('gradV') >= 0: + + # Ghosts synchronization + synchroOp.apply() +# OpSynchronize = Synchronize(self.topology) +# OpSynchronize.apply(self.field2) + if self.method.find('FD_order2') >= 0: + raise ValueError("2nd order scheme Not yet implemented") + + else: + maxArray = np.zeros(5, dtype=PARMES_REAL, order=ORDER) + +## Fourth order scheme +# X components of temp and result +# temp1 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp1 = self.field2[0][...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[0][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field2[0][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field2[0][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field2[0][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + +# temp2 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp2 = self.field2[0][...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[0][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field2[0][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field2[0][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field2[0][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + +# temp3 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp3 = self.field2[0][...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + + maxstr1 = np.max(abs(temp1) + abs(temp2) + abs(temp3)) + maxadv1 = np.max(abs(temp1)) + +# Y components of temp and result +# temp4 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp4 = self.field2[1][...] * 0. + temp4[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[1][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field2[1][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field2[1][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field2[1][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + +# temp5 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp5 = self.field2[1][...] * 0. + temp5[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[1][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field2[1][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field2[1][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field2[1][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + +# temp6 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp6 = self.field2[1][...] * 0. + temp6[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + + maxstr2 = np.max(abs(temp4)+abs(temp5)+abs(temp6)) + maxadv2 = np.max(abs(temp5)) + +# Z components of temp and result +# temp7 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp7 = self.field2[2][...] * 0. + temp7[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[2][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field2[2][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field2[2][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field2[2][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + +# temp8 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp8 = self.field2[2][...] * 0. + temp8[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[2][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field2[2][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field2[2][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field2[2][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + +# temp9 = np.zeros( +# (self.resolution), dtype=PARMES_REAL, order=ORDER) + temp9 = self.field2[2][...] * 0. + temp9[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + + maxstr3 = np.max(abs(temp7)+abs(temp8)+abs(temp9)) + maxadv3 = np.max(abs(temp9)) + + # grad(V) result + result = np.concatenate(( + np.array([temp1, temp2, temp3]), + np.array([temp4, temp5, temp6]), + np.array([temp7, temp8, temp9]) + )) + # div(V) result + divergence = np.array(temp1 + temp5 + temp9) + + # maxima of partial derivatives : needed for stab conditions + # advection stab + maxArray[0] = max(maxstr1, maxstr2, maxstr3) + # stretching stab + maxArray[1] = max(maxadv1, maxadv2, maxadv3) + + return result, maxArray, divergence + + elif (self.choice.find('gradS') >= 0): + + # Ghosts synchronization + #OpSynchronize = SynchronizeS(self.topology) + #OpSynchronize.apply(self.field2) + synchroOp.apply() + + if self.method.find('FD_order2') >= 0: + raise ValueError("2nd order scheme Not yet implemented") + + else: + # Fourth order scheme + temp1 = self.field2[...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field2[ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field2[ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field2[ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + + temp2 = self.field2[...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field2[ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field2[ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field2[ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + + temp3 = self.field2[...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field2[ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field2[ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field2[ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field2[ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + + result = np.array([temp1, temp2, temp3]) + + return result + + elif self.choice.find('laplacianV') >= 0: + + # Ghosts synchronization +# OpSynchronize = Synchronize(self.topology) +# OpSynchronize.apply(self.field2) + + synchroOp.apply() + if self.method.find('FD_order2') >= 0: + raise ValueError("2nd order scheme Not yet implemented") + + else: +## Fourth order scheme for the laplacian operator +# X components of temp and result + temp1 = self.field2[0][...] * 0. + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + - 1. / 12. * + self.field2[0][ind0-2, ind1a:ind1b, ind2a:ind2b] + + 4. / 3. * + self.field2[0][ind0-1, ind1a:ind1b, ind2a:ind2b] + + - 5. / 2. * + self.field2[0][ind0+0, ind1a:ind1b, ind2a:ind2b] + + 4. / 3. * + self.field2[0][ind0+1, ind1a:ind1b, ind2a:ind2b] + + - 1. / 12. * + self.field2[0][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (self.meshSize[0]**2) + + temp2 = self.field2[0][...] * 0. + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1./12. * + self.field2[0][ind0a:ind0b, ind1-2, ind2a:ind2b] + + 4. / 3. * + self.field2[0][ind0a:ind0b, ind1-1, ind2a:ind2b] + + -5. / 2. * + self.field2[0][ind0a:ind0b, ind1+0, ind2a:ind2b] + + 4. / 3. * + self.field2[0][ind0a:ind0b, ind1+1, ind2a:ind2b] + + -1. / 12. * + self.field2[0][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (self.meshSize[1]**2) + + temp3 = self.field2[0][...] * 0. + temp3[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-2] + + 4. / 3. * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2-1] + + -5. / 2. * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+0] + + 4. / 3. * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+1] + + -1. / 12. * + self.field2[0][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (self.meshSize[2]**2) + temp1 = temp1 + temp2 + temp3 + +# Y components of temp and result + temp4 = self.field2[1][...] * 0. + temp4[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[1][ind0-2, ind1a:ind1b, ind2a:ind2b] + + 4. / 3. * + self.field2[1][ind0-1, ind1a:ind1b, ind2a:ind2b] + + - 5. / 2. * + self.field2[1][ind0+0, ind1a:ind1b, ind2a:ind2b] + + 4. / 3. * + self.field2[1][ind0+1, ind1a:ind1b, ind2a:ind2b] + + -1. / 12. * + self.field2[1][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (self.meshSize[0]**2) + + temp5 = self.field2[1][...] * 0. + temp5[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[1][ind0a:ind0b, ind1-2, ind2a:ind2b] + + 4. / 3. * + self.field2[1][ind0a:ind0b, ind1-1, ind2a:ind2b] + + -5. / 2. * + self.field2[1][ind0a:ind0b, ind1+0, ind2a:ind2b] + + 4. / 3. * + self.field2[1][ind0a:ind0b, ind1+1, ind2a:ind2b] + + -1. / 12. * + self.field2[1][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (self.meshSize[1]**2) + + temp6 = self.field2[1][...] * 0. + temp6[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-2] + + 4. / 3. * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2-1] + + -5. / 2. * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+0] + + 4. / 3. * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+1] + + -1. / 12. * + self.field2[1][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (self.meshSize[2]**2) + temp4 = temp4 + temp5 + temp6 + +# Z components of temp and result + temp7 = self.field2[2][...] * 0. + temp7[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[2][ind0-2, ind1a:ind1b, ind2a:ind2b] + + 4./3. * + self.field2[2][ind0-1, ind1a:ind1b, ind2a:ind2b] + + - 5. / 2. * + self.field2[2][ind0+0, ind1a:ind1b, ind2a:ind2b] + + 4. / 3. * + self.field2[2][ind0+1, ind1a:ind1b, ind2a:ind2b] + + -1. / 12. * + self.field2[2][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (self.meshSize[0]**2) + + temp8 = self.field2[2][...] * 0. + temp8[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[2][ind0a:ind0b, ind1-2, ind2a:ind2b] + + 4. / 3. * + self.field2[2][ind0a:ind0b, ind1-1, ind2a:ind2b] + + -5. / 2. * + self.field2[2][ind0a:ind0b, ind1+0, ind2a:ind2b] + + 4. / 3. * + self.field2[2][ind0a:ind0b, ind1+1, ind2a:ind2b] + + -1. / 12. * + self.field2[2][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (self.meshSize[1]**2) + + temp9 = self.field2[2][...] * 0. + temp9[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + -1. / 12. * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-2] + + 4. / 3. * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2-1] + + -5. / 2. * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+0] + + 4. / 3. * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+1] + + -1. / 12. * + self.field2[2][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (self.meshSize[2]**2) + temp7 = temp7 + temp8 + temp9 + + result = np.concatenate(( + np.array([temp1]), np.array([temp4]), np.array([temp7]) + )) + + return result + + elif self.choice.find('curl') >= 0: + + # Ghosts synchronization +# OpSynchronize = Synchronize(self.topology) +# OpSynchronize.apply(self.field1) + + synchroOp.apply() + if self.method.find('FD_order2') >= 0: + raise ValueError("2nd order scheme Not yet implemented") + + else: + temp1 = self.field1[0][...] * 0. + temp2 = self.field1[0][...] * 0. + + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[2][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field1[2][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field1[2][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field1[2][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[1][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field1[1][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field1[1][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field1[1][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + res1 = temp1 - temp2 + + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[0][ind0a:ind0b, ind1a:ind1b, ind2-2] - + 8.0 * self.field1[0][ind0a:ind0b, ind1a:ind1b, ind2-1] + + 8.0 * self.field1[0][ind0a:ind0b, ind1a:ind1b, ind2+1] - + 1.0 * self.field1[0][ind0a:ind0b, ind1a:ind1b, ind2+2] + ) / (12. * self.meshSize[2]) + + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[2][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field1[2][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field1[2][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field1[2][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + res2 = temp1 - temp2 + + temp1[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[1][ind0-2, ind1a:ind1b, ind2a:ind2b] - + 8.0 * self.field1[1][ind0-1, ind1a:ind1b, ind2a:ind2b] + + 8.0 * self.field1[1][ind0+1, ind1a:ind1b, ind2a:ind2b] - + 1.0 * self.field1[1][ind0+2, ind1a:ind1b, ind2a:ind2b] + ) / (12. * self.meshSize[0]) + + temp2[ind0a:ind0b, ind1a:ind1b, ind2a:ind2b] = ( + 1.0 * self.field1[0][ind0a:ind0b, ind1-2, ind2a:ind2b] - + 8.0 * self.field1[0][ind0a:ind0b, ind1-1, ind2a:ind2b] + + 8.0 * self.field1[0][ind0a:ind0b, ind1+1, ind2a:ind2b] - + 1.0 * self.field1[0][ind0a:ind0b, ind1+2, ind2a:ind2b] + ) / (12. * self.meshSize[1]) + res3 = temp1 - temp2 + result = np.concatenate(( + np.array([res1]), np.array([res2]), np.array([res3]) + )) + return result + + else: + raise ValueError( + "Unknown differiential operator property " + + str(self.choice)) + + def printComputeTime(self): + self.timings_info[0] = "\"Differential Operator total\"" + self.timings_info[1] = str(self.total_time) + self.timings_info[1] += str(self.compute_time[0]) + " " +\ + str(self.compute_time[1]) + " " + str(self.compute_time[2]) + " " + print "Differential Operator total time ind ", self.total_time + print "\t Differential Operator ind", self.compute_time + + def __str__(self): + s = "DifferentialOperator (DiscreteOperator). " +\ + DiscreteOperator.__str__(self) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class ind DifferentialOperator" + print DifferentialOperator.__doc__ diff --git a/HySoP/unusedOrObsolet/differentialOperator_d.py b/HySoP/unusedOrObsolet/differentialOperator_d.py new file mode 100755 index 000000000..1cf369491 --- /dev/null +++ b/HySoP/unusedOrObsolet/differentialOperator_d.py @@ -0,0 +1,443 @@ +# -*- codingind utf-8 -*- +""" +@package operator +Discrete stretching representation +""" +from parmepy.constants import np, PARMES_REAL, ORDER +from parmepy.operator.discrete import DiscreteOperator +from parmepy.tools.cpu_data_transfer import Synchronize +import sys +import time +import io + + +class DifferentialOperator_d(DiscreteOperator): + """ + Operator representation. + DiscreteOperator.DiscreteOperator specialization. + """ + + def __init__(self, diffop, method=''): + """ + Constructor. + Create a Stretching operator on a given continuous domain. + Work on a given field2 and field1 to compute the stretching term. + + @param stretch ind Stretching operator. + """ + DiscreteOperator.__init__(self) + self.field1 = diffop.field1 + self.field2 = diffop.field2 + self.choice = diffop.choice + self.compute_time = 0. + + def setUp(self): + #La topologie est recuperee des variables discretes + self.topology = self.field1.topology + self.topology = self.field2.topology + self.meshSize = self.topology.mesh.space_step_size + + def apply(self): + """ + Apply operator. + """ + ind0a = self.topology.mesh.local_start[0] + ind0b = self.topology.mesh.local_end[0] + 1 + ind1a = self.topology.mesh.local_start[1] + ind1b = self.topology.mesh.local_end[1] + 1 + ind2a = self.topology.mesh.local_start[2] + ind2b = self.topology.mesh.local_end[2] + 1 + ind0 = np.arange(ind0a,ind0b) + ind1 = np.arange(ind1a,ind1b) + ind2 = np.arange(ind2a,ind2b) + + if self.choice == 'divWU': +## second order scheme +## X components of temp and result +# temp1 = ( self.field1[0][ind+1,ind,ind] * self.field2[0][ind+1,ind,ind] -\ +# self.field1[0][ind-1,ind,ind] * self.field2[0][ind-1,ind,ind]) / (2. * self.meshSize[0]) + +# temp2 = (self.field1[1][ind,ind+1,ind] * self.field2[0][ind,ind+1,ind] -\ +# self.field1[1][ind,ind-1,ind] * self.field2[0][ind,ind-1,ind] ) / (2. * self.meshSize[1]) +# +# temp3 = (self.field1[2][ind,ind,ind+1] * self.field2[0][ind,ind,ind+1] -\ +# self.field1[2][ind,ind,ind-1] * self.field2[0][ind,ind,ind-1] ) / (2. * self.meshSize[2]) + +# self.result[0][ind,ind]= temp1 + temp2 + temp3 + +## Y components of temp and result +# temp1 = (self.field1[0][ind+1,ind,ind] * self.field2[1][ind+1,ind,ind] -\ +# self.field1[0][ind-1,ind,ind] * self.field2[1][ind-1,ind,ind] ) / (2. * self.meshSize[0]) + +# temp2 = (self.field1[1][ind,ind+1,ind] * self.field2[1][ind,ind+1,ind] -\ +# self.field1[1][ind,ind-1,ind] * self.field2[1][ind,ind-1,ind] ) / (2. * self.meshSize[1]) +# +# temp3 = (self.field1[2][ind,ind,ind+1] * self.field2[1][ind,ind,ind+1] -\ +# self.field1[2][ind,ind,ind-1] * self.field2[1][ind,ind,ind-1] ) / (2. * self.meshSize[2]) + +# self.result[1][ind,ind]= temp1 + temp2 +temp3 + +## Z components of temp and result +# temp1 = (self.field1[0][ind+1,ind,ind] * self.field2[2][ind+1,ind,ind] -\ +# self.field1[0][ind-1,ind,ind] * self.field2[2][ind-1,ind,ind] ) / (2. * self.meshSize[0]) + +# temp2 = (self.field1[1][ind,ind+1,ind] * self.field2[2][ind,ind+1,ind] -\ +# self.field1[1][ind,ind-1,ind] * self.field2[2][ind,ind-1,ind] ) / (2. * self.meshSize[1]) +# +# temp3 = (self.field1[2][ind,ind,ind+1] * self.field2[2][ind,ind,ind+1] -\ +# self.field1[2][ind,ind,ind-1] * self.field2[2][ind,ind,ind-1]) / (2. * self.meshSize[2]) + + # Ghosts synchronization + linenb = 0 + if (self.topology.rank == 0): + time.sleep(2) + print 'Bligne 1', field1[:,linenb,linenb] + time.sleep(2) + print 'Bligne 2', field1[linenb,:,linenb] + time.sleep(2) + print 'Bligne 3', field1[linenb,linenb,:] + time.sleep(2) + + OpSynchronize = Synchronize(self.topology) + OpSynchronize.apply(self.field2, self.field1) + + if (self.topology.rank == 0): + time.sleep(2) + print 'Aligne 1', field1[:,linenb,linenb] + time.sleep(2) + print 'Aligne 2', field1[linenb,:,linenb] + time.sleep(2) + print 'Aligne 3', field1[linenb,linenb,:] + time.sleep(2) + +# OpSynchronize.apply(self.field2) +# OpSynchronize.apply(self.field1) +# X components of temp and result + temp1 = (1.0 * self.field1[0][ind0-2,ind1a:ind1b,ind2a:ind2b] * self.field2[0][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1,ind1a:ind1b,ind2a:ind2b] * self.field2[0][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field1[0][ind0+1,ind1a:ind1b,ind2a:ind2b] * self.field2[0][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field1[0][ind0+2,ind1a:ind1b,ind2a:ind2b] * self.field2[0][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + + temp2 = (1.0 * self.field1[1][ind0a:ind0b,ind1-2,ind2a:ind2b] * self.field2[0][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field1[1][ind0a:ind0b,ind1-1,ind2a:ind2b] * self.field2[0][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field1[1][ind0a:ind0b,ind1+1,ind2a:ind2b] * self.field2[0][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field1[1][ind0a:ind0b,ind1+2,ind2a:ind2b] * self.field2[0][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + + temp3 = (1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-2] * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-1] * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+1] * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+2] * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + tmp1 = np.array([temp1 + temp2 + temp3]) + +# Y components of temp and result + temp1 = (1.0 * self.field1[0][ind0-2,ind1a:ind1b,ind2a:ind2b] * self.field2[1][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1,ind1a:ind1b,ind2a:ind2b] * self.field2[1][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field1[0][ind0+1,ind1a:ind1b,ind2a:ind2b] * self.field2[1][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field1[0][ind0+2,ind1a:ind1b,ind2a:ind2b] * self.field2[1][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + + temp2 = (1.0 * self.field1[1][ind0a:ind0b,ind1-2,ind2a:ind2b] * self.field2[1][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field1[1][ind0a:ind0b,ind1-1,ind2a:ind2b] * self.field2[1][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field1[1][ind0a:ind0b,ind1+1,ind2a:ind2b] * self.field2[1][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field1[1][ind0a:ind0b,ind1+2,ind2a:ind2b] * self.field2[1][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + + temp3 = (1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-2] * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-1] * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+1] * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+2] * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + tmp2 = np.array([temp1 + temp2 + temp3]) + +# Z components of temp and result + temp1 = (1.0 * self.field1[0][ind0-2,ind1a:ind1b,ind2a:ind2b] * self.field2[2][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field1[0][ind0-1,ind1a:ind1b,ind2a:ind2b] * self.field2[2][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field1[0][ind0+1,ind1a:ind1b,ind2a:ind2b] * self.field2[2][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field1[0][ind0+2,ind1a:ind1b,ind2a:ind2b] * self.field2[2][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + + temp2 = (1.0 * self.field1[1][ind0a:ind0b,ind1-2,ind2a:ind2b] * self.field2[2][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field1[1][ind0a:ind0b,ind1-1,ind2a:ind2b] * self.field2[2][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field1[1][ind0a:ind0b,ind1+1,ind2a:ind2b] * self.field2[2][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field1[1][ind0a:ind0b,ind1+2,ind2a:ind2b] * self.field2[2][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + + temp3 = (1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-2] * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2-1] * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+1] * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field1[2][ind0a:ind0b,ind1a:ind1b,ind2+2] * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + tmp3 = np.array([temp1 + temp2 + temp3]) + result = np.concatenate((np.array(tmp1), np.array(tmp2), np.array(tmp3))) + return result + + elif self.choice == 'gradV': + + # Ghosts synchronization + OpSynchronize = Synchronize(self.topology) + OpSynchronize.apply(self.field2) + + + maxgersh = np.zeros(2, dtype=PARMES_REAL, order=ORDER) + +## Fourth order scheme +# X components of temp and result +# temp1 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp1 = self.field2[0][...] * 0. + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[0][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field2[0][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field2[0][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field2[0][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + +# temp2 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp2 = self.field2[0][...] * 0. + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[0][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field2[0][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field2[0][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field2[0][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + +# temp3 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp3 = self.field2[0][...] * 0. + temp3[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + maxstr1= np.max(abs(temp1)+abs(temp2)+abs(temp3)) + maxadv1= np.max(abs(temp1)) + +# Y components of temp and result +# temp4 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp4 = self.field2[1][...] * 0. + temp4[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[1][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field2[1][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field2[1][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field2[1][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + +# temp5 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp5 = self.field2[1][...] * 0. + temp5[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[1][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field2[1][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field2[1][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field2[1][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + +# temp6 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp6 = self.field2[1][...] * 0. + temp6[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + maxstr2= np.max(abs(temp4)+abs(temp5)+abs(temp6)) + maxadv2= np.max(abs(temp5)) + +# Z components of temp and result +# temp7 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp7 = self.field2[2][...] * 0. + temp7[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[2][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field2[2][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field2[2][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field2[2][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + +# temp8 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp8 = self.field2[2][...] * 0. + temp8[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[2][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field2[2][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field2[2][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field2[2][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + +# temp9 = np.zeros((self.resolution), dtype=PARMES_REAL, order=ORDER) + temp9 = self.field2[2][...] * 0. + temp9[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + maxstr3= np.max(abs(temp7)+abs(temp8)+abs(temp9)) + maxadv3= np.max(abs(temp9)) + maxgersh[0] = max(maxstr1,maxstr2,maxstr3) + maxgersh[1] = max(maxadv1,maxadv2,maxadv3) + result = np.concatenate((np.array([temp1, temp2, temp3]),np.array([temp4, temp5, temp6]),np.array([temp7, temp8, temp9]))) + + return result, maxgersh + + + elif self.choice == 'gradS': + + # Ghosts synchronization + OpSynchronize = SynchronizeS(self.topology) + OpSynchronize.apply(self.field2) + + # Fourth order scheme + temp1 = self.field2[...] * 0. + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field2[ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field2[ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field2[ind0+2,ind1a:ind1b,ind2a:ind2b]) / (12. * self.meshSize[0]) + + temp2 = self.field2[...] * 0. + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field2[ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field2[ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field2[ind0a:ind0b,ind1+2,ind2a:ind2b]) / (12. * self.meshSize[1]) + + temp3 = self.field2[...] * 0. + temp3[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field2[ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field2[ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field2[ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field2[ind0a:ind0b,ind1a:ind1b,ind2+2]) / (12. * self.meshSize[2]) + + result = np.array([temp1, temp2, temp3]) + + return result + + elif self.choice == 'laplacianV': + + # Ghosts synchronization + OpSynchronize = Synchronize(self.topology) + OpSynchronize.apply(self.field2) + + +## Fourth order scheme for the laplacian operator +# X components of temp and result + temp1 = self.field2[0][...] * 0. + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + (-1./12. * self.field2[0][ind0-2,ind1a:ind1b,ind2a:ind2b] + + 4./3. * self.field2[0][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + - 5./2. * self.field2[0][ind0+0,ind1a:ind1b,ind2a:ind2b] +\ + 4./3. * self.field2[0][ind0+1,ind1a:ind1b,ind2a:ind2b] +\ + -1./12. * self.field2[0][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (self.meshSize[0]**2) + + temp2 = self.field2[0][...] * 0. + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[0][ind0a:ind0b,ind1-2,ind2a:ind2b] +\ + 4./3.* self.field2[0][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + -5./2.* self.field2[0][ind0a:ind0b,ind1+0,ind2a:ind2b] +\ + 4./3.* self.field2[0][ind0a:ind0b,ind1+1,ind2a:ind2b] +\ + -1./12.* self.field2[0][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (self.meshSize[1]**2) + + temp3 = self.field2[0][...] * 0. + temp3[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-2] +\ + 4./3.* self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + -5./2.* self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+0] +\ + 4./3.* self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+1] +\ + -1./12.* self.field2[0][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (self.meshSize[2]**2) + temp1 = temp1 + temp2 + temp3 + +# Y components of temp and result + temp4 = self.field2[1][...] * 0. + temp4[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + (-1./12. * self.field2[1][ind0-2,ind1a:ind1b,ind2a:ind2b] + + 4./3. * self.field2[1][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + - 5./2. * self.field2[1][ind0+0,ind1a:ind1b,ind2a:ind2b] +\ + 4./3. * self.field2[1][ind0+1,ind1a:ind1b,ind2a:ind2b] +\ + -1./12. * self.field2[1][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (self.meshSize[0]**2) + + temp5 = self.field2[1][...] * 0. + temp5[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[1][ind0a:ind0b,ind1-2,ind2a:ind2b] +\ + 4./3.* self.field2[1][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + -5./2.* self.field2[1][ind0a:ind0b,ind1+0,ind2a:ind2b] +\ + 4./3.* self.field2[1][ind0a:ind0b,ind1+1,ind2a:ind2b] +\ + -1./12.* self.field2[1][ind0a:ind0b,ind1+2,ind2a:ind2b]) / (self.meshSize[1]**2) + + temp6 = self.field2[1][...] * 0. + temp6[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-2] +\ + 4./3.* self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + -5./2.* self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+0] +\ + 4./3.* self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+1] +\ + -1./12.* self.field2[1][ind0a:ind0b,ind1a:ind1b,ind2+2]) / (self.meshSize[2]**2) + temp4 = temp4 + temp5 + temp6 + +# Z components of temp and result + temp7 = self.field2[2][...] * 0. + temp7[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + (-1./12. * self.field2[2][ind0-2,ind1a:ind1b,ind2a:ind2b] + + 4./3. * self.field2[2][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + - 5./2. * self.field2[2][ind0+0,ind1a:ind1b,ind2a:ind2b] +\ + 4./3. * self.field2[2][ind0+1,ind1a:ind1b,ind2a:ind2b] +\ + -1./12. * self.field2[2][ind0+2,ind1a:ind1b,ind2a:ind2b]) / (self.meshSize[0]**2) + + temp8 = self.field2[2][...] * 0. + temp8[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[2][ind0a:ind0b,ind1-2,ind2a:ind2b] +\ + 4./3.* self.field2[2][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + -5./2.* self.field2[2][ind0a:ind0b,ind1+0,ind2a:ind2b] +\ + 4./3.* self.field2[2][ind0a:ind0b,ind1+1,ind2a:ind2b] +\ + -1./12.* self.field2[2][ind0a:ind0b,ind1+2,ind2a:ind2b]) / ( self.meshSize[1]**2) + + temp9 = self.field2[2][...] * 0. + temp9[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = \ + ( -1./12.* self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-2] +\ + 4./3.* self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + -5./2.* self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+0] +\ + 4./3.* self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+1] +\ + -1./12.* self.field2[2][ind0a:ind0b,ind1a:ind1b,ind2+2]) / ( self.meshSize[2]**2) + temp7 = temp7 + temp8 + temp9 + + result = np.concatenate((np.array([temp1]),np.array([temp4]),np.array([temp7]))) + + return result + + + elif self.choice == 'curl': + + OpSynchronize = Synchronize(self.topology) + OpSynchronize.apply(self.field1) + + temp1 = self.field1[0][...] * 0. + temp2 = self.field1[0][...] * 0. + + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[2][ind0a:ind0b,ind1-2,ind2a:ind2b] - + 8.0 * self.field1[2][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field1[2][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field1[2][ind0a:ind0b,ind1+2,ind2a:ind2b] ) / (12. * self.meshSize[1]) + + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[1][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field1[1][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field1[1][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field1[1][ind0a:ind0b,ind1a:ind1b,ind2+2] ) / (12. * self.meshSize[2]) + res1 = temp1 - temp2 + + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[0][ind0a:ind0b,ind1a:ind1b,ind2-2] -\ + 8.0 * self.field1[0][ind0a:ind0b,ind1a:ind1b,ind2-1] +\ + 8.0 * self.field1[0][ind0a:ind0b,ind1a:ind1b,ind2+1] -\ + 1.0 * self.field1[0][ind0a:ind0b,ind1a:ind1b,ind2+2] ) / (12. * self.meshSize[2]) + + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[2][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field1[2][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field1[2][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field1[2][ind0+2,ind1a:ind1b,ind2a:ind2b] ) / (12. * self.meshSize[0]) + res2 = temp1 - temp2 + + temp1[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[1][ind0-2,ind1a:ind1b,ind2a:ind2b] - + 8.0 * self.field1[1][ind0-1,ind1a:ind1b,ind2a:ind2b] +\ + 8.0 * self.field1[1][ind0+1,ind1a:ind1b,ind2a:ind2b] -\ + 1.0 * self.field1[1][ind0+2,ind1a:ind1b,ind2a:ind2b] ) / (12. * self.meshSize[0]) + + temp2[ind0a:ind0b,ind1a:ind1b,ind2a:ind2b] = (1.0 * self.field1[0][ind0a:ind0b,ind1-2,ind2a:ind2b] -\ + 8.0 * self.field1[0][ind0a:ind0b,ind1-1,ind2a:ind2b] +\ + 8.0 * self.field1[0][ind0a:ind0b,ind1+1,ind2a:ind2b] -\ + 1.0 * self.field1[0][ind0a:ind0b,ind1+2,ind2a:ind2b] ) / (12. * self.meshSize[1]) + res3 = temp1 - temp2 + result = np.concatenate((np.array([res1]), np.array([res2]), np.array([res3]))) + return result + + else: + raise ValueError("Unknown differiential operatorind " + str(self.choice)) + + def printComputeTime(self): + self.timings_info[0] = "\"Differential Operator total\"" + self.timings_info[1] = str(self.total_time) + self.timings_info[1] += str(self.compute_time[0]) + " " + str(self.compute_time[1]) + " " + str(self.compute_time[2]) + " " + print "Differential Operator total time ind ", self.total_time + print "\t Differential Operator ind", self.compute_time + + + def __str__(self): + s = "DifferentialOperator_d (DiscreteOperator). " + DiscreteOperator.__str__(self) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class ind DifferentialOperator_d" + print DifferentialOperator_d.__doc__ diff --git a/HySoP/unusedOrObsolet/discrete.py b/HySoP/unusedOrObsolet/discrete.py new file mode 100644 index 000000000..6023b35c7 --- /dev/null +++ b/HySoP/unusedOrObsolet/discrete.py @@ -0,0 +1,121 @@ +""" +@package parmepy.problem.discrete + +Problem representation. +""" +from ..Param import * + + +class DiscreteProblem: + """ + Abstract description of discrete problem. + """ + + def __init__(self): + """ + Create an empty discerte problem. + """ + print "DISCRETE PROBLEM" + ## Domains of the problem. + self.domains = [] + ## Variables of the problem. + self.variables = [] + ## Operators of the problem. + self.operators = [] + ## Problem solver + self.solver = None + ## Results printer + self.printer = None + + def addDomain(self, cDomain): + """ + Add a DiscreteDomain.DiscreteDomain to the problem. + + @param cDomain DiscreteDomain.DiscreteDomain : list of domains to add. + """ + print "Add domain" + for d in cDomain: + if self.domains.count(d) == 0: + self.domains.append(d) + + def addVariable(self, cVariable): + """ + Add a DiscreteVariable.DiscreteVariable to the problem. + Also add variables' domains to the problem. + + @param cVariable DiscreteVariable.DiscreteVariable : list of variables to add. + """ + print "add variable" + for v in cVariable: + if self.variables.count(v) == 0: + self.variables.append(v) + if self.domains.count(v.domain) == 0: + self.domains.append(v.domain) + + def addOperator(self, cOperator, index=None): + """ + Add a DiscreteOperator.DiscreteOperator to the problem. + Also add operators' variables and variables' domains to the problem. + + @param cOperator DiscreteOperator.DiscreteOperator : list od operators to add. + """ + print "add operator" + if isinstance(cOperator, list): + for i,o in enumerate(cOperator): + if self.operators.count(o) == 0: + try: + self.operators.insert(index[i],o) + except TypeError: + self.operators.append(o) + for v in o.variables: + if self.variables.count(v) == 0: + self.variables.append(v) + if self.domains.count(v.domain) == 0: + self.domains.append(v.domain) + else: + if self.operators.count(cOperator) == 0: + print index + try: + self.operators.insert(index, cOperator) + except TypeError: + self.operators.append(cOperator) + for v in cOperator.variables: + if self.variables.count(v) == 0: + self.variables.append(v) + if self.domains.count(v.domain) == 0: + self.domains.append(v.domain) + + def setSolver(self, solver): + """ + Set solver for the discrete problem. + + @param solver : Solver.Solver to use. + """ + print "set solver" + self.solver = solver + self.solver.initialize() + + def setPrinter(self, printer): + """ + Set results printer. + + @param printer : Printer.Printer to use. + """ + print "set printer" + self.printer = printer + + def solve(self, T, dt): + """ + Abstract method. + Must be implemented by sub-class. + + @param T : Simulation final time. + @param dt : Simulation time step. + """ + raise NotImplementedError("Need to override method in a subclass of " + providedClass) + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : DiscreteProblem" + print DiscreteProblem.__doc__ diff --git a/HySoP/unusedOrObsolet/forward_euler.py b/HySoP/unusedOrObsolet/forward_euler.py new file mode 100644 index 000000000..9e95c38dd --- /dev/null +++ b/HySoP/unusedOrObsolet/forward_euler.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +Forward Euler method. +""" +from ODESolver import ODESolver + + +providedClass = "ForwardEuler" + + +class ForwardEuler(ODESolver): + """ + ODESolver implementation for solving an equation system with forward Euler method. + y'(t) = f(t,y) + + y(t_{n+1}) = y(t_n) + dt*f(y(t_n)) + + """ + def __init__(self, f=None, dim=1, conditions=lambda x: x): + """ + Constructor. + + @param f function f(t,y) : Right hand side of the equation to solve. + @param dim : dimensions + @param conditions : function to apply boundary conditions. + """ + ODESolver.__init__(self, f) + # Boundary conditions function. + self.boundaryConditions = conditions + # Integration methods for each direction. + self.integrate = [self._integrate for i in xrange(dim)] + + def _integrate(self, y, t, dt): + """ + Integration step for forward Euler method. + y(t_{n+1}) = y(t_n) + dt*f(y(t_n)) + + @param y : position at time t. + @param t : current time. + @param dt : time step. + @return y at t+dt. + """ + return [y[i] + dt * self.f(t, y, i)[i] for i in xrange(len(y))] + + def __str__(self): + """ToString method""" + return "Forward Euler Method" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ diff --git a/HySoP/unusedOrObsolet/gpu_analytic.py b/HySoP/unusedOrObsolet/gpu_analytic.py new file mode 100644 index 000000000..5832a863e --- /dev/null +++ b/HySoP/unusedOrObsolet/gpu_analytic.py @@ -0,0 +1,114 @@ +""" +@file gpu_analytic.py +Analytic operator on GPU. +""" +from parmepy.operator.discrete.discrete import DiscreteOperator +from parmepy.constants import debug, np, PARMES_INDEX, S_DIR +from parmepy import __VERBOSE__ +from parmepy.gpu.tools import get_opencl_environment +from parmepy.gpu.gpu_kernel import KernelLauncher +from parmepy.tools.timers import timed_function +from parmepy.methods_keys import Support +from parmepy.tools.timers import Timer + + +class GPUAnalytic(DiscreteOperator): + """ + Analytic operator on GPU. + + Evaluates a formula on a GPU field. + """ + + @debug + def __init__(self, variables, + platform_id=0, device_id=0, + device_type='gpu', + method={Support: 'gpu'}, src=None, precision=None): + """ + Constructor. + + Computes the OpenCL environment with + parmepy.gpu.tools.get_opencl_environment. + + @param variables a list of discrete variables + @param platform_id OpenCL platform id + @param device_id OpenCL device id + @param device_type OpenCL device type + @param method Method to use + @param src User OpenCL source file + @param precision Floating point precision + """ + DiscreteOperator.__init__(self, variables, method) + ## OpenCL work-item number + self.workItemNumber = 0 + ## Operated field + self.field = self.variables[0] + ## User source file + self.usr_src = src + ## Field resolution + self.resolution = self.field.topology.mesh.resolution + ## OpenCL environment + self.cl_env = get_opencl_environment(platform_id, device_id, + device_type, precision) + self.numMethod = None + ## Object to store computational times of OpenCL kernels + self.kernels_timer = Timer(self) + + @debug + def setUp(self): + """ + Set up. + Compute OpenCL work-item number and space index.\n + Compile OpenCL sources. The OpenCL kernel mus be named as follows : + <code>analytic"FieldName"</code> with <code>"FieldName"</code> is the + name of the field as given by user. + """ + ## Floating point precision + self.gpu_precision = self.cl_env.precision + ## OpenCL space index + self.workItemNumber, self.gwi, self.lwi = self.cl_env.get_WorkItems( + self.resolution) + if __VERBOSE__: + print "Work-items basic config : ", + print self.workItemNumber, self.gwi, self.lwi + dim = self.field.dimension + ## Minimum field coordinate (as GPU float4) + self.coord_min = np.ones(4, dtype=self.gpu_precision) + ## Field mesh size (as GPU float4) + self.mesh_size = np.ones(4, dtype=self.gpu_precision) + self.coord_min[0:dim] = np.asarray(self.field.topology.mesh.origin, + dtype=self.gpu_precision) + self.mesh_size[0:dim] = np.asarray(self.field.topology.mesh.space_step, + dtype=self.gpu_precision) + # Kernel sources + if __VERBOSE__: + print "=== Kernel sources ===" + ## OpenCL compiling options + self.build_options = "" + resol = np.ones((3,), dtype=PARMES_INDEX) + resol[:dim] = self.resolution[...] + for i in xrange(3): + self.build_options += " -D NB" + S_DIR[i] + "=" + str(resol[i]) + self.build_options += " -D WI_NB=" + str(self.workItemNumber) + ## OpenCL Binaries + if self.usr_src is not None: + self.prg = self.cl_env.build_src(self.usr_src, self.build_options) + kernel_name = 'analytic' + self.field.name.rsplit('_', 1)[0] + self.numMethod = KernelLauncher(eval('self.prg.' + kernel_name), + self.cl_env.queue, + self.gwi, self.lwi) + + @debug + @timed_function + def apply(self, simulation): + t = self.gpu_precision(simulation.time) + self.field.initialize(self.numMethod, t) + if self.numMethod is None: + self.field.toDevice() + + def finalize(self): + if self.numMethod is not None and self.numMethod.f_timer is not None: + for f_timer in self.numMethod.f_timer: + self.kernels_timer.addFunctionTimer(f_timer) + self.timer.addSubTimer(self.kernels_timer, 'Details:') + DiscreteOperator.finalize(self) diff --git a/HySoP/unusedOrObsolet/obstacle_d_old.py b/HySoP/unusedOrObsolet/obstacle_d_old.py new file mode 100644 index 000000000..5985ef293 --- /dev/null +++ b/HySoP/unusedOrObsolet/obstacle_d_old.py @@ -0,0 +1,157 @@ +""" +Discrete obstacles description +@todo write test in parmepy/domain/test/test_obstacle.py +""" +from parmepy.constants import np + + +class Obstacle_d(object): + """ + Discrete obstacles representation. + """ + + def __init__(self, parent, topology=None, name='sphere', idFromParent=None): + """ + Creates discrete obsctacle and z-boundaries and returns 3 arrays corresponding + to the three different porous media. + porosity in the solid = 0 + porosity in the fluid = infinity + + @param parent : Continuous obstacle. + @param topology : Topology informations + @param name : Obstacle name + @param idFromParent : Index in the parent's discrete obstacles + """ + + ## Topology of the obstacle + if(topology is not None): + self.topology = topology + else: + raise NotImplementedError() + ## Name of the obstacle + self.name = name + ## Obstacle dimension + self.dimension = topology.domain.dimension + ## Obstacle resolution + self.resolution = topology.mesh.resolution + ## @private Continuous obstacle + self.__parentObstacle = parent + ## @private Index in parent's discrete obstacle + self.__idFromParent = idFromParent + ## Width of z-boundaries layer + self.zlayer = self.__parentObstacle.zlayer + ## Radius of the obstacle + self.radius = self.__parentObstacle.radius + ## Position of the obstacle center + self.center = self.__parentObstacle.center + ## Orientation of the obstacle + self.orientation = self.__parentObstacle.orientation + ## Thickness of the porous layer at the obstacle surface + self.porousLayer = self.__parentObstacle.porousLayer + ## Chi function (array) for z-boundaries + self.chiBoundary = None + ## Chi function (array) for the solid + self.chiSolid = None + ## Chi function (array) for the porous area + self.chiPorous = None + ## Determine characteristic function Chi of Obstacle + self.chiFunctions() + + def chiFunctions(self): + """ + Compute the chi functions associated to z-boundaries and solid + """ +# boolOrientation=[np.bool(0) for i in range (6)] +# boolOrientation[self.indOrientation(self.orientation)]=True + + ## Temporary arrays + chiBoundary_i = [] + chiBoundary_j = [] + chiBoundary_k = [] + chiSolid_i = [] + chiSolid_j = [] + chiSolid_k = [] + chiPorous_i = [] + chiPorous_j = [] + chiPorous_k = [] + + step = self.topology.mesh.space_step_size + ghosts = self.topology.ghosts + coord_start = self.topology.mesh.origin + coord_end = self.topology.mesh.end * step + self.topology.domain.origin - (ghosts * step) + layerMin = coord_start[2] + ghosts[2] * step[2] + self.zlayer + layerMax = coord_end[2] - ghosts[2] * step[2] - self.zlayer + radiusMinuslayer = self.radius- self.porousLayer + print 'start, end, layerMin, layerMax', coord_start, coord_end, layerMin, layerMax + for k in xrange (ghosts[2], self.resolution[2] - ghosts[2]): + rz = coord_start[2] + step[2] * k + for j in xrange (ghosts[1], self.resolution[1] - ghosts[1]): + ry = coord_start[1] + step[1] * j + for i in xrange (ghosts[0], self.resolution[0] - ghosts[0]): + if (rz > layerMax or rz < layerMin): + # we are in the z-layer (North or South): +# chiBoundaryTmp.append([i,j,k]) + chiBoundary_i.append(i) + chiBoundary_j.append(j) + chiBoundary_k.append(k) + else : + rx = coord_start[0] + step[0] * i + dist = np.sqrt((rx - self.center[0]) **2 + + (ry - self.center[1]) **2 + + (rz - self.center[2]) **2) +# if (self.name=='sphere'): + if (radiusMinuslayer < dist and dist <= self.radius + 1E-12 and self.porousLayer != 0.): + # we are in the porous area of the sphere: +# chiPorousTmp.append([i,j,k]) + chiPorous_i.append(i) + chiPorous_j.append(j) + chiPorous_k.append(k) + if (dist <= radiusMinuslayer + 1E-12): + # we are in the solid area of the sphere: +# chiSolidTmp.append([i,j,k]) + chiSolid_i.append(i) + chiSolid_j.append(j) + chiSolid_k.append(k) +# else : +# if (radiusMinuslayer < dist and dist <= self.radius and rx <= self.center[0]): +# # we are in the porous area of the hemisphere: +## chiPorousTmp.append([i,j,k]) +# chiPorous_i.append(i) +# chiPorous_j.append(j) +# chiPorous_k.append(k) +# if (dist <= radiusMinuslayer and rx <= self.center[0]): +# # we are in the solid area of the hemisphere: +## chiSolidTmp.append([i,j,k]) +# chiSolid_i.append(i) +# chiSolid_j.append(j) +# chiSolid_k.append(k) + + ## Characteristic function of penalized boundaries + chiBoundary_i = np.asarray(chiBoundary_i) + chiBoundary_j = np.asarray(chiBoundary_j) + chiBoundary_k = np.asarray(chiBoundary_k) + self.chiBoundary = chiBoundary(chiBoundary_i, chiBoundary_j, chiBoundary_k) + + ## Characteristic function of solid areas + chiSolid_i = np.asarray(chiSolid_i) + chiSolid_j = np.asarray(chiSolid_j) + chiSolid_k = np.asarray(chiSolid_k) + self.chiSolid = chiSolid(chiSolid_i, chiSolid_j, chiSolid_k) + + ## Characteristic function of porous areas + chiPorous_i = np.asarray(chiPorous_i) + chiPorous_j = np.asarray(chiPorous_j) + chiPorous_k = np.asarray(chiPorous_k) + self.chiPorous = chiPorous(chiPorous_i, chiPorous_j, chiPorous_k) + + + def indOrientation(orientation): + return {'West':0, 'East':1, 'South':2, 'North':3, 'Forward':4, 'Backward':5}.get(orientation, 0) + + def __str__(self): + """ToString method""" + return "Obstacle_d (discrete obstacles)" + +if __name__ == "__main__" : + print "This module defines the following classes:" + print "Obstacle_d: ", Obstacle_d.__doc__ diff --git a/HySoP/unusedOrObsolet/obstacle_old.py b/HySoP/unusedOrObsolet/obstacle_old.py new file mode 100644 index 000000000..db9342b21 --- /dev/null +++ b/HySoP/unusedOrObsolet/obstacle_old.py @@ -0,0 +1,72 @@ +""" +Obstacles representation. +""" +from parmepy.constants import np, PARMES_REAL +from obstacle_d import Obstacle_d + + +class Obstacle(object): + """ + Obstacles representation. + """ + + def __init__(self, domain, name='sphere', zlayer=0.001, radius=0.05, + center=[0.5, 0.5, 0.5], orientation='West', + porousLayer=0.001): + """ + Constructor. + Create an obsctacle and z-boundaries from given parameters : + + @param domain : obstacle application domain. + @param name : name of the obstacle ("sphere" or "hemisphere") + @param zlayer : width of z-boundaries layer + @param radius : radius of the obstacle + @param center : position of the obstacle center + """ + ## Application domain of the obstacle + self.domain = domain + ## Obstacle dimension. + self.dimension = self.domain.dimension + ## Obstacle discretisation + self.discreteObstacle = None + ## Number of different discretizations + self._obstacleId = -1 + ## List of the various discretizations of the obstacle + self.discreteObstacle = [] + ## Obstacle name + self.name = name + ## Width of z-boundaries layer + self.zlayer = zlayer + ## Obstacle radius + self.radius = radius + ## Position of the obstacle center + self.center = np.asarray(center, dtype=PARMES_REAL) + ## Obstacle orientation + self.orientation = orientation + ## Thickness of the porous layer at the obstacle surface + self.porousLayer = porousLayer + + def discretize(self, topology=None): + """ + Obstacle discretization method. + """ + self._obstacleId += 1 + self.discreteObstacle.append(Obstacle_d(self, topology, + name=self.name, + idFromParent=self._obstacleId)) + + def __str__(self): + """ Obstacle info display """ + s = self.name + ' , ' + str(self.dimension) + 'D obstacle ' + if len(self.Obstacle_d) != 0: + s += "with the following discretizations:\n" + for i in range(len(self.Obstacle_d)): + s += self.Obstacle_d[i].__str__() + else: + s += ". Not discretised\n" + return s + +if __name__ == "__main__" : + print __doc__ + print "- Provided class : Obstacle" + print Obstacle.__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/__init__.py b/HySoP/unusedOrObsolet/particular_solvers/__init__.py new file mode 100644 index 000000000..8a853e394 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/__init__.py @@ -0,0 +1,6 @@ +""" +@package parmepy.particular_solvers + +Everything concerning particle solvers. + +""" diff --git a/HySoP/unusedOrObsolet/particular_solvers/basic.py b/HySoP/unusedOrObsolet/particular_solvers/basic.py new file mode 100644 index 000000000..01e24a6e7 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/basic.py @@ -0,0 +1,168 @@ +""" +@package parmepy.particular_solvers.basic + +Particular solver description. +""" +from solver import Solver +from parmepy.fields.continuous import ContinuousField +from parmepy.operator.transport import Transport +from parmepy.operator.stretching import Stretching +from parmepy.operator.remeshing import Remeshing +from parmepy.operator.penalization import Penalization +from parmepy.operator.advec_scales import Advec_scales +from parmepy.operator.diffusion import Diffusion +from parmepy.operator.poisson import Poisson +from parmepy.operator.splitting import Splitting +from parmepy.tools.timer import Timer +from parmepy.tools.printer import Printer +from parmepy.integrator import RK3 + + +class ParticleSolver(Solver): + """ + Particular solver description. + + Link with differents numericals methods used. + """ + def __init__(self, problem, t_end, dt, + ODESolver=RK3, + InterpolationMethod=None, + RemeshingMethod=None, + splittingMethod='strang', + timer=None, + io=None): + """ + Create a solver description. + + @param problem : problen that solve this solver. + @param t_end : Simulation final time. + @param dt : Simulation time step. + @param ODESolver : ODE solver method. + @param InterpolationMethod : Interpolation method. + @param RemeshingMethod : Remeshing method. + @param splittingMethod : Splitting type. + @param timer : Simulation time step manager. + @param io : Simulation io manager. + """ + Solver.__init__(self, problem) + ## Advection operator of the problem. Advection need special + ## treatment in particle methods. + self.advection = None + self.stretch = None + self.penal = None + self.advec_scales = None + self.diffusion = None + self.poisson = None + ## ODE Solver method. + self.ODESolver = ODESolver + ## Interpolation method. + self.InterpolationMethod = InterpolationMethod + ## Remeshing method. + self.RemeshingMethod = RemeshingMethod + ## Splitting Method + self.splittingMethod = splittingMethod + ## Is solver initialized + self.isInitialized = False + if timer is None: + self.problem.setTimer(Timer(t_end, dt)) + else: + self.problem.setTimer(timer) + if io is None: + self.problem.setIO(Printer()) + else: + self.problem.setIO(io) + for op in self.problem.operators: + if isinstance(op, Transport): + self.advection = op + if isinstance(op, Stretching): + self.stretch = op + if isinstance(op, Penalization): + self.penal = op + if isinstance(op, Advec_scales): + self.advec_scales = op + if isinstance(op, Diffusion): + self.diffusion = op + if isinstance(op, Poisson): + self.poisson = op + #if isinstance(op, Velocity) + #self.velocity = op + #if self.advection is None: + # raise ValueError("Particular Solver : + # Cannot create from a problem with no Transport operator") + + def initialize(self): + """ + Solver initialisation. + Initialize a particle method solver regarding the problem. + """ + self.p_position = ContinuousField(domain=self.problem.domains[0], + name='ParticlePosition') + self.p_scalar = ContinuousField(domain=self.problem.domains[0], + name='ParticleScalar') + self.problem.addVariable([self.p_position, self.p_scalar]) + ## Discretise domains + ## Note FP : this is probably useless??? + #for d in self.problem.domains: + # d.discretize(self.problem.topology.globalMeshResolution) + ## Discretise fields and initialize + for v in self.problem.variables: + v.discretize(self.problem.topology) + print "=== Fields initialization ===" + for v in self.problem.variables: + v.initialize() + print "==\n" + ## Discretise operators + for op in self.problem.operators: + if op is self.advection: + op.discretize(result_position=self.p_position, + result_scalar=self.p_scalar, + method=self.ODESolver) + if op is self.stretch: + op.discretize(topology=self.problem.topology, + method=self.ODESolver) + if op is self.penal: + op.obstacle.discretize(self.problem.topology) + op.discretize() + if op is self.advec_scales: + op.discretize(topology=self.problem.topology) + if op is self.diffusion: + op.discretize(topology=self.problem.topology) + if op is self.poisson: + op.discretize(topology=self.problem.topology) + ## Velocity is only program on gpu for instance + #elif op is self.velocity: + # op.discretize(result_position=self.p_position, + # result_scalar=self.p_scalar, method=self.ODESolver) + else: + op.discretize() + if self.advection is not None and not self.advection.include_remesh: + ## Create remeshing operator + self.remeshing = Remeshing( + partPositions=self.advection.discreteOperator.res_position, + partScalar=self.advection.discreteOperator.res_scalar, + resscal=self.advection.discreteOperator.scalar, + method=self.RemeshingMethod) + + for op in self.problem.operators: + if op.needSplitting: + index = self.problem.operators.index(op) + if op is self.advection and not self.advection.include_remesh: + self.problem.operators[index] = Splitting( + [op, self.remeshing], dim=self.problem.topology.dim) + else: + self.problem.operators[index] = Splitting( + [op], dim=self.problem.topology.dim) + self.isInitialized = True + + def end(self): + """\todo : Put here memory free instructions""" + + def __str__(self): + """ToString method""" + s = " Particle solver " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : ParticleSolver" + print ParticleSolver.__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu.py b/HySoP/unusedOrObsolet/particular_solvers/gpu.py new file mode 100644 index 000000000..f0c9f39c3 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu.py @@ -0,0 +1,638 @@ +""" +@package parmepy.particular_solvers.gpu + +Particular solver description. Computations are performed on GPU device. +""" +from ..constants import * +from basic import ParticleSolver +from ..fields.continuous import ContinuousField +from ..operator.transport import Transport +from ..operator.remeshing import Remeshing +from ..operator.splitting import Splitting +from ..tools.timer import Timer +from ..tools.printer import Printer +import pyopencl as cl +from ..tools.gpu_data_transfer import hostToDevice +from ..tools.gpu_data_transfer import deviceToHost + + +class GPUParticleSolver(ParticleSolver): + """ + GPU Particular solver description. + + Link with differents numericals methods used. + Prepare GPU side (memory, kernels, ...) + """ + def __init__(self, problem, t_end, dt, + ODESolver=None, + InterpolationMethod=None, + RemeshingMethod=None, + splittingMethod='strang', + timer=None, + io=None, + platform_id=0, device_id=0, + device_type='gpu', + src=None, + precision=PARMES_REAL_GPU): + """ + @copydoc ParticleSolver.__init__() + @param platform_id : OpenCL platform id to use. + @param device_id : OpenCL device id to use. + @param device_type='gpu' : OpenCL device type to use. + @param src : OpenCL kernel sources given by user. + + Discover OpenCL environment. + """ + ParticleSolver.__init__(self, problem, t_end, dt, + ODESolver=ODESolver, + InterpolationMethod=InterpolationMethod, + RemeshingMethod=RemeshingMethod, + splittingMethod=splittingMethod, + timer=timer, + io=io) + ## User kernel sources filename + self.user_gpu_src = src + self.gpu_precision = precision + print "=== OpenCL environment ===" + #Get platform. + try: + ## OpenCL platform + self.platform = cl.get_platforms()[platform_id] + except IndexError: + print " Incorrect platform_id :", platform_id, ".", + print " Only ", len(cl.get_platforms()), " available.", + print " Getting defalut platform. " + self.platform = cl.get_platforms()[0] + print " Platform " + print " - Name :", self.platform.name + print " - Version :", self.platform.version + #Get device. + try: + ## OpenCL device + self.device = self.platform.get_devices( + eval("cl.device_type." + device_type.upper()))[device_id] + except cl.RuntimeError as e: + print "RuntimeError:", e + self.device = cl.create_some_context().devices[0] + except AttributeError as e: + print "AttributeError:", e + self.device = cl.create_some_context().devices[0] + print " Device" + print " - Name :", + print self.device.name + print " - Type :", + print cl.device_type.to_string(self.device.type) + print " - C Version :", + print self.device.opencl_c_version + print " - Global mem size :", + print self.device.global_mem_size / (1024 ** 3), "GB" + print "===\n" + #Creates GPU Context + ## OpenCL context + self.ctx = cl.Context([self.device]) + #Create CommandQueue on the GPU Context + ## OpenCL command queue + self.queue = cl.CommandQueue( + self.ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) + + def initialize(self): + """ + @copydoc ParticleSolver.initialize(self) + Compile kernel sources. \n + Allocate device memory as OpenCL Buffers.\n + Initialize memory on device. \n + Link kernels ans parmepy.operators. + @todo : Take non square resolutions + """ + ParticleSolver.initialize(self) + # kernels compilation + print "=== Kernel sources compiling ===" + self.gpu_src = "" + if self.user_gpu_src is not None: + if isinstance(self.user_gpu_src, list): + for user_src in self.user_gpu_src: + print "Sources files (user): ", user_src + f = open(user_src, 'r') + self.gpu_src += "".join(f.readlines()) + f.close() + else: + print "Sources files (user): ", self.user_gpu_src + f = open(self.user_gpu_src, 'r') + self.gpu_src += "".join(f.readlines()) + f.close() + resolution = self.problem.topology.mesh.resolution + ## Optimal work item number + if len(resolution) == 3: + workItemNumber = 64 + else: + workItemNumber = 256 + print " Work-Item number: ", workItemNumber + ## Precision supported + print " Precision capability ", + self.correctlyroundeddividesqrt = True + if self.gpu_precision is np.float32: + print "for Single Precision: " + for v in ['DENORM', 'INF_NAN', + 'ROUND_TO_NEAREST', 'ROUND_TO_ZERO', 'ROUND_TO_INF', + 'FMA', 'CORRECTLY_ROUNDED_DIVIDE_SQRT', 'SOFT_FLOAT']: + try: + if eval('(self.device.single_fp_config &' + + ' cl.device_fp_config.' + + v + ') == cl.device_fp_config.' + v): + print v + except AttributeError as ae: + if v is 'CORRECTLY_ROUNDED_DIVIDE_SQRT': + self.correctlyroundeddividesqrt = False + print v, 'is not supported in OpenCL C 1.2.\n', + print ' Exception catched : ', ae + else: + print "for Double Precision: " + if self.device.double_fp_config > 0: + for v in ['DENORM', 'INF_NAN', 'FMA', + 'ROUND_TO_NEAREST', 'ROUND_TO_ZERO', 'ROUND_TO_INF', + 'CORRECTLY_ROUNDED_DIVIDE_SQRT', 'SOFT_FLOAT']: + try: + if eval('(self.device.double_fp_config &' + + ' cl.device_fp_config.' + + v + ') == cl.device_fp_config.' + v): + print v + except AttributeError as ae: + if v is 'CORRECTLY_ROUNDED_DIVIDE_SQRT': + self.correctlyroundeddividesqrt = False + print v, 'is supported in OpenCL C 1.2.\n', + print ' Exception catched : ', ae + else: + raise ValueError("Double Precision is not supported by device") + ## Building options and kernel settings + build_options = '' + if self.correctlyroundeddividesqrt: + build_options += " -cl-fp32-correctly-rounded-divide-sqrt " + if self.gpu_precision is np.float32: + build_options += " -cl-single-precision-constant" + build_options += " -D WIDTH=" + str(resolution[0]) + build_options += " -D WGN=" + str(workItemNumber) + + ## Collect OpenCL source code + print "\n Source code:" + ## advection + if self.advection.include_remesh: + if len(resolution) == 3: + if self.gpu_precision is np.float32: + if self.RemeshingMethod is 'm6prime': + src_remesh_weights = 'weights_m6prime_opt4_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_3D_opt4_builtin_private4.cl' + else: + src_remesh_weights = 'weights_m8prime_opt4_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_m8prime_3D_opt4_builtin_private4.cl' + else: + if self.RemeshingMethod is 'm6prime': + src_remesh_weights = 'weights_m6prime_opt4_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_3D_opt4_builtin_private4_noBC.cl' + else: + src_remesh_weights = 'weights_m8prime_opt4_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_m8prime_3D_opt4_builtin_private4_noBC.cl' + advec_and_remesh_gwi = (int(workItemNumber), int(resolution[1]), int(resolution[2])) + advec_and_remesh_lwi = (int(workItemNumber), 1, 1) + else: + if self.gpu_precision is np.float32: + if self.RemeshingMethod is 'm6prime': + src_remesh_weights = 'weights_m6prime_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_2D_opt8_builtin_noBC.cl' + else: + src_remesh_weights = 'weights_m8prime_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_m8prime_2D_opt8_builtin_noBC.cl' + else: + if self.RemeshingMethod is 'm6prime': + src_remesh_weights = 'weights_m6prime_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_2D_opt4_builtin_noBC.cl' + else: + src_remesh_weights = 'weights_m8prime_builtin.cl' + src_advec_and_remesh = 'advection_and_remesh_m8prime_2D_opt4_builtin_noBC.cl' + advec_and_remesh_gwi = (int(workItemNumber), int(resolution[1])) + advec_and_remesh_lwi = (int(workItemNumber), 1) + f = open(os.path.join(GPU_SRC, src_remesh_weights)) + self.gpu_src += "".join(f.readlines()) + print " - remeshing weights:", f.name + f.close() + f = open(os.path.join(GPU_SRC, src_advec_and_remesh)) + print " - advection and remesh:", f.name + self.gpu_src += "".join(f.readlines()) + f.close() + else: + if len(resolution) == 3: + if self.gpu_precision is np.float32: + src_advec = 'advection_3D_opt4_builtin.cl' + else: + src_advec = 'advection_3D_opt2_builtin.cl' + advec_gwi = (int(workItemNumber), int(resolution[1]), int(resolution[2])) + advec_lwi = (int(workItemNumber), 1, 1) + else: + if self.gpu_precision is np.float32: + src_advec = 'advection_2D_opt4_builtin.cl' + else: + src_advec = 'advection_2D_builtin.cl' + advec_gwi = (int(workItemNumber), int(resolution[1])) + advec_lwi = (int(workItemNumber), 1) + f = open(os.path.join(GPU_SRC, src_advec)) + print " - advection:", f.name + self.gpu_src += "".join(f.readlines()) + f.close() + ## remeshing + if len(resolution) == 3: + if self.RemeshingMethod is 'm6prime': + src_remesh = 'remeshing_3D_opt4_private4.cl' + src_remesh_weights = 'weights_m6prime_opt4_builtin.cl' + else: + src_remesh = 'remeshing_m8prime_3D_opt4_private4.cl' + src_remesh_weights = 'weights_m8prime_opt4_builtin.cl' + remesh_gwi = (int(workItemNumber), int(resolution[1]), int(resolution[2])) + remesh_lwi = (int(workItemNumber), 1, 1) + else: + if self.RemeshingMethod is 'm6prime': + src_remesh = 'remeshing_2D_opt4_noBC.cl' + src_remesh_weights = 'weights_m6prime_builtin.cl' + else: + src_remesh = 'remeshing_m8prime_2D_opt4_noBC.cl' + src_remesh_weights = 'weights_m8prime_builtin.cl' + remesh_gwi = (int(workItemNumber), int(resolution[1])) + remesh_lwi = (int(workItemNumber), 1) + f = open(os.path.join(GPU_SRC, src_remesh_weights)) + self.gpu_src += "".join(f.readlines()) + print " - remeshing weights:", f.name + f.close() + f = open(os.path.join(GPU_SRC, src_remesh)) + print " - remeshing:", f.name + self.gpu_src += "".join(f.readlines()) + f.close() + ## copy + if len(resolution) == 3: + if self.gpu_precision is np.float32: + src_copy = 'copy_3D_opt4.cl' + build_options += " -D TILE_DIM_COPY=16 -D BLOCK_ROWS_COPY=8" + copy_gwi = (int(resolution[0] / 4), int(resolution[1] / 2), int(resolution[2])) + copy_lwi = (4, 8, 1) + else: + src_copy = 'copy_3D_locMem.cl' + build_options += " -D TILE_DIM_COPY=32 -D BLOCK_ROWS_COPY=8" + copy_gwi = (int(resolution[0]), int(resolution[1] / 4), int(resolution[2])) + copy_lwi = (32, 8, 1) + else: + if self.gpu_precision is np.float32: + src_copy = 'copy_2D_opt2.cl' + build_options += " -D TILE_DIM_COPY=16 -D BLOCK_ROWS_COPY=8" + copy_gwi = (int(resolution[0] / 2), int(resolution[1] / 2)) + copy_lwi = (8, 8) + else: + src_copy = 'copy_2D_opt2.cl' + build_options += " -D TILE_DIM_COPY=32 -D BLOCK_ROWS_COPY=2" + copy_gwi = (int(resolution[0] / 2), int(resolution[1] / 16)) + copy_lwi = (16, 2) + f = open(os.path.join(GPU_SRC, src_copy)) + print " - copy:", f.name + self.gpu_src += "".join(f.readlines()) + f.close() + ## transpose + if len(resolution) == 3: + if self.gpu_precision is np.float32: + src_transpose_xy = 'transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl' + build_options += " -D TILE_DIM_XY=16 -D BLOCK_ROWS_XY=8" + transpose_xy_gwi = (int(resolution[0] / 2), int(resolution[1] / 2), int(resolution[2])) + transpose_xy_lwi = (8, 8, 1) + src_transpose_xz = 'transpose_3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl' + build_options += " -D TILE_DIM_XZ=16 -D BLOCK_ROWS_XZ=4" + transpose_xz_gwi = (int(resolution[0]), int(resolution[1] / 4), int(resolution[2] / 4)) + transpose_xz_lwi = (16, 4, 4) + else: + src_transpose_xy = 'transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl' + build_options += " -D TILE_DIM_XY=32 -D BLOCK_ROWS_XY=4" + transpose_xy_gwi = (int(resolution[0] / 4), int(resolution[1] / 8), int(resolution[2])) + transpose_xy_lwi = (8, 4, 1) + src_transpose_xz = 'transpose_3D_xz_coalesced_Diag_bis_3DBlock.cl' + build_options += " -D TILE_DIM_XZ=8 -D BLOCK_ROWS_XZ=2" + transpose_xz_gwi = (int(resolution[0]), int(resolution[1] / 4), int(resolution[2] / 4)) + transpose_xz_lwi = (8, 2, 2) + else: + if self.gpu_precision is np.float32: + src_transpose_xy = 'transpose_2D_xy_coalesced_locPad_Diag_opt4.cl' + build_options += " -D TILE_DIM_XY=32 -D BLOCK_ROWS_XY=8" + transpose_xy_gwi = (int(resolution[0] / 4), int(resolution[1]) / 4) + transpose_xy_lwi = (8, 8) + else: + src_transpose_xy = 'transpose_2D_xy_coalesced_locPad_Diag_opt4.cl' + build_options += " -D TILE_DIM_XY=32 -D BLOCK_ROWS_XY=2" + transpose_xy_gwi = (int(resolution[0] / 4), int(resolution[1]) / 16) + transpose_xy_lwi = (8, 2) + f = open(os.path.join(GPU_SRC, src_transpose_xy)) + print " - transpose_xy:", f.name + self.gpu_src += "".join(f.readlines()) + f.close() + if len(resolution) == 3: + f = open(os.path.join(GPU_SRC, src_transpose_xz)) + self.gpu_src += "".join(f.readlines()) + f.close() + + ## Build code + if self.gpu_precision is np.float32: + prg = cl.Program(self.ctx, self.gpu_src.replace('.0', '.0f')) + else: + prg = cl.Program(self.ctx, self.gpu_src.replace('float', 'double')) + + ## OpenCL program + self.prg = prg.build(build_options) + print "Compiler options : ", + print self.prg.get_build_info(self.device, cl.program_build_info.OPTIONS) + print "Compiler status : ", + print self.prg.get_build_info(self.device, cl.program_build_info.STATUS) + print "Compiler log : ", + print self.prg.get_build_info(self.device, cl.program_build_info.LOG) + print "===\n" + # Convert fields to recquired precision (self.gpu_precision) and ensure order + for f in self.problem.variables: + for df in f.discreteField: + if f.vector: + for d in xrange(len(df.data)): + df.data[d] = np.asarray(df.data[d], dtype=self.gpu_precision, order='F') + else: + df.data = np.asarray(df.data, dtype=self.gpu_precision, order='F') + # Create OpenCL Buffers from fields + print "=== OpenCL Buffer allocations ===" + total_mem_used = 0 + for f in self.problem.variables: + print f.name, "allocate ", + temp_mem_used = 0 + for df in f.discreteField: + if f.vector: + for d in xrange(len(df.data)): + df.gpu_data[d] = cl.Buffer(self.ctx, + cl.mem_flags.READ_WRITE, + size=df.data[d].nbytes) + temp_mem_used += df.gpu_data[d].size + else: + df.gpu_data = cl.Buffer(self.ctx, + cl.mem_flags.READ_WRITE, + size=df.data.nbytes) + temp_mem_used += df.gpu_data.size + total_mem_used += temp_mem_used + print temp_mem_used, "Bytes (", temp_mem_used / (1024 ** 2), "MB)" + print "Total Global Memory used : ", total_mem_used, "Bytes (", total_mem_used / (1024 ** 2), "MB)", + print "({0:.3f} %)".format(100 * total_mem_used / (self.device.global_mem_size * 1.)) + print "===\n" + print "=== OpenCL Buffer initialisation ===" + data, transfer_time, compute_time = 0, 0., 0. + for f in self.problem.variables: + initKernel = None + # Looking for initKernel + for k in self.prg.all_kernels(): + if k.get_info(cl.kernel_info.FUNCTION_NAME) == ('init' + f.name): + initKernel = cl.Kernel(self.prg, 'init' + f.name) + if initKernel is not None: + for df in f.discreteField: + print f.name, ": kernel init", + global_wg = df.resolution.tolist() + if global_wg[0] / workItemNumber > 0: + global_wg[0] = workItemNumber + if len(global_wg) == 3: + local_wg = (workItemNumber, 1, 1) + else: + local_wg = (workItemNumber, 1) + else: + local_wg = None + global_wg = tuple(global_wg) + print global_wg, local_wg, + dim = df.topology.dim + coord_min = np.ones(4, dtype=self.gpu_precision) + mesh_size = np.ones(4, dtype=self.gpu_precision) + coord_min[0:dim] = df.topology.mesh.origin + mesh_size[0:dim] = df.topology.mesh.size + print "...", + if f.vector: + if dim == 3: + evt = initKernel(self.queue, + global_wg, + local_wg, + df.gpu_data[XDIR], df.gpu_data[YDIR], df.gpu_data[ZDIR], + coord_min, + mesh_size) + else: + evt = initKernel(self.queue, + global_wg, + local_wg, + df.gpu_data[XDIR], df.gpu_data[YDIR], + coord_min, + mesh_size) + else: + evt = initKernel(self.queue, + global_wg, + local_wg, + df.gpu_data, + coord_min, + mesh_size) + self.queue.finish() + temp_time = (evt.profile.end - evt.profile.start) * 1e-9 + print "Done in ", temp_time, "sec" + compute_time += temp_time + else: + for df in f.discreteField: + if df.contains_data: + print f.name, ":", + temp_data, temp_time = hostToDevice(self.queue, df) + data += temp_data + transfer_time += temp_time + if data > 0: + print "Total Transfers : ", data, "Bytes transfered at {0:.3f} GBytes/sec".format((data * 1e-9) / transfer_time) + if compute_time > 0.: + print "Total Computing : ", compute_time, "sec" + print "===\n" + # Setting advection and remeshing kernels: + print "=== OpenCL Kernels setting ===" + for op in self.problem.operators: + if op.discreteOperator.name == "splitting": + for sop in op.operators: + print sop.discreteOperator.name, + sop.discreteOperator.gpu_precision = self.gpu_precision + if sop.discreteOperator.name == 'advection': + sop.setMethod(KernelLauncher(self.prg.advection, + self.queue, + advec_gwi, + advec_lwi)) + elif sop.discreteOperator.name == 'remeshing': + sop.setMethod(KernelLauncher(self.prg.remeshing, + self.queue, + remesh_gwi, + remesh_lwi)) + elif sop.discreteOperator.name == 'advection_and_remeshing': + sop.setMethod(KernelLauncher(self.prg.advection_and_remeshing, + self.queue, + advec_and_remesh_gwi, + advec_and_remesh_lwi)) + else: + raise ValueError("Unknown operator : " + sop.discreteOperator.name) + else: + raise ValueError("Unknown operator : " + op.discreteOperator.name) + print self.advection.discreteOperator.name, + self.advection.discreteOperator.init_copy = KernelLauncher(self.prg.copy, + self.queue, + copy_gwi, + copy_lwi) + if len(resolution) == 3: + print self.advection.discreteOperator.name, + k = KernelListLauncher([self.prg.transpose_xy, + self.prg.transpose_xz], + self.queue, + [transpose_xy_gwi, + transpose_xz_gwi], + [transpose_xy_lwi, + transpose_xz_lwi]) + self.advection.discreteOperator.init_transpose = k + else: + print self.advection.discreteOperator.name, + k = KernelLauncher(self.prg.transpose_xy, + self.queue, + transpose_xy_gwi, + transpose_xy_lwi) + self.advection.discreteOperator.init_transpose = k + self.problem.io.set_get_data_method(self.get_data_from_device) + print "===\n" + + def end(self): + print "=== OpenCL Buffer deallocations ===" + for f in self.problem.variables: + print f.name, "deallocate " + temp_mem_used = 0 + for df in f.discreteField: + if f.vector: + for d in xrange(len(df.data)): + if isinstance(df.gpu_data[d], cl.MemoryObject): + df.gpu_data[d].release() + else: + if isinstance(df.gpu_data, cl.MemoryObject): + df.gpu_data.release() + print "===\n" + + def get_data_from_device(self, field): + """Data collect method.""" + deviceToHost(self.queue, field) + + def __str__(self): + """ToString method""" + s = " Particular solver " + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : ParticularSolver" + print ParticularSolver.__doc__ + + +class KernelListLauncher: + """ + OpenCL kernel list launcher. + + Manage launching of OpenCL kernels as a list. + """ + def __init__(self, kernel, queue, gsize=None, lsize=None): + """ + Create a kernel list launcher. + @param kernel : kernel list. + @param queue : OpenCL command queue. + @param gsize : OpenCL global size index. + @param lsize : OpenCL local size index. + """ + ## OpenCL Kernel list + self.kernel = kernel + print [k.function_name for k in self.kernel] + ## OpenCL command queue + self.queue = queue + ## OpenCL global size index. + self.global_size = gsize + ## OpenCL local size index. + self.local_size = lsize + self.call_number = [0 for k in self.kernel] + + def launch(self, d, *args): + """ + Launch a kernel. + + @param d : kernel index in kernel list. + @param args : kernel arguments. + @return OpenCL Event + + OpenCL global size and local sizes are not given in args. Class member are used. + """ + return KernelListLauncher.launch_sizes_in_args(self, d, self.global_size[d], self.local_size[d], *args) + + def launch_sizes_in_args(self, d, *args): + """ + Launch a kernel. + + @param d : kernel index in kernel list. + @param args : kernel arguments. + @return OpenCL Event. + + Opencl global and local sizes are given in args. + """ + #print self.kernel[d].function_name, args[0], args[1] + self.call_number[d] += 1 + evt = self.kernel[d](self.queue, *args) + return evt + + def finish(self): + self.queue.finish() + + def function_name(self, d=None): + """Prints OpenCL Kernels function names informations""" + if d is not None: + return self.kernel[d].get_info(cl.kernel_info.FUNCTION_NAME) + else: + return [k.get_info(cl.kernel_info.FUNCTION_NAME) for k in self.kernel] + + +class KernelLauncher(KernelListLauncher): + """ + OpenCL kernel launcher. + + Manage launching of one OpenCL kernel as a KernelListLauncher with a list of one kernel. + """ + def __init__(self, kernel, queue, gsize, lsize): + """ + Create a KernelLauncher. + + @param kernel : kernel. + @param queue : OpenCL command queue. + @param gsize : OpenCL global size index. + @param lsize : OpenCL local size index. + + Create a KernelListLauncher with a list of one kernel. + """ + KernelListLauncher.__init__(self, [kernel], queue, [gsize], [lsize]) + + def launch_sizes_in_args(self, *args): + """ + Launch the kernel. + + @param args : kernel arguments. + @return OpenCL Event. + + Opencl global and local sizes are given in args. + """ + return KernelListLauncher.launch_sizes_in_args(self, 0, *args) + + def finish(self): + """Wrapping OpenCL queue.finish() method.""" + self.queue.finish() + + def launch(self, *args): + """ + Launch the kernel. + + @param args : kernel arguments. + @return OpenCL Event + + OpenCL global size and local sizes are not given in args. Class member are used. + """ + return KernelListLauncher.launch(self, 0, *args) + + def function_name(self): + """Prints OpenCL Kernel function name informations""" + res = KernelListLauncher.function_name(self, 0) + return res diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src.cl new file mode 100644 index 000000000..af81deb01 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src.cl @@ -0,0 +1,604 @@ +inline float alpha(float y, float s){ + return (y * (y * (y * (y * (13.0f - 5.0f * y) - 9.0f) - 1.0f) + 2.0f) / 24.0f) * s;} +inline float beta(float y, float s){ + return (y * (y * (y * (y * (25.0f * y - 64.0f) + 39.0f) + 16.0f) - 16.0f) / 24.0f)*s;} +inline float gamma(float y, float s){ + return (y * y * (y * (y * (126.0f - 50.0f * y) - 70.0f) - 30.0f) / 24.0f + 1.0f)*s;} +inline float delta(float y, float s){ + return (y * (y * (y * (y * (50.0f * y - 124.0f) + 66.0f) + 16.0f) + 16.0f) / 24.0f)*s;} +inline float eta(float y, float s){ + return (y * (y * (y * (y * (61.0f - 25.0f * y) - 33.0f) - 1.0f) - 2.0f) / 24.0f)*s;} +inline float zeta(float y, float s){ + return (y * y * y * (y * (5.0f * y - 12.0f) + 7.0f) / 24.0f)*s;} + +#if DIM==3 +__kernel void advection_3D_basic(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int ind, i_ind, i_ind_p; + float invdx = 1.0f/dx; + uint i; + float v, y, p; + for(i=gidX; i<WIDTH; i+=NB_WI_ADVECTION) + { + v = gvelo[i+gidY*WIDTH+gidZ*WIDTH*WIDTH]; + p = i*dx + 0.5f*dt*v; + ind = convert_int_rtn(p * invdx); + y = (p - convert_float(ind) * dx) * invdx; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((ind + 1) % WIDTH); + p=(gvelo[i_ind+gidY*WIDTH+gidZ*WIDTH*WIDTH]*(1.0f - y) + gvelo[i_ind_p+gidY*WIDTH+gidZ*WIDTH*WIDTH]*y)*dt + i*dx + min_position; + ppos[i+gidY*WIDTH+gidZ*WIDTH*WIDTH] = p; + } +} +__kernel void advection_3D_float4(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int4 ind, i_ind, i_ind_p; + float invdx = 1.0f/dx; + uint i; + float4 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=NB_WI_ADVECTION*4) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + velocity_cache[i+2] = v.z; + velocity_cache[i+3] = v.w; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*4; i<WIDTH; i+=NB_WI_ADVECTION*4) + { + v = vload4(i/4, velocity_cache); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = coord + 0.5f*dt*v; + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(velocity_cache[i_ind.x], velocity_cache[i_ind.y], velocity_cache[i_ind.z], velocity_cache[i_ind.w]); + vp = (float4)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y], velocity_cache[i_ind_p.z], velocity_cache[i_ind_p.w]); + p = (v*(1.0f - y) + vp*y)*dt + coord + (float4)(min_position); + vstore4(p, (i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, ppos); + } +} +__kernel void remeshing_3D_float4(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0f/dx; + int4 ind; + uint i, nb_part = WIDTH/NB_WI_REMESHING; + float4 p, s, y; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(NB_WI_REMESHING*4)) +{ + gscal_loc[i] = 0.0f; + gscal_loc[i+1] = 0.0f; + gscal_loc[i+2] = 0.0f; + gscal_loc[i+3] = 0.0f; +} + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gscal_loc[index4.x] += (alpha(y.x,s.x)); + gscal_loc[index4.y] += (alpha(y.y,s.y)); + gscal_loc[index4.z] += (alpha(y.z,s.z)); + gscal_loc[index4.w] += (alpha(y.w,s.w)); +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[index4.x] += (beta(y.x,s.x)); + gscal_loc[index4.y] += (beta(y.y,s.y)); + gscal_loc[index4.z] += (beta(y.z,s.z)); + gscal_loc[index4.w] += (beta(y.w,s.w)); +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[index4.x] += (gamma(y.x, s.x)); + gscal_loc[index4.y] += (gamma(y.y, s.y)); + gscal_loc[index4.z] += (gamma(y.z, s.z)); + gscal_loc[index4.w] += (gamma(y.w, s.w)); +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[index4.x] += (delta(y.x, s.x)); + gscal_loc[index4.y] += (delta(y.y, s.y)); + gscal_loc[index4.z] += (delta(y.z, s.z)); + gscal_loc[index4.w] += (delta(y.w, s.w)); +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[index4.x] += (eta(y.x, s.x)); + gscal_loc[index4.y] += (eta(y.y, s.y)); + gscal_loc[index4.z] += (eta(y.z, s.z)); + gscal_loc[index4.w] += (eta(y.w, s.w)); +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[index4.x] += (zeta(y.x, s.x)); + gscal_loc[index4.y] += (zeta(y.y, s.y)); + gscal_loc[index4.z] += (zeta(y.z, s.z)); + gscal_loc[index4.w] += (zeta(y.w, s.w)); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(NB_WI_REMESHING*4)) + vstore4((float4)(gscal_loc[i],gscal_loc[i+1], gscal_loc[i+2], gscal_loc[i+3]), (i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, gscal); +} + +__kernel void copyLocMem_3D(__global const float* in, + __global float* out) +{ + uint xIndex = get_group_id(0) * TILE_DIM_COPY_3D + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_COPY_3D + get_local_id(1); + uint zIndex = get_global_id(2); + uint index = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_COPY_3D][TILE_DIM_COPY_3D]; + + for(uint i=0; i<TILE_DIM_COPY_3D; i+=BLOCK_ROWS_COPY_3D) + { + tile[get_local_id(1)+i][get_local_id(0)] = in[index + i*WIDTH]; + } +barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_COPY_3D; i+=BLOCK_ROWS_COPY_3D) + { + out[index + i*WIDTH] = tile[get_local_id(1)+i][get_local_id(0)]; + } +} + +__kernel void transpose_3D_xy_coalesced_locPad_Diag(__global const float* in, + __global float* out) +{ + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_TRANSPOSE_3D_XY + get_local_id(0); + uint yIndex = group_id_y * TILE_DIM_TRANSPOSE_3D_XY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_y * TILE_DIM_TRANSPOSE_3D_XY + get_local_id(0); + yIndex = group_id_x * TILE_DIM_TRANSPOSE_3D_XY + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_TRANSPOSE_3D_XY][TILE_DIM_TRANSPOSE_3D_XY+1]; + + for(uint i=0; i<TILE_DIM_TRANSPOSE_3D_XY; i+=BLOCK_ROWS_TRANSPOSE_3D_XY) + { + tile[get_local_id(1) + i][get_local_id(0)] = in[index_in + i*WIDTH]; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_TRANSPOSE_3D_XY; i+=BLOCK_ROWS_TRANSPOSE_3D_XY) + { + out[index_out + i*WIDTH] = tile[get_local_id(0)][get_local_id(1) + i]; + } +} +__kernel void transpose_3D_xz_coalesced(__global const float* in, + __global float* out) +{ + uint xIndex = get_group_id(0) * TILE_DIM_TRANSPOSE_3D_XZ + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_TRANSPOSE_3D_XZ + get_local_id(1); + uint zIndex = get_group_id(2) * TILE_DIM_TRANSPOSE_3D_XZ + get_local_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = get_group_id(2) * TILE_DIM_TRANSPOSE_3D_XZ + get_local_id(0); + zIndex = get_group_id(0) * TILE_DIM_TRANSPOSE_3D_XZ + get_local_id(2); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_TRANSPOSE_3D_XZ][TILE_DIM_TRANSPOSE_3D_XZ][TILE_DIM_TRANSPOSE_3D_XZ]; + +for(uint j=0; j<TILE_DIM_TRANSPOSE_3D_XZ; j+=BLOCK_ROWS_TRANSPOSE_3D_XZ) +{ + for(uint i=0; i<TILE_DIM_TRANSPOSE_3D_XZ; i+=BLOCK_ROWS_TRANSPOSE_3D_XZ) + { + tile[get_local_id(2) + j][get_local_id(1) + i][get_local_id(0)] = in[index_in + i*WIDTH + j*WIDTH*WIDTH]; + } +} + barrier(CLK_LOCAL_MEM_FENCE); +for(uint j=0; j<TILE_DIM_TRANSPOSE_3D_XZ; j+=BLOCK_ROWS_TRANSPOSE_3D_XZ) +{ + for(uint i=0; i<TILE_DIM_TRANSPOSE_3D_XZ; i+=BLOCK_ROWS_TRANSPOSE_3D_XZ) + { + out[index_out + i*WIDTH + j*WIDTH*WIDTH] = tile[get_local_id(0)][get_local_id(1)+i][get_local_id(2) + j]; + } +} +} +#else +__kernel void advection_2D_float4(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int4 ind, i_ind, i_ind_p; + float invdx = 1.0f/dx; + uint i; + float4 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=NB_WI_ADVECTION*4) + { + v = vload4((i+gidY*WIDTH)/4, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + velocity_cache[i+2] = v.z; + velocity_cache[i+3] = v.w; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*4; i<WIDTH; i+=NB_WI_ADVECTION*4) + { + v = vload4(i/4, velocity_cache); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = coord + 0.5f*dt*v; + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(velocity_cache[i_ind.x], velocity_cache[i_ind.y], velocity_cache[i_ind.z], velocity_cache[i_ind.w]); + vp = (float4)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y], velocity_cache[i_ind_p.z], velocity_cache[i_ind_p.w]); + p = (v*(1.0f - y) + vp*y)*dt + coord + (float4)(min_position); + vstore4(p, (i+gidY*WIDTH)/4, ppos); + } +} + +__kernel void advection_2D_basic(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int ind, i_ind, i_ind_p; + float invdx = 1.0f/dx; + uint i; + float v, y, p; + for(i=gidX; i<WIDTH; i+=NB_WI_ADVECTION) + { + v = gvelo[i+gidY*WIDTH]; + p = i*dx + 0.5f*dt*v; + ind = convert_int_rtn(p * invdx); + y = (p - convert_float(ind) * dx) * invdx; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((ind + 1) % WIDTH); + p=(gvelo[i_ind+gidY*WIDTH]*(1.0f - y) + gvelo[i_ind_p+gidY*WIDTH]*y)*dt + i*dx + min_position; + ppos[i+gidY*WIDTH] = p; + } +} + + +__kernel void remeshing_2D_float4(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0f/dx; + int4 ind; + uint i, nb_part = WIDTH/NB_WI_REMESHING; + float4 p, s, y; + float gsx, gsy, gsz, gsw; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(NB_WI_REMESHING*4)) +{ + gscal_loc[i] = 0.0f; + gscal_loc[i+1] = 0.0f; + gscal_loc[i+2] = 0.0f; + gscal_loc[i+3] = 0.0f; +} + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (alpha(y.x, s.x)); + gsy = gsy + (alpha(y.y, s.y)); + gsz = gsz + (alpha(y.z, s.z)); + gsw = gsw + (alpha(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (beta(y.x, s.x)); + gsy = gsy + (beta(y.y, s.y)); + gsz = gsz + (beta(y.z, s.z)); + gsw = gsw + (beta(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (gamma(y.x, s.x)); + gsy = gsy + (gamma(y.y, s.y)); + gsz = gsz + (gamma(y.z, s.z)); + gsw = gsw + (gamma(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (delta(y.x, s.x)); + gsy = gsy + (delta(y.y, s.y)); + gsz = gsz + (delta(y.z, s.z)); + gsw = gsw + (delta(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (eta(y.x, s.x)); + gsy = gsy + (eta(y.y, s.y)); + gsz = gsz + (eta(y.z, s.z)); + gsw = gsw + (eta(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; +barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gsx = gscal_loc[index4.x]; + gsy = gscal_loc[index4.y]; + gsz = gscal_loc[index4.z]; + gsw = gscal_loc[index4.w]; + gsx = gsx + (zeta(y.x, s.x)); + gsy = gsy + (zeta(y.y, s.y)); + gsz = gsz + (zeta(y.z, s.z)); + gsw = gsw + (zeta(y.w, s.w)); + gscal_loc[index4.x] = gsx; + gscal_loc[index4.y] = gsy; + gscal_loc[index4.z] = gsz; + gscal_loc[index4.w] = gsw; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(NB_WI_REMESHING*4)) + vstore4((float4)(gscal_loc[i],gscal_loc[i+1], gscal_loc[i+2], gscal_loc[i+3]), (i + gidY*WIDTH)/4, gscal); +} + +__kernel void copyLocMem_2D(__global const float* in, + __global float* out) +{ + uint xIndex = get_group_id(0) * TILE_DIM_COPY_2D + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_COPY_2D + get_local_id(1); + uint index = xIndex + yIndex * WIDTH; + + __local float tile[TILE_DIM_COPY_2D][TILE_DIM_COPY_2D]; + + for(uint i=0; i<TILE_DIM_COPY_2D; i+=BLOCK_ROWS_COPY_2D) + { + tile[get_local_id(1)+i][get_local_id(0)] = in[index + i*WIDTH]; + } +barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_COPY_2D; i+=BLOCK_ROWS_COPY_2D) + { + out[index + i*WIDTH] = tile[get_local_id(1)+i][get_local_id(0)]; + } +} + +__kernel void transpose_2D_coalesced_locPad_Diag(__global const float* in, + __global float* out) +{ + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_TRANSPOSE_2D + get_local_id(0); + uint yIndex = group_id_y * TILE_DIM_TRANSPOSE_2D + get_local_id(1); + uint index_in = xIndex + yIndex * WIDTH; + + xIndex = group_id_y * TILE_DIM_TRANSPOSE_2D + get_local_id(0); + yIndex = group_id_x * TILE_DIM_TRANSPOSE_2D + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH; + + __local float tile[TILE_DIM_TRANSPOSE_2D][TILE_DIM_TRANSPOSE_2D+1]; + + for(uint i=0; i<TILE_DIM_TRANSPOSE_2D; i+=BLOCK_ROWS_TRANSPOSE_2D) + { + tile[get_local_id(1) + i][get_local_id(0)] = in[index_in + i*WIDTH]; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_TRANSPOSE_2D; i+=BLOCK_ROWS_TRANSPOSE_2D) + { + out[index_out + i*WIDTH] = tile[get_local_id(0)][get_local_id(1) + i]; + } +} + + +#endif + + + + + + + + + + + + +/* + +// volume computing +__kernel void volume(__global const float* pscal, + __global float* volume, + __private const float level, + __private const float particle_volume, + __private const int dir, + __private const uint line_nb_pts, + __private const float4 min_v, + __private const float4 max_v, + __private const uint4 nb, + __private const float4 size + ) +{ + __private uint p; // Particle line loop index + __private uint stride_along_dir, stride_along_dir_scal; // Buffer stride between two particle of the same line + __private uint ind_line, ind_line_scal; // Line begin buffer index + __private float dx_dir; // Space step along line + __private float pscal_c; // Particle scalar along line + // Compute strides and index. Depend on array order (C order here) + dx_dir = size[dir]; + + if(DIM == 3){ + if (dir == 0) + { + kernel_init_3_0(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + } + else if (dir == 1) + { + kernel_init_3_1(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + } + else + { + kernel_init_3_2(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + }} + else{ + if (dir == 0) + { + kernel_init_2_0(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + } + else + { + kernel_init_2_1(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + } + } + + volume[ind_line_scal]= 0.0f; + for(p=0;p<line_nb_pts;p++) + { + // read particle scalar + pscal_c = pscal[ind_line_scal + p*stride_along_dir_scal]; // Read : 1float + if (pscal_c > level) + volume[ind_line_scal] += particle_volume; + } +} + + + + +// Colorize scalar +__kernel void colorize(__global const float* pscal, + __global float* pcolor, + __global float* points, + __private const uint dir, + __private const uint line_nb_pts, + __private const float4 min, + __private const uint4 nb, + __private const float4 size + ) +{ + __private uint p; + __private float color, dx_dir; + __private size_t stride_vec; + __private uint stride_along_dir, stride_along_dir_scal; + __private uint ind_line, ind_line_scal; + __private float line_c[DIM]; + stride_vec = 1; // Les composantes des vecteurs sont à la suite dans les buffers + dx_dir = size[dir]; + if(DIM == 3) + { + if (dir == 0) + { + kernel_init_3_0(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + advection_init_3_0(size, line_c); + } + else if (dir == 1) + { + kernel_init_3_1(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + advection_init_3_1(size, line_c); + } + else + { + kernel_init_3_2(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + advection_init_3_2(size, line_c); + } + } + else + { + if (dir == 0) + { + kernel_init_2_0(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + advection_init_2_0(size, line_c); + } + else + { + kernel_init_2_1(nb, &stride_along_dir, &stride_along_dir_scal, &ind_line, &ind_line_scal); + advection_init_2_1(size, line_c); + } + } + + for(p=0;p<line_nb_pts;p++) + { + // Write result in buffer + line_c[dir] = p*dx_dir; + points[ind_line + p*stride_along_dir] = min.s0 + line_c[0]; + points[ind_line + stride_vec + p*stride_along_dir] = min.s1 + line_c[1]; +#if DIM == 3 + points[ind_line + 2*stride_vec + p*stride_along_dir] = min.s2 + line_c[2]; +#else + points[ind_line + 2*stride_vec + p*stride_along_dir] = 0.0f; +#endif + color = pscal[ind_line_scal + p*stride_along_dir_scal]; + if (color > 0.5){ + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal] = 1.0f; //Red + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal + 3] = 1.0f; //Alpha + } + else{ + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal] = 1.0f; //Red + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal + 3] = 0.0f; //Alpha + } + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal + 1] = 0.0f; //Green + pcolor[4*ind_line_scal + 4*p*stride_along_dir_scal + 2] = 0.0f; //Blue + } + +} +*/ diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_builtin.cl new file mode 100644 index 000000000..008be61a9 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_builtin.cl @@ -0,0 +1,34 @@ +/** + * 2D advection kernel. + * + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float v, y, p; + for(i=gidX; i<WIDTH; i+=WGN) + { + v = gvelo[i+gidY*WIDTH]; + p = fma((float)(0.5*dt),v,i*dx); + ind = convert_int_rtn(p * invdx); + y = (fma(- convert_float(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((ind + 1) % WIDTH); + p=fma(mix(gvelo[i_ind+gidY*WIDTH],gvelo[i_ind_p+gidY*WIDTH],y),dt,i*dx + min_position); + ppos[i+gidY*WIDTH] = p; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt2_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt2_builtin.cl new file mode 100644 index 000000000..d99fe5342 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt2_builtin.cl @@ -0,0 +1,49 @@ +/** + * 2D advection kernel. + * + * Memory reads and writes are performed using 2 element OpenCL vectors (float2 or double2). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int2 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float2 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*2; i<WIDTH; i+=WGN*2) + { + v = vload2((i+gidY*WIDTH)/2, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*2; i<WIDTH; i+=WGN*2) + { + v = vload2(i/2, velocity_cache); + coord = (float2)(i*dx, (i+1)*dx); + p = fma((float2)(0.5*dt),v,coord); + ind = convert_int2_rtn(p * invdx); + y = (fma(- convert_float2(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float2)(velocity_cache[i_ind.x], velocity_cache[i_ind.y]); + vp = (float2)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y]); + p=fma(mix(v,vp,y),dt,coord + (float2)(min_position)); + vstore2(p, (i+gidY*WIDTH)/2, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt4_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt4_builtin.cl new file mode 100644 index 000000000..c9d9637ad --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt4_builtin.cl @@ -0,0 +1,53 @@ +/** + * 2D advection kernel. + * + * Memory reads and writes are performed using 4 element OpenCL vectors (float4 or double4). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int4 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float4 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=WGN*4) + { + v = vload4((i+gidY*WIDTH)/4, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + velocity_cache[i+2] = v.z; + velocity_cache[i+3] = v.w; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*4; i<WIDTH; i+=WGN*4) + { + v = vload4(i/4, velocity_cache); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(velocity_cache[i_ind.x], velocity_cache[i_ind.y], + velocity_cache[i_ind.z], velocity_cache[i_ind.w]); + vp = (float4)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y], + velocity_cache[i_ind_p.z], velocity_cache[i_ind_p.w]); + p=fma(mix(v,vp,y),dt,coord + (float4)(min_position)); + vstore4(p, (i+gidY*WIDTH)/4, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt8_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt8_builtin.cl new file mode 100644 index 000000000..cab7c1dd4 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_2D_opt8_builtin.cl @@ -0,0 +1,76 @@ +/** + * 2D advection kernel. + * + * Memory reads and writes are performed using 8 element OpenCL vectors (float8 or double8). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + int8 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float8 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*8; i<WIDTH; i+=WGN*8) + { + v = vload8((i+gidY*WIDTH)/8, gvelo); + velocity_cache[i] = v.s0; + velocity_cache[i+1] = v.s1; + velocity_cache[i+2] = v.s2; + velocity_cache[i+3] = v.s3; + velocity_cache[i+4] = v.s4; + velocity_cache[i+5] = v.s5; + velocity_cache[i+6] = v.s6; + velocity_cache[i+7] = v.s7; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*8; i<WIDTH; i+=WGN*8) + { + v = vload8(i/8, velocity_cache); + coord = (float8)(i*dx, + (i+1)*dx, + (i+2)*dx, + (i+3)*dx, + (i+4)*dx, + (i+5)*dx, + (i+6)*dx, + (i+7)*dx); + p = fma((float8)(0.5*dt),v,coord); + ind = convert_int8_rtn(p * invdx); + y = (fma(- convert_float8(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float8)(velocity_cache[i_ind.s0], + velocity_cache[i_ind.s1], + velocity_cache[i_ind.s2], + velocity_cache[i_ind.s3], + velocity_cache[i_ind.s4], + velocity_cache[i_ind.s5], + velocity_cache[i_ind.s6], + velocity_cache[i_ind.s7]); + vp = (float8)(velocity_cache[i_ind_p.s0], + velocity_cache[i_ind_p.s1], + velocity_cache[i_ind_p.s2], + velocity_cache[i_ind_p.s3], + velocity_cache[i_ind_p.s4], + velocity_cache[i_ind_p.s5], + velocity_cache[i_ind_p.s6], + velocity_cache[i_ind_p.s7]); + p = fma(mix(v,vp,y),dt,coord + (float8)(min_position)); + vstore8(p, (i+gidY*WIDTH)/8, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_builtin.cl new file mode 100644 index 000000000..c54dd7267 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_builtin.cl @@ -0,0 +1,37 @@ +/** + * 3D advection kernel. + * + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float v, y, p; + for(i=gidX; i<WIDTH; i+=WGN) + { + v = gvelo[i+gidY*WIDTH+gidZ*WIDTH*WIDTH]; + p = fma((float)(0.5*dt),v,i*dx); + ind = convert_int_rtn(p * invdx); + y = (fma(- convert_float(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((ind + 1) % WIDTH); + p=fma(mix(gvelo[i_ind+gidY*WIDTH+gidZ*WIDTH*WIDTH], + gvelo[i_ind_p+gidY*WIDTH+gidZ*WIDTH*WIDTH],y), + dt,i*dx + min_position); + ppos[i+gidY*WIDTH+gidZ*WIDTH*WIDTH] = p; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt2_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt2_builtin.cl new file mode 100644 index 000000000..3891bb10d --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt2_builtin.cl @@ -0,0 +1,50 @@ +/** + * 3D advection kernel. + * + * Memory reads and writes are performed using 2 element OpenCL vectors (float2 or double2). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int2 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float2 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*2; i<WIDTH; i+=WGN*2) + { + v = vload2((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/2, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*2; i<WIDTH; i+=WGN*2) + { + v = vload2(i/2, velocity_cache); + coord = (float2)(i*dx, (i+1)*dx); + p = fma((float2)(0.5*dt),v,coord); + ind = convert_int2_rtn(p * invdx); + y = (fma(- convert_float2(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float2)(velocity_cache[i_ind.x], velocity_cache[i_ind.y]); + vp = (float2)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y]); + p=fma(mix(v,vp,y),dt,coord + (float2)(min_position)); + vstore2(p, (i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/2, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt4_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt4_builtin.cl new file mode 100644 index 000000000..49ae8e1d4 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt4_builtin.cl @@ -0,0 +1,54 @@ +/** + * 3D advection kernel. + * + * Memory reads and writes are performed using 4 element OpenCL vectors (float4 or double4). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int4 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float4 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=WGN*4) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + velocity_cache[i] = v.x; + velocity_cache[i+1] = v.y; + velocity_cache[i+2] = v.z; + velocity_cache[i+3] = v.w; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*4; i<WIDTH; i+=WGN*4) + { + v = vload4(i/4, velocity_cache); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(velocity_cache[i_ind.x], velocity_cache[i_ind.y], + velocity_cache[i_ind.z], velocity_cache[i_ind.w]); + vp = (float4)(velocity_cache[i_ind_p.x], velocity_cache[i_ind_p.y], + velocity_cache[i_ind_p.z], velocity_cache[i_ind_p.w]); + p=fma(mix(v,vp,y),dt,coord + (float4)(min_position)); + vstore4(p, (i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt8_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt8_builtin.cl new file mode 100644 index 000000000..db3fb09a7 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_3D_opt8_builtin.cl @@ -0,0 +1,77 @@ +/** + * 3D advection kernel. + * + * Memory reads and writes are performed using 8 element OpenCL vectors (float8 or double8). + * Computations are done using builtin functions on vector types. + * A local array is used un local memory as a cache for velocity. + * + * @param gvelo Velocity. + * @param ppos Particle position. + * @param dt Time step. + * @param min_position Domain lower point. + * @param dx Space step. + */ +__kernel void advection(__global const float* gvelo, + __global float* ppos, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + int8 ind, i_ind, i_ind_p; + float invdx = 1.0/dx; + uint i; + float8 v, vp, y, p, coord; + __local float velocity_cache[WIDTH]; + + for(i=gidX*8; i<WIDTH; i+=WGN*8) + { + v = vload8((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/8, gvelo); + velocity_cache[i] = v.s0; + velocity_cache[i+1] = v.s1; + velocity_cache[i+2] = v.s2; + velocity_cache[i+3] = v.s3; + velocity_cache[i+4] = v.s4; + velocity_cache[i+5] = v.s5; + velocity_cache[i+6] = v.s6; + velocity_cache[i+7] = v.s7; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for(i=gidX*8; i<WIDTH; i+=WGN*8) + { + v = vload8(i/8, velocity_cache); + coord = (float8)(i*dx, + (i+1)*dx, + (i+2)*dx, + (i+3)*dx, + (i+4)*dx, + (i+5)*dx, + (i+6)*dx, + (i+7)*dx); + p = fma((float8)(0.5*dt),v,coord); + ind = convert_int8_rtn(p * invdx); + y = (fma(- convert_float8(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float8)(velocity_cache[i_ind.s0], + velocity_cache[i_ind.s1], + velocity_cache[i_ind.s2], + velocity_cache[i_ind.s3], + velocity_cache[i_ind.s4], + velocity_cache[i_ind.s5], + velocity_cache[i_ind.s6], + velocity_cache[i_ind.s7]); + vp = (float8)(velocity_cache[i_ind_p.s0], + velocity_cache[i_ind_p.s1], + velocity_cache[i_ind_p.s2], + velocity_cache[i_ind_p.s3], + velocity_cache[i_ind_p.s4], + velocity_cache[i_ind_p.s5], + velocity_cache[i_ind_p.s6], + velocity_cache[i_ind_p.s7]); + p = fma(mix(v,vp,y),dt,coord + (float8)(min_position)); + vstore8(p, (i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/8, ppos); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt4_builtin_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt4_builtin_noBC.cl new file mode 100644 index 000000000..2eaec614a --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt4_builtin_noBC.cl @@ -0,0 +1,95 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH)/4, gvelo); + gvelo_loc[noBC_id(i,nb_part)] = v.x; + gvelo_loc[noBC_id(i+1,nb_part)] = v.y; + gvelo_loc[noBC_id(i+2,nb_part)] = v.z; + gvelo_loc[noBC_id(i+3,nb_part)] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = (float4)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)]); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[noBC_id(i_ind.x,nb_part)], gvelo_loc[noBC_id(i_ind.y,nb_part)], + gvelo_loc[noBC_id(i_ind.z,nb_part)], gvelo_loc[noBC_id(i_ind.w,nb_part)]); + vp = (float4)(gvelo_loc[noBC_id(i_ind_p.x,nb_part)], gvelo_loc[noBC_id(i_ind_p.y,nb_part)], + gvelo_loc[noBC_id(i_ind_p.z,nb_part)], gvelo_loc[noBC_id(i_ind_p.w,nb_part)]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gscal_loc[noBC_id(index4.x,nb_part)] += (alpha(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (alpha(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (alpha(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (alpha(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (beta(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (beta(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (beta(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (beta(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (gamma(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (gamma(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (gamma(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (gamma(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (delta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (delta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (delta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (delta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (eta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (eta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (eta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (eta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (zeta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (zeta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (zeta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (zeta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i,nb_part)],gscal_loc[noBC_id(i+1,nb_part)], gscal_loc[noBC_id(i+2,nb_part)], gscal_loc[noBC_id(i+3,nb_part)]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt8_builtin_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt8_builtin_noBC.cl new file mode 100644 index 000000000..289b9d4a6 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_2D_opt8_builtin_noBC.cl @@ -0,0 +1,157 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt,float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int8 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float8 p, s, y, gs, v, vp, coord; + uint8 index8; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*8; i<WIDTH; i+=(WGN*8)) + { + v = vload8((i+gidY*WIDTH)/8, gvelo); + gvelo_loc[noBC_id(i,nb_part)] = v.s0; + gvelo_loc[noBC_id(i+1,nb_part)] = v.s1; + gvelo_loc[noBC_id(i+2,nb_part)] = v.s2; + gvelo_loc[noBC_id(i+3,nb_part)] = v.s3; + gvelo_loc[noBC_id(i+4,nb_part)] = v.s4; + gvelo_loc[noBC_id(i+5,nb_part)] = v.s5; + gvelo_loc[noBC_id(i+6,nb_part)] = v.s6; + gvelo_loc[noBC_id(i+7,nb_part)] = v.s7; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + gscal_loc[i+4] = 0.0; + gscal_loc[i+5] = 0.0; + gscal_loc[i+6] = 0.0; + gscal_loc[i+7] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=8) + { + v = (float8)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)], + gvelo_loc[noBC_id(i+4,nb_part)], + gvelo_loc[noBC_id(i+5,nb_part)], + gvelo_loc[noBC_id(i+6,nb_part)], + gvelo_loc[noBC_id(i+7,nb_part)]); + coord = (float8)(i*dx, + (i+1)*dx, + (i+2)*dx, + (i+3)*dx, + (i+4)*dx, + (i+5)*dx, + (i+6)*dx, + (i+7)*dx); + p = fma((float8)(0.5*dt),v,coord); + ind = convert_int8_rtn(p * invdx); + y = (fma(- convert_float8(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float8)(gvelo_loc[noBC_id(i_ind.s0,nb_part)], + gvelo_loc[noBC_id(i_ind.s1,nb_part)], + gvelo_loc[noBC_id(i_ind.s2,nb_part)], + gvelo_loc[noBC_id(i_ind.s3,nb_part)], + gvelo_loc[noBC_id(i_ind.s4,nb_part)], + gvelo_loc[noBC_id(i_ind.s5,nb_part)], + gvelo_loc[noBC_id(i_ind.s6,nb_part)], + gvelo_loc[noBC_id(i_ind.s7,nb_part)]); + vp = (float8)(gvelo_loc[noBC_id(i_ind_p.s0,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s1,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s2,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s3,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s4,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s5,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s6,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s7,nb_part)]); + p = fma(mix(v,vp,y),dt,coord); + + s = vload8((i + gidY*WIDTH)/8, pscal); + ind = convert_int8_rtn(p * invdx); + y = (p - convert_float8(ind) * dx) * invdx; + index8 = convert_uint8((ind - 2 + WIDTH) % WIDTH); + gscal_loc[noBC_id(index8.s0,nb_part)] += (alpha(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (alpha(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (alpha(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (alpha(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (alpha(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (alpha(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (alpha(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (alpha(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (beta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (beta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (beta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (beta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (beta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (beta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (beta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (beta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (gamma(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (gamma(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (gamma(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (gamma(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (gamma(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (gamma(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (gamma(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (gamma(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (delta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (delta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (delta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (delta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (delta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (delta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (delta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (delta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (eta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (eta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (eta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (eta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (eta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (eta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (eta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (eta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (zeta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (zeta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (zeta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (zeta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (zeta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (zeta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (zeta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (zeta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*8; i<WIDTH; i+=(WGN*8)) + vstore8((float8)(gscal_loc[noBC_id(i,nb_part)], + gscal_loc[noBC_id(i+1,nb_part)], + gscal_loc[noBC_id(i+2,nb_part)], + gscal_loc[noBC_id(i+3,nb_part)], + gscal_loc[noBC_id(i+4,nb_part)], + gscal_loc[noBC_id(i+5,nb_part)], + gscal_loc[noBC_id(i+6,nb_part)], + gscal_loc[noBC_id(i+7,nb_part)]), (i + gidY*WIDTH)/8, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4.cl new file mode 100644 index 000000000..46e9bc59b --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4.cl @@ -0,0 +1,101 @@ + +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + gvelo_loc[i] = v.x; + gvelo_loc[i+1] = v.y; + gvelo_loc[i+2] = v.z; + gvelo_loc[i+3] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = vload4(i/4, gvelo_loc); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[i_ind.x], gvelo_loc[i_ind.y], + gvelo_loc[i_ind.z], gvelo_loc[i_ind.w]); + vp = (float4)(gvelo_loc[i_ind_p.x], gvelo_loc[i_ind_p.y], + gvelo_loc[i_ind_p.z], gvelo_loc[i_ind_p.w]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + barrier(CLK_LOCAL_MEM_FENCE); + gs = (alpha(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (beta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (gamma(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (delta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (eta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (zeta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[i],gscal_loc[i+1], gscal_loc[i+2], gscal_loc[i+3]), (i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4_noBC.cl new file mode 100644 index 000000000..5d221f673 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_3D_opt4_builtin_private4_noBC.cl @@ -0,0 +1,101 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + gvelo_loc[noBC_id(i, nb_part)] = v.x; + gvelo_loc[noBC_id(i+1, nb_part)] = v.y; + gvelo_loc[noBC_id(i+2, nb_part)] = v.z; + gvelo_loc[noBC_id(i+3, nb_part)] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = (float4)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)]); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[noBC_id(i_ind.x,nb_part)], gvelo_loc[noBC_id(i_ind.y,nb_part)], + gvelo_loc[noBC_id(i_ind.z,nb_part)], gvelo_loc[noBC_id(i_ind.w,nb_part)]); + vp = (float4)(gvelo_loc[noBC_id(i_ind_p.x,nb_part)], gvelo_loc[noBC_id(i_ind_p.y,nb_part)], + gvelo_loc[noBC_id(i_ind_p.z,nb_part)], gvelo_loc[noBC_id(i_ind_p.w,nb_part)]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i, nb_part)],gscal_loc[noBC_id(i+1, nb_part)], gscal_loc[noBC_id(i+2, nb_part)], gscal_loc[noBC_id(i+3, nb_part)]), (i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt4_builtin_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt4_builtin_noBC.cl new file mode 100644 index 000000000..0a52ced9c --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt4_builtin_noBC.cl @@ -0,0 +1,107 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH)/4, gvelo); + gvelo_loc[noBC_id(i,nb_part)] = v.x; + gvelo_loc[noBC_id(i+1,nb_part)] = v.y; + gvelo_loc[noBC_id(i+2,nb_part)] = v.z; + gvelo_loc[noBC_id(i+3,nb_part)] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = (float4)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)]); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[noBC_id(i_ind.x,nb_part)], gvelo_loc[noBC_id(i_ind.y,nb_part)], + gvelo_loc[noBC_id(i_ind.z,nb_part)], gvelo_loc[noBC_id(i_ind.w,nb_part)]); + vp = (float4)(gvelo_loc[noBC_id(i_ind_p.x,nb_part)], gvelo_loc[noBC_id(i_ind_p.y,nb_part)], + gvelo_loc[noBC_id(i_ind_p.z,nb_part)], gvelo_loc[noBC_id(i_ind_p.w,nb_part)]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 3 + WIDTH) % WIDTH); + gscal_loc[noBC_id(index4.x,nb_part)] += (alpha(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (alpha(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (alpha(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (alpha(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (beta(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (beta(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (beta(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (beta(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (gamma(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (gamma(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (gamma(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (gamma(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (delta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (delta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (delta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (delta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (eta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (eta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (eta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (eta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (zeta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (zeta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (zeta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (zeta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (theta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (theta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (theta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (theta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (iota(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (iota(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (iota(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (iota(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i,nb_part)],gscal_loc[noBC_id(i+1,nb_part)], gscal_loc[noBC_id(i+2,nb_part)], gscal_loc[noBC_id(i+3,nb_part)]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt8_builtin_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt8_builtin_noBC.cl new file mode 100644 index 000000000..043ba841f --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_2D_opt8_builtin_noBC.cl @@ -0,0 +1,177 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt,float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int8 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float8 p, s, y, gs, v, vp, coord; + uint8 index8; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*8; i<WIDTH; i+=(WGN*8)) + { + v = vload8((i+gidY*WIDTH)/8, gvelo); + gvelo_loc[noBC_id(i,nb_part)] = v.s0; + gvelo_loc[noBC_id(i+1,nb_part)] = v.s1; + gvelo_loc[noBC_id(i+2,nb_part)] = v.s2; + gvelo_loc[noBC_id(i+3,nb_part)] = v.s3; + gvelo_loc[noBC_id(i+4,nb_part)] = v.s4; + gvelo_loc[noBC_id(i+5,nb_part)] = v.s5; + gvelo_loc[noBC_id(i+6,nb_part)] = v.s6; + gvelo_loc[noBC_id(i+7,nb_part)] = v.s7; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + gscal_loc[i+4] = 0.0; + gscal_loc[i+5] = 0.0; + gscal_loc[i+6] = 0.0; + gscal_loc[i+7] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=8) + { + v = (float8)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)], + gvelo_loc[noBC_id(i+4,nb_part)], + gvelo_loc[noBC_id(i+5,nb_part)], + gvelo_loc[noBC_id(i+6,nb_part)], + gvelo_loc[noBC_id(i+7,nb_part)]); + coord = (float8)(i*dx, + (i+1)*dx, + (i+2)*dx, + (i+3)*dx, + (i+4)*dx, + (i+5)*dx, + (i+6)*dx, + (i+7)*dx); + p = fma((float8)(0.5*dt),v,coord); + ind = convert_int8_rtn(p * invdx); + y = (fma(- convert_float8(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float8)(gvelo_loc[noBC_id(i_ind.s0,nb_part)], + gvelo_loc[noBC_id(i_ind.s1,nb_part)], + gvelo_loc[noBC_id(i_ind.s2,nb_part)], + gvelo_loc[noBC_id(i_ind.s3,nb_part)], + gvelo_loc[noBC_id(i_ind.s4,nb_part)], + gvelo_loc[noBC_id(i_ind.s5,nb_part)], + gvelo_loc[noBC_id(i_ind.s6,nb_part)], + gvelo_loc[noBC_id(i_ind.s7,nb_part)]); + vp = (float8)(gvelo_loc[noBC_id(i_ind_p.s0,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s1,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s2,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s3,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s4,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s5,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s6,nb_part)], + gvelo_loc[noBC_id(i_ind_p.s7,nb_part)]); + p = fma(mix(v,vp,y),dt,coord); + + s = vload8((i + gidY*WIDTH)/8, pscal); + ind = convert_int8_rtn(p * invdx); + y = (p - convert_float8(ind) * dx) * invdx; + index8 = convert_uint8((ind - 3 + WIDTH) % WIDTH); + gscal_loc[noBC_id(index8.s0,nb_part)] += (alpha(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (alpha(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (alpha(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (alpha(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (alpha(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (alpha(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (alpha(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (alpha(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (beta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (beta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (beta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (beta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (beta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (beta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (beta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (beta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (gamma(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (gamma(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (gamma(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (gamma(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (gamma(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (gamma(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (gamma(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (gamma(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (delta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (delta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (delta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (delta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (delta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (delta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (delta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (delta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (eta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (eta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (eta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (eta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (eta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (eta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (eta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (eta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (zeta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (zeta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (zeta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (zeta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (zeta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (zeta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (zeta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (zeta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (theta(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (theta(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (theta(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (theta(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (theta(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (theta(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (theta(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (theta(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + index8 = (index8 + 1) % WIDTH; + gscal_loc[noBC_id(index8.s0,nb_part)] += (iota(y.s0,s.s0)); + gscal_loc[noBC_id(index8.s1,nb_part)] += (iota(y.s1,s.s1)); + gscal_loc[noBC_id(index8.s2,nb_part)] += (iota(y.s2,s.s2)); + gscal_loc[noBC_id(index8.s3,nb_part)] += (iota(y.s3,s.s3)); + gscal_loc[noBC_id(index8.s4,nb_part)] += (iota(y.s4,s.s4)); + gscal_loc[noBC_id(index8.s5,nb_part)] += (iota(y.s5,s.s5)); + gscal_loc[noBC_id(index8.s6,nb_part)] += (iota(y.s6,s.s6)); + gscal_loc[noBC_id(index8.s7,nb_part)] += (iota(y.s7,s.s7)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*8; i<WIDTH; i+=(WGN*8)) + vstore8((float8)(gscal_loc[noBC_id(i,nb_part)], + gscal_loc[noBC_id(i+1,nb_part)], + gscal_loc[noBC_id(i+2,nb_part)], + gscal_loc[noBC_id(i+3,nb_part)], + gscal_loc[noBC_id(i+4,nb_part)], + gscal_loc[noBC_id(i+5,nb_part)], + gscal_loc[noBC_id(i+6,nb_part)], + gscal_loc[noBC_id(i+7,nb_part)]), (i + gidY*WIDTH)/8, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4.cl new file mode 100644 index 000000000..92b508820 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4.cl @@ -0,0 +1,115 @@ + +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + gvelo_loc[i] = v.x; + gvelo_loc[i+1] = v.y; + gvelo_loc[i+2] = v.z; + gvelo_loc[i+3] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = vload4(i/4, gvelo_loc); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[i_ind.x], gvelo_loc[i_ind.y], + gvelo_loc[i_ind.z], gvelo_loc[i_ind.w]); + vp = (float4)(gvelo_loc[i_ind_p.x], gvelo_loc[i_ind_p.y], + gvelo_loc[i_ind_p.z], gvelo_loc[i_ind_p.w]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 3 + WIDTH) % WIDTH); + barrier(CLK_LOCAL_MEM_FENCE); + gs = (alpha(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (beta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (gamma(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (delta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (eta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (zeta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (theta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + index4 = (index4 + 1) % WIDTH; + //barrier(CLK_LOCAL_MEM_FENCE); + gs = (iota(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[i],gscal_loc[i+1], gscal_loc[i+2], gscal_loc[i+3]), (i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4_noBC.cl new file mode 100644 index 000000000..1557aaffc --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/advection_and_remesh_m8prime_3D_opt4_builtin_private4_noBC.cl @@ -0,0 +1,115 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void advection_and_remeshing(__global const float* gvelo, + __global const float* pscal, + __global float* gscal, + float dt, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind, i_ind, i_ind_p; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs, v, vp, coord; + uint4 index4; + + __local float gscal_loc[WIDTH]; + __local float gvelo_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + v = vload4((i+gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gvelo); + gvelo_loc[noBC_id(i, nb_part)] = v.x; + gvelo_loc[noBC_id(i+1, nb_part)] = v.y; + gvelo_loc[noBC_id(i+2, nb_part)] = v.z; + gvelo_loc[noBC_id(i+3, nb_part)] = v.w; + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + v = (float4)(gvelo_loc[noBC_id(i,nb_part)], + gvelo_loc[noBC_id(i+1,nb_part)], + gvelo_loc[noBC_id(i+2,nb_part)], + gvelo_loc[noBC_id(i+3,nb_part)]); + coord = (float4)(i*dx, (i+1)*dx, (i+2)*dx, (i+3)*dx); + p = fma((float4)(0.5*dt),v,coord); + ind = convert_int4_rtn(p * invdx); + y = (fma(- convert_float4(ind),dx,p))* invdx ; + i_ind = ((ind + WIDTH) % WIDTH); + i_ind_p = ((i_ind + 1) % WIDTH); + v = (float4)(gvelo_loc[noBC_id(i_ind.x,nb_part)], gvelo_loc[noBC_id(i_ind.y,nb_part)], + gvelo_loc[noBC_id(i_ind.z,nb_part)], gvelo_loc[noBC_id(i_ind.w,nb_part)]); + vp = (float4)(gvelo_loc[noBC_id(i_ind_p.x,nb_part)], gvelo_loc[noBC_id(i_ind_p.y,nb_part)], + gvelo_loc[noBC_id(i_ind_p.z,nb_part)], gvelo_loc[noBC_id(i_ind_p.w,nb_part)]); + p=fma(mix(v,vp,y),dt,coord); + + s = vload4((i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 3 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (theta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (iota(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i, nb_part)],gscal_loc[noBC_id(i+1, nb_part)], gscal_loc[noBC_id(i+2, nb_part)], gscal_loc[noBC_id(i+3, nb_part)]), (i + gidY*WIDTH+gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D.cl new file mode 100644 index 000000000..1af25c6d5 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D.cl @@ -0,0 +1,14 @@ + +__kernel void copy(__global const float* in, + __global float* out) +{ + uint xIndex = get_group_id(0) * TILE_DIM_COPY + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_COPY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index = xIndex + yIndex * WIDTH + zIndex*WIDTH*WIDTH; + + for(uint i=0; i<TILE_DIM_COPY; i+=BLOCK_ROWS_COPY) + { + out[index + i*WIDTH] = in[index + i*WIDTH]; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D_opt2.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D_opt2.cl new file mode 100644 index 000000000..7c2f3a950 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_2D_opt2.cl @@ -0,0 +1,17 @@ + +__kernel void copy(__global const float* in, + __global float* out) +{ + uint xIndex = (get_group_id(0) * TILE_DIM_COPY + get_local_id(0)*2); + uint yIndex = get_group_id(1) * TILE_DIM_COPY + get_local_id(1); + uint index = xIndex + yIndex * WIDTH; + float x,y; + + for(uint i=0; i<TILE_DIM_COPY; i+=BLOCK_ROWS_COPY) + { + x = in[index + i*WIDTH]; + y = in[index + 1 + i*WIDTH]; + out[index + i*WIDTH] = x; + out[index + 1 + i*WIDTH] = y; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_locMem.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_locMem.cl new file mode 100644 index 000000000..b13c4b735 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_locMem.cl @@ -0,0 +1,21 @@ + +__kernel void copy(__global const float* in, + __global float* out) +{ + uint xIndex = get_group_id(0) * TILE_DIM_COPY + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_COPY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index = xIndex + yIndex * WIDTH + zIndex*WIDTH*WIDTH; + + __local float tile[TILE_DIM_COPY][TILE_DIM_COPY]; + + for(uint i=0; i<TILE_DIM_COPY; i+=BLOCK_ROWS_COPY) + { + tile[get_local_id(1)+i][get_local_id(0)] = in[index + i*WIDTH]; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_COPY; i+=BLOCK_ROWS_COPY) + { + out[index + i*WIDTH] = tile[get_local_id(1)+i][get_local_id(0)]; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_opt4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_opt4.cl new file mode 100644 index 000000000..e5bec1c04 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/copy_3D_opt4.cl @@ -0,0 +1,22 @@ + +__kernel void copy(__global const float* in, + __global float* out) +{ + uint xIndex = (get_group_id(0) * TILE_DIM_COPY + get_local_id(0)*4); + uint yIndex = get_group_id(1) * TILE_DIM_COPY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index = xIndex + yIndex * WIDTH + zIndex*WIDTH*WIDTH; + float x,y,z,w; + + for(uint i=0; i<TILE_DIM_COPY; i+=BLOCK_ROWS_COPY) + { + x = in[index + i*WIDTH]; + y = in[index + 1 + i*WIDTH]; + z = in[index + 2 + i*WIDTH]; + w = in[index + 3 + i*WIDTH]; + out[index + i*WIDTH] = x; + out[index + 1 + i*WIDTH] = y; + out[index + 2 + i*WIDTH] = z; + out[index + 3 + i*WIDTH] = w; + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_noBC.cl new file mode 100644 index 000000000..895250723 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_noBC.cl @@ -0,0 +1,90 @@ +/** + * Local memory as a 2D array to avoid bank conflicts. + * + * @param id Index 1D + * @param nb_part Particle number per work-item + * + * @return Index in a 2D space. + */ +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} + +/** + * 2D Remeshing kernel. + * + * @param ppos Particle position + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param min_position Domain lower point + * @param dx Space step + */ +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gscal_loc[noBC_id(index4.x,nb_part)] += (alpha(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (alpha(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (alpha(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (alpha(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (beta(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (beta(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (beta(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (beta(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (gamma(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (gamma(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (gamma(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (gamma(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (delta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (delta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (delta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (delta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (eta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (eta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (eta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (eta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gscal_loc[noBC_id(index4.x,nb_part)] += (zeta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (zeta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (zeta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (zeta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i,nb_part)],gscal_loc[noBC_id(i+1,nb_part)], gscal_loc[noBC_id(i+2,nb_part)], gscal_loc[noBC_id(i+3,nb_part)]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4.cl new file mode 100644 index 000000000..bd831d5ab --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4.cl @@ -0,0 +1,76 @@ + +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[index4.x]+= gs.x; + gscal_loc[index4.y]+= gs.y; + gscal_loc[index4.z]+= gs.z; + gscal_loc[index4.w]+= gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[i],gscal_loc[i+1], gscal_loc[i+2], gscal_loc[i+3]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4_noBC.cl new file mode 100644 index 000000000..014edd316 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_2D_opt4_private4_noBC.cl @@ -0,0 +1,79 @@ + +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[noBC_id(index4.x, nb_part)] += gs.x; + gscal_loc[noBC_id(index4.y, nb_part)] += gs.y; + gscal_loc[noBC_id(index4.z, nb_part)] += gs.z; + gscal_loc[noBC_id(index4.w, nb_part)] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i, nb_part)],gscal_loc[noBC_id(i+1, nb_part)], gscal_loc[noBC_id(i+2, nb_part)], gscal_loc[noBC_id(i+3, nb_part)]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_3D_opt4_private4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_3D_opt4_private4.cl new file mode 100644 index 000000000..eb67791af --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_3D_opt4_private4.cl @@ -0,0 +1,81 @@ + +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 2 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[index4.x]+= gs.x; + gscal_loc[index4.y]+= gs.y; + gscal_loc[index4.z]+= gs.z; + gscal_loc[index4.w]+= gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[i], + gscal_loc[i+1], + gscal_loc[i+2], + gscal_loc[i+3]), + (i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_2D_opt4_noBC.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_2D_opt4_noBC.cl new file mode 100644 index 000000000..69fddc7f9 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_2D_opt4_noBC.cl @@ -0,0 +1,102 @@ +/** + * Local memory as a 2D array to avoid bank conflicts. + * + * @param id Index 1D + * @param nb_part Particle number per work-item + * + * @return Index in a 2D space. + */ +inline uint noBC_id(int id, int nb_part){ + return (id%nb_part)*WGN+(id/nb_part); +} + +/** + * 2D Remeshing kernel. + * + * @param ppos Particle position + * @param pscal Particle scalar + * @param gscal Grid scalar + * @param min_position Domain lower point + * @param dx Space step + */ +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 3 + WIDTH) % WIDTH); // i-3 + gscal_loc[noBC_id(index4.x,nb_part)] += (alpha(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (alpha(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (alpha(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (alpha(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i-2 + gscal_loc[noBC_id(index4.x,nb_part)] += (beta(y.x,s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (beta(y.y,s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (beta(y.z,s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (beta(y.w,s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i-1 + gscal_loc[noBC_id(index4.x,nb_part)] += (gamma(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (gamma(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (gamma(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (gamma(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i + gscal_loc[noBC_id(index4.x,nb_part)] += (delta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (delta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (delta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (delta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; //i+1 + gscal_loc[noBC_id(index4.x,nb_part)] += (eta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (eta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (eta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (eta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i+2 + gscal_loc[noBC_id(index4.x,nb_part)] += (zeta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (zeta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (zeta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (zeta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i+3 + gscal_loc[noBC_id(index4.x,nb_part)] += (theta(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (theta(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (theta(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (theta(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; // i+4 + gscal_loc[noBC_id(index4.x,nb_part)] += (iota(y.x, s.x)); + gscal_loc[noBC_id(index4.y,nb_part)] += (iota(y.y, s.y)); + gscal_loc[noBC_id(index4.z,nb_part)] += (iota(y.z, s.z)); + gscal_loc[noBC_id(index4.w,nb_part)] += (iota(y.w, s.w)); + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[noBC_id(i,nb_part)],gscal_loc[noBC_id(i+1,nb_part)], gscal_loc[noBC_id(i+2,nb_part)], gscal_loc[noBC_id(i+3,nb_part)]), (i + gidY*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_3D_opt4_private4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_3D_opt4_private4.cl new file mode 100644 index 000000000..6af20d005 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/remeshing_m8prime_3D_opt4_private4.cl @@ -0,0 +1,95 @@ + +__kernel void remeshing(__global const float* ppos, + __global const float* pscal, + __global float* gscal, float min_position, float dx) +{ + uint gidX = get_global_id(0); + uint gidY = get_global_id(1); + uint gidZ = get_global_id(2); + float invdx = 1.0/dx; + int4 ind; + uint i, nb_part = WIDTH/WGN; + float4 p, s, y, gs; + uint4 index4; + + __local float gscal_loc[WIDTH]; + + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + { + gscal_loc[i] = 0.0; + gscal_loc[i+1] = 0.0; + gscal_loc[i+2] = 0.0; + gscal_loc[i+3] = 0.0; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*nb_part; i<(gidX + 1)*nb_part; i+=4) + { + p = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, ppos) - (float4)(min_position); + s = vload4((i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, pscal); + ind = convert_int4_rtn(p * invdx); + y = (p - convert_float4(ind) * dx) * invdx; + index4 = convert_uint4((ind - 3 + WIDTH) % WIDTH); + gs = (alpha(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (beta(y, s)); + gscal_loc[index4.x]+= gs.x; + gscal_loc[index4.y]+= gs.y; + gscal_loc[index4.z]+= gs.z; + gscal_loc[index4.w]+= gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (gamma(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (delta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (eta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (zeta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (theta(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + index4 = (index4 + 1) % WIDTH; + gs = (iota(y, s)); + gscal_loc[index4.x] += gs.x; + gscal_loc[index4.y] += gs.y; + gscal_loc[index4.z] += gs.z; + gscal_loc[index4.w] += gs.w; + barrier(CLK_LOCAL_MEM_FENCE); + } + barrier(CLK_LOCAL_MEM_FENCE); + for(i=gidX*4; i<WIDTH; i+=(WGN*4)) + vstore4((float4)(gscal_loc[i], + gscal_loc[i+1], + gscal_loc[i+2], + gscal_loc[i+3]), + (i + gidY*WIDTH + gidZ*WIDTH*WIDTH)/4, gscal); +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_2D_xy_coalesced_locPad_Diag_opt4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_2D_xy_coalesced_locPad_Diag_opt4.cl new file mode 100644 index 000000000..b6853e37b --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_2D_xy_coalesced_locPad_Diag_opt4.cl @@ -0,0 +1,36 @@ + +__kernel void transpose_xy(__global const float* in, + __global float* out) +{ + float4 temp; + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XY + get_local_id(0)*4; + uint yIndex = group_id_y * TILE_DIM_XY + get_local_id(1); + uint index_in = xIndex + yIndex * WIDTH; + + xIndex = group_id_y * TILE_DIM_XY + get_local_id(0)*4; + yIndex = group_id_x * TILE_DIM_XY + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH; + + __local float tile[TILE_DIM_XY][TILE_DIM_XY+1]; + + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = vload4((index_in + i*WIDTH)/4, in); + tile[get_local_id(1) + i][get_local_id(0)*4] = temp.x; + tile[get_local_id(1) + i][get_local_id(0)*4+1] = temp.y; + tile[get_local_id(1) + i][get_local_id(0)*4+2] = temp.z; + tile[get_local_id(1) + i][get_local_id(0)*4+3] = temp.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = (float4)(tile[get_local_id(0)*4][get_local_id(1) + i], + tile[get_local_id(0)*4+1][get_local_id(1) + i], + tile[get_local_id(0)*4+2][get_local_id(1) + i], + tile[get_local_id(0)*4+3][get_local_id(1) + i]); + vstore4(temp, (index_out + i*WIDTH)/4, out); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl new file mode 100644 index 000000000..f94717ae5 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt2.cl @@ -0,0 +1,33 @@ + +__kernel void transpose_xy(__global const float* in, + __global float* out) +{ + float2 temp; + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XY + get_local_id(0)*2; + uint yIndex = group_id_y * TILE_DIM_XY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_y * TILE_DIM_XY + get_local_id(0)*2; + yIndex = group_id_x * TILE_DIM_XY + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_XY][TILE_DIM_XY+1]; + + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = vload2((index_in + i*WIDTH)/2, in); + tile[get_local_id(1) + i][get_local_id(0)*2] = temp.x; + tile[get_local_id(1) + i][get_local_id(0)*2+1] = temp.y; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = (float2)(tile[get_local_id(0)*2][get_local_id(1) + i], + tile[get_local_id(0)*2+1][get_local_id(1) + i]); + vstore2(temp, (index_out + i*WIDTH)/2, out); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl new file mode 100644 index 000000000..e8afa56b9 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_2Dslice_opt4.cl @@ -0,0 +1,37 @@ + +__kernel void transpose_xy(__global const float* in, + __global float* out) +{ + float4 temp; + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XY + get_local_id(0)*4; + uint yIndex = group_id_y * TILE_DIM_XY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_y * TILE_DIM_XY + get_local_id(0)*4; + yIndex = group_id_x * TILE_DIM_XY + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_XY][TILE_DIM_XY+1]; + + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = vload4((index_in + i*WIDTH)/4, in); + tile[get_local_id(1) + i][get_local_id(0)*4] = temp.x; + tile[get_local_id(1) + i][get_local_id(0)*4+1] = temp.y; + tile[get_local_id(1) + i][get_local_id(0)*4+2] = temp.z; + tile[get_local_id(1) + i][get_local_id(0)*4+3] = temp.w; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = (float4)(tile[get_local_id(0)*4][get_local_id(1) + i], + tile[get_local_id(0)*4+1][get_local_id(1) + i], + tile[get_local_id(0)*4+2][get_local_id(1) + i], + tile[get_local_id(0)*4+3][get_local_id(1) + i]); + vstore4(temp, (index_out + i*WIDTH)/4, out); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_opt2.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_opt2.cl new file mode 100644 index 000000000..f94717ae5 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xy_coalesced_locPad_Diag_opt2.cl @@ -0,0 +1,33 @@ + +__kernel void transpose_xy(__global const float* in, + __global float* out) +{ + float2 temp; + uint group_id_x = get_group_id(0); + uint group_id_y = (get_group_id(0) + get_group_id(1)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XY + get_local_id(0)*2; + uint yIndex = group_id_y * TILE_DIM_XY + get_local_id(1); + uint zIndex = get_global_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_y * TILE_DIM_XY + get_local_id(0)*2; + yIndex = group_id_x * TILE_DIM_XY + get_local_id(1); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_XY][TILE_DIM_XY+1]; + + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = vload2((index_in + i*WIDTH)/2, in); + tile[get_local_id(1) + i][get_local_id(0)*2] = temp.x; + tile[get_local_id(1) + i][get_local_id(0)*2+1] = temp.y; + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint i=0; i<TILE_DIM_XY; i+=BLOCK_ROWS_XY) + { + temp = (float2)(tile[get_local_id(0)*2][get_local_id(1) + i], + tile[get_local_id(0)*2+1][get_local_id(1) + i]); + vstore2(temp, (index_out + i*WIDTH)/2, out); + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_Diag_bis_3DBlock.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_Diag_bis_3DBlock.cl new file mode 100644 index 000000000..67e8891bd --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_Diag_bis_3DBlock.cl @@ -0,0 +1,34 @@ + +__kernel void transpose_xz(__global const float* in, + __global float* out) +{ + uint group_id_x = get_group_id(0); + uint group_id_z = (get_group_id(0) + get_group_id(2)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XZ + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_XZ + get_local_id(1); + uint zIndex = group_id_z * TILE_DIM_XZ + get_local_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_z * TILE_DIM_XZ + get_local_id(0); + zIndex = group_id_x * TILE_DIM_XZ + get_local_id(2); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_XZ][TILE_DIM_XZ][TILE_DIM_XZ]; + + for(uint j=0; j<TILE_DIM_XZ; j+=BLOCK_ROWS_XZ) + { + for(uint i=0; i<TILE_DIM_XZ; i+=BLOCK_ROWS_XZ) + { + tile[get_local_id(2) + j][get_local_id(1) + i][get_local_id(0)] = in[index_in + i*WIDTH + j*WIDTH*WIDTH]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint j=0; j<TILE_DIM_XZ; j+=BLOCK_ROWS_XZ) + { + for(uint i=0; i<TILE_DIM_XZ; i+=BLOCK_ROWS_XZ) + { + out[index_out + i*WIDTH + j*WIDTH*WIDTH] = tile[get_local_id(0)][get_local_id(1)+i][get_local_id(2) + j]; + } + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl new file mode 100644 index 000000000..a112ea199 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/transpose_3D_xz_coalesced_locPad_Diag_bis_3DBlock.cl @@ -0,0 +1,34 @@ + +__kernel void transpose_xz(__global const float* in, + __global float* out) +{ + uint group_id_x = get_group_id(0); + uint group_id_z = (get_group_id(0) + get_group_id(2)) % get_num_groups(0); + + uint xIndex = group_id_x * TILE_DIM_XZ + get_local_id(0); + uint yIndex = get_group_id(1) * TILE_DIM_XZ + get_local_id(1); + uint zIndex = group_id_z * TILE_DIM_XZ + get_local_id(2); + uint index_in = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + xIndex = group_id_z * TILE_DIM_XZ + get_local_id(0); + zIndex = group_id_x * TILE_DIM_XZ + get_local_id(2); + uint index_out = xIndex + yIndex * WIDTH + zIndex * WIDTH * WIDTH; + + __local float tile[TILE_DIM_XZ][TILE_DIM_XZ][TILE_DIM_XZ+1]; + + for(uint j=0; j<TILE_DIM_XZ; j+=BLOCK_ROWS_XZ) + { + for(uint i=0; i<TILE_DIM_XZ; i+=BLOCK_ROWS_XZ) + { + tile[get_local_id(2) + j][get_local_id(1) + i][get_local_id(0)] = in[index_in + i*WIDTH + j*WIDTH*WIDTH]; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + for(uint j=0; j<TILE_DIM_XZ; j+=BLOCK_ROWS_XZ) + { + for(uint i=0; i<TILE_DIM_XZ; i+=BLOCK_ROWS_XZ) + { + out[index_out + i*WIDTH + j*WIDTH*WIDTH] = tile[get_local_id(0)][get_local_id(1)+i][get_local_id(2) + j]; + } + } +} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime.cl new file mode 100644 index 000000000..cd21a32e7 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime.cl @@ -0,0 +1,20 @@ +/** + * M6prime weights. + * + * @param y Distance between the particle and left-hand grid point + * @param s Scalar of the particle + * + * @return weights + */ +inline float alpha(float y, float s){ + return (y * (y * (y * (y * (13.0 - 5.0 * y) - 9.0) - 1.0) + 2.0) / 24.0) * s;} +inline float beta(float y, float s){ + return (y * (y * (y * (y * (25.0 * y - 64.0) + 39.0) + 16.0) - 16.0) / 24.0)*s;} +inline float gamma(float y, float s){ + return (y * y * (y * (y * (126.0 - 50.0 * y) - 70.0) - 30.0) / 24.0 + 1.0)*s;} +inline float delta(float y, float s){ + return (y * (y * (y * (y * (50.0 * y - 124.0) + 66.0) + 16.0) + 16.0) / 24.0)*s;} +inline float eta(float y, float s){ + return (y * (y * (y * (y * (61.0 - 25.0 * y) - 33.0) - 1.0) - 2.0) / 24.0)*s;} +inline float zeta(float y, float s){ + return (y * y * y * (y * (5.0 * y - 12.0) + 7.0) / 24.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_builtin.cl new file mode 100644 index 000000000..f63a41952 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_builtin.cl @@ -0,0 +1,13 @@ + +inline float alpha(float y, float s){ + return (y * fma(y , fma(y , fma(y , fma(-5.0, y, 13.0),- 9.0),- 1.0), 2.0) / 24.0) * s;} +inline float beta(float y, float s){ + return (y * fma(y , fma(y , fma(y , fma(25.0 , y ,- 64.0), 39.0) , 16.0), - 16.0) / 24.0)*s;} +inline float gamma(float y, float s){ + return (y * y * fma(y , fma(y , fma( - 50.0 , y, 126.0) ,- 70.0) ,- 30.0) / 24.0 + 1.0)*s;} +inline float delta(float y, float s){ + return (y * fma(y , fma(y, fma(y, fma(50.0, y, - 124.0), 66.0) , 16.0) , 16.0) / 24.0)*s;} +inline float eta(float y, float s){ + return (y * fma(y , fma(y , fma(y , fma(- 25.0 , y, 61.0), - 33.0), - 1.0), - 2.0) / 24.0)*s;} +inline float zeta(float y, float s){ + return (y * y * y * fma(y , fma(5.0 , y ,- 12.0) , 7.0) / 24.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4.cl new file mode 100644 index 000000000..865327f31 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4.cl @@ -0,0 +1,13 @@ + +inline float4 alpha(float4 y, float4 s){ + return (y * (y * (y * (y * (13.0 - 5.0 * y) - 9.0) - 1.0) + 2.0) / 24.0) * s;} +inline float4 beta(float4 y, float4 s){ + return (y * (y * (y * (y * (25.0 * y - 64.0) + 39.0) + 16.0) - 16.0) / 24.0)*s;} +inline float4 gamma(float4 y, float4 s){ + return (y * y * (y * (y * (126.0 - 50.0 * y) - 70.0) - 30.0) / 24.0 + 1.0)*s;} +inline float4 delta(float4 y, float4 s){ + return (y * (y * (y * (y * (50.0 * y - 124.0) + 66.0) + 16.0) + 16.0) / 24.0)*s;} +inline float4 eta(float4 y, float4 s){ + return (y * (y * (y * (y * (61.0 - 25.0 * y) - 33.0) - 1.0) - 2.0) / 24.0)*s;} +inline float4 zeta(float4 y, float4 s){ + return (y * y * y * (y * (5.0 * y - 12.0) + 7.0) / 24.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4_builtin.cl new file mode 100644 index 000000000..3a4c2eaeb --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m6prime_opt4_builtin.cl @@ -0,0 +1,13 @@ + +inline float4 alpha(float4 y, float4 s){ + return (y * fma(y , fma(y , fma(y , fma(-5.0, y, 13.0),- 9.0),- 1.0), 2.0) / 24.0) * s;} +inline float4 beta(float4 y, float4 s){ + return (y * fma(y , fma(y , fma(y , fma(25.0 , y ,- 64.0), 39.0) , 16.0), - 16.0) / 24.0)*s;} +inline float4 gamma(float4 y, float4 s){ + return (y * y * fma(y , fma(y , fma( - 50.0 , y, 126.0) ,- 70.0) ,- 30.0) / 24.0 + 1.0)*s;} +inline float4 delta(float4 y, float4 s){ + return (y * fma(y , fma(y, fma(y, fma(50.0, y, - 124.0), 66.0) , 16.0) , 16.0) / 24.0)*s;} +inline float4 eta(float4 y, float4 s){ + return (y * fma(y , fma(y , fma(y , fma(- 25.0 , y, 61.0), - 33.0), - 1.0), - 2.0) / 24.0)*s;} +inline float4 zeta(float4 y, float4 s){ + return (y * y * y * fma(y , fma(5.0 , y ,- 12.0) , 7.0) / 24.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8_prime.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8_prime.cl new file mode 100644 index 000000000..84c4032b0 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8_prime.cl @@ -0,0 +1,31 @@ +/** + * M8prime weights. + * + * @param y Distance between the particle and left-hand grid point + * @param s Scalar of the particle + * + * @return weights + */ +inline float alpha(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(-10.0*y + 21.0) + 28.0) - 105.0) + 70.0) + 35.0) - 56.0) + 17.0) / 3360.0) * s;} + +inline float beta(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(70.0*y - 175.0) - 140.0) + 770.0) - 560.0) - 350.0) + 504.0) - 102.0) / 3360.0)*s;} + +inline float gamma(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(-210.0*y + 609.0) + 224.0) - 2135.0) + 910.0) + 2765.0) - 2520.0) + 255.0) / 3360.0)*s;} + +inline float delta(float y, float s){ + return ((y*y*(y*y*(y*y*(70.0*y - 231.0) + 588.0) - 980.0) + 604.0) / 672.0)*s;} + +inline float eta(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(-70.0*y + 259.0) - 84.0) - 427.0) - 182.0) + 553.0) + 504.0) + 51.0) / 672.0)*s;} + +inline float zeta(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(210.0*y - 861.0) + 532.0) + 770.0) + 560.0) - 350.0) - 504.0) - 102.0) / 3360.0)*s;} + +inline float theta(float y, float s){ + return ((y*(y*(y*(y*(y*(y*(-70.0*y + 315.0) - 280.0) - 105.0) - 70.0) + 35.0) + 56.0) + 17.0) / 3360.0)*s;} + +inline float iota(float y, float s){ + return ((y*y*y*y*y*(y*(10.*y - 49.) + 56.))/3360.)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_builtin.cl new file mode 100644 index 000000000..94d393d33 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_builtin.cl @@ -0,0 +1,33 @@ +/** + * M8prime weights. + * + * @param y Distance between the particle and left-hand grid point + * @param s Scalar of the particle + * + * @return weights + * + * Use OpenCL fma builtin function. + */ +inline float alpha(float y, float s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-10.0,y, + 21.0), + 28.0), - 105.0), + 70.0), + 35.0), - 56.0), + 17.0) / 3360.0) * s;} + +inline float beta(float y, float s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(70.0,y, - 175.0), - 140.0), + 770.0), - 560.0), - 350.0), + 504.0), - 102.0) / 3360.0)*s;} + +inline float gamma(float y, float s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-210.0,y, + 609.0), + 224.0), - 2135.0), + 910.0), + 2765.0), - 2520.0), + 255.0) / 3360.0)*s;} + +inline float delta(float y, float s){ + return (fma(y*y, fma(y*y, fma(y*y, fma(70.0,y, - 231.0), + 588.0), - 980.0), + 604.0) / 672.0)*s;} + +inline float eta(float y, float s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-70.0,y, 259.0), - 84.0), - 427.0), - 182.0), + 553.0), + 504.0), + 51.0) / 672.0)*s;} + +inline float zeta(float y, float s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(210.0,y,- 861.0), + 532.0), + 770.0), + 560.0), - 350.0), - 504.0), - 102.0) / 3360.0)*s;} + +inline float theta(float y, float s){ + return (fma(y, fma(y, fma(y, fma(y, fma(y, fma(y, fma(-70.0, y, 315.0), -280.0), -105.0), -70.0), 35.0), 56.0), 17.0) / 3360.0)*s;} + +inline float iota(float y, float s){ + return ((y * y * y * y * y * fma(y , fma(10.0 , y ,- 49.0) , 56.0)) / 3360.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_opt4_builtin.cl b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_opt4_builtin.cl new file mode 100644 index 000000000..90f28e492 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/gpu_src/weights_m8prime_opt4_builtin.cl @@ -0,0 +1,33 @@ +/** + * M8prime weights. + * + * @param y Distance between the particle and left-hand grid point + * @param s Scalar of the particle + * + * @return weights + * + * Use OpenCL fma builtin function, computed by float4. + */ +inline float4 alpha(float4 y, float4 s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-10.0,y, + 21.0), + 28.0), - 105.0), + 70.0), + 35.0), - 56.0), + 17.0) / 3360.0) * s;} + +inline float4 beta(float4 y, float4 s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(70.0,y, - 175.0), - 140.0), + 770.0), - 560.0), - 350.0), + 504.0), - 102.0) / 3360.0)*s;} + +inline float4 gamma(float4 y, float4 s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-210.0,y, + 609.0), + 224.0), - 2135.0), + 910.0), + 2765.0), - 2520.0), + 255.0) / 3360.0)*s;} + +inline float4 delta(float4 y, float4 s){ + return (fma(y*y, fma(y*y, fma(y*y, fma(70.0,y, - 231.0), + 588.0), - 980.0), + 604.0) / 672.0)*s;} + +inline float4 eta(float4 y, float4 s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(-70.0,y, 259.0), - 84.0), - 427.0), - 182.0), + 553.0), + 504.0), + 51.0) / 672.0)*s;} + +inline float4 zeta(float4 y, float4 s){ + return (fma(y,fma(y,fma(y,fma(y,fma(y,fma(y,fma(210.0,y,- 861.0), + 532.0), + 770.0), + 560.0), - 350.0), - 504.0), - 102.0) / 3360.0)*s;} + +inline float4 theta(float4 y, float4 s){ + return (fma(y, fma(y, fma(y, fma(y, fma(y, fma(y, fma(-70.0, y, 315.0), -280.0), -105.0), -70.0), 35.0), 56.0), 17.0) / 3360.0)*s;} + +inline float4 iota(float4 y, float4 s){ + return ((y * y * y * y * y * fma(y , fma(10.0 , y ,- 49.0) , 56.0)) / 3360.0)*s;} diff --git a/HySoP/unusedOrObsolet/particular_solvers/interpolation/__init__.py b/HySoP/unusedOrObsolet/particular_solvers/interpolation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/HySoP/unusedOrObsolet/particular_solvers/interpolation/interpolation.py b/HySoP/unusedOrObsolet/particular_solvers/interpolation/interpolation.py new file mode 100644 index 000000000..308ca5ae3 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/interpolation/interpolation.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +InterpolationMethod interface. +""" + + +class InterpolationMethod: + """ + Interpolation method interface. + """ + def __init__(self): + """ + Constructor. + """ + ## Grid + self.grid = None + ## Values to interpolate + self.gvalues = None + + def interpolate(self, ppos, grid, gvelo): + """ + Abstract method, apply operaton on a variable. + Must be implemented by sub-class. + + @param ppos : particle position. + @param grid : grid points. + @param gvelo : grid velocity field. + @return particle velocity, velocity at position ppos. + """ + raise NotImplementedError("Need to override method in a subclass of " + providedClass) + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/interpolation/linear.py b/HySoP/unusedOrObsolet/particular_solvers/interpolation/linear.py new file mode 100644 index 000000000..38fe792b5 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/interpolation/linear.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +InterpolationMethod interface. +""" +from ..Param import * +from InterpolationMethod import InterpolationMethod + + +providedClass = "Linear" + + +class Linear(InterpolationMethod): + """ + Lambda1 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + + @param grid : Grid values + @param gvalues : Values to interpolate + """ + InterpolationMethod.__init__(self) + self.grid = grid + self.gvalues = gvalues + self.dim_range = xrange(self.grid.dimension) + self.nb_flop = 9 + + def interpolate(self, t, ppos, dir): + """ + Abstract method, apply operaton on a variable. + Must be implemented by sub-class. + + @param t : current time + @param ppos : particle position. + @param dir : interpolation direction + @return particle velocity, velocity at position ppos. + """ + ind = np.empty(self.grid.shape, dtype=dtype_integer) + a0 = ((ppos - self.grid.min) / self.grid.elementSize) + ind[...] = (np.round(np.abs(a0))) * np.sign(a0) + ind[..., dir] = np.floor(a0[..., dir]) + #ind[...] = (np.round(np.abs(a0))) * np.sign(a0) + index = [ind[..., i] for i in self.dim_range] + index[dir] = (index[dir] + self.grid.elementNumber[dir]) % self.grid.elementNumber[dir] + y = (ppos[..., dir] - self.grid[index][..., dir]) / self.grid.elementSize[dir] + res = np.copy(self.gvalues.values) + res[..., dir] = res[..., dir] * (1. - y) + index[dir] = (index[dir] + 1) % self.grid.elementNumber[dir] + res[..., dir] += self.gvalues.values[index][..., dir] * y + return res + + def __call__(self, ppos, t, dir): + return self.interpolate(ppos, t, dir) + + def __str__(self): + """ToString method""" + return "Linear" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ + + +class Linear2D(InterpolationMethod): + """ + Lambda1 remeshing method implementation 2D. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + self.grid = grid + self.gvalues = gvalues + + def interpolate(self, t, ppos): + """ + Linear interpolation. + Interpolate the velocity at the given particle position. + + @param position : position to compute + @param grid Grid.Grid : grid data to interpolate + @return velocity : velocity at particle position + """ + ii = xrange(len(ppos)) + # Calcul des indices + ind = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXY = [(ind[i] % self.grid.elementNumber[i]) for i in ii] + iXpY = [iXY[i] for i in ii] + iXpY[0] = (iXpY[0] + 1) % self.grid.elementNumber[0] + iXYp = [iXY[i] for i in ii] + iXYp[1] = (iXYp[1] + 1) % self.grid.elementNumber[1] + iXpYp = [iXY[i] for i in ii] + iXpYp[0] = (iXpYp[0] + 1) % self.grid.elementNumber[0] + iXpYp[1] = (iXpYp[1] + 1) % self.grid.elementNumber[1] + # Calcul de la distance + y = [((ppos[i] - self.grid[iXY][i]) / self.grid.elementSize[i]) for i in ii] + # Calcul des poids + wXY = (1. - y[0]) * (1. - y[1]) + wXpY = (y[0]) * (1. - y[1]) + wXYp = (1. - y[0]) * (y[1]) + wXpYp = (y[0]) * (y[1]) + # Calcul du resultat + res = [0. for i in ii] + res = [res[i] + wXY * self.gvalues.values[tuple(iXY)][i] for i in ii] + res = [res[i] + wXpY * self.gvalues.values[tuple(iXpY)][i] for i in ii] + res = [res[i] + wXYp * self.gvalues.values[tuple(iXYp)][i] for i in ii] + res = [res[i] + wXpYp * self.gvalues.values[tuple(iXpYp)][i] for i in ii] + return res + + def __call__(self, ppos, t): + return self.interpolate(ppos, t) + + def __str__(self): + """ToString method""" + return "Linear" + + +class Linear3D(InterpolationMethod): + """ + Lambda1 remeshing method implementation 2D. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + self.grid = grid + self.gvalues = gvalues + + def interpolate(self, t, ppos): + """ + Linear interpolation. + Interpolate the velocity at the given particle position. + + @param position : position to compute + @param grid Grid.Grid : grid data to interpolate + @return velocity : velocity at particle position + """ + ii = xrange(len(ppos)) + # Calcul des indices + ind = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXYZ = [(ind[i] % self.grid.elementNumber[i]) for i in ii] + iXpYZ = [iXYZ[i] for i in ii] + iXpYZ[0] = (iXpYZ[0] + 1) % self.grid.elementNumber[0] + iXYpZ = [iXYZ[i] for i in ii] + iXYpZ[1] = (iXYpZ[1] + 1) % self.grid.elementNumber[1] + iXYZp = [iXYZ[i] for i in ii] + iXYZp[2] = (iXYZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZ = [iXYZ[i] for i in ii] + iXpYpZ[0] = (iXpYpZ[0] + 1) % self.grid.elementNumber[0] + iXpYpZ[1] = (iXpYpZ[1] + 1) % self.grid.elementNumber[1] + iXpYZp = [iXYZ[i] for i in ii] + iXpYZp[0] = (iXpYZp[0] + 1) % self.grid.elementNumber[0] + iXpYZp[2] = (iXpYZp[2] + 1) % self.grid.elementNumber[2] + iXYpZp = [iXYZ[i] for i in ii] + iXYpZp[1] = (iXYpZp[1] + 1) % self.grid.elementNumber[1] + iXYpZp[2] = (iXYpZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZp = [iXYZ[i] for i in ii] + iXpYpZp[0] = (iXpYpZp[0] + 1) % self.grid.elementNumber[0] + iXpYpZp[1] = (iXpYpZp[1] + 1) % self.grid.elementNumber[1] + iXpYpZp[2] = (iXpYpZp[2] + 1) % self.grid.elementNumber[2] + # Calcul de la distance + y = [(ppos[i] - self.grid[iXYZ][i]) / self.grid.elementSize[i] for i in ii] + # Calcul des poids + wXYZ = (1. - y[0]) * (1. - y[1]) * (1. - y[2]) + wXpYZ = (y[0]) * (1. - y[1]) * (1. - y[2]) + wXYpZ = (1. - y[0]) * (y[1]) * (1. - y[2]) + wXYZp = (1. - y[0]) * (1. - y[1]) * (y[2]) + wXpYpZ = (y[0]) * (y[1]) * (1. - y[2]) + wXpYZp = (y[0]) * (1. - y[1]) * (y[2]) + wXYpZp = (1. - y[0]) * (y[1]) * (y[2]) + wXpYpZp = (y[0]) * (y[1]) * (y[2]) + # Calcul du resultat + res = [0. for i in ii] + res = [res[i] + wXYZ * self.gvalues.values[tuple(iXYZ)][i] for i in ii] + res = [res[i] + wXpYZ * self.gvalues.values[tuple(iXpYZ)][i] for i in ii] + res = [res[i] + wXYpZ * self.gvalues.values[tuple(iXYpZ)][i] for i in ii] + res = [res[i] + wXYZp * self.gvalues.values[tuple(iXYZp)][i] for i in ii] + res = [res[i] + wXpYpZ * self.gvalues.values[tuple(iXpYpZ)][i] for i in ii] + res = [res[i] + wXpYZp * self.gvalues.values[tuple(iXpYZp)][i] for i in ii] + res = [res[i] + wXYpZp * self.gvalues.values[tuple(iXYpZp)][i] for i in ii] + res = [res[i] + wXpYpZp * self.gvalues.values[tuple(iXpYpZp)][i] for i in ii] + return res + + def __call__(self, ppos, t): + return self.interpolate(ppos, t) + + def __str__(self): + """ToString method""" + return "Linear" diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/__init__.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda1.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda1.py new file mode 100644 index 000000000..631b6370c --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda1.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RemeshingMethod interface. +""" +from RemeshingMethod import RemeshingMethod + + +providedClass = "Lambda1" + + +class Lambda1(RemeshingMethod): + """ + Lambda1 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + raise Exception("Obsolete methods : Lambda1 (not implemented with tag)") + RemeshingMethod.__init__(self) + self.grid = grid + self.gvalues = gvalues + + def remesh(self, ppos, pscal): + """ + Abstract method, apply operaton on a variable. + Must be implemented by sub-class. + + @param ppos : particle position. + @param pscal : particle scalar. + @param gvalues : grid scalar field. + """ + ii = xrange(len(ppos)) + # Calcul des indices sur la grille + indGrid = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iX = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + iXp = [iX[i] for i in ii] + iXp[0] = (iXp[0] + 1) % self.grid.elementNumber[0] + # Calcul de la distance + y = [(ppos[i] - self.grid[iX][i]) / self.grid.elementSize[i] for i in ii] + # Remaillage + self.gvalues.values[tuple(iX)] += (1. - y[0]) * pscal + self.gvalues.values[tuple(iXp)] += y[0] * pscal + + def __str__(self): + """ToString method""" + return "Lambda1 kernel" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ + + +class Lambda12D(RemeshingMethod): + """ + Lambda1 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + self.grid = grid + self.gvalues = gvalues + + def remesh(self, ppos, pscal): + """ + \Lambda_1 2D tensorial remeshing kernel implementation. + Remesh the given particle on the grid according to \Lambda_1 remeshing kernel. + + @param part Particle.Particle : particle to remesh + """ + ii = xrange(len(ppos)) + # Calcul des l'indices sur la grille + indGrid = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXY = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + iXpY = [iXY[i] for i in ii] + iXpY[0] = (iXpY[0] + 1) % self.grid.elementNumber[0] + iXYp = [iXY[i] for i in ii] + iXYp[1] = (iXYp[1] + 1) % self.grid.elementNumber[1] + iXpYp = [iXY[i] for i in ii] + iXpYp[0] = (iXpYp[0] + 1) % self.grid.elementNumber[0] + iXpYp[1] = (iXpYp[1] + 1) % self.grid.elementNumber[1] + # Calcul de la distance + y = [(ppos[i] - self.grid[iXY][i]) / self.grid.elementSize[i] for i in ii] + # Remaillage + self.gvalues.values[tuple(iXY)] += (1. - y[0]) * (1. - y[1]) * pscal + self.gvalues.values[tuple(iXpY)] += (y[0]) * (1. - y[1]) * pscal + self.gvalues.values[tuple(iXYp)] += (1. - y[0]) * (y[1]) * pscal + self.gvalues.values[tuple(iXpYp)] += (y[0]) * (y[1]) * pscal + + def __str__(self): + """ToString method""" + return "Lambda1 kernel" + + +class Lambda13D(RemeshingMethod): + """ + Lambda1 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + self.grid = grid + self.gvalues = gvalues + + def remesh(self, ppos, pscal): + """ + \Lambda_1 3D tensorial remeshing kernel implementation. + Remesh the given particle on the grid according to \Lambda_1 remeshing kernel. + + @param part Particle.Particle : particle to remesh + """ + ii = xrange(len(ppos)) + # Calcul des l'indices sur la grille + indGrid = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXYZ = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + iXpYZ = [iXYZ[i] for i in ii] + iXpYZ[0] = (iXpYZ[0] + 1) % self.grid.elementNumber[0] + iXYpZ = [iXYZ[i] for i in ii] + iXYpZ[1] = (iXYpZ[1] + 1) % self.grid.elementNumber[1] + iXYZp = [iXYZ[i] for i in ii] + iXYZp[2] = (iXYZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZ = [iXYZ[i] for i in ii] + iXpYpZ[0] = (iXpYpZ[0] + 1) % self.grid.elementNumber[0] + iXpYpZ[1] = (iXpYpZ[1] + 1) % self.grid.elementNumber[1] + iXpYZp = [iXYZ[i] for i in ii] + iXpYZp[0] = (iXpYZp[0] + 1) % self.grid.elementNumber[0] + iXpYZp[2] = (iXpYZp[2] + 1) % self.grid.elementNumber[2] + iXYpZp = [iXYZ[i] for i in ii] + iXYpZp[1] = (iXYpZp[1] + 1) % self.grid.elementNumber[1] + iXYpZp[2] = (iXYpZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZp = [iXYZ[i] for i in ii] + iXpYpZp[0] = (iXpYpZp[0] + 1) % self.grid.elementNumber[0] + iXpYpZp[1] = (iXpYpZp[1] + 1) % self.grid.elementNumber[1] + iXpYpZp[2] = (iXpYpZp[2] + 1) % self.grid.elementNumber[2] + # Calcul des distances + y = [(ppos[i] - self.grid[iXYZ][i]) / self.grid.elementSize[i] for i in ii] + # Remaillage + self.gvalues.values[tuple(iXYZ)] += (1. - y[0]) * (1. - y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXpYZ)] += (y[0]) * (1. - y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXYpZ)] += (1. - y[0]) * (y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXYZp)] += (1. - y[0]) * (1. - y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXpYpZ)] += (y[0]) * (y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXpYZp)] += (y[0]) * (1. - y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXYpZp)] += (1. - y[0]) * (y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXpYpZp)] += (y[0]) * (y[1]) * (y[2]) * pscal + + def __str__(self): + """ToString method""" + return "Lambda1 kernel" diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda2.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda2.py new file mode 100644 index 000000000..2436eda56 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/remesh/lambda2.py @@ -0,0 +1,303 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RemeshingMethod interface. +""" +from RemeshingMethod import RemeshingMethod +import math + +providedClass = "Lambda2" + + +class Lambda2(RemeshingMethod): + """ + Lambda2 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + RemeshingMethod.__init__(self, grid, gvalues) + # Epsilon value to avoid rounding errors. + self.epsilon = self.grid.elementSize[0] * 0.000000001 + + def nint(self, x): + """ + Nearest interger function. + + @param x : real number. + @return : x nearest integer. + """ + if x > -0.5: + return int(x + 0.5) + else: + return int(x + 0.5) - 1 + + def remesh_Tag_Center(self, ppos, pscal, pposP, pscalP, splittingDirection): + """ + Remeshing method for Tagged Center particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param pposP : following particle position. + @param pscalP : following particle scalar. + @param splittingDirection : direction to remesh. + """ + print "Remaillage Tag Centré" + ii = xrange(len(ppos)) + d = splittingDirection + # Calcul des indices sur la grille + indGrid = [self.nint((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon) for i in ii] + indGrid_bis = [int(math.floor((pposP[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon)) for i in ii] + i0 = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + i0_bis = [indGrid_bis[i] % self.grid.elementNumber[i] for i in ii] + i0m = [(i0[i] - 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0p = [(i0[i] + 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # Calcul de la distance + x0 = (ppos[d] - i0[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + x0_bis = (pposP[d] - i0_bis[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + if x0 <= 0.5: # Article Table 2, case (d') + # Calcul des poids + a0m = 0.5 * x0 * (x0 - 1.) + a0 = 1. - a0m + b0p = 0.5 * x0_bis * (x0_bis + 1.) + b0 = 1. - b0p + else: # Article Table 2, case (c') + # Calcul des poids + a0m = 0.5 * (x0 - 1.) * (x0 - 2.) + a0 = 1. - a0m + b0p = 0.5 * x0_bis * (x0_bis + 1.) + b0 = 1. - b0p + # Remaillage + self.gvalues.values[tuple(i0m)] += pscal * a0m + self.gvalues.values[tuple(i0)] += pscal * a0 + pscalP * b0 + self.gvalues.values[tuple(i0p)] += pscalP * b0p + + def remesh_Tag_Left(self, ppos, pscal, pposP, pscalP, splittingDirection): + """ + Remeshing method for Tagged Left particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param pposP : following particle position. + @param pscalP : following particle scalar. + @param splittingDirection : direction to remesh. + """ + print "Remaillage Tag Left" + ii = xrange(len(ppos)) + d = splittingDirection + # Calcul des indices sur la grille + indGrid = [int(math.floor((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon)) for i in ii] + indGrid_bis = [self.nint((pposP[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon) for i in ii] + i0 = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + i0_bis = [indGrid_bis[i] % self.grid.elementNumber[i] for i in ii] + i0m = [(i0[i] - 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0p = [(i0[i] + 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0p2 = [(i0[i] + 2) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0p3 = [(i0[i] + 3) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # Calcul de la distance + x0 = (ppos[d] - i0[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + x0_bis = (pposP[d] - i0_bis[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + if x0_bis <= 0.5: # Article Table 1, case (d) + # Calcul des poids + am = 0.5 * x0 * (x0 - 1.) + a0 = 1. - x0 * x0 + ap = x0 + ap2 = 0.5 * x0 * (x0 - 1.) + b0 = 0.5 * (x0_bis + 1.) * x0_bis + bp = -x0_bis + bp2 = 1. - x0_bis * x0_bis + bp3 = 0.5 * x0_bis * (x0_bis + 1.) + else: # Article Table 1, case (c) + # Calcul des poids + am = 0.5 * x0 * (x0 - 1.) + a0 = 1. - x0 * x0 + ap = x0 + ap2 = 0.5 * x0 * (x0 - 1.) + b0 = 0.5 * x0_bis * (x0_bis - 1.) + bp = 1. - x0_bis + bp2 = x0_bis * (2. - x0_bis) + bp3 = 0.5 * x0_bis * (x0_bis - 1.) + # Remaillage + self.gvalues.values[tuple(i0m)] += pscal * am + self.gvalues.values[tuple(i0)] += pscal * a0 + pscalP * b0 + self.gvalues.values[tuple(i0p)] += pscal * ap + pscalP * bp + self.gvalues.values[tuple(i0p2)] += pscal * ap2 + pscalP * bp2 + self.gvalues.values[tuple(i0p3)] += pscalP * bp3 + + def remesh_noTag_Center(self, ppos, pscal, splittingDirection): + """ + Remeshong method for non-Tagged Center particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param splittingDirection : direction to remesh. + """ + #print "Remaillage noTag Centre" + ii = xrange(len(ppos)) + d = splittingDirection + # Calcul des indices sur la grille + indGrid = [self.nint((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon) for i in ii] + i0 = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + i0p = [(i0[i] + 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0p2 = [(i0[i] + 2) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0m = [(i0[i] - 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # Calcul de la distance + x0 = (ppos[d] - indGrid[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + if x0 <= 0.5: + # Calcul des poids + am = 0.5 * x0 * (x0 - 1.) + a0 = 1. - x0 * x0 + ap = 0.5 * x0 * (x0 + 1.) + # Remaillage + self.gvalues.values[tuple(i0m)] += pscal * am + self.gvalues.values[tuple(i0)] += pscal * a0 + self.gvalues.values[tuple(i0p)] += pscal * ap + else: + # Calcul des poids + am = 0.5 * (x0 - 1.) * (x0 - 2.) + a0 = x0 * (2. - x0) + ap = 0.5 * x0 * (x0 - 1.) + # Remaillage + self.gvalues.values[tuple(i0)] += pscal * am + self.gvalues.values[tuple(i0p)] += pscal * a0 + self.gvalues.values[tuple(i0p2)] += pscal * ap + + def remesh_noTag_Left(self, ppos, pscal, splittingDirection): + """ + Remeshing method for non-Tagged Left particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param splittingDirection : direction to remesh. + """ + #print "Remaillage no Tag Left" + ii = xrange(len(ppos)) + d = splittingDirection + # Calcul des indices sur la grille + indGrid = [int(math.floor((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon)) for i in ii] + i0 = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + i0p = [(i0[i] + 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + i0m = [(i0[i] - 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # Calcul de la distance + x0 = (ppos[d] - indGrid[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + # Calcul des poids + am = 0.5 * x0 * (x0 - 1.) + a0 = 1. - x0 * x0 + ap = 0.5 * x0 * (x0 + 1.) + # Remaillage + self.gvalues.values[tuple(i0m)] += pscal * am + self.gvalues.values[tuple(i0)] += pscal * a0 + self.gvalues.values[tuple(i0p)] += pscal * ap + + def __str__(self): + """ToString method""" + return "Lambda2 kernel" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ + + +class Lambda22D(RemeshingMethod): + """ + Lambda2 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + raise Exception("Obsolete methods : Must use 1D version with splitting.") + self.grid = grid + self.gvalues = gvalues + + def remesh(self, ppos, pscal): + """ + \Lambda_1 2D tensorial remeshing kernel implementation. + Remesh the given particle on the grid according to \Lambda_1 remeshing kernel. + + @param part Particle.Particle : particle to remesh + """ + ii = xrange(len(ppos)) + # Calcul des l'indices sur la grille + indGrid = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXY = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + iXpY = [iXY[i] for i in ii] + iXpY[0] = (iXpY[0] + 1) % self.grid.elementNumber[0] + iXYp = [iXY[i] for i in ii] + iXYp[1] = (iXYp[1] + 1) % self.grid.elementNumber[1] + iXpYp = [iXY[i] for i in ii] + iXpYp[0] = (iXpYp[0] + 1) % self.grid.elementNumber[0] + iXpYp[1] = (iXpYp[1] + 1) % self.grid.elementNumber[1] + # Calcul de la distance + y = [(ppos[i] - self.grid[iXY][i]) / self.grid.elementSize[i] for i in ii] + # Remaillage + self.gvalues.values[tuple(iXY)] += (1. - y[0]) * (1. - y[1]) * pscal + self.gvalues.values[tuple(iXpY)] += (y[0]) * (1. - y[1]) * pscal + self.gvalues.values[tuple(iXYp)] += (1. - y[0]) * (y[1]) * pscal + self.gvalues.values[tuple(iXpYp)] += (y[0]) * (y[1]) * pscal + + def __str__(self): + """ToString method""" + return "Lambda2 kernel" + + +class Lambda23D(RemeshingMethod): + """ + Lambda2 remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + raise Exception("Obsolete methods : Must use 1D version with splitting.") + self.grid = grid + self.gvalues = gvalues + + def remesh(self, ppos, pscal): + """ + \Lambda_1 3D tensorial remeshing kernel implementation. + Remesh the given particle on the grid according to \Lambda_1 remeshing kernel. + + @param part Particle.Particle : particle to remesh + """ + ii = xrange(len(ppos)) + # Calcul des l'indices sur la grille + indGrid = [int((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i]) for i in ii] + iXYZ = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + iXpYZ = [iXYZ[i] for i in ii] + iXpYZ[0] = (iXpYZ[0] + 1) % self.grid.elementNumber[0] + iXYpZ = [iXYZ[i] for i in ii] + iXYpZ[1] = (iXYpZ[1] + 1) % self.grid.elementNumber[1] + iXYZp = [iXYZ[i] for i in ii] + iXYZp[2] = (iXYZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZ = [iXYZ[i] for i in ii] + iXpYpZ[0] = (iXpYpZ[0] + 1) % self.grid.elementNumber[0] + iXpYpZ[1] = (iXpYpZ[1] + 1) % self.grid.elementNumber[1] + iXpYZp = [iXYZ[i] for i in ii] + iXpYZp[0] = (iXpYZp[0] + 1) % self.grid.elementNumber[0] + iXpYZp[2] = (iXpYZp[2] + 1) % self.grid.elementNumber[2] + iXYpZp = [iXYZ[i] for i in ii] + iXYpZp[1] = (iXYpZp[1] + 1) % self.grid.elementNumber[1] + iXYpZp[2] = (iXYpZp[2] + 1) % self.grid.elementNumber[2] + iXpYpZp = [iXYZ[i] for i in ii] + iXpYpZp[0] = (iXpYpZp[0] + 1) % self.grid.elementNumber[0] + iXpYpZp[1] = (iXpYpZp[1] + 1) % self.grid.elementNumber[1] + iXpYpZp[2] = (iXpYpZp[2] + 1) % self.grid.elementNumber[2] + # Calcul des distances + y = [(ppos[i] - self.grid[iXYZ][i]) / self.grid.elementSize[i] for i in ii] + # Remaillage + self.gvalues.values[tuple(iXYZ)] += (1. - y[0]) * (1. - y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXpYZ)] += (y[0]) * (1. - y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXYpZ)] += (1. - y[0]) * (y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXYZp)] += (1. - y[0]) * (1. - y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXpYpZ)] += (y[0]) * (y[1]) * (1. - y[2]) * pscal + self.gvalues.values[tuple(iXpYZp)] += (y[0]) * (1. - y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXYpZp)] += (1. - y[0]) * (y[1]) * (y[2]) * pscal + self.gvalues.values[tuple(iXpYpZp)] += (y[0]) * (y[1]) * (y[2]) * pscal + + def __str__(self): + """ToString method""" + return "Lambda2 kernel" diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/m4p.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/m4p.py new file mode 100644 index 000000000..8c56a30d8 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/remesh/m4p.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RemeshingMethod interface. +""" +from RemeshingMethod import RemeshingMethod +import numpy as np +import math + +providedClass = "M4Prime" + + +class M4Prime(RemeshingMethod): + """ + M4Prime remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + RemeshingMethod.__init__(self, grid, gvalues) + # Epsilon value to avoid rounding errors. + self.epsilon = self.grid.elementSize[0] * 0.000000001 + self.dim_range = xrange(self.grid.dimension) + + def remesh(self, ppos, pscal, dir): + """ + Remeshing method for non-Tagged Left particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param dir : direction to remesh. + """ + #print "Remaillage no Tag Left" + # ii = xrange(len(ppos)) + # d = splittingDirection + # # Calcul des indices sur la grille + # indGrid = [int(math.floor((ppos[i] - self.grid.min[i]) / self.grid.elementSize[i] + self.epsilon)) for i in ii] + # i0 = [indGrid[i] % self.grid.elementNumber[i] for i in ii] + # i0p = [(i0[i] + 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # i0p2 = [(i0[i] + 2) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # i0m = [(i0[i] - 1) % self.grid.elementNumber[i] if i == d else i0[i] for i in ii] + # # Calcul de la distance + # x0 = (ppos[d] - indGrid[d] * self.grid.elementSize[d] - self.grid.min[d]) / self.grid.elementSize[d] + # # Calcul des poids + # am = -0.5 * x0 * (x0 - 1.) * (x0 - 1.) + # a0 = 0.5 * (x0 - 1.) * (3. * x0 * x0 - 2 * x0 - 2.) + # ap = 0.5 * x0 * (1. + 4. * x0 - 3. * x0 * x0) + # ap2 = 0.5 * x0 * x0 * (x0 - 1.) + # # Remaillage + # self.gvalues.values[tuple(i0m)] += pscal * am + # self.gvalues.values[tuple(i0)] += pscal * a0 + # self.gvalues.values[tuple(i0p)] += pscal * ap + # self.gvalues.values[tuple(i0p2)] += pscal * ap2 + ## ------------------- NumPy Optimisation + ind = ((ppos - self.grid.min) / self.grid.elementSize + self.epsilon).astype(np.int) + i0 = ind % self.grid.elementNumber + ip = np.copy(i0) + ip[..., dir] = (i0[..., dir] + 1) % self.grid.elementNumber[dir] + ip2 = np.copy(i0) + ip2[..., dir] = (i0[..., dir] + 2) % self.grid.elementNumber[dir] + im = np.copy(i0) + im[..., dir] = (i0[..., dir] - 1) % self.grid.elementNumber[dir] + i0 = tuple([i0[..., i] for i in self.dim_range]) + ip = tuple([ip[..., i] for i in self.dim_range]) + ip2 = tuple([ip2[..., i] for i in self.dim_range]) + im = tuple([im[..., i] for i in self.dim_range]) + x0 = (ppos[..., dir] - ind[..., dir] * self.grid.elementSize[dir] - self.grid.min[dir]) / self.grid.elementSize[dir] + am = -0.5 * x0 * (x0 - 1.) * (x0 - 1.) + a0 = 0.5 * (x0 - 1.) * (3. * x0 * x0 - 2 * x0 - 2.) + ap = 0.5 * x0 * (1. + 4. * x0 - 3. * x0 * x0) + ap2 = 0.5 * x0 * x0 * (x0 - 1.) + self.gvalues.values[i0] += pscal * a0 + self.gvalues.values[im] += pscal * am + self.gvalues.values[ip] += pscal * ap + self.gvalues.values[ip2] += pscal * ap2 + ## ------------------- + + def __str__(self): + """ToString method""" + return "M4Prime kernel" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : " + providedClass + print eval(providedClass).__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/m6p.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/m6p.py new file mode 100644 index 000000000..034ed3e54 --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/remesh/m6p.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RemeshingMethod interface. +""" +from ..Param import * +from RemeshingMethod import RemeshingMethod + + +class M6Prime(RemeshingMethod): + """ + M6Prime remeshing method implementation. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + RemeshingMethod.__init__(self, grid, gvalues) + self.dim_range = xrange(self.grid.dimension) + self.nb_flop = 106 + + def remesh(self, ppos, pscal, dir): + """ + Remeshing method for non-Tagged Left particles. + + @param ppos : particle position. + @param pscal : particle scalar. + @param dir : direction to remesh. + """ + ind = np.empty(self.grid.shape, dtype=dtype_integer) + a0 = ((ppos - self.grid.min) / self.grid.elementSize) + ind[...] = (np.round(np.abs(a0))) * np.sign(a0) + ind[..., dir] = np.floor(a0[..., dir]) + x0 = (ppos[..., dir] - ind[..., dir] * self.grid.elementSize[dir] - self.grid.min[dir]) / self.grid.elementSize[dir] + am2 = x0 * (x0 * (x0 * (x0 * (-5. * x0 + 13.) - 9.) - 1.) + 2.) / 24. + am = x0 * (x0 * (x0 * (x0 * (25. * x0 - 64.) + 39.) + 16.) - 16.) / 24. + a0 = x0 * x0 * (x0 * (x0 * (-50. * x0 + 126.) - 70.) - 30.) / 24. + 1. + ap = x0 * (x0 * (x0 * (x0 * (50. * x0 - 124.) + 66.) + 16.) + 16.) / 24. + ap2 = x0 * (x0 * (x0 * (x0 * (-25. * x0 + 61.) - 33.) - 1.) - 2.) / 24. + ap3 = x0 * x0 * x0 * (x0 * (5. * x0 - 12.) + 7.) / 24. + + ind[..., dir] = (ind[..., dir] - 2 + self.grid.elementNumber[dir]) % self.grid.elementNumber[dir] + + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), am2.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + ind[..., dir] = (ind[..., dir] + 1) % self.grid.elementNumber[dir] + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), am.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + ind[..., dir] = (ind[..., dir] + 1) % self.grid.elementNumber[dir] + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), a0.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + ind[..., dir] = (ind[..., dir] + 1) % self.grid.elementNumber[dir] + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), ap.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + ind[..., dir] = (ind[..., dir] + 1) % self.grid.elementNumber[dir] + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), ap2.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + ind[..., dir] = (ind[..., dir] + 1) % self.grid.elementNumber[dir] + for i_index, ps, w in zip(ind.reshape((-1,self.grid.dimension)), pscal.reshape((-1)), ap3.reshape((-1))): + self.gvalues.values[tuple(i_index)] += ps * w + + def __str__(self): + """ToString method""" + return "M6Prime kernel" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : M6Prime" + print M6Prime.__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/remesh/method.py b/HySoP/unusedOrObsolet/particular_solvers/remesh/method.py new file mode 100644 index 000000000..ade97b75e --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/remesh/method.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RemeshingMethod interface. +""" + + +class RemeshingMethod: + """ + Remeshing method interface. + """ + def __init__(self, grid, gvalues): + """ + Constructor. + """ + ## Grid + self.grid = grid + ## Values to remesh + self.gvalues = gvalues + + def remesh(self, ppos, pscal, grid, gscal): + """ + Abstract method, apply operaton on a variable. + Must be implemented by sub-class. + + @param ppos : particle position. + @param pscal : particle scalar. + @param grid : grid points. + @param gscal : grid scalar field. + """ + raise NotImplementedError("Need to override method in a subclass of " + providedClass) + +if __name__ == "__main__": + print __doc__ + print "- Provided class : RemeshingMethod" + print RemeshingMethod.__doc__ diff --git a/HySoP/unusedOrObsolet/particular_solvers/solver.py b/HySoP/unusedOrObsolet/particular_solvers/solver.py new file mode 100644 index 000000000..4a01d273f --- /dev/null +++ b/HySoP/unusedOrObsolet/particular_solvers/solver.py @@ -0,0 +1,36 @@ +""" +@package parmepy.particular_solvers.solver + +Solver class interface. +""" +from abc import ABCMeta, abstractmethod + + +class Solver: + """ + Solver interface. + """ + + __metaclass__ = ABCMeta + + @abstractmethod + def __init__(self, problem): + """ + Abstract constructor. + @param : the problem associated with this solver. + """ + ## Problem to solve + self.problem = problem + + @abstractmethod + def initialize(self): + """ + Solver initialisation for a given DiscreteProblem.DiscreteProblem. + Abstract method, apply operaton on a variable. + Must be implemented by sub-class. + """ + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Solver (abstract)" + print Solver.__doc__ diff --git a/HySoP/unusedOrObsolet/runge_kutta.py b/HySoP/unusedOrObsolet/runge_kutta.py new file mode 100644 index 000000000..05bc5793e --- /dev/null +++ b/HySoP/unusedOrObsolet/runge_kutta.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RK2 method interface. +""" +from ..Param import * +from ODESolver import ODESolver + + +class RK2(ODESolver): + """ + ODESolver implementation for solving an equation system with RK2 method. + y'(t) = f(t,y) + + y(t_n+1)= y(t_n) + dt*y'[y(t_n)+dt/2*y'(y(t_n))]. + + """ + def __init__(self, f=None, conditions=lambda x: x, dim=3): + """ + Constructor. + + @param f function f(t,y) : Right hand side of the equation to solve. + @param dim : dimensions + @param conditions : function to apply boundary conditions. + """ + ODESolver.__init__(self, f) + # Boundary conditions function. + self.boundaryConditions = conditions + self.gpu_kernel = """ + """ + self.nb_flop = 5 + + def integrate(self, y, fy, yp, t, dt, dir): + """ + Integration step for RK2 Method. + yp= y + dt*y'[y+dt/2*y'(y)]. + + @param y : position at time t. + @param fy : y'(y) value at time t. + @param yp : result position at time t + dt + @param t : current time. + @param dt : time step. + """ + ## ------------------- NumPy Optimisation + p1 = np.copy(y[..., dir]) + yp[..., dir] = p1 + fy[..., dir] * dt * 0.5 + self.boundaryConditions(yp, dir) # TODO: A tester aussi avec return dans la fonction + vp1 = self.f(t, yp, dir) + yp[..., dir] = p1 + vp1[..., dir] * dt + self.boundaryConditions(yp, dir) + ## ------------------- + + def __str__(self): + """ToString method""" + return "RK2 Method" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : RK2" + print RK2.__doc__ diff --git a/HySoP/unusedOrObsolet/runge_kutta2stretching.py b/HySoP/unusedOrObsolet/runge_kutta2stretching.py new file mode 100755 index 000000000..bf2c86807 --- /dev/null +++ b/HySoP/unusedOrObsolet/runge_kutta2stretching.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RK2 method interface. +""" +from .integrator import ODESolver +from ...operator.differentialOperator_d import DifferentialOperator_d +from ...operator.differentialOperator import DifferentialOperator +from parmepy.constants import * +import copy +import sys +import numpy as np + + +class RK2Stretch(ODESolver): + """ + ODESolver implementation for solving an equation system with RK2 method. + y'(t) = f(t,y) + + y(t_n+1)= y(t_n) + dt*y'[y(t_n)+dt/2*y'(y(t_n))]. + + """ + def __init__(self, f=None, dim=3): + """ + Constructor. + + @param f function f(t,y) : Right hand side of the equation to solve. + @param dim : dimensions + @param conditions : function to apply boundary conditions. + """ + ODESolver.__init__(self, f) + + + def integrate(self, f, fd ,field1 , field2, res_vorticity, t, dt, dimension): +# def integrate(self, f,field1 , field2, res_vorticity, t, dt, dimension): + """ + Integration step for RK4 Method + yp= y + dt*y'[y+dt/2*y'(y)]. + + @param y : position at time t. + @param f : operator to calcul y'(y) value at time t. + @param fd : result position at time t + dt + @param field1 : vorticity field discretized + @param field2 : velocity field discretized + @param t : current time. + @param dt : time step. + """ + maxgersh = np.zeros(1, dtype=PARMES_REAL, order=ORDER) + resultTmp = np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K1=np.asarray(fd) + K1[:,:,:,:]= K1[:,:,:,:] *0.5*dt + field1[:,:,:] + if False in [(field1[i][...].shape == field2[i][...].shape) for i in xrange(dimension)] : + print "Error, not the same mesh on field1 and on field2" + f.discreteOperator = DifferentialOperator_d(field1=K1, field2=field2, result=resultTmp, choice='divConservation', maxgersh=maxgersh) + f.discreteOperator.apply() + res_vorticity[:,:,:] = field1[:,:,:] + resultTmp[:,:,:,:] * dt + return res_vorticity + + + + def __str__(self): + """ToString method""" + return "RK2 Method" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : RK2" + print RK2.__doc__ diff --git a/HySoP/unusedOrObsolet/runge_kutta3stretching.py b/HySoP/unusedOrObsolet/runge_kutta3stretching.py new file mode 100644 index 000000000..9d9c62ecf --- /dev/null +++ b/HySoP/unusedOrObsolet/runge_kutta3stretching.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RK3 method interface. +""" +from .integrator import ODESolver +from ...operator.differentialOperator_d import DifferentialOperator_d +from ...operator.differentialOperator import DifferentialOperator +from parmepy.constants import * +import numpy as np +import copy + +class RK3Stretch(ODESolver): + """ + ODESolver implementation for solving an equation system with RK3 method. + y'(t) = f(t,y) + + y(t_n+1)= y(t_n) + dt*y'[y(t_n)+dt/2*y'(y(t_n))]. + + """ + def __init__(self, f=None, dim=3): + """ + Constructor. + + @param f function f(t,y) : Right hand side of the equation to solve. + @param dim : dimensions + @param conditions : function to apply boundary conditions. + """ + ODESolver.__init__(self, f) + + + def integrate(self, f, fd, field1, field2, res_vorticity, t, dt, dimension): + """ + Integration step for RK3 Method + yp= y + dt*y'[y+dt/2*y'(y)]. + + @param y : position at time t. + @param f : operator to calcul y'(y) value at time t. + @param fd : result position at time t + dt + @param field1 : vorticity field discretized + @param field2 : velocity field discretized + @param t : current time. + @param dt : time step. + """ + # RK3 TVD + maxgersh = np.zeros(1, dtype=PARMES_REAL, order=ORDER) + K1=np.asarray(fd) + K2=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K1[:,:,:,:] = field1[:,:,:] + dt * K1[:,:,:,:] + f.discreteOperator = DifferentialOperator_d(K1, field2, K2, choice='divConservation',maxgersh=maxgersh) + f.discreteOperator.apply() + K2[:,:,:,:] = 3./4. * field1[:,:,:] + 1./4. * (K1[:,:,:,:] + dt * K2[:,:,:,:]) + f.discreteOperator = DifferentialOperator_d(K2, field2, res_vorticity, choice='divConservation',maxgersh=maxgersh) + f.discreteOperator.apply() + res_vorticity[:,:,:] = 1./3. * field1[:,:,:] + 2./3. * (K2[:,:,:,:] + dt * res_vorticity[:,:,:]) + return res_vorticity + + # RK3 V1 +# maxgersh = np.zeros(1, dtype=PARMES_REAL, order=ORDER) +# K1=np.asarray(fd) +# K2=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) +# K3=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) +# resultTmp = np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) +# K1[:,:,:,:] = dt * K1[:,:,:,:] +# resultTmp[:,:,:] = field1[:,:,:] + 1./3. * K1[:,:,:,:] +# f.discreteOperator = DifferentialOperator_d(f, resultTmp, field2, K2, choice='divConservation',maxgersh=maxgersh) +# f.discreteOperator.apply() +# K2[:,:,:,:] = field1[:,:,:] + 2./3. * dt * K2[:,:,:,:] +# f.discreteOperator = DifferentialOperator_d(f, K2, field2, K3, choice='divConservation',maxgersh=maxgersh) +# f.discreteOperator.apply() +# K3[:,:,:,:] = dt * K3[:,:,:,:] +# res_vorticity[:,:,:] = field1[:,:,:] + 1./4. * (K1[:,:,:,:] + 3 * K3[:,:,:,:]) +# return res_vorticity + + + def __str__(self): + """ToString method""" + return "RK3 Method" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : RK3" + print RK3.__doc__ diff --git a/HySoP/unusedOrObsolet/runge_kutta4stretching.py b/HySoP/unusedOrObsolet/runge_kutta4stretching.py new file mode 100755 index 000000000..6427adefa --- /dev/null +++ b/HySoP/unusedOrObsolet/runge_kutta4stretching.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +""" +@package Utils +RK4 method interface. +""" +from .integrator import ODESolver +from ...operator.differentialOperator_d import DifferentialOperator_d +from ...operator.differentialOperator import DifferentialOperator +from parmepy.constants import * +import numpy as np +import copy + +class RK4Stretch(ODESolver): + """ + ODESolver implementation for solving an equation system with RK4 method. + y'(t) = f(t,y) + + y(t_n+1)= y(t_n) + dt*y'[y(t_n)+dt/2*y'(y(t_n))]. + + """ + def __init__(self, f=None, dim=3): + """ + Constructor. + + @param f function f(t,y) : Right hand side of the equation to solve. + @param dim : dimensions + @param conditions : function to apply boundary conditions. + """ + ODESolver.__init__(self, f) + + + def integrate(self, f, fd ,field1 , field2, res_vorticity, t, dt, dimension): + """ + Integration step for RK4 Method + yp= y + dt*y'[y+dt/2*y'(y)]. + + @param y : position at time t. + @param f : operator to calcul y'(y) value at time t. + @param fd : result position at time t + dt + @param field1 : vorticity field discretized + @param field2 : velocity field discretized + @param t : current time. + @param dt : time step. + """ + print "ehoh" + maxgersh = np.zeros(1, dtype=PARMES_REAL, order=ORDER) + resultTmp = np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K1=np.asarray(fd) + K2=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K3=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K4=np.asarray([np.zeros((field2.topology.resolution), dtype=PARMES_REAL, order=ORDER) for d in xrange(field2.topology.dim)]) + K1[:,:,:,:] =K1[:,:,:,:]* dt + resultTmp[:,:,:,:] = K1[:,:,:,:] * 0.5 + field1[:,:,:] + f.discreteOperator = DifferentialOperator_d(resultTmp , field2, K2, choice='divConservation',maxgersh=maxgersh) + f.discreteOperator.apply() + K2[:,:,:,:] = K2[:,:,:,:] * dt + resultTmp[:,:,:,:] = K2[:,:,:,:] * 0.5 + field1[:,:,:] + f.discreteOperator = DifferentialOperator_d(resultTmp, field2, K3, choice='divConservation',maxgersh=maxgersh) + f.discreteOperator.apply() + K3[:,:,:,:] = K3[:,:,:,:] * dt + resultTmp[:,:,:,:] = K3[:,:,:,:] + field1[:,:,:] + f.discreteOperator = DifferentialOperator_d(resultTmp, field2, K4, choice='divConservation',maxgersh=maxgersh) + f.discreteOperator.apply() + K4[:,:,:,:] = K4[:,:,:,:] * dt + res_vorticity[:,:,:] = field1[:,:,:] + 1./6. * (K1[:,:,:,:] + 2.0 * K2[:,:,:,:] + 2.0 * K3[:,:,:,:] + K4[:,:,:,:]) + return res_vorticity + + + def __str__(self): + """ToString method""" + return "RK4 Method" + + +if __name__ == "__main__": + print __doc__ + print "- Provided class : RK4" + print RK4.__doc__ diff --git a/HySoP/unusedOrObsolet/splitting.py b/HySoP/unusedOrObsolet/splitting.py new file mode 100644 index 000000000..97f736689 --- /dev/null +++ b/HySoP/unusedOrObsolet/splitting.py @@ -0,0 +1,91 @@ +""" +@file splitting.py + +Splitting operator representation +""" +from parmepy.numerics.method import NumMethod + + +class Splitting(NumMethod): + """ + Splitting operator representation. + + Operator of operators applying in a Strang splitting. + + Implements a 2nd order splitting in 3D: + @li X-dir, half time step + @li Y-dir, half time step + @li Z-dir, full time step + @li Y-dir, half time step + @li X-dir, half time step + \n + Implements a 2nd order splitting in 2D: + @li X-dir, half time step + @li Y-dir, full time step + @li X-dir, half time step + """ + + def __init__(self, function, dim, config='o2_FullHalf'): + """ + Create a Splitting operator on a given list of operators + and a dimension. + + @param function : function to split. + @param dim : problem dimension. + @param config : Splitting configuration : + - o2_FullHalf : All steps are performed with time step equals to dt/2 + - o2 : middle step is performed with time step equals to dt + """ + raise ValueError("Splitting became obsolete") + NumMethod.__init__(self, name="splitting") + ## Operators to split + self.function = function + ## Splitting at 2nd order. + self.splitting = [] + if config == 'o2_FullHalf': + ## Half timestep in all directions + [self.splitting.append((i, 0.5)) for i in xrange(dim)] + [self.splitting.append((dim - 1 - i, 0.5)) for i in xrange(dim)] + elif config == 'o2': + ## Half timestep in all directions but last + [self.splitting.append((i, 0.5)) for i in xrange(dim - 1)] + self.splitting.append((dim - 1, 1.)) + [self.splitting.append((dim - 2 - i, 0.5)) + for i in xrange(dim - 1)] + elif config == 'o1': + [self.splitting.append((i, 1.)) for i in xrange(dim)] + elif config == 'x_only': + self.splitting.append((0, 1.)) + elif config == 'y_only': + self.splitting.append((1, 1.)) + elif config == 'z_only': + self.splitting.append((2, 1.)) + else: + ## Full timestep in all directions + [self.splitting.append((i, 1.)) for i in xrange(dim)] + + def __call__(self, t, dt): + """ + Apply Remeshing operator. + + @param t : current time. + @param dt : time step. + """ + for split_id, split in enumerate(self.splitting): + print "direction : " + str(split[0]) +\ + " dt*" + str(split[1]) + " id:" + str(split_id) + self.function(t, dt * split[1], split[0], split_id) + + def __str__(self): + s = "Splitting (DiscreteOperator). Splitting steps : \n" + for split in self.splitting: + s += "direction : " + str(split[0]) + " dt=" + str(split[1]) + "\n" + s += "Concerned operators : \n" + for op in self.operators: + s += str(op) + return s + +if __name__ == "__main__": + print __doc__ + print "- Provided class : Splitting" + print Splitting.__doc__ diff --git a/HySoP/unusedOrObsolet/synchronizeGhosts.py b/HySoP/unusedOrObsolet/synchronizeGhosts.py new file mode 100644 index 000000000..0eff6764f --- /dev/null +++ b/HySoP/unusedOrObsolet/synchronizeGhosts.py @@ -0,0 +1,493 @@ +""" +@file operator/discrete/synchronizeGhosts.py + +Update ghost points for some fields defined on a specific topology. +""" +from parmepy.constants import debug, ORDER, PARMES_INTEGER, PARMES_REAL +from parmepy.mpi.main_var import main_comm, main_rank +from discrete import DiscreteOperator +from parmepy.tools.timers import timed_function +import numpy as np + + +class SynchronizeGhosts_d(DiscreteOperator): + """ + Ghost points synchronization. + """ + + @debug + def __init__(self, fieldslist, topology, transferMethod='greaterSend'): + """ + Defines a way to send/recv values at ghosts points for a list + of fields, discretized on a given topology. + + @param fieldslist : a list of fields + @param topology : the topology common to all fields. + @param transferMethod : which type of exchange is used. + """ + DiscreteOperator.__init__(self, fieldslist, method=transferMethod, + name="Ghosts Synchronization") + self.input = fieldslist + self.output = fieldslist + self.compute_time = 0. + self.fieldslist = fieldslist + self.topology = topology + if (main_rank == 0): + print 'CUT SPACE', self.topology.dims + self.transferMethod = transferMethod + + @debug + def setUp(self): + + self.topoMPI = \ + self.topology.comm.Create_cart( + self.topology.dims, + periods=self.topology.periods) + ghosts = self.topology.ghosts + resolution = self.topology.mesh.resolution + self.fieldslist = np.asarray([self.fieldslist]) + if (self.transferMethod == 'SendRecv'): + # Allocation of space for reciev data + self.dataRecvX = np.zeros(( + ghosts[0], resolution[1], resolution[2]), + dtype=PARMES_REAL, order=ORDER) + self.dataRecvY = np.zeros(( + resolution[0], ghosts[1], resolution[2]), + dtype=PARMES_REAL, order=ORDER) + self.dataRecvZ = np.zeros(( + resolution[0], resolution[1], ghosts[2]), + dtype=PARMES_REAL, order=ORDER) + self.SendRecvList = np.zeros( + self.topology.dim * 2, + order=ORDER, dtype=PARMES_INTEGER) + self.SendRecvList[0], self.SendRecvList[1] = \ + self.topology.Shift(0, 1) + self.SendRecvList[2], self.SendRecvList[3] = \ + self.topology.Shift(1, 1) + if (self.topology.dim > 2): + self.SendRecvList[4], self.SendRecvList[5] = \ + self.topology.Shift(2, 1) + + if (self.transferMethod == 'greaterSend'): + tab = self.topology.neighbours + self.tabSort = np.zeros( + [self.topology.dim * 2, 2], + order=ORDER, dtype=PARMES_INTEGER) + self.tabSort[:, 1] = range(self.topology.dim * 2) + self.tabSort[0, 0] = tab[0, 0] + self.tabSort[1, 0] = tab[1, 0] + self.tabSort[2, 0] = tab[0, 1] + self.tabSort[3, 0] = tab[1, 1] + if(self.topology.dim > 2): + self.tabSort[4, 0] = tab[0, 2] + self.tabSort[5, 0] = tab[1, 2] + tabSort1 = self.tabSort[self.tabSort[:, 0] <= main_rank] + tabSort2 = self.tabSort[self.tabSort[:, 0] > main_rank] + if (np.asarray(tabSort1[:, 0].shape) > 0): + tabSort1 = tabSort1[tabSort1[:, 0].argsort()] + if (np.asarray(tabSort2[:, 0].shape) > 0): + tabSort2 = tabSort2[tabSort2[:, 0].argsort()] + tabSort2 = self.TabInvSort(tabSort2) + self.tabSort = np.concatenate((tabSort1, tabSort2)) + + if ((self.transferMethod == 'greaterSend') or + (self.transferMethod == 'SendRecv')): + # Allocation of space for send and reciev data + self.dataSendX = np.zeros(( + ghosts[0], resolution[1], resolution[2]), + dtype=PARMES_REAL, order=ORDER) + self.dataSendY = np.zeros(( + resolution[0], ghosts[1], resolution[2]), + dtype=PARMES_REAL, order=ORDER) + self.dataSendZ = np.zeros(( + resolution[0], resolution[1], ghosts[2]), + dtype=PARMES_REAL, order=ORDER) + # 1 - get discrete fields arrays + # 2 - get list of ghosts area + # 3 - get neighbours + # 4 - find what is to be send/recv, the size of the arrays and + # allocate buffers if required + # 5 - set send/recv order + #self.discreteOperator.setUp() + + @debug + @timed_function + def apply(self, simulation=None): + self.resolution = self.topology.mesh.resolution + resolution = self.topology.mesh.resolution + ghosts = self.topology.ghosts + dim = self.topology.dim + # Do the send/recv as defined in setup. + #### if args is None: \todo : A verifier. +# args = self.fieldslist +# self.fieldslist = np.asarray([self.fieldslist]) + if (self.transferMethod == 'SendRecv'): + for f in fieldslist: + # DOWN + if (main_rank != self.SendRecvList[0]): + self.dataSendZ = f[j][:, :, ghosts[2]:2. * ghosts[2]] + main_comm.Sendrecv( + self.dataSendZ, + dest=self.SendRecvList[0], + sendtag=22, + recvbuf=self.dataRecvZ, + source=main_rank, + recvtag=11, status=None) + f[j][:, :, resolution[2] - ghosts[2]: resolution[2]] = \ + self.dataRecvZ + else: + f[j][:, :, resolution[2] - ghosts[2]: resolution[2] + ] = f[j][:, :, ghosts[2]:2 * ghosts[2]] + # UP + if (main_rank != self.SendRecvList[1]): + self.dataSendZ = np.array(np.copy(f[j][ + :, :, + resolution[2] - ghosts[2]:resolution[2]], + order=ORDER, dtype=PARMES_REAL)) + main_comm.Sendrecv( + self.dataSendZ, + dest=self.SendRecvList[1], + sendtag=11, + recvbuf=self.dataRecvZ, + source=main_rank, + recvtag=22, status=None) + else: + f[j][:, :, ghosts[2]:2 * ghosts[2] + ] = \ + f[j][:, :, resolution[2] - ghosts[2]:resolution[2]] + # SOUTH + if (main_rank != self.SendRecvList[2]): + self.dataSendY = f[j][:, ghosts[1]:2. * ghosts[1], :] + main_comm.Sendrecv( + self.dataSendY, + dest=self.SendRecvList[2], + sendtag=44, + recvbuf=self.dataRecvY, + source=main_rank, + recvtag=33, status=None) + f[j][:, resolution[2] - ghosts[2]:resolution[2], :] \ + = self.dataRecvY + else: + f[j][:, resolution[1] - ghosts[1]:resolution[1], : + ] = f[j][:, ghosts[1]:2 * ghosts[1], :] + # NORTH + if (main_rank != self.SendRecvList[3]): + self.dataSendY = np.array(np.copy(f[j][ + :, + resolution[1] - ghosts[1]:resolution[1], + :], + order=ORDER, dtype=PARMES_REAL)) + main_comm.Sendrecv( + self.dataSendY, + dest=self.SendRecvList[3], + sendtag=33, + recvbuf=self.dataRecvY, + source=main_rank, + recvtag=44, status=None) + else: + f[j][:, ghosts[1]:2 * ghosts[1], :] =\ + f[j][:, resolution[1] - ghosts[1]:resolution[1], :] + # EAST + if (main_rank != self.SendRecvList[4]): + self.dataSendX = f[j][ghosts[0]:2. * ghosts[0], :, :] + main_comm.Sendrecv( + self.dataSendX, + dest=self.SendRecvList[4], + sendtag=66, + recvbuf=self.dataRecvX, + source=main_rank, + recvtag=55, status=None) + f[j][resolution[0] - ghosts[0]:resolution[0], :, :] \ + = self.dataRecvX + else: + f[j][resolution[0] - ghosts[0]:resolution[0], :, : + ] = f[j][:, :, ghosts[2]:2 * ghosts[2]] + # WEST + if (main_rank != self.SendRecvList[5]): + self.dataSendX = np.array(np.copy(f[j][ + resolution[0] - ghosts[0]:resolution[0], + :, :], + order=ORDER, dtype=PARMES_REAL)) + main_comm.Sendrecv( + self.dataSendX, + dest=self.SendRecvList[5], + sendtag=55, + recvbuf=self.dataRecvX, + source=main_rank, + recvtag=66, status=None) + else: + f[j][ghosts[0]:2 * ghosts[0], :, :] =\ + f[j][resolution[0] - ghosts[0]:resolution[0], :, :] + + if (self.transferMethod == 'greaterSend'): + for f in self.fieldslist: +# print 'tabsort', main_rank, self.tabSort + for i in xrange(self.tabSort[:, 0].shape[0]): +# print 'Cours', main_rank, self.tabSort[i, :] + if (main_rank == self.tabSort[i, 0]): + ## Without communication + # WEST + if (self.tabSort[i, 1] == 0): + for j in xrange(dim): + #print '\nTEST', resolution, f[j][...].shape, '\t' , ghosts + f[j][resolution[0] - ghosts[0]: resolution[0], + :, :] =\ + f[j][ghosts[0]:2 * ghosts[0], :, :] + # EAST + if (self.tabSort[i, 1] == 1): + for j in xrange(dim): + f[j][0:ghosts[0], :, :] =\ + f[j][ + resolution[0] - 2 * + ghosts[0]:resolution[0] - ghosts[0], + :, :] + + # SOUTH + if (self.tabSort[i, 1] == 2): + for j in xrange(dim): + f[j][:, resolution[1] - + ghosts[1]:resolution[1], :] =\ + f[j][:, ghosts[1]:2 * ghosts[1], :] + #NORTH + if(self.tabSort[i, 1] == 3): + for j in xrange(dim): + f[j][:, 0:ghosts[1], :] =\ + f[j][ + :, + resolution[1] - 2 * + ghosts[1]:resolution[1] - ghosts[1], + :] + + # DOWN + if(self.tabSort[i, 1] == 4): + for j in xrange(dim): + f[j][:, :, resolution[2] - + ghosts[2]:resolution[2]] =\ + f[j][:, :, ghosts[2]:2 * ghosts[2]] + # UP + if(self.tabSort[i, 1] == 5): + for j in xrange(dim): + f[j][:, :, 0:ghosts[2]] =\ + f[j][ + :, :, + resolution[2] - 2 * + ghosts[2]:resolution[2] - ghosts[2]] +# print 'ok', main_rank, self.tabSort[i, :] + else: + ### PART COMMUNICATION + # WEST + if(self.tabSort[i, 1] == 0): + if (main_rank < self.tabSort[i, 0]): + self.WESTsend(self.tabSort[i, 0], f) + else: + self.WESTrecv(self.tabSort[i, 0], f) + # EST + if (self.tabSort[i, 1] == 1): + if (main_rank < self.tabSort[i, 0]): + self.EASTsend(self.tabSort[i, 0], f) + else: + self.EASTrecv(self.tabSort[i, 0], f) + # SOUTH + if(self.tabSort[i, 1] == 2): + if (main_rank < self.tabSort[i, 0]): + self.SOUTHsend(self.tabSort[i, 0], f) + else: + self.SOUTHrecv(self.tabSort[i, 0], f) + # NORTH + if (self.tabSort[i, 1] == 3): + if (main_rank < self.tabSort[i, 0]): + self.NORTHsend(self.tabSort[i, 0], f) + else: + self.NORTHrecv(self.tabSort[i, 0], f) + # DOWN + if (self.tabSort[i, 1] == 4): + if (main_rank < self.tabSort[i, 0]): + self.DOWNsend(self.tabSort[i, 0], f) + else: + self.DOWNrecv(self.tabSort[i, 0], f) + # UP + if (self.tabSort[i, 1] == 5): + if (main_rank < self.tabSort[i, 0]): + self.UPsend(self.tabSort[i, 0], f) + else: + self.UPrecv(self.tabSort[i, 0], f) +# print 'ok', main_rank, self.tabSort[i, :] +# return self.discreteOperator.apply(*args) + + def TabInvSort(self, tab): + tmp = tab[0, 0] + deb = 0 + tabcont = 0 + tabfinal = np.copy(tab) + if tab[:, 0].shape[0] == 1: + return tab + for i in xrange(1, tab[:, 0].shape[0]): + if tmp == tab[i, 0]: + tabcont = tabcont + 1 + else: + tmp = tab[i, 0] + if tabcont == 0: + tabfinal[deb, :] = tab[deb, :] + else: + tabNew = tab[deb:i, :] +# for l in xrange(int(tabNew[:,1].shape[0] / 2)): +# tmp = tabNew[2 * l, 1] +# tabNew[2 * l, 1] = tabNew[2 * l + 1,1] +# tabNew[2 * l + 1, 1] = tmp + tabNew = tabNew[np.invert(tabNew[:, 1].argsort())] + tabfinal[deb:i, :] = tabNew + deb = i + tabcont = 0 + if deb == tab[:, 0].shape[0]: + tabfinal[deb, :] = tab[deb, :] + if tabcont > 0: + tabNew = tab[deb:tab[:, 0].shape[0], :] + tabNew = tabNew[np.invert(tabNew[:, 1].argsort())] + tabfinal[deb:tab[:, 0].shape[0], :] = tabNew + return tabfinal + + def WESTsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendX = np.array(np.copy(listFields[i][ + ghosts[0]:ghosts[0] * 2, :, :]), order=ORDER) + main_comm.Ssend(self.dataSendX, dest=proc, tag=66) + main_comm.Recv(self.dataSendX, source=proc, tag=55) + listFields[i][0:ghosts[0], :, :] = self.dataSendX + + def EASTsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendX = np.array(np.copy(listFields[i][ + resolution[0] - 2 * ghosts[0]:resolution[0] - ghosts[0], + :, :]), + order=ORDER) + main_comm.Ssend(self.dataSendX, dest=proc, tag=66) + main_comm.Recv(self.dataSendX, source=proc, tag=55) + listFields[i][resolution[0] - ghosts[0]:resolution[0], :, :] =\ + self.dataSendX + + def SOUTHsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendY = np.array(np.copy(listFields[i][ + :, ghosts[1]:2 * ghosts[1], :]), order=ORDER) + main_comm.Ssend(self.dataSendY, dest=proc, tag=44) + main_comm.Recv(self.dataSendY, source=proc, tag=33) + listFields[i][:, 0:ghosts[1], :] = self.dataSendY + + def NORTHsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendY = np.array(np.copy(listFields[i][ + :, + resolution[1] - 2 * ghosts[1]:resolution[1] - ghosts[1], :]), + order=ORDER) + main_comm.Ssend(self.dataSendY, dest=proc, tag=33) + main_comm.Recv(self.dataSendY, source=proc, tag=44) + listFields[i][:, resolution[1] - ghosts[1]:resolution[1], :] =\ + self.dataSendY + + def DOWNsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendZ = np.array(np.copy(listFields[i][ + :, :, ghosts[2]:2 * ghosts[2]]), order=ORDER) + main_comm.Ssend(self.dataSendZ, dest=proc, tag=11) + main_comm.Recv(self.dataSendZ, source=proc, tag=22) + listFields[i][:, :, 0:ghosts[2]] = self.dataSendZ + + def UPsend(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + self.dataSendZ = np.array(np.copy(listFields[i][ + :, :, + resolution[2] - 2 * ghosts[2]:resolution[2] - ghosts[2] + ]), order=ORDER) + main_comm.Ssend(self.dataSendZ, dest=proc, tag=22) + main_comm.Recv(self.dataSendZ, source=proc, tag=11) + listFields[i][ + :, :, + resolution[2] - ghosts[2]:resolution[2]] =\ + self.dataSendZ + + def WESTrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendX, source=proc, tag=66) + listFields[i][0:ghosts[0], :, :] = self.dataSendX + self.dataSendX = np.array(np.copy(listFields[i][ + ghosts[0]:2 * ghosts[0], :, :]), order=ORDER) + main_comm.Ssend(self.dataSendX, dest=proc, tag=55) + + def EASTrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendX, source=proc, tag=66) + listFields[i][resolution[0] - ghosts[0]:resolution[0], :, :] =\ + self.dataSendX + self.dataSendX = np.array(np.copy(listFields[i][ + resolution[0] - 2 * ghosts[0]:resolution[0] - ghosts[0], + :, :]), + order=ORDER) + main_comm.Ssend(self.dataSendX, dest=proc, tag=55) + + def SOUTHrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendY, source=proc, tag=33) + listFields[i][:, 0:ghosts[1], :] = self.dataSendY + self.dataSendY = np.array(np.copy(listFields[i][ + :, ghosts[1]:2 * ghosts[1], :]), order=ORDER) + main_comm.Ssend(self.dataSendY, dest=proc, tag=44) + + def NORTHrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendY, source=proc, tag=44) + listFields[i][:, resolution[1] - ghosts[1]:resolution[1], :] =\ + self.dataSendY + self.dataSendY = np.array(np.copy(listFields[i][ + :, resolution[1] - 2 * ghosts[1]:resolution[1] - + ghosts[1], :]), + order=ORDER) + main_comm.Ssend(self.dataSendY, dest=proc, tag=33) + + def DOWNrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendZ, source=proc, tag=22) + listFields[i][:, :, 0:ghosts[2]] = self.dataSendZ + data = np.array(np.copy(listFields[i][ + :, :, ghosts[2]:ghosts[2] * 2]), order=ORDER) + main_comm.Ssend(self.dataSendZ, dest=proc, tag=11) + + def UPrecv(self, proc, listFields): + ghosts = self.topology.ghosts + resolution = self.resolution + for i in xrange(self.topology.dim): + main_comm.Recv(self.dataSendZ, source=proc, tag=11) + listFields[i][:, :, resolution[2] - ghosts[2]:resolution[2]] =\ + self.dataSendZ + self.dataSendZ = np.array(np.copy(listFields[i][ + :, :, + resolution[2] - 2 * ghosts[2]:resolution[2] - ghosts[2] + ]), order=ORDER) + main_comm.Ssend(self.dataSendZ, dest=proc, tag=22) + + +if (__name__ == "__main__"): + print __doc__ + print "- Provided class : SynchronizeGhosts" + print SynchronizeGhosts_d.__doc__ diff --git a/HySoP/unusedOrObsolet/test_cpu_data_tranfert.py b/HySoP/unusedOrObsolet/test_cpu_data_tranfert.py new file mode 100755 index 000000000..991ffeb8b --- /dev/null +++ b/HySoP/unusedOrObsolet/test_cpu_data_tranfert.py @@ -0,0 +1,93 @@ +# -*- coding: utf-8 -*- +import time +import parmepy as pp +import numpy as np +from parmepy.tools.cpu_data_transfer import Synchronize +from parmepy.tools.printer import Printer +from math import * +import unittest + + + +class test_Cpu_data_transfert(unittest.TestCase): + """ + DiscreteVariable test class + """ + + def vitesse(self,x, y, z): + vx = x + vy = y + vz = z + return vx, vy, vz + + + def analyticalDivProduct(self, x, y, z): + sx = np.cos(x) + sy = np.cos(y) + sz = np.cos(z) + return sx, sy, sz + + def setUp(self): + nb = 32. + # Parameters + self.finalTime = 0.09 + self.t = 0. + self.e = 0.002 # Accepted error between result and analytical result + self.dim = 3 + self.boxLength = [1., 1., 1.] + self.boxMin = [ 0., 0., 0.] + self.nbPts = [nb, nb, nb] + self.timeStep = 0.02 + self.comm = main_comm + self.outputFilePrefix0 = './parmepy/test/test_tools/INIT_' + self.outputFilePrefix = './parmepy/test/test_tools/Trans_' + ## Domain + self.box = pp.Box(dimension=self.dim, + length=self.boxLength, + origin=self.boxMin) + + def testOperatorSynchronize(self): + t0 = time.time() + + ## Fields + velo = pp.AnalyticalField(domain=self.box, formula=self.vitesse, name='Velocity', vector=True) + + ## Solver creation (discretisation of objects is done in solver initialisation) + topo3D = pp.CartesianTopology(domain=self.box, resolution=self.nbPts, dim=self.dim, periods=[True,True,True] ,ghosts=[2.,2.,2.]) + + +# self.anal=np.asarray(np.vectorize(self.analyticalDivProduct)(self.topo3D.mesh.coords[0], \ +# self.topo3D.mesh.coords[1], \ +# self.topo3D.mesh.coords[2])) + + OpSynchronize = Synchronize(topo3D) + ## Discretization + velo.discretize(topo3D) + velo.initialize() + t1 = time.time() +# print 'rank', topo3D.rank, 'tab', topo3D.tabSort + io = Printer(fields=[velo], frequency=1, outputPrefix=self.outputFilePrefix0+str(topo3D.rank)) +# io.step() + OpSynchronize.apply(velo.discreteField[0]) + io = Printer(fields=[velo], frequency=1, outputPrefix=self.outputFilePrefix+str(topo3D.rank)) + io.step() + + tf = time.time() +# print 'velo :', velo.discreteField[0].data[0][:,0,0],velo.discreteField[0].data[0][:,1,1] + + print "\n" + print "Total time : ", tf - t0, "sec (CPU)" + print "Init time : ", t1 - t0, "sec (CPU)" + print "Solving time : ", tf - t1, "sec (CPU)" + + + def runTest(self): + self.testOperatorSynchronize() + +def suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(test_Cpu_data_transfert)) + return suite + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) diff --git a/README b/README new file mode 100644 index 000000000..a9760ebc5 --- /dev/null +++ b/README @@ -0,0 +1,10 @@ +FFTPAR02COR : code Guillaume, version 17/20/2011 + +Remesh/ +Split2d, Split3d : code d'Adrien +4GB, FFTPAR : morceaux de code de GH et Guillaume, à trier. + +NavierStokes3D-Penalization : code d'Adrien + + + diff --git a/SandBox/ppm_interface/README b/SandBox/ppm_interface/README new file mode 100644 index 000000000..8efc64d02 --- /dev/null +++ b/SandBox/ppm_interface/README @@ -0,0 +1,28 @@ +To create ppm interface ... + + +1 - Create signature file : + +f2py -h interf2ppm.pyf -m interf2ppm interf2ppm.f95 + +2 - edit (optional ...) the generated pyf file + +3 - f2py --fcompiler=gfortran -m interf2ppm interf2ppm.pyf interf2ppm.f95 -c -I/home/perignon/install/ppm-core/include/Modules/ -I/usr/lib/openmpi/lib -L/home/perignon/install/ppm-core/lib -lppm_core -L/usr/lib/openmpi/lib -lmpi_f90 -lmpi_f77 -lmpi -lopen-rte -lopen-pal -ldl -I/usr/lib/openmpi/include + + +Dans python + +import interf2ppm +import mpi4py.MPI as mpi +print interf2ppm.interf2ppm.init.__doc__ +print interf2ppm.interf2ppm.finalize.__doc__ + +interf2ppm.interf2ppm.init(debug=2) + +info = interf2ppm.interf2ppm.finalize() + +ou en ligne de commande: + +mpirun -np 2 python runPPM.py + + diff --git a/SandBox/ppm_interface/interf2ppm.f95 b/SandBox/ppm_interface/interf2ppm.f95 new file mode 100644 index 000000000..d7593611f --- /dev/null +++ b/SandBox/ppm_interface/interf2ppm.f95 @@ -0,0 +1,33 @@ +module interf2ppm + + use ppm_module_init + use ppm_module_finalize + use ppm_module_data + use mpi + + implicit none + +contains + + subroutine init(dime,prec,tol,debug) + + integer, intent(in) :: dime + integer, intent(in) :: prec + integer, intent(in) :: tol + integer, intent(in) :: debug + + integer :: info, comm + comm = MPI_COMM_WORLD + + call ppm_init(dime,prec,tol,comm,debug,info) + + end subroutine init + + subroutine finalize(info) + integer, intent(out) :: info + + call ppm_finalize(info) + + end subroutine finalize + +end module interf2ppm diff --git a/SandBox/ppm_interface/interf2ppm.pyf b/SandBox/ppm_interface/interf2ppm.pyf new file mode 100644 index 000000000..a388a14b5 --- /dev/null +++ b/SandBox/ppm_interface/interf2ppm.pyf @@ -0,0 +1,26 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +python module interf2ppm ! in + interface ! in :interf2ppm + module interf2ppm ! in :interf2ppm:interf2ppm.f95 + use ppm_module_data + use ppm_module_ +finalize + use ppm_module_init + use mpi + subroutine init(dime,prec,tol,debug) ! in :interf2ppm:interf2ppm.f95:interf2ppm + integer optional :: dime = 3 + integer optional :: prec = 8 + integer optional :: tol = -10 + integer optional :: debug = 0 + end subroutine init + subroutine finalize(info) ! in :interf2ppm:interf2ppm.f95:interf2ppm + integer intent(out) :: info + end subroutine finalize + end module interf2ppm + end interface +end python module interf2ppm + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/SandBox/ppm_interface/interf2ppm.pyf.modif b/SandBox/ppm_interface/interf2ppm.pyf.modif new file mode 100644 index 000000000..a388a14b5 --- /dev/null +++ b/SandBox/ppm_interface/interf2ppm.pyf.modif @@ -0,0 +1,26 @@ +! -*- f90 -*- +! Note: the context of this file is case sensitive. + +python module interf2ppm ! in + interface ! in :interf2ppm + module interf2ppm ! in :interf2ppm:interf2ppm.f95 + use ppm_module_data + use ppm_module_ +finalize + use ppm_module_init + use mpi + subroutine init(dime,prec,tol,debug) ! in :interf2ppm:interf2ppm.f95:interf2ppm + integer optional :: dime = 3 + integer optional :: prec = 8 + integer optional :: tol = -10 + integer optional :: debug = 0 + end subroutine init + subroutine finalize(info) ! in :interf2ppm:interf2ppm.f95:interf2ppm + integer intent(out) :: info + end subroutine finalize + end module interf2ppm + end interface +end python module interf2ppm + +! This file was auto-generated with f2py (version:2). +! See http://cens.ioc.ee/projects/f2py2e/ diff --git a/SandBox/ppm_interface/runPPM.py b/SandBox/ppm_interface/runPPM.py new file mode 100644 index 000000000..a5394474d --- /dev/null +++ b/SandBox/ppm_interface/runPPM.py @@ -0,0 +1,9 @@ +import interf2ppm +import mpi4py.MPI as mpi + +print interf2ppm.interf2ppm.init.__doc__ +print interf2ppm.interf2ppm.finalize.__doc__ + +interf2ppm.interf2ppm.init(debug=2) + +info = interf2ppm.interf2ppm.finalize() diff --git a/SandBox/src/Mesh.hpp b/SandBox/src/Mesh.hpp new file mode 100644 index 000000000..4fc1107e9 --- /dev/null +++ b/SandBox/src/Mesh.hpp @@ -0,0 +1,47 @@ +#ifndef MESHHPP +#define MESHHPP +#include<iostream> +class Mesh { + +public : + Mesh(int *a, int *b, int *c,double*d) + { + nx = *a; + ny = *b; + nz = *c; + *geometry = *d; + grid = new double(nx*ny*nz); + for (int i = 0; i <nx*ny*nz ; ++i) + { + grid[i] = i*2.5; + std::cout << grid[i] << " " ; + } + std::cout << std::endl; + std::cout << "Constr Mesh " << std::endl; + + } + + Mesh(double*d) + { + *geometry = *d; + std::cout << "Constr Mesh " << std::endl; + + } + + + ~Mesh(){std::cout<< "del Mesh " << std::endl;} + + double *getGrid() const {return grid;} + int getSizeX() const {return nx;} + int getSizeY() const{return ny;} + int getSizeZ() const{return nz;} + +private: + + double * grid; + int nx, ny, nz; + double geometry[4]; +}; + +#endif + diff --git a/SandBox/src/MeshModule.f90 b/SandBox/src/MeshModule.f90 new file mode 100644 index 000000000..b73d2c75f --- /dev/null +++ b/SandBox/src/MeshModule.f90 @@ -0,0 +1,68 @@ +MODULE MeshModule + + implicit none + + + PUBLIC initMesh, initMesh2, getGrid, deleteMesh, aliasGrid, getPtr, alias + PRIVATE + + INTEGER :: nx, ny, nz + REAL*8, pointer :: grid(:,:,:) + real(kind =8), pointer :: fptr(:) + +CONTAINS + + SUBROUTINE initMesh(L,M,N,g) + INTEGER :: L,M,N + REAL*8 :: g(4) + CALL cinitmesh(L,M,N,g) + end SUBROUTINE initMesh + + SUBROUTINE initMesh2(L,M,N,g) + INTEGER :: L,M,N + REAL*8 :: g(4) + CALL cinitmesh(g) + end SUBROUTINE initMesh2 + + SUBROUTINE aliasGrid(n1,n2,n3,a) + INTEGER :: n1,n2,n3 + REAL*8, TARGET :: a(n1,n2,n3) + nx = n1 + ny = n2 + ny = n3 + print *, 'alias ... ', a(2,1,1) + grid => a(1:nx,1:ny,1:nz) + print *, grid(2,1,1) + print *, 'end alias ' + end SUBROUTINE aliasGrid + + SUBROUTINE alias(n1,a) + INTEGER :: n1 + REAL(kind=8), TARGET :: a(n1) + nx = n1 + print *, 'alias ... ' + fptr => a(1:nx) + print *, 'end alias ' + end SUBROUTINE alias + + SUBROUTINE deleteMesh() + CALL cdeleteMesh() + END SUBROUTINE deleteMesh + + + FUNCTION getGrid() result(p) + REAL*8, POINTER :: p(:,:,:) + CALL cgetGrid() + p => grid(1:nx,1:ny,1:nz) + end FUNCTION getGrid + + function getPtr() result(p) + real(kind=8), pointer :: p(:) + call cgetptr() + p=>fptr(1:nx) + end function getPtr + + + + +end MODULE MeshModule diff --git a/SandBox/src/modTest.f90 b/SandBox/src/modTest.f90 new file mode 100644 index 000000000..1fecf042e --- /dev/null +++ b/SandBox/src/modTest.f90 @@ -0,0 +1,179 @@ +module modTest + +implicit none + +contains + + subroutine testglob() + + real(kind=8), dimension(:), pointer :: vec + allocate(vec(4)) + vec = 3.4 + + call cas6(vec) + print *, ' test ....', vec + + if(associated(vec)) then + print *, 'free ' + deallocate(vec) + nullify(vec) + end if + + end subroutine testglob + + subroutine cas1(x) + + real*8, dimension(2) :: x + + x(2) = x(2) +1.65 + print *, 'cas 1', x(1), ' ', x(2) + + end subroutine cas1 + + subroutine cas2(x) + + real*8, dimension(*), intent(inout) :: x + + + print *, 'cas2a', x(1), ' ', x(2) + + x(2) = x(2) +1.65 + print *, 'cas 2b', x(1), ' ', x(2) + + end subroutine cas2 + + subroutine cas3(x) + + real(kind=8), dimension(:), intent(in) :: x + + + print *, 'cas3a', x(1), ' ', x(2) + + end subroutine cas3 + subroutine cas4(x) + + real(kind=8), dimension(:), intent(inout) :: x + + + print *, 'cas3a', x(1), ' ', x(2) + + x(2) = x(2) +1.65 + print *, 'cas 3b', x(1), ' ', x(2) + + end subroutine cas4 + + subroutine cas5(x) + + !! integer, intent(in) :: size + real(kind=8), pointer, dimension(:) :: x + + allocate(x(2)) + x(1) =12 + x(2) = 8 + print *, 'cas5a', x(1), ' ', x(2) + + x(2) = 1.65 + print *, 'cas 5b', x(1), ' ', x(2) + print * , x + end subroutine cas5 + + subroutine cas6(x) + + !! integer, intent(in) :: size + real(kind=8), pointer, dimension(:) :: x + + x(1) =12 + x(2) = 8 + !print *, 'cas6a', shape(x), ' ', x(1), ' ', x(2) + + x(2) = 1.65 + print *, 'cas 6b', x(1), ' ', x(2) + print * , x + + end subroutine cas6 + + + subroutine Application() + USE MeshModule, ONLY : initMesh, getGrid, deleteMesh + + INTEGER :: n1, n2, n3 + REAL*8 :: geometry(3,3) + REAL*8, pointer :: grid(:,:,:) + print *, 'start applic ...' + READ(*,*)n1, n2, n3, geometry(1:2,1:2) + CALL initMesh(n1, n2, n3, geometry) + + grid => getGrid() + print *, 'shape ', shape(grid) + print *, 'grid : ', grid(2,1,1) + print *, 'end appli ...' + CALL deleteMesh() + + end subroutine Application + subroutine Application2() + USE MeshModule, ONLY : initMesh2, getGrid, deleteMesh + + INTEGER :: n1, n2, n3 + REAL*8 :: geometry(3,3) + REAL*8, pointer :: grid(:,:,:) + print *, 'start applic2 ...' + !!READ(*,*)n1, n2, n3, geometry(1:2,1:2) + geometry = 12 + n1 = 2 + n2 = 3 + n3 = 4 + CALL initMesh2(n1, n2, n3, geometry) + + grid => getGrid() + allocate(grid(n1,n2,n3)) + grid(2,1,1) = 12.4 + print *, 'shape ', shape(grid) + print *, 'grid : ', grid(2,1,1) + print *, 'end appli2 ...' + CALL deleteMesh() + + end subroutine Application2 + subroutine Application3() + USE MeshModule, ONLY : getPtr, deleteMesh + + INTEGER :: nx + REAL(kind=8), pointer :: xp(:) + print *, 'start applic3 ...' + + nx = 4 + xp => getPtr() + allocate(xp(nx)) + xp = 12.4 + print *, 'shape ', shape(xp) + print *, 'xp : ', xp(1:nx) + print *, 'end appli3 ...' + !! CALL deleteMesh() + + end subroutine Application3 + + SUBROUTINE bridge(nx, ny, nz, a) + USE MeshModule, only: aliasGrid + INTEGER, INTENT(IN) :: nx,ny,nz + REAL*8, INTENT(IN) :: a(nx*ny*nz) + + print *, "BRIDGE ", a(2) + + CALL aliasGrid(nx, ny, nz, a) + + print *, 'end bridge' + END SUBROUTINE bridge + + SUBROUTINE bridge2(nx, a) + USE MeshModule, only: alias + INTEGER, INTENT(IN) :: nx + REAL*8, INTENT(IN) :: a(nx) + + print *, "BRIDGE 2" + + CALL alias(nx,a) + + print *, 'end bridge2 ' + END SUBROUTINE bridge2 + + +end module modTest diff --git a/SandBox/src/ppm_wrapper.hpp b/SandBox/src/ppm_wrapper.hpp new file mode 100644 index 000000000..168c56d35 --- /dev/null +++ b/SandBox/src/ppm_wrapper.hpp @@ -0,0 +1,152 @@ +/** \file ppm_wrapper.hpp Interfaces to ppm (fortran) routines + */ +#ifndef PPMWRAPPER_HPP +#define PPMWRAPPER_HPP +#include"FCMangle.h" +#include<mpi.h> +#include <cstring> +#include "Mesh.hpp" + +/** Namespace for ppm functions and subroutines */ + +Mesh* p_obj = 0; +double * globalPtr = 0; + +namespace PPM +{ + + + + + extern "C" { + // Init and close ppm + void PPM_MODULE(ppm_module_init,ppm_init, PPM_MODULE_INIT,PPM_INIT)(int*, int*,int*,int*,int*,int*,int*,int*,int*); + void PPM_MODULE(ppm_module_finalize, ppm_finalize,PPM_MODULE_FINALIZE,PPM_FINALIZE)(int&); + // Display functions + void PPM_MODULE(charfunctions, start, CHARFUNCTIONS, START)(double*,int*,char*,int ); + void PPM_MODULE(charfunctions, stop, CHARFUNCTIONS, stop)(double*,int*,char*,int ); + + void PPM_MODULE(testppm,mult,TESTPPM,MULT)(double*,double*,int*); + // Topologies + // void PPM_MODULE(ppm_module_mktopo, ppm_mktopo, PPM_MODULE_MKTOPO,PPM_MKTOPO)(int*, double*, int*, + + void PPM_MODULE(modtest, cas1, MODTEST,CAS1)(double*); + void PPM_MODULE(modtest, cas2, MODTEST,CAS2)(double*); + void PPM_MODULE(modtest, cas3, MODTEST,CAS3)(double*); + void PPM_MODULE(modtest, cas4, MODTEST,CAS4)(double*); + void PPM_MODULE(modtest, cas5, MODTEST,CAS5)(double*); + void PPM_MODULE(modtest, cas6, MODTEST,CAS6)(double**); + void PPM_MODULE(modtest, testglob, MODTEST,TESTGLOB)(); + void PPM_MODULE(modtest, application, MODTEST,APPLICATION)(); + void PPM_MODULE(modtest, application2, MODTEST,APPLICATION2)(); + void PPM_MODULE(modtest, application3, MODTEST,APPLICATION3)(); + void PPM_MODULE(modtest, bridge, MODTEST,BRIDGE)(int*,int*,int*,double*); + void PPM_MODULE(modtest, bridge2, MODTEST,BRIDGE2)(int*,double*); + + // int PPM_MODULE(ppm_module_data,ppm_debug, PPM_MODULE_DATA,PPM_DEBUG); + + + + + } + + //#define DEBUG PPM_MODULE_(ppm_module_data,ppm_debug, PPM_MODULE_DATA,PPM_DEBUG) + + /** A static class to call wrapped ppm functions */ + class wrapper + { + + static int _info; + + public : + + /** PPM initialization + \param problem dimension + \param precision for real numbers + \param exp tolerance + \param MPI comm + \param debug mode value + \param error status + \param log unit value for io + \param stderr unit value + \param stdout unit value + */ + static void init(int ndim, int MK,int tolexp, MPI::Intracomm& comm, int debug, int* info, int ppm_log_unit, int err, int out) + { + MPI_Fint Fcomm = MPI_Comm_c2f(comm); + PPM_MODULE(ppm_module_init,ppm_init, PPM_MODULE_INIT,PPM_INIT)(&ndim,&MK,&tolexp,&Fcomm,&debug,info,&ppm_log_unit,&err,&out); + } + + /** Terminates ppm library + \param[in,out] error status + */ + static void finalize(int& info) + { + PPM_MODULE(ppm_module_finalize, ppm_finalize,PPM_MODULE_FINALIZE,PPM_FINALIZE)(info); + } + + /** Wrapper to ppm substart function + @param[in] caller name + @param[in,out] cpu time when this function is called + @param[in] error status + */ + static void substart(std::string& msg, double* t0, int* info) + { + size_t size = msg.size()+1; + char * msgF = new char[size]; + strncpy(msgF, msg.c_str(),size); + PPM_MODULE(charfunctions, start, CHARFUNCTIONS, START)(t0,info,msgF,strlen(msgF)); + } + + /** Wrapper to ppm substopt function + @param[in] caller name + @param[in] cpu time when substart for this function has been called + @param[in] error status + */ + static void substop(std::string& msg, double* t0, int* info) + { + size_t size = msg.size()+1; + char * msgF = new char[size]; + strncpy(msgF, msg.c_str(),size); + PPM_MODULE(charfunctions, stop, CHARFUNCTIONS, STOP)(t0,info,msgF,strlen(msgF)); + } + + }; + +} + extern "C" { + void cinitmesh_(int *nx, int *ny, int *nz, double *geom) { + p_obj = new Mesh(nx,ny,nz,geom); + } + + + void cdeletemesh_() { delete p_obj; } + + void cgetgrid_() { + std::cout << "cgetgrid ..." << std::endl; + double *p_mem = p_obj->getGrid(); + int nx = p_obj->getSizeX(); + int ny = p_obj->getSizeY(); + int nz = p_obj->getSizeZ(); + std::cout << p_mem[1] << std::endl; + PPM::PPM_MODULE(modtest, bridge, MODTEST,BRIDGE)(&nx, &ny, &nz, p_mem); + p_mem = 0; + std::cout << "Fin cgetgrid ..." << std::endl; + } + + void cinit_(double* toto) + { + globalPtr = toto; + } + + void cgetptr_() { + std::cout << "cgetPtr ..." << std::endl; + double *p_mem = globalPtr; + int nx = 2; + PPM::PPM_MODULE(modtest, bridge2, MODTEST,BRIDGE2)(&nx, p_mem); + p_mem = 0; + std::cout << "Fin cgetptr ..." << std::endl; + } + } + +#endif diff --git a/todo.org b/todo.org index bc29ee25e..2dda25cb2 100644 --- a/todo.org +++ b/todo.org @@ -1,11 +1,4 @@ -========= -todo list -========= -Items should contain a brief description and a date of completion. - -* Redistributes MPI tag should depend on variables names. It prevent from mixing simultaneous async messages. - -* update/clean this file ... +Bilan réunion du 15/02/2012 * Tests operations sur tableaux (Franck) ** tests numpy : timer + mémoire *** operations algebriques linéaires -- GitLab