diff --git a/.gitmodules b/.gitmodules index 6e3fd50b51812a1f685daf8fec649be368904e06..6b30b305dd992cbc0eae8c5c1da296699017a1a4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,15 @@ [submodule "openfpm_vcluster"] path = openfpm_vcluster - url = ssh://git@ppmcore.mpi-cbg.de/incardon/openfpm_vcluster.git + url = ssh://git@git.mpi-cbg.de/openfpm/openfpm_vcluster.git [submodule "openfpm_devices"] path = openfpm_devices - url = ssh://git@ppmcore.mpi-cbg.de/incardon/openfpm_devices.git + url = ssh://git@git.mpi-cbg.de/openfpm/openfpm_devices.git [submodule "openfpm_io"] path = openfpm_io - url = ssh://git@ppmcore.mpi-cbg.de/incardon/openfpm_io.git + url = ssh://git@git.mpi-cbg.de/openfpm/openfpm_io.git [submodule "openfpm_data"] path = openfpm_data - url = ssh://git@ppmcore.mpi-cbg.de/incardon/openfpm_data.git + url = ssh://git@git.mpi-cbg.de/openfpm/openfpm_data.git [submodule "openfpm_numerics"] path = openfpm_numerics - url = ssh://git@ppmcore.mpi-cbg.de/incardon/openfpm_numerics.git + url = ssh://git@git.mpi-cbg.de/openfpm/openfpm_numerics.git diff --git a/CHANGELOG.md b/CHANGELOG.md index a7c64dd8d614791a26373e5639d545886e1a184c..738d4505251c4b2e185184286302d0b9177bd706 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,52 @@ # Change Log All notable changes to this project will be documented in this file. -## [0.5.1] - Mid september +## [0.6.0] - End October 2016 + +### Added +- Symmetric cell-list/verlet list +- Multi-phase cell-list and Multi-phase cell-list +- Added ghost_get that keep properties +- Examples: 1_ghost_get_put it show how to use ghost_get and put with the new options + 4_multiphase_celllist_verlet completely rewritten for new Cell-list and multiphase verlet + 5_molecular_dynamic use case of symmetric cell-list and verlet list with ghost put + 6_complex_usage It show how the flexibility of openfpm can be used to debug your program +- Plotting system can export graph in svg (to be included in the paper) + + +### Fixed +- Option NO_POSITION was untested +- Regression: Examples code compilation was broken on OSX (Affect only 0.5.1) + (Internal: Added OSX examples compilarion/running test in the release pipeline) +- gray_scott example code (variable not initialized) + + +### Changes + + +## [0.5.1] - 27 September 2016 ### Added - ghost_put support for particles -- Full-Support for complex property on vector-dist (Serialization) + example +- Full-Support for complex property on vector_dist (Serialization) +- Added examples for serialization of complex properties 4_Vector +- improved speed of the iterators ### Fixed - Installation PETSC installation fail in case of preinstalled MPI - Miss-compilation of SUITESPARSE on gcc-6.2 - vector_dist with negative domain (Now supported) - Grid 1D has been fixed +- One constructor of Box had arguments inverted. + PLEASE CAREFULL ON THIS BUG + float xmin[] = {0.0,0.0}; + float xmax[] = {1.0,1.0}; + // Box<2,float> box(xmax,xmin) BUG IT WAS xmax,xmin + Box<2,float> box(xmin,xmax) <--- NOW IT IS xmin,xmax + Box<2,float> box({0.0,0.0},{1.0,1.0}) <---- This constructor is not affected by the BUG ### Changed +- On gcc the -fext-numeric-literals compilation flag is now mandatory ## [0.5.0] - 15 August 2016 @@ -110,29 +143,26 @@ All notable changes to this project will be documented in this file. # Planned in the next Releases +## [0.9.0] - Mid March + +- Algebraic Multigrid solver +- Parallel VTK, improved visualization + ## [0.8.0] - Mid January 2017 -## [0.7.0] - December 2016 ### Added - Dynamic Load Balancies examples and interface fixation - Check Point restart - More example and documentations -### Proposal - -- Algebraic Multigrid solver -- Parallel VTK, improved visualization - -## [0.6.0] - Middle of October +## [0.7.0] - December of October ### Added +- Asynchronous communication +- Support for Microsoft Windows with Cygwin +- Support for Docker/codenvy +- Defining a domain an invalid domain like Box<2,float> box({0.0,1.0},{0.0,1.0}) (the correct is {0.0,0.0},{1.0,1.0} ) + produce dead-lock or unclear error message in SE_CLASS1, not hint is given, added usefull error message -- Symmetric Cell list and Verlet (15 days) -- Semantic communication (??) -- Improved Finite difference interface (15 days) - - -## [0.6.0] - Beginning of September -- Complex properties and serialization interface (15 days) diff --git a/Jenkins_high_scal_test b/Jenkins_high_scal_test new file mode 100644 index 0000000000000000000000000000000000000000..b7908b699e38937d8540b9bb8ca48c1a98e80de3 --- /dev/null +++ b/Jenkins_high_scal_test @@ -0,0 +1,25 @@ +#!groovy + +node ('taurus') +{ + deleteDir() + checkout scm + stage ('build_taurus') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata" + } + + stage ('run_taurus') + { + parallel ( + "24" : {sh "./run.sh $WORKSPACE $NODE_NAME 24 1 24"}, + "48" : {sh "./run.sh $WORKSPACE $NODE_NAME 48 2 24"}, + "96" : {sh "./run.sh $WORKSPACE $NODE_NAME 96 4 24"}, + "192" : {sh "./run.sh $WORKSPACE $NODE_NAME 192 8 24"}, + "240" : {sh "./run.sh $WORKSPACE $NODE_NAME 240 10 24"} + ) + } +} + + + diff --git a/Jenkins_med_scal_test b/Jenkins_med_scal_test new file mode 100644 index 0000000000000000000000000000000000000000..cd6fd5db3517c211257f74786391be26b60fa254 --- /dev/null +++ b/Jenkins_med_scal_test @@ -0,0 +1,23 @@ +#!groovy + +node ('gin') +{ + deleteDir() + checkout scm + stage ('build_gin') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata" + } + + stage ('run_gin') + { + sh "./run.sh $WORKSPACE $NODE_NAME 5" + sh "./run.sh $WORKSPACE $NODE_NAME 6" + sh "./run.sh $WORKSPACE $NODE_NAME 7" + sh "./run.sh $WORKSPACE $NODE_NAME 8" + sh "./run.sh $WORKSPACE $NODE_NAME 9" + sh "./run.sh $WORKSPACE $NODE_NAME 10" + sh "./run.sh $WORKSPACE $NODE_NAME 11" + } +} + diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..442596592fe166a9bf6c1d9b1969193100e7feb5 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,81 @@ +#!groovy + +parallel ( + + +"nyu" : {node ('nyu') + { + deleteDir() + checkout scm + stage ('build_nyu') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata" + } + + stage ('run_nyu') + { + parallel ( + "1" : {sh "./run.sh $WORKSPACE $NODE_NAME 1"}, + "2" : {sh "./run.sh $WORKSPACE $NODE_NAME 2"}, + "3" : {sh "./run.sh $WORKSPACE $NODE_NAME 3"}) + sh "./run.sh $WORKSPACE $NODE_NAME 5" + sh "./success.sh 2 nyu opefpm_pdata" + } + } + }, + + + + +"sb15" : {node ('sbalzarini-mac-15') + { + deleteDir() + env.PATH = "/usr/local/bin:${env.PATH}" + checkout scm + stage ('build_sb15') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata" + } + + stage ('run_sb15') + { + parallel ( + "1" : {sh "./run.sh $WORKSPACE $NODE_NAME 1"}, + "2" : {sh "./run.sh $WORKSPACE $NODE_NAME 2"}, + "3" : {sh "./run.sh $WORKSPACE $NODE_NAME 3"} + ) + sh "./run.sh $WORKSPACE $NODE_NAME 4" + sh "./run.sh $WORKSPACE $NODE_NAME 5" + sh "./run.sh $WORKSPACE $NODE_NAME 6" + sh "./run.sh $WORKSPACE $NODE_NAME 7" + sh "./success.sh 2 sbalzarini-mac-15 opefpm_pdata" + } + } + }, + + +"gin" : {node ('gin') + { + deleteDir() + env.PATH = "/usr/local/bin:${env.PATH}" + checkout scm + stage ('build_gin') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata" + } + + stage ('run_gin') + { + parallel ( + "p1" : {sh "./run.sh $WORKSPACE $NODE_NAME 1"}, + "p2" : {sh "./run.sh $WORKSPACE $NODE_NAME 2"}, + "p3" : {sh "./run.sh $WORKSPACE $NODE_NAME 3"}, + "p4" : {sh "./run.sh $WORKSPACE $NODE_NAME 5"} + ) + sh "./success.sh 2 gin opefpm_pdata" + } + } + } + +) + diff --git a/Jenkinsfile_examples_test b/Jenkinsfile_examples_test new file mode 100644 index 0000000000000000000000000000000000000000..abd390c12b0efff3b8aabe342d5cae656f9d0b01 --- /dev/null +++ b/Jenkinsfile_examples_test @@ -0,0 +1,37 @@ +#!groovy + +parallel ( + +"gin" : {node ('gin') + { + deleteDir() + checkout scm + stage ('build_gin') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata full && make install" + } + + stage ('run_example_gin') + { + sh "source $HOME/openfpm_vars && cd example && make" + } + }}, + +"sb15" : {node ('sbalzarini-mac-15') + { + deleteDir() + checkout scm + env.PATH = "/usr/local/bin:${env.PATH}" + stage ('build_sb15') + { + sh "./build.sh $WORKSPACE $NODE_NAME pdata full && make install" + } + + stage ('run_example_sb15') + { + sh "source $HOME/openfpm_vars && cd example && make" + } + } + } +) + diff --git a/Jenkinsfile_numerics b/Jenkinsfile_numerics new file mode 100644 index 0000000000000000000000000000000000000000..ee201dfc16c83ef4a6e9af46ef69b980eea96055 --- /dev/null +++ b/Jenkinsfile_numerics @@ -0,0 +1,55 @@ +#!groovy + +parallel ( + + +"gin" : {node ('gin') + { + deleteDir() + checkout scm + stage ('build_gin') + { + sh "./build.sh $WORKSPACE $NODE_NAME numerics" + } + + stage ('run_gin') + { + parallel ( + "1" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 1"}, + "2" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 2"}, + "3" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 3"}, + "4" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 4"} + ) + sh "./success.sh 2 gin openfpm_numerics" + } + } + }, + + + + +"sb15" : {node ('sbalzarini-mac-15') + { + deleteDir() + env.PATH = "/usr/local/bin:${env.PATH}" + checkout scm + stage ('build_sb15') + { + sh "./build.sh $WORKSPACE $NODE_NAME numerics" + } + + stage ('run_sb15') + { + parallel ( + "1" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 1"}, + "2" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 2"}, + "3" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 3"}, + "4" : {sh "cd openfpm_numerics && ./run.sh $WORKSPACE $NODE_NAME 4"} + ) + sh "./success.sh 2 sbalzarini-mac-15 openfpm_numerics" + } + } + } + +) + diff --git a/Makefile.am b/Makefile.am index 437d908cb4fb476ceb849aa3d0370e4dfe673d55..51fbbec93340c1f40a608725684510d268d3b7da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,6 +2,27 @@ SUBDIRS = src images openfpm_data openfpm_io openfpm_devices openfpm_vcluster op bin_PROGRAMS = +pdata: + cd src && make + +data: + cd openfpm_data/src && make + +devices: + cd openfpm_devices/src && make + +vcluster: + cd openfpm_vcluster/src && make + +io: + cd openfpm_io/src && make + +numerics: + cd openfpm_numerics/src && make + + + + test_pdata: cd src && make test diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..70c61712deec2d95b19cdd79ba689999caebfbbc --- /dev/null +++ b/build.sh @@ -0,0 +1,116 @@ +#! /bin/bash + +# Make a directory in /tmp/OpenFPM_pdata + +echo "Directory: $1" +echo "Machine: $2" + +mkdir src/config + +git submodule init +if [ $? -ne 0 ]; then + echo -e "Configure\033[91;5;1m FAILED \033[0m" + exit 1 +fi + +git submodule update +if [ $? -ne 0 ]; then + echo -e "Configure\033[91;5;1m FAILED \033[0m" + exit 1 +fi + +mkdir openfpm_numerics/src/config + + +if [ "$2" == "gin" ] +then + echo "Compiling on gin\n" + source ~/.bashrc + module load gcc/4.9.2 + if [ x"$4" == x"full" ]; then + ./install -s -c "--prefix=/home/jenkins/openfpm_install" + elif [ x"$3" == x"numerics" ]; then + ./install -m -s -c "--prefix=/home/jenkins/openfpm_install" + make $3 + else + ./install -m -s -c "--prefix=/home/jenkins/openfpm_install --no-recursion" + make $3 + fi + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + + source $HOME/openfpm_vars + + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + +elif [ "$2" == "wetcluster" ] +then + echo "Compiling on wetcluster" + +## produce the module path + + source ~/.bashrc + module load gcc/4.9.2 + module load openmpi/1.8.1 + module load boost/1.54.0 + + sh ./autogen.sh + ./install -m -s -c "--with-boost=/sw/apps/boost/1.54.0/ CXX=mpic++ --no-recursion" + make $3 + + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + +elif [ "$2" == "taurus" ] +then + echo "Compiling on taurus" + + source /etc/profile + echo "$PATH" + module load eigen/3.2.0 + module load suitesparse/4.2.1-gnu-multimkl + module load boost/1.60.0 + module load gcc/5.3.0 + module load openmpi/1.10.2-gnu + module unload bullxmpi + + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/incard/PARMETIS/lib:/home/incard/METIS/lib:/home/incard/HDF5/lib" + + ./install -m -i "/scratch/p_ppm/" -s -c"CXX=mpic++ --no-recursion" + make $3 + + source $HOME/openfpm_vars + + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi +else + echo "Compiling general" + source ~/.bashrc + + if [ x"$4" == x"full" ]; then + ./install -s -c "--prefix=/Users/jenkins/openfpm_install" + elif [ x"$3" == x"numerics" ]; then + ./install -m -s -c "--prefix=/home/jenkins/openfpm_install" + make $3 + else + ./install -m -s -c "--prefix=/Users/jenkins/openfpm_install --no-recursion" + make $3 + fi + + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + +fi + + diff --git a/build_pdata.sh b/build_pdata.sh index 0118e49eeeb1546febad3f1af1c21ae2e45c3f04..14a46441e5f18bf0238fdff4b246c15b558c1e8f 100644 --- a/build_pdata.sh +++ b/build_pdata.sh @@ -213,12 +213,12 @@ then export which salloc - salloc --nodes=1 --ntasks-per-node=24 --time=00:10:00 --mem-per-cpu=1900 --partition=haswell bash -c "ulimit -s unlimited && mpirun -np 24 src/pdata --report_level=no" + salloc --nodes=1 --ntasks-per-node=24 --time=00:15:00 --mem-per-cpu=1900 --partition=haswell bash -c "ulimit -s unlimited && mpirun -np 24 src/pdata --report_level=no" if [ $? -ne 0 ]; then curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 exit 1 ; fi - salloc --nodes=2 --ntasks-per-node=24 --time=00:10:00 --mem-per-cpu=1900 --partition=haswell bash -c "ulimit -s unlimited && mpirun -np 48 src/pdata --report_level=no" + salloc --nodes=2 --ntasks-per-node=24 --time=00:15:00 --mem-per-cpu=1900 --partition=haswell bash -c "ulimit -s unlimited && mpirun -np 48 src/pdata --report_level=no" if [ $? -ne 0 ]; then curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 exit 1 ; diff --git a/configure.ac b/configure.ac index 5c2ee700a22ab9cc59019ea0bda7dcf11a46e063..78e94cf7416e3d83aa6719b401c3d66ec75a5c83 100644 --- a/configure.ac +++ b/configure.ac @@ -143,9 +143,21 @@ AX_LIB_PETSC() ## Check for quadmath -AC_CHECK_LIB(quadmath, sinq, [AC_DEFINE(HAVE_LIBQUADMATH,[],[Have quad math lib]) - LIBQUADMATH=" -lquadmath " - ], []) + +have_quad_lib=no +have_quad_head=no +AC_CHECK_LIB(quadmath, sinq, [have_quad_lib=yes], []) +AC_CHECK_HEADER(quadmath.h,[have_quad_head=yes],[]) + +if [x"have_quad_math" == x"yes" $&& x"have_quad_math" == x"yes" ]; then + AC_DEFINE(HAVE_LIBQUADMATH,[],[Have quad math lib]) + LIBQUADMATH=" -lquadmath " +fi + +AC_SUBST(OPENMP_CFLAGS) +AC_SUBST(OPENMP_LDFLAGS) + +echo "$OPENMP_CFLAGS" > openmp_flags ######## @@ -167,6 +179,28 @@ if test x"$scancoverty" = x"yes"; then fi +###### Checking for compiler flags -fext-numeric-literals + +AC_LANG_PUSH([C++]) + +my_save_cflags="$CXXFLAGS" +CXXFLAGS=-fext-numeric-literals +AC_MSG_CHECKING([whether CXX supports -fext-numeric-literals]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], + [AC_MSG_RESULT([yes]) + AM_CXXFLAGS="-fext-numeric-literals" + echo "-fext-numeric-literals" > openfpm_flags + ], + [ + AC_MSG_RESULT([no]) + echo "" > openfpm_flags + ] +) +AC_LANG_POP([C++]) +CXXFLAGS="$my_save_cflags" +AC_SUBST([AM_CXXFLAGS]) + + ## Check for parMetis IMMDX_LIB_PARMETIS([],[echo "Cannot detect parmetis, use the --with-parmetis option if it is not installed in the default location" diff --git a/example/Grid/0_simple/Makefile b/example/Grid/0_simple/Makefile index 927a794d2b42b777e0946ac63f508c180b333fae..26bd7de19ab527d116d6ee67307b07d016111c44 100644 --- a/example/Grid/0_simple/Makefile +++ b/example/Grid/0_simple/Makefile @@ -15,7 +15,7 @@ grid: $(OBJ) all: grid run: all - source $$HOME/openfpm_vars; mpirun -np 2 ./grid + mpirun -np 2 ./grid .PHONY: clean all run diff --git a/example/Grid/1_stencil/Makefile b/example/Grid/1_stencil/Makefile index 12399cc8db6278b2af91051f4d11a071bce0730d..bb7b0ec2e27f77da6ea3ebccae9f34147e128bf4 100644 --- a/example/Grid/1_stencil/Makefile +++ b/example/Grid/1_stencil/Makefile @@ -15,7 +15,7 @@ stencil: $(OBJ) all: stencil run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./stencil + mpirun -np 3 ./stencil .PHONY: clean all run diff --git a/example/Grid/2_solve_eq/Makefile b/example/Grid/2_solve_eq/Makefile index 9295477e1029761cc9dbac6de7ff727df0114b21..9f4b7160aaedb1c193c95ca1d4bdf594176e6a97 100644 --- a/example/Grid/2_solve_eq/Makefile +++ b/example/Grid/2_solve_eq/Makefile @@ -15,7 +15,7 @@ periodic: $(OBJ) all: periodic run: all - source $$HOME/openfpm_vars; mpirun -np 4 ./periodic + mpirun -np 4 ./periodic .PHONY: clean all run diff --git a/example/Grid/3_gray_scott/Makefile b/example/Grid/3_gray_scott/Makefile index df84f0c12a5d30d2ee28986342a38ad054f6407a..170e428569ba200362dfa7bbc4a5d533f4006696 100644 --- a/example/Grid/3_gray_scott/Makefile +++ b/example/Grid/3_gray_scott/Makefile @@ -15,7 +15,7 @@ gray_scott: $(OBJ) all: gray_scott run: all - source $$HOME/openfpm_vars; mpirun -np 4 ./gray_scott + mpirun -np 4 ./gray_scott .PHONY: clean all run diff --git a/example/Grid/3_gray_scott/main.cpp b/example/Grid/3_gray_scott/main.cpp index 19cf14a1c10e88b40e7386df8bc8db0696c00311..932a15a344d334fac6856c49bcfad017d2caf543 100644 --- a/example/Grid/3_gray_scott/main.cpp +++ b/example/Grid/3_gray_scott/main.cpp @@ -261,7 +261,7 @@ int main(int argc, char* argv[]) //! \cond [time stepping] \endcond // sync the ghost - size_t count; + size_t count = 0; Old.template ghost_get<U,V>(); // because we assume that spacing[x] == spacing[y] we use formula 2 diff --git a/example/Numerics/PSE/0_Derivative_approx_1D/Makefile b/example/Numerics/PSE/0_Derivative_approx_1D/Makefile index 4399591ae91a611106e5536aa126a7b37fbbaf70..da76a97b081f678675d3c9ca416664098dcdd671 100644 --- a/example/Numerics/PSE/0_Derivative_approx_1D/Makefile +++ b/example/Numerics/PSE/0_Derivative_approx_1D/Makefile @@ -15,7 +15,7 @@ pse_1d: $(OBJ) all: pse_1d run: all - source $$HOME/openfpm_vars; ./pse_1d + ./pse_1d .PHONY: clean all run diff --git a/example/Numerics/PSE/1_Derivative_approx_1D_mp/Makefile b/example/Numerics/PSE/1_Derivative_approx_1D_mp/Makefile index ebc14e337fa48a2799b11e46e4af7178835af825..a89794a539aa80a4703f3d8a138b3eff72242635 100644 --- a/example/Numerics/PSE/1_Derivative_approx_1D_mp/Makefile +++ b/example/Numerics/PSE/1_Derivative_approx_1D_mp/Makefile @@ -1,3 +1,6 @@ +# This example does not work using clang +# Eliminate the comment to activate it + include ../../../example.mk CC=mpic++ @@ -7,17 +10,17 @@ LDIR = OBJ_128 = main_float128.o %.o: %.cpp - $(CC) -O3 -c -fext-numeric-literals --std=c++11 -o $@ $< $(INCLUDE_PATH) + $(CC) -O3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH) -pse_1d_128: $(OBJ_128) - $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -lquadmath +# pse_1d_128: $(OBJ_128) +# $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -lquadmath -all: pse_1d_128 +#all: pse_1d_128 -run: all - source $$HOME/openfpm_vars; ./pse_1d_128 +run: #all +# source $$HOME/openfpm_vars;# ./pse_1d_128 -.PHONY: clean all run +#.PHONY: clean all run clean: rm -f *.o *~ core pse_1d_128 diff --git a/example/Numerics/PSE/1_Derivative_approx_1D_mp/main_float128.cpp b/example/Numerics/PSE/1_Derivative_approx_1D_mp/main_float128.cpp index b350abd88140f5ff92a0d00bb26b9ee700855b14..94e89fda5376355b119ae1e7b1a2f80bd96a8091 100644 --- a/example/Numerics/PSE/1_Derivative_approx_1D_mp/main_float128.cpp +++ b/example/Numerics/PSE/1_Derivative_approx_1D_mp/main_float128.cpp @@ -10,11 +10,16 @@ * */ +#include "config/config.h" #include "Vector/vector_dist.hpp" #include "Decomposition/CartDecomposition.hpp" #include "PSE/Kernels.hpp" #include "data_type/aggregate.hpp" #include <cmath> + +// This example only work if there is HAVE_LIBQUADMATH +#ifdef HAVE_LIBQUADMATH + #include <boost/multiprecision/float128.hpp> typedef boost::multiprecision::float128 float128; @@ -310,3 +315,11 @@ int main(int argc, char* argv[]) // openfpm_finalize(); } + +#else + +int main(int argc, char* argv[]) +{ +} + +#endif diff --git a/example/Numerics/PSE/1_Diffusion_1D/Makefile b/example/Numerics/PSE/1_Diffusion_1D/Makefile index 80cc4ffee6942f9638dff20b8b6ef4fa3b122fb4..502affc0c3379bdd1e290d47424388bf2aa333ba 100644 --- a/example/Numerics/PSE/1_Diffusion_1D/Makefile +++ b/example/Numerics/PSE/1_Diffusion_1D/Makefile @@ -15,7 +15,7 @@ diff_1d: $(OBJ) all: diff_1d run: all - source $$HOME/openfpm_vars; mpirun -np 4 ./diff_1d + mpirun -np 4 ./diff_1d .PHONY: clean all diff --git a/example/Numerics/PSE/1_Diffusion_1D/main.cpp b/example/Numerics/PSE/1_Diffusion_1D/main.cpp index 93299113c5b601b9effe678b94eb842d07fe8552..32a36ddebf1c7fd2c6f25c1bf7a7bfc4948a1a40 100644 --- a/example/Numerics/PSE/1_Diffusion_1D/main.cpp +++ b/example/Numerics/PSE/1_Diffusion_1D/main.cpp @@ -425,7 +425,7 @@ int main(int argc, char* argv[]) double val; // usefull to sort the particle by position - bool operator<(const pos_val & p) + bool operator<(const pos_val & p) const { return pos < p.pos; } diff --git a/example/Numerics/Stoke_flow/0_2D_incompressible/Makefile b/example/Numerics/Stoke_flow/0_2D_incompressible/Makefile index b6512e4ce8a11840a6ea123ee2a7d6c8b3330bd9..1378bd05620783aa79a98e4e354aa19131c86921 100644 --- a/example/Numerics/Stoke_flow/0_2D_incompressible/Makefile +++ b/example/Numerics/Stoke_flow/0_2D_incompressible/Makefile @@ -19,7 +19,7 @@ stokes_2d_petsc: $(OBJ_PETSC) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./stokes_2d_eigen; mpirun -np 3 ./stokes_2d_petsc + mpirun -np 3 ./stokes_2d_eigen && mpirun -np 3 ./stokes_2d_petsc .PHONY: clean all diff --git a/example/Numerics/Stoke_flow/1_3D_incompressible/Makefile b/example/Numerics/Stoke_flow/1_3D_incompressible/Makefile index 37f936486b6cc6be32d4a89c8f4f7a648d8cee14..5186ac565a358b610c6ed1df82c9dd83fb310bd4 100644 --- a/example/Numerics/Stoke_flow/1_3D_incompressible/Makefile +++ b/example/Numerics/Stoke_flow/1_3D_incompressible/Makefile @@ -19,7 +19,7 @@ stokes_3d_petsc: $(OBJ_PETSC) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./stokes_3d_eigen; mpirun -np 3 ./stokes_3d_petsc + mpirun -np 3 ./stokes_3d_eigen && mpirun -np 3 ./stokes_3d_petsc .PHONY: clean all run diff --git a/example/Plot/0_simple_graph/Makefile b/example/Plot/0_simple_graph/Makefile index cb8e065eb73e9d0696276dfce9814c3e99f1ec29..e2885ae2a21a84bd8bb036284446869a47318c85 100644 --- a/example/Plot/0_simple_graph/Makefile +++ b/example/Plot/0_simple_graph/Makefile @@ -7,15 +7,15 @@ LDIR = OBJ = main.o %.o: %.cpp - $(CC) -O3 -g3 -c --std=c++11 -fext-numeric-literals -o $@ $< $(INCLUDE_PATH) + $(CC) -O3 -g3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH) plot: $(OBJ) - $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -lquadmath + $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) all: plot run: all - source $$HOME/openfpm_vars; ./plot + ./plot .PHONY: clean all run diff --git a/example/Plot/2_PSE_convergence/Makefile b/example/Plot/2_PSE_convergence/Makefile index 5fc0c0db5d1a5c30b275761dd024fe52881b5a68..93559efaca0d5cbe5c7f095888e9cc61632d658c 100644 --- a/example/Plot/2_PSE_convergence/Makefile +++ b/example/Plot/2_PSE_convergence/Makefile @@ -1,23 +1,26 @@ include ../../example.mk +#### this example work only if you have quadmath activated ### +#### (only if -lquadmath work) uncomment to reactivate + CC=mpic++ LDIR = -OBJ = main.o +#OBJ = main.o -%.o: %.cpp - $(CC) -O3 -g3 -c --std=c++11 -fext-numeric-literals -o $@ $< $(INCLUDE_PATH) +#%.o: %.cpp +# $(CC) -O3 -g3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH) -conv_p: $(OBJ) - $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -lquadmath +#conv_p: $(OBJ) +# $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -lquadmath -all: conv_p +#all: conv_p -run: all - source $$HOME/openfpm_vars; ./conv_p +run: #all +# source $$HOME/openfpm_vars;# ./conv_p -.PHONY: clean all run +#.PHONY: clean all run clean: rm -f *.o *~ core conv_p diff --git a/example/Plot/2_PSE_convergence/main.cpp b/example/Plot/2_PSE_convergence/main.cpp index 91dcda24debd2134f8381c0bf29e8974c0158816..7e0f1b27fc13171ba24fa87e6ae38543c46b37cd 100644 --- a/example/Plot/2_PSE_convergence/main.cpp +++ b/example/Plot/2_PSE_convergence/main.cpp @@ -10,6 +10,14 @@ * */ +#include "config/config.h" + +// Some compiler like clang does not have libquadmath this example +// require libquadmath. So is active only if in openfpm installation +// such library has been detected + +#ifdef HAVE_LIBQUADMATH + #include "VCluster.hpp" #include "PSE/Kernels_test_util.hpp" #include "Plot/GoogleChart.hpp" @@ -158,5 +166,11 @@ int main(int argc, char* argv[]) openfpm_finalize(); } +#else +int main() +{ + +} +#endif diff --git a/example/VCluster/0_simple/Makefile b/example/VCluster/0_simple/Makefile index b54f7e1f340ba22c321088dc49992f4241f802e3..721c8d9f7e9f12f7260d5883ef719e5f8a02305c 100644 --- a/example/VCluster/0_simple/Makefile +++ b/example/VCluster/0_simple/Makefile @@ -15,7 +15,7 @@ vcluster: $(OBJ) all: vcluster run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./vcluster + mpirun -np 3 ./vcluster .PHONY: clean all run diff --git a/example/Vector/0_simple/Makefile b/example/Vector/0_simple/Makefile index 646357e9532c2ba26a3df94534201be645d20608..741431e3ec68fb44b3398aa609c511546007e813 100644 --- a/example/Vector/0_simple/Makefile +++ b/example/Vector/0_simple/Makefile @@ -15,7 +15,7 @@ vect: $(OBJ) all: vect run: all - source $$HOME/openfpm_vars; mpirun -np 2 ./vect + mpirun -np 2 ./vect .PHONY: clean all run diff --git a/example/Vector/0_simple/main.cpp b/example/Vector/0_simple/main.cpp index 8a19b9e1d19614a02e0d2d4e86997b80696f433a..0e6a334477539f0632710a74a26b19a9236587e4 100644 --- a/example/Vector/0_simple/main.cpp +++ b/example/Vector/0_simple/main.cpp @@ -2,12 +2,14 @@ * * \subpage Vector_0_simple * \subpage Vector_1_celllist + * \subpage Vector_1_ghost_get * \subpage Vector_2_expression * \subpage Vector_3_md - * \subpage Vector_4_reo - * \subpage Vector_4_comp_reo - * \subpage Vector_4_complex_prop + * \subpage Vector_4_reo_root + * \subpage Vector_4_cp * \subpage Vector_4_mp_cl + * \subpage Vector_5_md_vl_sym + * \subpage Vector_6_complex_usage * */ @@ -38,7 +40,7 @@ * </div> * \endhtmlonly * - * ## inclusion ## {#inclusion} + * ## inclusion ## {#e0_v_inclusion} * * In order to use distributed vectors in our code we have to include the file Vector/vector_dist.hpp * @@ -61,7 +63,7 @@ int main(int argc, char* argv[]) * Here we * * Initialize the library * * we create a Box that define our domain - * * An array that define out boundary conditions + * * An array that define our boundary conditions * * A Ghost object that will define the extension of the ghost part in physical units * * @@ -346,7 +348,7 @@ int main(int argc, char* argv[]) * * ## Finalize ## {#finalize_e0_sim} * - * At the very end of the program we have always to de-initialize the library + * At the very end of the program we have always de-initialize the library * * \snippet Vector/0_simple/main.cpp finalize * diff --git a/example/Vector/1_celllist/Makefile b/example/Vector/1_celllist/Makefile index 6e6e5296445bb2a09a5c71ee0b6520c894689aba..c9a76a23b45b50e073b571f48fa3653a60cdbc13 100644 --- a/example/Vector/1_celllist/Makefile +++ b/example/Vector/1_celllist/Makefile @@ -15,7 +15,7 @@ cell: $(OBJ) all: cell run: all - source $$HOME/openfpm_vars; mpirun -np 2 ./cell + mpirun -np 2 ./cell .PHONY: clean all run diff --git a/example/Vector/1_celllist/main.cpp b/example/Vector/1_celllist/main.cpp index 653c6dfe81c7c93bd49d6786846e3d3c0560a64b..96aa95f7463ff4e30d7369746c8c17827e8130cb 100644 --- a/example/Vector/1_celllist/main.cpp +++ b/example/Vector/1_celllist/main.cpp @@ -173,6 +173,9 @@ int main(int argc, char* argv[]) * no properties. If we want to synchronize also properties we have to specify which one. * For example with <0,1,2> here we synchronize the scalar property (0), the vector (1), and the rank 2 tensor (2) * + * \warning Every ghost_get by default reset the status of the ghost so the information are lost + * + * \see \ref e1_gg_options * * \htmlonly * <a href="#" onclick="hide_show('vector-video-5')" >Video 1</a> @@ -308,7 +311,7 @@ int main(int argc, char* argv[]) //! \cond [verletlist] \endcond openfpm::vector<openfpm::vector<size_t>> verlet; - vd.getVerlet(verlet,r_cut); + vd.getVerletDeprecated(verlet,r_cut); // For each particle i verlet.size() == Number of particles for (size_t i = 0 ; i < verlet.size() ; i++) diff --git a/example/Vector/4_multiphase_celllist/Makefile b/example/Vector/1_ghost_get_put/Makefile similarity index 51% rename from example/Vector/4_multiphase_celllist/Makefile rename to example/Vector/1_ghost_get_put/Makefile index 0acbf7c250aa29ced27edf2e97ebd17536e30c67..57bab07e06ec25f5e2ef2af05f63a2ef90b89be9 100644 --- a/example/Vector/4_multiphase_celllist/Makefile +++ b/example/Vector/1_ghost_get_put/Makefile @@ -7,18 +7,18 @@ LDIR = OBJ = main.o %.o: %.cpp - $(CC) -O0 -g -c --std=c++11 -o $@ $< $(INCLUDE_PATH) + $(CC) -O3 -g -c --std=c++11 -o $@ $< $(INCLUDE_PATH) -cell: $(OBJ) +ghost: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -all: cell +all: ghost run: all - source $$HOME/openfpm_vars; mpirun -np 2 ./cell + mpirun -np 2 ./ghost .PHONY: clean all run clean: - rm -f *.o *~ core cell + rm -f *.o *~ core ghost diff --git a/example/Vector/4_multiphase_celllist/config.cfg b/example/Vector/1_ghost_get_put/config.cfg similarity index 100% rename from example/Vector/4_multiphase_celllist/config.cfg rename to example/Vector/1_ghost_get_put/config.cfg diff --git a/example/Vector/1_ghost_get_put/main.cpp b/example/Vector/1_ghost_get_put/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0180e4942c5241f87f32ef83e34f6fe1fdf22313 --- /dev/null +++ b/example/Vector/1_ghost_get_put/main.cpp @@ -0,0 +1,397 @@ +/*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * + * [TOC] + * + * + * # Ghost get and ghost put # {#ghost_get_put} + * + * + * This example shows more in details the functionalities of **ghost_get** and **ghost_put** for a distributed vector. + * + * + * ## Inclusion ## {#e1_v_inclusion} + * + * We activate the vector_dist functionalities + * + * \snippet Vector/1_ghost_get_put/main.cpp inclusion + * + * \see \ref e0_v_inclusion + * + */ + +//! \cond [inclusion] \endcond +#include "Vector/vector_dist.hpp" +//! \cond [inclusion] \endcond + +int main(int argc, char* argv[]) +{ + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Initialization ## {#e1_s_init} + * + * Here we + * * Initialize the library + * * we create a Box that define our domain + * * An array that define our boundary conditions + * * A Ghost object that will define the extension of the ghost part in physical units + * + * \see \ref e0_s_init + * + * \snippet Vector/1_ghost_get_put/main.cpp Initialization and parameters + * + * + */ + + //! \cond [Initialization and parameters] \endcond + + // initialize the library + openfpm_init(&argc,&argv); + + // Here we define our domain a 2D box with internals from 0 to 1.0 for x and y + Box<2,float> domain({0.0,0.0},{1.0,1.0}); + + // Here we define the boundary conditions of our problem + size_t bc[2]={PERIODIC,PERIODIC}; + + // extended boundary around the domain, and the processor domain + Ghost<2,float> g(0.01); + + //! \cond [Initialization and parameters] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Vector instantiation ## {#e1_v_init} + * + * Here we are creating a distributed vector following the previous example + * + * \see \ref e0_s_vector_inst + * + * \snippet Vector/1_ghost_get_put/main.cpp vector instantiation + * + */ + + //! \cond [vector instantiation] \endcond + + vector_dist<2,float, aggregate<float,float[3],float[3][3]> > vd(4096,domain,bc,g); + + // the scalar is the element at position 0 in the aggregate + const int scalar = 0; + + // the vector is the element at position 1 in the aggregate + const int vector = 1; + + // the tensor is the element at position 2 in the aggregate + const int tensor = 2; + + //! \cond [vector instantiation] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Assign values ## {#e1_s_assign_pos} + * + * We get an iterator and we iterate across the 4096 particles where we define their positions and properties + * + * \see \ref e0_s_assign_pos + * + * \snippet Vector/1_ghost_get_put/main.cpp assign position + * + */ + + //! \cond [assign position] \endcond + + auto it = vd.getDomainIterator(); + + while (it.isNext()) + { + // Particle p + auto p = it.get(); + + // we define x, assign a random position between 0.0 and 1.0 + vd.getPos(p)[0] = (float)rand() / RAND_MAX; + + // we define y, assign a random position between 0.0 and 1.0 + vd.getPos(p)[1] = (float)rand() / RAND_MAX; + + // the scalar property + vd.template getProp<scalar>(p) = vd.getPos(p)[0]; + + // The vector + vd.template getProp<vector>(p)[0] = 1.0; + vd.template getProp<vector>(p)[1] = 2.0; + vd.template getProp<vector>(p)[2] = 3.0; + + // The tensor + vd.template getProp<tensor>(p)[0][0] = 1.0; + vd.template getProp<tensor>(p)[0][1] = 2.0; + vd.template getProp<tensor>(p)[0][2] = 3.0; + vd.template getProp<tensor>(p)[1][0] = 4.0; + vd.template getProp<tensor>(p)[1][1] = 5.0; + vd.template getProp<tensor>(p)[1][2] = 6.0; + vd.template getProp<tensor>(p)[2][0] = 7.0; + vd.template getProp<tensor>(p)[2][1] = 8.0; + vd.template getProp<tensor>(p)[2][2] = 9.0; + + // next particle + ++it; + } + + //! \cond [assign position] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Mapping particles ## {#e1_s_map} + * + * We redistribute the particles according to the underline decomposition + * + * \snippet Vector/1_ghost_get_put/main.cpp map + * + * + */ + + //! \cond [map] \endcond + + vd.map(); + + //! \cond [map] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## ghost_get ## {#e1_v_assign_prop} + * + * Here we synchronize the ghosts in the standard way, updating the scalar and + * the tensor property. + * + * \warning Every **ghost_get** by default reset the status of the ghost so the previous information is lost + * + * In the 2 images below we see what happen when we do a standard **ghost_get** + * Before and after. The blue arrows in the first image indicate the vector field + * for the real particles. In the second image instead the red arrow indicate the + * vector field for the real particle. The blue arrow indicate the ghosts. We can + * note that the blue arrow doea not contain the correct vector. The reason is that + * when we used **ghost_get** we synchronized the scalar, and the tensor, but not the vector. + * + * \see \ref e1_part_ghost + * + * \snippet Vector/1_ghost_get_put/main.cpp ghost_get_some_prop + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/before_ghost_get.jpg"/> + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/after_ghost_get.jpg"/> + * \endhtmlonly + * + * + */ + + //! \cond [ghost_get_some_prop] \endcond + + // write in vtk to see the result before + vd.write("before_ghost_get"); + + // Here we synchronize the ghost get only the scalar and the tensor property + vd.ghost_get<scalar,tensor>(); + + // write in vtk to see the result after + vd.write("after_ghost_get"); + + //! \cond [ghost_get_some_prop] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## ghost_get KEEP_PROPERTIES ## {#e1_gg_options} + * + * As described before every ghost_get reset the status of the ghost. In particular + * all the informations are lost. So for example doing a **ghost_get<scalar>** followed + * by a **ghost_get<vector>** will not preserve the information of the **ghost_get<scalar>**. + * This because in general **ghost_get** + * recompute the set of particles to send to the other processor based on their + * geometrical position. If the particles move between the **ghost_get<scalar>** and the + * the **ghost_get<vector>** the set of the particles sent can change between the 2 **ghost_get**. + * Merge the information between the two different set of particles would end up to be non trivial and would + * require to send additional information. This will make the communication inconveniently + * heavier. In the case the particles does not move on the other hand it would be + * possible to do a trivial merge of the information. The library is not able to + * detect automatically such cases. The information must be given explicitly. + * **KEEP_PROPERTIES** is an option that can be given to ghost_get to force to do + * a trivial merge in case the particles do not move. More in general such property is + * safe to be used in case that the particles move between **ghost_get**. What will + * happen is that the computation of the set of the particles to send will be fully skipped. + * OpenFPM will send the same set of particles from the previous ghost_get. Such functionality + * is important in case of usage of Verlet-List with radius+skin. This functionality is + * advanced and will be explained in a next example. + * + * \see \ref Vector_5_md_vl_sym + * + * Because the option **KEEP_PROPERTIES** has the functionality to keep the properties + * and skip the labelling. The option **KEEP_PROPERTIES** is also names **SKIP_LABELLING**. + * The two options are exactly equivalents. + * + * In the picture below we can see what happen when from the previous situation, + * we do a **ghost_get** with **KEEP_PROPERTIES** for the vector field. The vector change + * pointing to the right direction. On the other hand also the scalar (The dot color)is kept and the information + * is not destroyed. + * + * \snippet Vector/1_ghost_get_put/main.cpp keep prop + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/after_ghost_get_kp.jpg"/> + * \endhtmlonly + * + * + */ + + //! \cond [keep prop] \endcond + + vd.ghost_get<vector>(KEEP_PROPERTIES); + + // write in vtk to see the result before + vd.write("after_ghost_get_kp"); + + //! \cond [keep prop] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## ghost_get NO_POSITION ## + * + * **ghost_get** in general send automatically the information about position. + * If we are sure that the particles position did not change its position we + * can use the option NO_POSITION, to avoid to send the positional informations. + * With the only purpose to show what happens we shift the particle position of the + * ghost parts by one. We also force the vector to point to the opposite direction. + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/before_ghost_get_kp_no_pos.jpg"/> + * \endhtmlonly + * + * Doing a **ghost_get** with KEEP_PROPERTY and NO_POSITION, it will updates the information + * of the vectors, but the position will remain the same. + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/after_ghost_get_kp_no_pos.jpg"/> + * \endhtmlonly + * + * We can restore the positioninformation doing a **ghost_get** without NO_POSITION + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/after_ghost_get_kp_restore.jpg"/> + * \endhtmlonly + * + * \snippet Vector/1_ghost_get_put/main.cpp ghost_get no pos + * + * + * + */ + + //! \cond [ghost_get no pos] \endcond + + it = vd.getGhostIterator(); + + while (it.isNext()) + { + // Particle p + auto p = it.get(); + + // we shift down he particles + vd.getPos(p)[0] -= 1.0; + + // we shift + vd.getPos(p)[1] -= 1.0; + + // The vector + vd.template getProp<vector>(p)[0] = -1.0; + vd.template getProp<vector>(p)[1] = -2.0; + vd.template getProp<vector>(p)[2] = -3.0; + + // next particle + ++it; + } + + vd.ghost_get<vector>(KEEP_PROPERTIES | NO_POSITION); + + // write in vtk to see the result before + vd.write("after_ghost_get_kp_no_pos"); + + vd.ghost_get<vector>(KEEP_PROPERTIES); + + vd.write("after_ghost_get_kp_no_pos_restore"); + + //! \cond [ghost_get no pos] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## ghost_put ## {#ghost_put_e1} + * + * **ghost_put** is another particular function. It work similarly to **ghost_get** + * but in the inverted direction. In particular it take the information from + * the ghost particles and it send the information back to the real particles. + * How to merge the information back to the real particles is defined by an operation. + * + * In this particular case we scatter back the information present in the ghost. + * + * \note **ghost_put** does not re-compute the set of + * the particles to send. This mean that the set of particles communicated back from + * ghost_put is given by the set of particles received by the last ghost_get. The + * reason of this are similar to the **ghost_get**. If the set of particles is recomputed + * there is no trivial way for the other processor to merge the information. This mean + * that additional information must be sent and this is most of the time inconvenient. + * + * Once the particles are received back we add_ such contributions to the real particles. + * A typical real application of such functionality is in the case of symmetric interactions + * + * As we can see from the image below some of red particles near the ghost has a bigger arrow + * + * \htmlonly + * <img src="http://ppmcore.mpi-cbg.de/web/images/examples/after_ghost_put.jpg"/> + * \endhtmlonly + * + * \see \ref Vector_5_md_vl_sym + * + * \snippet Vector/1_ghost_get_put/main.cpp ghost_put + * + */ + + //! \cond [ghost_put] \endcond + + vd.ghost_put<add_,vector>(); + + // write in vtk to see the result before + vd.write("after_ghost_put"); + + //! \cond [ghost_put] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Finalize ## {#finalize_e1_sim} + * + * At the very end of the program we have always de-initialize the library + * + * \snippet Vector/1_ghost_get_put/main.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond + + /*! + * \page Vector_1_ghost_get Vector 1 ghost get and ghost put + * + * ## Full code ## {#code_e1_sim} + * + * \include Vector/1_ghost_get_put/main.cpp + * + */ +} diff --git a/example/Vector/2_expressions/Makefile b/example/Vector/2_expressions/Makefile index a7705b979c6bc1afbfb7d920e5f21da8684f4cea..7ab3093eedd5282dcf9269bd222005e21e2bf357 100644 --- a/example/Vector/2_expressions/Makefile +++ b/example/Vector/2_expressions/Makefile @@ -15,7 +15,7 @@ expr: $(OBJ) all: expr run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./expr + mpirun -np 3 ./expr .PHONY: clean all run diff --git a/example/Vector/3_molecular_dynamic/Makefile b/example/Vector/3_molecular_dynamic/Makefile index 9c467c81200347d1095a4195d16202566f07968a..98e3f7a4b4b8cefca7cdcd5c0937198887ed81a7 100644 --- a/example/Vector/3_molecular_dynamic/Makefile +++ b/example/Vector/3_molecular_dynamic/Makefile @@ -7,9 +7,8 @@ LDIR = OBJ = main.o OBJ_EXPR = main_expr.o OBJ_VL = main_vl.o -OBJ_VL_SYM = main_vl_sym.o -all: md_dyn md_dyn_expr md_dyn_vl md_dyn_vl_sym +all: md_dyn md_dyn_expr md_dyn_vl %.o: %.cpp $(CC) -O3 -g -c --std=c++11 -o $@ $< $(INCLUDE_PATH) @@ -23,14 +22,11 @@ md_dyn_expr: $(OBJ_EXPR) md_dyn_vl: $(OBJ_VL) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -md_dyn_vl_sym: $(OBJ_VL_SYM) - $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) - run: all - source $$HOME/openfpm_vars; mpirun -np 3 ./md_dyn; mpirun -np 3 ./md_dyn_expr; mpirun -np 3 ./md_dyn_vl; mpirun -np 3 ./md_dyn_vl_sym; + mpirun -np 3 ./md_dyn && mpirun -np 3 ./md_dyn_expr && mpirun -np 3 ./md_dyn_vl; .PHONY: clean all run clean: - rm -f *.o *~ core md_dyn md_dyn_expr md_dyn_vl md_dyn_vl_sym + rm -f *.o *~ core md_dyn md_dyn_expr md_dyn_vl diff --git a/example/Vector/3_molecular_dynamic/config.cfg b/example/Vector/3_molecular_dynamic/config.cfg index 5ce0ebb452c5db2263236e650fe2335b7db89535..affb95228371d1b31557fd85a962cf3db3e6746b 100644 --- a/example/Vector/3_molecular_dynamic/config.cfg +++ b/example/Vector/3_molecular_dynamic/config.cfg @@ -1,2 +1,2 @@ [pack] -files = main.cpp main_expr.cpp Makefile +files = main.cpp main_expr.cpp main_vl.cpp Makefile diff --git a/example/Vector/3_molecular_dynamic/main_expr_vl.cpp b/example/Vector/3_molecular_dynamic/main_expr_vl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e214636672e0866c109717a775c9fd444f9f1bf --- /dev/null +++ b/example/Vector/3_molecular_dynamic/main_expr_vl.cpp @@ -0,0 +1,151 @@ +#include "Vector/vector_dist.hpp" +#include "Plot/GoogleChart.hpp" +#include "Operators/Vector/vector_dist_operators.hpp" +#include "timer.hpp" + +constexpr int velocity = 0; +constexpr int force = 1; + +struct ln_potential +{ + double sigma12,sigma6,r_cut2,shift; + + ln_potential(double sigma12_, double sigma6_, double r_cut2_, double shift_) {sigma12 = sigma12_; sigma6 = sigma6_; r_cut2 = r_cut2_;shift = shift_;} + + Point<2,double> value(const Point<3,double> & xp, const Point<3,double> xq) + { + double rn = norm2(xp - xq); + if (rn >= r_cut2) return 0.0; + + Point<2,double> E({2.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ) - shift,0.0}); + + return E; + } +}; + +struct ln_force +{ + double sigma12,sigma6,r_cut2; + + ln_force(double sigma12_, double sigma6_, double r_cut2_) {sigma12 = sigma12_; sigma6 = sigma6_;r_cut2 = r_cut2_;} + + Point<3,double> value(const Point<3,double> & xp, const Point<3,double> xq) + { + Point<3,double> r = xp - xq; + double rn = norm2(r); + + if (rn > r_cut2) return 0.0; + + return 24.0*(2.0 * sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r; + } +}; + +int main(int argc, char* argv[]) +{ + double dt = 0.0005, sigma = 0.1, r_cut = 3.0*sigma; + + double sigma6 = pow(sigma,6), sigma12 = pow(sigma,12); + double rc2 = r_cut * r_cut; + double shift = 2.0 * ( sigma12 / (rc2*rc2*rc2*rc2*rc2*rc2) - sigma6 / ( rc2*rc2*rc2) ); + + openfpm::vector<double> x; + openfpm::vector<openfpm::vector<double>> y; + + + openfpm_init(&argc,&argv); + Vcluster & vcl = create_vcluster(); + + size_t sz[3] = {10,10,10}; + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + Ghost<3,float> ghost(r_cut); + + ln_force lf(sigma12,sigma6,r_cut*r_cut); + ln_potential lp(sigma12,sigma6,r_cut*r_cut,shift); + + vector_dist<3,double, aggregate<Point<3,double>,Point<3,double>> > vd(0,box,bc,ghost); + + auto v_force = getV<force>(vd); + auto v_velocity = getV<velocity>(vd); + auto v_pos = getV<PROP_POS>(vd); + + auto it = vd.getGridIterator(sz); + + while (it.isNext()) + { + vd.add(); + + auto key = it.get(); + + vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); + vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); + vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); + + ++it; + } + + v_force = 0; + v_velocity = 0; + + timer tsim; + tsim.start(); + + auto NN = vd.getCellList(r_cut); + + vd.updateCellList(NN); + v_force = applyKernel_in_sim(vd,NN,lf); + unsigned long int f = 0; + + // MD time stepping + for (size_t i = 0; i < 10000 ; i++) + { + assign(v_velocity, v_velocity + 0.5*dt*v_force, + v_pos, v_pos + v_velocity*dt); + + vd.map(); + vd.template ghost_get<>(); + + // calculate forces or a(tn + 1) Step 2 + vd.updateCellList(NN); + v_force = applyKernel_in_sim(vd,NN,lf); + + v_velocity = v_velocity + 0.5*dt*v_force; + + if (i % 100 == 0) + { + vd.deleteGhost(); + vd.write("particles_",f); + vd.ghost_get<>(); + + vd.updateCellList(NN); + Point<2,double> E = rsum(applyKernel_in_sim(vd,NN,lp) + (v_velocity * v_velocity)/2.0,vd).get(); + + vcl.sum(E.get(0));vcl.sum(E.get(1)); + vcl.execute(); + + // we save the energy calculated at time step i c contain the time-step y contain the energy + x.add(i); + y.add({E.get(0),E.get(1),E.get(0) - E.get(1)}); + + if (vcl.getProcessUnitID() == 0) + std::cout << "Energy Total: " << E.get(0) << " Kinetic: " << E.get(1) << " Potential: " << E.get(0) - E.get(1) << std::endl; + + f++; + } + } + + tsim.stop(); + std::cout << "Time: " << tsim.getwct() << std::endl; + + GCoptions options; + options.title = std::string("Energy with time"); + options.yAxis = std::string("Energy"); + options.xAxis = std::string("iteration"); + options.lineWidth = 1.0; + + GoogleChart cg; + cg.AddLinesGraph(x,y,options); + cg.write("gc_plot2_out.html"); + + openfpm_finalize(); +} diff --git a/example/Vector/3_molecular_dynamic/main_vl.cpp b/example/Vector/3_molecular_dynamic/main_vl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c039c99101b4756e658cd9bb5ef3ed420353102f --- /dev/null +++ b/example/Vector/3_molecular_dynamic/main_vl.cpp @@ -0,0 +1,482 @@ + +#include "Vector/vector_dist.hpp" +#include "Decomposition/CartDecomposition.hpp" +#include "data_type/aggregate.hpp" +#include "Plot/GoogleChart.hpp" +#include "Plot/util.hpp" +#include "timer.hpp" + +/*! + * \page Vector_3_md_vl Vector 3 molecular dynamic with Verlet list + * + * + * [TOC] + * + * # Molecular Dynamic with Lennard-Jones potential with verlet list # {#e3_md_vl} + * + * This example show a simple Lennard-Jones molecular dynamic simulation in a stable regime. + * We will use Verlet-list in order to get a speed-up from force calculation + * + * ## Constants ## + * + * Here we define some useful constants + * + * \snippet Vector/3_molecular_dynamic/main_vl.cpp constants + * + */ + +//! \cond [constants] \endcond + +constexpr int velocity = 0; +constexpr int force = 1; + +//! \cond [constants] \endcond + +/*! + * + * \page Vector_3_md_vl Vector 3 molecular dynamic with Verlet list + * + * ## Calculate forces ## {#e3_md_vl_cf} + * + * In this function we calculate the forces between particles. It require the vector of particles, + * the Verlet-list and sigma for the Lennard-Jhones potential. The function is exactly the same + * as the original with the following changes + * + * \see \ref e3_md_cf + * + * * The function accept a VerletList instead of a CellList + * \snippet main_vl.cpp arg diff + * + * * There is no call to updateCellList + * + * * How to get an iterator over neighborhood of a particle + * \snippet main_vl.cpp NN iterator + * + * Teh rest remain the same + * + * \snippet Vector/3_molecular_dynamic/main_vl.cpp calc forces vl + * + */ + +//! \cond [calc forces vl] \endcond + +//! \cond [arg diff] \endcond + +void calc_forces(vector_dist<3,double, aggregate<double[3],double[3]> > & vd, VerletList<3, double, FAST, shift<3, double> > & NN, double sigma12, double sigma6, double r_cut) +{ + //! \cond [arg diff] \endcond + + // Get an iterator over particles + auto it2 = vd.getDomainIterator(); + + // For each particle p ... + while (it2.isNext()) + { + // ... get the particle p + auto p = it2.get(); + + // Get the position xp of the particle + Point<3,double> xp = vd.getPos(p); + + // Reset the forice counter + vd.template getProp<force>(p)[0] = 0.0; + vd.template getProp<force>(p)[1] = 0.0; + vd.template getProp<force>(p)[2] = 0.0; + + //! \cond [NN iterator] \endcond + + // Get an iterator over the neighborhood particles of p + auto Np = NN.template getNNIterator<NO_CHECK>(p.getKey()); + + //! \cond [NN iterator] \endcond + + // For each neighborhood particle ... + while (Np.isNext()) + { + // ... q + auto q = Np.get(); + + // if (p == q) skip this particle + if (q == p.getKey()) {++Np; continue;}; + + // Get the position of p + Point<3,double> xq = vd.getPos(q); + + // Get the distance between p and q + Point<3,double> r = xp - xq; + + // take the norm of this vector + double rn = norm2(r); + + if (rn > r_cut * r_cut) {++Np;continue;} + + // Calculate the force, using pow is slower + Point<3,double> f = 24.0*(2.0 *sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r; + + // we sum the force produced by q on p + vd.template getProp<force>(p)[0] += f.get(0); + vd.template getProp<force>(p)[1] += f.get(1); + vd.template getProp<force>(p)[2] += f.get(2); + + // Next neighborhood + ++Np; + } + + // Next particle + ++it2; + } +} + +//! \cond [calc forces vl] \endcond + +/*! + * \page Vector_3_md_vl Vector 3 molecular dynamic with verlet list + * + * ## Calculate energy ## {#e3_md_vl_ce} + * + * We also need a function to calculate energy, this function require the same parameter as calculate forces + * + * \see \ref e3_md_ce + * + * The following changes has been made + * + * * The function accept a VerletList instead of a cell-List + * * There is no call to updateCellList + * * How to get an iterator over neigborhood particles + * + * \snippet Vector/3_molecular_dynamic/main_vl.cpp calc energy vl + * + */ + +//! \cond [calc energy vl] \endcond + +double calc_energy(vector_dist<3,double, aggregate<double[3],double[3]> > & vd, VerletList<3, double, FAST, shift<3, double> > & NN, double sigma12, double sigma6, double r_cut) +{ + double E = 0.0; + + double rc = r_cut*r_cut; + double shift = 2.0 * ( sigma12 / (rc*rc*rc*rc*rc*rc) - sigma6 / ( rc*rc*rc) ); + + // Get the iterator + auto it2 = vd.getDomainIterator(); + + // For each particle ... + while (it2.isNext()) + { + // ... p + auto p = it2.get(); + + // Get the position of the particle p + Point<3,double> xp = vd.getPos(p); + + // Get an iterator over the neighborhood of the particle p + auto Np = NN.template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q + auto q = Np.get(); + + // if p == q skip this particle + if (q == p.getKey()) {++Np; continue;}; + + // Get position of the particle q + Point<3,double> xq = vd.getPos(q); + + // take the normalized direction + double rn = norm2(xp - xq); + + if (rn >= r_cut*r_cut) + {++Np;continue;} + + // potential energy (using pow is slower) + E += 2.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ) - shift; + + // Next neighborhood + ++Np; + } + + // Kinetic energy of the particle given by its actual speed + E += (vd.template getProp<velocity>(p)[0]*vd.template getProp<velocity>(p)[0] + + vd.template getProp<velocity>(p)[1]*vd.template getProp<velocity>(p)[1] + + vd.template getProp<velocity>(p)[2]*vd.template getProp<velocity>(p)[2]) / 2; + + // Next Particle + ++it2; + } + + // Calculated energy + return E; +} + +//! \cond [calc energy vl] \endcond + +int main(int argc, char* argv[]) +{ + /*! + * \page Vector_3_md_vl Vector 3 molecular dynamic with Verlet list + * + * ## Simulation ## {#e3_md_vl_sim} + * + * The simulation is equal to the simulation explained in the example molecular dynamic + * + * \see \ref e3_md + * + * The differences are that: + * + * * The Ghost must be r_cut+skin + * \snippet + * + * * We create a Verlet list with skin instead of a Cell list + * \snippet Vector/3_molecular_dynamic/main_vl.cpp verlet skin + * + * * every 10 steps we do a map and update the verlet-list, in all the other case we just do skip labelling + * \snippet Vector/3_molecular_dynamic/main_vl.cpp update verlet + * + * **Explanation** + * + * Updating the verlet list is extremely expensive. For this reason we create a Verlet list + * that contain r_cut + skin particles. Using the fact that during the full simulation each + * particle does not move more than 0.0015 in one iteration, if the skin is 0.03 + * we can update the Verlet list every \f$ \frac{0.03}{2 \cdot 0.0015} = 10 \f$. The 2 factor if given by the fact + * that in the worst case where one particle is going left and one on the right from the prospective of + * one particle the particle moove \f$ 2 \cdot 0.0015 \f$. + * + * Because the Verlet lists are constructed based on the local-id of the particles a map or a ghost_get + * would invalidate the verlet. For this reason the map is called every 10 time-step (when we + * update the verlet), and a particular ghost_get with SKIP_LABELLING is used during every iteration. + * + * The function ghost_get with skip labeling does not recompute the particle to send but use the + * the ids of the old particles updating the positions (and properties if needed) and keeping the old + * indexes without invalidating the Verlet-list. Doing this we can avoid to send particles that are + * entering the ghost area r_cut+skin. Because we know that no particle in 10 iteration can travel for a + * distance bigger than the skin, we are sure that in 10 iteration no-new particle that were not in the + * r_cut+skin ghost area can enter the ghost area r_cut. + * + * + * \snippet Vector/3_molecular_dynamic/main_vl.cpp simulation + * + */ + + //! \cond [simulation] \endcond + + double dt = 0.00025; + double sigma = 0.1; + double r_cut = 3.0*sigma; + double r_gskin = 1.3*r_cut; + double sigma12 = pow(sigma,12); + double sigma6 = pow(sigma,6); + + openfpm::vector<double> x; + openfpm::vector<openfpm::vector<double>> y; + + openfpm_init(&argc,&argv); + Vcluster & v_cl = create_vcluster(); + + // we will use it do place particles on a 10x10x10 Grid like + size_t sz[3] = {10,10,10}; + + // domain + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + // ghost, big enough to contain the interaction radius + Ghost<3,float> ghost(r_gskin); + + vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost); + + auto it = vd.getGridIterator(sz); + + while (it.isNext()) + { + vd.add(); + + auto key = it.get(); + + vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); + vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); + vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); + + vd.template getLastProp<velocity>()[0] = 0.0; + vd.template getLastProp<velocity>()[1] = 0.0; + vd.template getLastProp<velocity>()[2] = 0.0; + + vd.template getLastProp<force>()[0] = 0.0; + vd.template getLastProp<force>()[1] = 0.0; + vd.template getLastProp<force>()[2] = 0.0; + + ++it; + } + + timer tsim; + tsim.start(); + + //! \cond [verlet skin] \endcond + + // Get the Cell list structure + auto NN = vd.getVerlet(r_gskin); + + //! \cond [verlet skin] \endcond + + // calculate forces + calc_forces(vd,NN,sigma12,sigma6,r_cut); + unsigned long int f = 0; + + int cnt = 0; + double max_disp = 0.0; + + // MD time stepping + for (size_t i = 0; i < 10000 ; i++) + { + // Get the iterator + auto it3 = vd.getDomainIterator(); + + double max_displ = 0.0; + + // integrate velicity and space based on the calculated forces (Step1) + while (it3.isNext()) + { + auto p = it3.get(); + + // here we calculate v(tn + 0.5) + vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; + vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; + vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; + + Point<3,double> disp({vd.template getProp<velocity>(p)[0]*dt,vd.template getProp<velocity>(p)[1]*dt,vd.template getProp<velocity>(p)[2]*dt}); + + // here we calculate x(tn + 1) + vd.getPos(p)[0] += disp.get(0); + vd.getPos(p)[1] += disp.get(1); + vd.getPos(p)[2] += disp.get(2); + + if (disp.norm() > max_displ) + max_displ = disp.norm(); + + ++it3; + } + + if (max_disp < max_displ) + max_disp = max_displ; + + //! \cond [update verlet] \endcond + + // Because we moved the particles in space we have to map them and re-sync the ghost + if (cnt % 10 == 0) + { + vd.map(); + vd.template ghost_get<>(); + // Get the Cell list structure + vd.updateVerlet(NN,r_gskin); + } + else + { + vd.template ghost_get<>(SKIP_LABELLING); + } + + //! \cond [update verlet] \endcond + + cnt++; + + // calculate forces or a(tn + 1) Step 2 + calc_forces(vd,NN,sigma12,sigma6,r_cut); + + // Integrate the velocity Step 3 + auto it4 = vd.getDomainIterator(); + + while (it4.isNext()) + { + auto p = it4.get(); + + // here we calculate v(tn + 1) + vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; + vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; + vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; + + ++it4; + } + + // After every iteration collect some statistic about the confoguration + if (i % 100 == 0) + { + // We write the particle position for visualization (Without ghost) + vd.deleteGhost(); + vd.write("particles_",f); + + // we resync the ghost + vd.ghost_get<>(SKIP_LABELLING); + + // We calculate the energy + double energy = calc_energy(vd,NN,sigma12,sigma6,r_cut); + auto & vcl = create_vcluster(); + vcl.sum(energy); + vcl.max(max_disp); + vcl.execute(); + + // we save the energy calculated at time step i c contain the time-step y contain the energy + x.add(i); + y.add({energy}); + + // We also print on terminal the value of the energy + // only one processor (master) write on terminal + if (vcl.getProcessUnitID() == 0) + std::cout << "Energy: " << energy << " " << max_disp << " " << std::endl; + + max_disp = 0.0; + + f++; + } + } + + tsim.stop(); + std::cout << "Time: " << tsim.getwct() << std::endl; + + //! \cond [simulation] \endcond + + // Google charts options, it store the options to draw the X Y graph + GCoptions options; + + // Title of the graph + options.title = std::string("Energy with time"); + + // Y axis name + options.yAxis = std::string("Energy"); + + // X axis name + options.xAxis = std::string("iteration"); + + // width of the line + options.lineWidth = 1.0; + + // Object that draw the X Y graph + GoogleChart cg; + + // Add the graph + // The graph that it produce is in svg format that can be opened on browser + cg.AddLinesGraph(x,y,options); + + // Write into html format + cg.write("gc_plot2_out.html"); + + //! \cond [google chart] \endcond + + /*! + * \page Vector_3_md_vl Vector 3 molecular dynamic with Verlet list + * + * ## Finalize ## {#finalize_v_e3_md_vl} + * + * At the very end of the program we have always to de-initialize the library + * + * \snippet Vector/3_molecular_dynamic/main_vl.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond +} diff --git a/example/Vector/4_complex_prop/Makefile b/example/Vector/4_complex_prop/Makefile index 646357e9532c2ba26a3df94534201be645d20608..2de12f95f6b02c804e5fa5a0b835d5c78fa9337d 100644 --- a/example/Vector/4_complex_prop/Makefile +++ b/example/Vector/4_complex_prop/Makefile @@ -5,20 +5,24 @@ CC=mpic++ LDIR = OBJ = main.o +OBJ_SER = main_ser.o + +all: vect_cp vect_ser %.o: %.cpp $(CC) -O3 -c --std=c++11 -o $@ $< $(INCLUDE_PATH) -vect: $(OBJ) +vect_cp: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) -all: vect +vect_ser: $(OBJ_SER) + $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) run: all - source $$HOME/openfpm_vars; mpirun -np 2 ./vect + mpirun -np 2 ./vect_cp && mpirun -np 2 ./vect_ser .PHONY: clean all run clean: - rm -f *.o *~ core vect + rm -f *.o *~ core vect_cp vect_ser diff --git a/example/Vector/4_complex_prop/config.cfg b/example/Vector/4_complex_prop/config.cfg index 1eecbac3577c765edca7f90cf5f61cfb6b9f4880..6b1aea104e69c4b193ae20921b538d00a9bc2b9a 100644 --- a/example/Vector/4_complex_prop/config.cfg +++ b/example/Vector/4_complex_prop/config.cfg @@ -1,2 +1,2 @@ [pack] -files = main.cpp Makefile +files = main.cpp main_ser.cpp Makefile diff --git a/example/Vector/4_complex_prop/main.cpp b/example/Vector/4_complex_prop/main.cpp index 915f2868ecada4c9610274fbfb090d2af791d67c..8cbae93738629279706cf69e347e5f186f002238 100644 --- a/example/Vector/4_complex_prop/main.cpp +++ b/example/Vector/4_complex_prop/main.cpp @@ -1,12 +1,19 @@ +/*! \page Vector_4_cp Vector 4 complex properties and serialization + * + * \subpage Vector_4_complex_prop + * \subpage Vector_4_complex_prop_ser + * + */ + /*! * - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * * [TOC] * * - * # Vector 4 complex property # {#vector_example_cp} + * # Vector 4 complex properties # {#vector_example_cp} * * * This example show how we can use complex properties in a vector @@ -19,25 +26,62 @@ int main(int argc, char* argv[]) { /*! * - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * * ## Initialization and vector creation ## * + * We first initialize the library and define useful constants + * + * \see \ref e0_s_init + * + * \snippet Vector/4_complex_prop/main.cpp lib init + * + * We also define a custom structure + * + * \snippet Vector/4_complex_prop/main.cpp struct A + * * After we initialize the library we can create a vector with complex properties * with the following line * * \snippet Vector/4_complex_prop/main.cpp vect create * - * In This this particular case every particle carry a scalar, + * In this this particular case every particle carry a scalar, * a vector in form of float[3], a Point, a list - * in form of vector of float and a list of custom structures + * in form of vector of float and a list of custom structures, and a vector of vector. + * In general particles can have properties of arbitrary complexity. + * + * \warning For arbitrary complexity mean that we can use any openfpm data structure with and arbitrary nested complexity. + * For example a openfpm::vector<aggregate<grid_cpu<openfpm::vector<aggregate<double,double[3]>>>,openfpm::vector<float>> is valid + * \verbatim + + particle + * + vector + / \ + / \ + grid vector<float> + /\ + / \ + double double[3] + + * \endverbatim + * + * Our custom data-structure A is defined below. Note that this data-structure + * does not have pointers * * \snippet Vector/4_complex_prop/main.cpp struct A * * + * \warning custom data structure are allowed only if they does not have pointer. + * In case they have pointer we have to define how to serialize our data-structure + * + * \see \ref vector_example_cp_ser + * */ + //! \cond [lib init] \endcond + // initialize the library openfpm_init(&argc,&argv); @@ -50,9 +94,29 @@ int main(int argc, char* argv[]) // extended boundary around the domain, and the processor domain Ghost<2,float> g(0.01); + // the scalar is the element at position 0 in the aggregate + constexpr int scalar = 0; + + // the vector is the element at position 1 in the aggregate + constexpr int vector = 1; + + // the tensor is the element at position 2 in the aggregate + constexpr int point = 2; + + // A list1 + constexpr int list = 3; + + // A listA + constexpr int listA = 4; + + // A list of list + constexpr int listlist = 5; + + //! \cond [lib init] \endcond + //! \cond [struct A] \endcond - // The a custom structure + // The custom structure struct A { float p1; @@ -67,35 +131,21 @@ int main(int argc, char* argv[]) //! \cond [struct A] \endcond - // the scalar is the element at position 0 in the aggregate - constexpr int scalar = 0; - - // the vector is the element at position 1 in the aggregate - constexpr int vector = 1; - - // the tensor is the element at position 2 in the aggregate - constexpr int point = 2; - - // A list1 - constexpr int list = 3; - - // A listA - constexpr int listA = 4; - //! \cond [vect create] \endcond vector_dist<2,float, aggregate<float, float[3], Point<3,double>, openfpm::vector<float>, - openfpm::vector<A>>> + openfpm::vector<A>, + openfpm::vector<openfpm::vector<float>>> > vd(4096,domain,bc,g); //! \cond [vect create] \endcond /*! * - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * * ## Assign values to properties ## @@ -103,8 +153,8 @@ int main(int argc, char* argv[]) * Assign values to properties does not changes, from the simple case. Consider * now that each particle has a list, so when we can get the property listA for particle p * and resize such list with **vd.getProp<listA>(p).resize(...)**. We can add new elements at the - * end with **vd.getProp<listA>(p).add(...)** and get some element with **vd.getProp<listA>(p).get(i)**. - * More in general from vd.getProp<listA>(p) we can use the full openfpm::vector interface. + * end with **vd.getProp<listA>(p).add(...)** and get some element of this list with **vd.getProp<listA>(p).get(i)**. + * More in general vd.getProp<listA>(p) return a reference to the openfpm::vector contained by the particle. * * \snippet Vector/4_complex_prop/main.cpp vect assign * @@ -135,7 +185,7 @@ int main(int argc, char* argv[]) vd.getProp<point>(p).get(1) = 1.0; vd.getProp<point>(p).get(2) = 1.0; - size_t n_cp = (float)10 * rand()/RAND_MAX; + size_t n_cp = (float)10.0 * rand()/RAND_MAX; vd.getProp<listA>(p).resize(n_cp); @@ -146,10 +196,17 @@ int main(int argc, char* argv[]) vd.getProp<list>(p).add(i + 30); vd.getProp<listA>(p).get(i) = A(i+10.0,i+20.0); - vd.getProp<listA>(p).get(i) = A(i+30.0,i+40.0); - vd.getProp<listA>(p).get(i) = A(i+50.0,i+60.0); } + vd.getProp<listlist>(p).resize(2); + vd.getProp<listlist>(p).get(0).resize(2); + vd.getProp<listlist>(p).get(1).resize(2); + + vd.getProp<listlist>(p).get(0).get(0) = 1.0; + vd.getProp<listlist>(p).get(0).get(1) = 2.0; + vd.getProp<listlist>(p).get(1).get(0) = 3.0; + vd.getProp<listlist>(p).get(1).get(1) = 4.0; + // next particle ++it; } @@ -158,20 +215,20 @@ int main(int argc, char* argv[]) /*! * - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * * ## Mapping and ghost_get ## * - * Particles are redistributed across processors but only the scalar,vector and the point - * are communicated (properties 0,1,2). A lot of time complex properties can be recomputed and - * communicate them is not a good idea. The same concept also apply for ghost_get + * Particles are redistributed across processors all properties are communicated but instead of + * using map we use **map_list** that we can use to select properties. + * A lot of time complex properties can be recomputed and communicate them is not a good idea. + * The same concept also apply for ghost_get. In general we choose which properties to communicate * - * \note OpenFPM <= 0.5.0 cannot communicate complex properties like a vector or other structure - * that are not POD object * - * \note OpenFPM > 0.5.0 Does not have such limitation + * \see \ref e0_s_map * + * \see \ref e1_part_ghost * * \snippet Vector/4_complex_prop/main.cpp vect map ghost * @@ -181,16 +238,16 @@ int main(int argc, char* argv[]) // Particles are redistribued across the processors but only the scalar,vector, and point properties // are transfert - vd.map_list<scalar,vector,point>(); + vd.map_list<scalar,vector,point,list,listA,listlist>(); // Synchronize the ghost - vd.ghost_get<scalar,vector,point>(); + vd.ghost_get<scalar,vector,point,listA,listlist>(); //! \cond [vect map ghost] \endcond /*! * - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * * ## Output and VTK visualization ## @@ -198,6 +255,8 @@ int main(int argc, char* argv[]) * Vector with complex properties can be still be visualized, because unknown properties are * automatically excluded * + * \see \ref e0_s_vis_vtk + * * \snippet Vector/4_complex_prop/main.cpp vtk * */ @@ -209,7 +268,44 @@ int main(int argc, char* argv[]) //! \cond [vtk] \endcond /*! - * \page Vector_4_complex_prop Vector 4 complex property + * + * \page Vector_4_complex_prop Vector 4 complex properties + * + * ## Print 4 particles in the ghost area ## + * + * Here we print that the first 4 particles to show that the list of A and the list of list are filled + * and the ghosts contain the correct information + * + * \snippet Vector/4_complex_prop/main.cpp print ghost info + * + */ + + //! \cond [print ghost info] \endcond + + size_t fg = vd.size_local(); + + Vcluster & v_cl = create_vcluster(); + if (v_cl.getProcessUnitID() == 0) + { + for ( ; fg < vd.size_local()+4 ; fg++) + { + std::cout << "List of A" << std::endl; + for (size_t i = 0 ; i < vd.getProp<listA>(fg).size() ; i++) + std::cout << "Element: " << i << " p1=" << vd.getProp<listA>(fg).get(i).p1 << " p2=" << vd.getProp<listA>(fg).get(i).p2 << std::endl; + + std::cout << "List of list" << std::endl; + for (size_t i = 0 ; i < vd.getProp<listlist>(fg).size() ; i++) + { + for (size_t j = 0 ; j < vd.getProp<listlist>(fg).get(i).size() ; j++) + std::cout << "Element: " << i << " " << j << " " << vd.getProp<listlist>(fg).get(i).get(j) << std::endl; + } + } + } + + //! \cond [print ghost info] \endcond + + /*! + * \page Vector_4_complex_prop Vector 4 complex properties * * ## Finalize ## {#finalize} * @@ -226,7 +322,7 @@ int main(int argc, char* argv[]) //! \cond [finalize] \endcond /*! - * \page Vector_4_complex_prop Vector 4 complex property + * \page Vector_4_complex_prop Vector 4 complex properties * * # Full code # {#code} * diff --git a/example/Vector/4_complex_prop/main_ser.cpp b/example/Vector/4_complex_prop/main_ser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a7e91dbe282616d201d71f9c6a088c51749d71f --- /dev/null +++ b/example/Vector/4_complex_prop/main_ser.cpp @@ -0,0 +1,504 @@ +/*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * + * [TOC] + * + * + * # Vector 4 property serialization # {#vector_example_cp_ser} + * + * + * This example show how we can use complex properties in a vector when we use a custom structure with + * a pointer inside. In particular we will show how to construct the serialization and de-serialization + * methods for the structure my_struct defined here + * + * \snippet Vector/4_complex_prop/main_ser.cpp my structure + * + * \snippet Vector/4_complex_prop/main_ser.cpp my structure end + * + */ + +#include "Vector/vector_dist.hpp" + +//! \cond [my structure] \endcond + +struct my_struct +{ + //! C string size + size_t size; + + //! C string pointer + char * ptr; + + //! C++ string + std::string str; + + //! vector + openfpm::vector<int> v; + +//! \cond [my structure] \endcond + +public: + + //! Functions to check if the packing object is complex + static bool pack() {return true;} + + + //! \cond [con and dest] \endcond + + my_struct() + { + size = 0; + ptr = NULL; + } + + ~my_struct() + { + if (ptr != NULL) + delete [] ptr; + } + + //! \cond [con and dest] \endcond + + //! \cond [pack request] \endcond + + //! Serialization request + template<int ... prp> inline void packRequest(size_t & req) const + { + req += 2*sizeof(size_t) + size + str.size()+1; + v.packRequest(req); + } + + //! \cond [pack request] \endcond + + //! \cond [pack serialize] \endcond + + //! Serialize the data structure + template<typename Memory, int ... prp> inline void pack(ExtPreAlloc<Memory> & mem, Pack_stat & sts) const + { + //! \cond [packer ser pack] \endcond + + //Serialize the number that determine the C-string size + Packer<size_t, Memory>::pack(mem,size,sts); + + //! \cond [packer ser pack] \endcond + + //! \cond [pack ser copy] \endcond + + // Allocate and copy the string + mem.allocate(size); + void * t_ptr = mem.getPointer(); + memcpy(t_ptr,ptr,size); + + //! \cond [pack ser copy] \endcond + + //! \cond [pack ser other] \endcond + + //Serialize the number that determine the C++-string str.size()+1 given by the null terminator + Packer<size_t, Memory>::pack(mem,str.size()+1,sts); + + // Allocate and copy the string + mem.allocate(str.size()+1); + char * t_ptr2 = (char *)mem.getPointer(); + memcpy(t_ptr2,str.c_str(),str.size()); + + // Add null terminator + t_ptr2[str.size()] = 0; + + Packer<decltype(v), Memory>::pack(mem,v,sts); + + //! \cond [pack ser other] \endcond + } + + //! \cond [pack serialize] \endcond + + //! \cond [unpack de-serialize] \endcond + + //! De-serialize the data structure + template<typename Memory, int ... prp> inline void unpack(ExtPreAlloc<Memory> & mem, Unpack_stat & ps) + { + //! \cond [unpacker ser pack] \endcond + + // unpack the size of the C string + Unpacker<size_t, Memory>::unpack(mem,size,ps); + + //! \cond [unpacker ser pack] \endcond + + //! \cond [unpacker ser create] \endcond + + // Allocate the C string + ptr = new char[size]; + + // source pointer + char * ptr_src = (char *)mem.getPointerOffset(ps.getOffset()); + + // copy from the buffer to the destination + memcpy(ptr,ptr_src,size); + + // update the pointer + ps.addOffset(size); + + //! \cond [unpacker ser create] \endcond + + //! \cond [unpacker ser other] \endcond + + // get the the C++ string size + size_t cpp_size; + Unpacker<size_t, Memory>::unpack(mem,cpp_size,ps); + + // Create the string from the serialized data (de-serialize) + char * ptr_src2 = (char *)mem.getPointerOffset(ps.getOffset()); + str = std::string(ptr_src2); + ps.addOffset(cpp_size); + + // Unpack the vector + Unpacker<decltype(v), Memory>::unpack(mem,v,ps); + + //! \cond [unpacker ser other] \endcond + } + + //! \cond [unpack de-serialize] \endcond + +//! \cond [my structure end] \endcond + +}; + +//! \cond [my structure end] \endcond + +/*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * In order to make my_struct serializable we need 3 methods + * + * * **packRequest** This method indicate how many byte are needed to serialize this structure + * * **pack** This method serialize the data-structure + * * **unpack** This method de-serialize the data structure + * + * ### packRequest ### + * + * \snippet Vector/4_complex_prop/main_ser.cpp pack request + * + * This function calculate the size in byte to serialize this structure in this case we serialize + * 2 numbers so 2*sizeof(size_t). One C string of size "size" and one C++ string of size str.size(). Because + * std::string has a constructor from null terminating string we add the null terminator to easy construct an + * std::string. This mean that + * the C++ string will be serialized in str.size()+1 bytes. The result must be summed to counter req that is used + * to allocate a buffer big enough for serialization. The function is template and has a variadic argument + * "int ... prp" this can be ignored + * + * ### pack ### + * + * Here we serialize the object. The function give as argument + * + * * **ExtPreAlloc<Memory>** mem The memory where we have to serialize the information + * * **Pack_stat** unused + * * **int ... prp** unused + * + * The only important parameter is the object mem where we will serialize the information + * + * We first pack the number that indicate the size of the C string. A convenient way + * is use the function + * + * \snippet Vector/4_complex_prop/main_ser.cpp packer ser pack + * + * The function **Packer<decltype(object),Memory>::pack(object,sts)** work if **object** is a + * fundamental C++ type, a struct that does not contain pointers, any object that + * implement the interface pack,unpack,packRequest (like my_struct). Most openfpm + * data-structure like openfpm::vector and grid implement such interface and + * can be used directly with **Packer<...>::pack(...)**. + * After packed the size of the string we have to serialize the content of the pointer string. + * unfortunately there is no Packer<...>::pack(...) function to do this and must be + * manually done. This can be done with the following steps + * + * * Allocate the memory to copy the value of the string + * * Get the pointer to the memory allocated + * * copy the content of the string into the allocated memory + * + * \snippet Vector/4_complex_prop/main_ser.cpp pack ser copy + * + * For the C++ string the concept is the same, the difference is that we put a null terminator at the end + * of the serialized string + * + * \snippet Vector/4_complex_prop/main_ser.cpp pack ser other + * + * ### unpack ### + * + * Here we de-serialize the object. The function take a reference to object + * + * * **ExtPreAlloc<Memory>** mem, contain the serialized information that must be de-serialized + * * **Pack_stat** contain the offset to the memory to de-serialize + * * **int ... prp** unused + * + * De-serialization must be in general done in the same order as we serialized + * We first unpack the number that indicate the size of the C string. A convenient way + * is to use the function + * + * \snippet Vector/4_complex_prop/main_ser.cpp unpacker ser pack + * + * the variable **size** contain now the size of the packed string we can now + * + * * create memory with **new** that store the C string + * * Get the pointer to the serialized information + * * copy the string from mem into the created memory + * * update the offset pointer + * + * \snippet Vector/4_complex_prop/main_ser.cpp unpacker ser create + * + * For the C++ string is just the same + * + * * We get the size of the string + * * we create an std::string out of the null terminating serialized string + * * we assign the created std::string to str + * + * \snippet Vector/4_complex_prop/main_ser.cpp unpacker ser other + * + * ### Constructor and destructor ### + * + * Constructor and destructor are not releated to serialization and de-serialization concept. + * But on how my_struct is constructed and destructed in order to avoid memory + * leak/corruption. In the constructor we set ptr to NULL in the destructor we + * destroy the pointer (if different from NULL) to avoid memory leak + * + * \snippet Vector/4_complex_prop/main_ser.cpp con and dest + * + */ + +int main(int argc, char* argv[]) +{ + /*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * + * ## Initialization and vector creation ## + * + * After we initialize the library we can create a vector with complex properties + * with the following line + * + * \snippet Vector/4_complex_prop/main.cpp vect create + * + * In this this particular case every particle carry two my_struct object + * + */ + + // initialize the library + openfpm_init(&argc,&argv); + + // Here we define our domain a 2D box with internals from 0 to 1.0 for x and y + Box<2,float> domain({0.0,0.0},{1.0,1.0}); + + // Here we define the boundary conditions of our problem + size_t bc[2]={PERIODIC,PERIODIC}; + + // extended boundary around the domain, and the processor domain + Ghost<2,float> g(0.01); + + // my_struct at position 0 in the aggregate + constexpr int my_s1 = 0; + + // my_struct at position 1 in the aggregate + constexpr int my_s2 = 1; + + //! \cond [vect create] \endcond + + vector_dist<2,float, aggregate<my_struct,my_struct>> + vd(4096,domain,bc,g); + + std::cout << "HAS PACK: " << has_pack_agg<aggregate<my_struct,my_struct>>::result::value << std::endl; + + //! \cond [vect create] \endcond + + /*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * + * ## Assign values to properties ## + * + * In this loop we assign position to particles and we fill the two my_struct + * that each particle contain. As demostration the first my_struct is filled + * with the string representation of the particle coordinates. The second my struct + * is filled with the string representation of the particle position multiplied by 2.0. + * The the vectors of the two my_struct are filled respectively with the sequence + * 1,2,3 and 1,2,3,4 + * + * + * + * \snippet Vector/4_complex_prop/main_ser.cpp vect assign + * + */ + + //! \cond [vect assign] \endcond + + auto it = vd.getDomainIterator(); + + while (it.isNext()) + { + auto p = it.get(); + + // we define x, assign a random position between 0.0 and 1.0 + vd.getPos(p)[0] = (float)rand() / RAND_MAX; + + // we define y, assign a random position between 0.0 and 1.0 + vd.getPos(p)[1] = (float)rand() / RAND_MAX; + + // Get the particle position as point + Point<2,float> pt = vd.getPos(p); + + // create a C string from the particle coordinates + // and copy into my struct + vd.getProp<my_s1>(p).size = 32; + vd.getProp<my_s1>(p).ptr = new char[32]; + strcpy(vd.getProp<my_s1>(p).ptr,pt.toString().c_str()); + + // create a C++ string from the particle coordinates + vd.getProp<my_s1>(p).str = std::string(pt.toString()); + + vd.getProp<my_s1>(p).v.add(1); + vd.getProp<my_s1>(p).v.add(2); + vd.getProp<my_s1>(p).v.add(3); + + pt = pt * 2.0; + + // create a C string from the particle coordinates multiplied by 2.0 + // and copy into my struct + vd.getProp<my_s2>(p).size = 32; + vd.getProp<my_s2>(p).ptr = new char[32]; + strcpy(vd.getProp<my_s2>(p).ptr,pt.toString().c_str()); + + // create a C++ string from the particle coordinates + vd.getProp<my_s2>(p).str = std::string(pt.toString()); + + vd.getProp<my_s2>(p).v.add(1); + vd.getProp<my_s2>(p).v.add(2); + vd.getProp<my_s2>(p).v.add(3); + vd.getProp<my_s2>(p).v.add(4); + + // next particle + ++it; + } + + //! \cond [vect assign] \endcond + + /*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * + * ## Mapping and ghost_get ## + * + * Particles are redistributed across processors and we also synchronize the ghost + * + * \see \ref e0_s_map + * + * \see \ref e1_part_ghost + * + * \snippet Vector/4_complex_prop/main_ser.cpp vect map ghost + * + */ + + //! \cond [vect map ghost] \endcond + + // Particles are redistribued across the processors + vd.map(); + + // Synchronize the ghost + vd.ghost_get<my_s1,my_s2>(); + + //! \cond [vect map ghost] \endcond + + /*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * + * ## Output and VTK visualization ## + * + * Vector with complex properties can be still be visualized, because unknown properties are + * automatically excluded + * + * \see \ref e0_s_vis_vtk + * + * \snippet Vector/4_complex_prop/main.cpp vtk + * + */ + + //! \cond [vtk] \endcond + + vd.write("particles"); + + //! \cond [vtk] \endcond + + /*! + * + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * ## Print 4 particles in the ghost area ## + * + * Here we print that the first 4 particles to show that the two my_struct contain the + * right information + * + * \snippet Vector/4_complex_prop/main_ser.cpp print ghost info + * + */ + + //! \cond [print ghost info] \endcond + + size_t fg = vd.size_local(); + + Vcluster & v_cl = create_vcluster(); + + // Only the master processor print + if (v_cl.getProcessUnitID() == 0) + { + // Print 4 particles + for ( ; fg < vd.size_local()+4 ; fg++) + { + // Print my struct1 information + std::cout << "my_struct1:" << std::endl; + std::cout << "C-string: " << vd.getProp<my_s1>(fg).ptr << std::endl; + std::cout << "Cpp-string: " << vd.getProp<my_s1>(fg).str << std::endl; + + for (size_t i = 0 ; i < vd.getProp<my_s1>(fg).v.size() ; i++) + std::cout << "Element: " << i << " " << vd.getProp<my_s1>(fg).v.get(i) << std::endl; + + // Print my struct 2 information + std::cout << "my_struct2" << std::endl; + std::cout << "C-string: " << vd.getProp<my_s2>(fg).ptr << std::endl; + std::cout << "Cpp-string: " << vd.getProp<my_s2>(fg).str << std::endl; + + for (size_t i = 0 ; i < vd.getProp<my_s2>(fg).v.size() ; i++) + std::cout << "Element: " << i << " " << vd.getProp<my_s2>(fg).v.get(i) << std::endl; + } + } + + //! \cond [print ghost info] \endcond + + /*! + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * ## Finalize ## {#finalize} + * + * At the very end of the program we have always to de-initialize the library + * + * \snippet Vector/4_complex_prop/main_ser.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond + + /*! + * \page Vector_4_complex_prop_ser Vector 4 property serialization + * + * # Full code # {#code} + * + * \include Vector/4_complex_prop/main_ser.cpp + * + */ +} diff --git a/example/Vector/4_multiphase_celllist/main.cpp b/example/Vector/4_multiphase_celllist/main.cpp deleted file mode 100644 index 60a2007c24246f1e0a369ad75bde9c0c980743fd..0000000000000000000000000000000000000000 --- a/example/Vector/4_multiphase_celllist/main.cpp +++ /dev/null @@ -1,240 +0,0 @@ - -#include "Vector/vector_dist.hpp" -#include "Decomposition/CartDecomposition.hpp" -#include "data_type/aggregate.hpp" -#include "NN/CellList/CellListM.hpp" - -/*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * [TOC] - * - * - * # Vector Multi Phase cell-list # {#e4_ph_cl} - * - * This example show multi-phase cell lists for the distributed vector - * - * \warning BETA version - * - */ - -int main(int argc, char* argv[]) -{ - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * ## Initialization ## - * - * Here we Initialize the library, and we create a set of distributed vectors all forced to have the same - * decomposition. Each vector identify one phase - * - * \snippet Vector/4_multiphase_celllist/main.cpp Initialization and parameters - * - */ - - //! \cond [Initialization and parameters] \endcond - - openfpm_init(&argc,&argv); - Vcluster & v_cl = create_vcluster(); - - // we will place the particles on a grid like way with 128 particles on each direction - size_t sz[3] = {128,128,128}; - - // The domain - Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); - - // Boundary conditions - size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; - - float r_cut = 0.05; - - // ghost, big enough to contain the interaction radius - Ghost<3,float> ghost(r_cut); - - openfpm::vector< vector_dist<3,float, aggregate<double,double>> > phases; - - // first phase - phases.add( vector_dist<3,float, aggregate<double,double>>(4096,box,bc,ghost) ); - - // The other 3 phases - phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); - phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); - phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); - - - //! \cond [Initialization and parameters] \endcond - - - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * ## Initialization ## - * - * We initialize all the phases with particle randomly positioned in the space - * - * \snippet Vector/4_multiphase_celllist/main.cpp rand dist - * - */ - - //! \cond [rand dist] \endcond - - auto it = phases.get(0).getDomainIterator(); - - // For all the particles - while (it.isNext()) - { - // for all phases - for (size_t i = 0 ; i < phases.size() ; i++) - { - auto key = it.get(); - - phases.get(i).getPos(key)[0] = (float)rand() / RAND_MAX; - phases.get(i).getPos(key)[1] = (float)rand() / RAND_MAX; - phases.get(i).getPos(key)[2] = (float)rand() / RAND_MAX; - } - // next point - ++it; - } - - // Redistribute all the phases in the mean while also take the iterators of all the phases - - typedef decltype(phases.get(0).getIterator()) iterator; - openfpm::vector<iterator> phase_it; - - for (size_t i = 0 ; i < phases.size() ; i++) - phases.get(i).map(); - - //! \cond [rand dist] \endcond - - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * ## Multi-phase cell-list construction ## - * - * In this part we construct the Multi-phase cell list. The multiphase cell list has 3 parameters - * * one is the dimensionality (3) - * * The precision of the coordinates (float), - * * How many bit to use for the phase. - * Multi-phase cell-list try to pack into a 64bit number information about the particle id and the - * the phase id. - * - * \snippet Vector/4_multiphase_celllist/main.cpp cl construction - * - */ - - //! \cond [cl construction] \endcond - - // Construct one single Multi-phase cell list to use in the computation - // in 3d, precision float, 2 bit dedicated to the phase for a maximum of 2^2 = 4 (Maximum number of phase) - // - // - - size_t div[3]; - Box<3,float> box_cl; - phases.get(0).getCellListParams(r_cut,div,box_cl); - - CellListM<3,float,2> NN; - NN.Initialize(box_cl,div); - - // for all the phases i - for (size_t i = 0; i < phases.size() ; i++) - { - // iterate across all the particle of the phase i - auto it = phases.get(i).getDomainIterator(); - while (it.isNext()) - { - auto key = it.get(); - - // Add the particle of the phase i to the cell list - NN.add(phases.get(i).getPos(key), key.getKey(), i); - - ++it; - } - } - - //! \cond [cl construction] \endcond - - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * ## Multi-phase cell-list usage ## - * - * After construction we show how to use the Cell-list. In this case we accumulate on the property - * 0 of the phase 0 the distance of the near particles from all the phases - * - * \snippet Vector/4_multiphase_celllist/main.cpp cl usage - * - */ - - //! \cond [cl usage] \endcond - - vector_dist<3,float, aggregate<double,double> > & current_phase = phases.get(0); - - // Get the iterator of the particles of phase 0 - auto it2 = current_phase.getIterator(); - - // For each particle ... - while (it2.isNext()) - { - // ... p - auto p = it2.get(); - - // Get the position of the particle p - Point<3,float> xp = current_phase.getPos(p); - - // Get an iterator of all the particles neighborhood of p - auto Np = NN.getNNIterator(NN.getCell(current_phase.getPos(p))); - - // For each particle near p - while (Np.isNext()) - { - // Get the particle q near to p - auto q = Np.getP(); - - // Get from which phase it come from - auto ph_q = Np.getV(); - - Point<3,float> xq = phases.get(ph_q).getPos(q); - - // we accumulate all the distances - current_phase.getProp<0>(p) = norm(xp - xq); - - ++Np; - } - - // Next particle p - ++it2; - } - - //! \cond [cl usage] \endcond - - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * ## Finalize ## {#finalize} - * - * At the very end of the program we have always de-initialize the library - * - * \snippet Vector/4_multiphase_celllist/main.cpp finalize - * - */ - - //! \cond [finalize] \endcond - - openfpm_finalize(); - - //! \cond [finalize] \endcond - - /*! - * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list - * - * # Full code # {#code} - * - * \include Vector/4_multiphase_celllist/main.cpp - * - */ -} - - - - diff --git a/example/Vector/4_multiphase_celllist_verlet/Makefile b/example/Vector/4_multiphase_celllist_verlet/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e14eedbb41b3cc4cd79451b34eebcc209de98f2a --- /dev/null +++ b/example/Vector/4_multiphase_celllist_verlet/Makefile @@ -0,0 +1,24 @@ +include ../../example.mk + +CC=mpic++ + +LDIR = + +OBJ = main.o + +%.o: %.cpp + $(CC) -O3 -g -c --std=c++11 -o $@ $< $(INCLUDE_PATH) + +multip: $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) + +all: multip + +run: all + mpirun -np 2 ./multip + +.PHONY: clean all run + +clean: + rm -f *.o *~ core multip + diff --git a/example/Vector/4_multiphase_celllist_verlet/config.cfg b/example/Vector/4_multiphase_celllist_verlet/config.cfg new file mode 100644 index 0000000000000000000000000000000000000000..1eecbac3577c765edca7f90cf5f61cfb6b9f4880 --- /dev/null +++ b/example/Vector/4_multiphase_celllist_verlet/config.cfg @@ -0,0 +1,2 @@ +[pack] +files = main.cpp Makefile diff --git a/example/Vector/4_multiphase_celllist_verlet/main.cpp b/example/Vector/4_multiphase_celllist_verlet/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e426b889e26f9aec2d7d4a1a1e8c822a2e9c9809 --- /dev/null +++ b/example/Vector/4_multiphase_celllist_verlet/main.cpp @@ -0,0 +1,575 @@ + +#include "Vector/vector_dist.hpp" +#include "Decomposition/CartDecomposition.hpp" +#include "data_type/aggregate.hpp" +#include "NN/CellList/CellListM.hpp" +#include "Vector/vector_dist_multiphase_functions.hpp" + +/*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list and verlet + * + * [TOC] + * + * + * # Vector Multi Phase cell-list and Verlet # {#e4_ph_cl} + * + * This example show how to use multi-phase cell lists and Verlet-list.More in general + * it show how to construct Verlet and Cell-list between multiple vector_dist. + * + * + */ + +int main(int argc, char* argv[]) +{ + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Initialization ## + * + * Here we Initialize the library, and we create a set of distributed vectors all forced to have the same + * decomposition. Each vector identify one phase. + * + * \note Be carefull on how you initialize the other phases. All the other phases + * must be forced to use the same decomposition. In order to do this we have + * to use the special constructor where we pass the decomposition from the first + * phase. The second parameter is just the the number of particles + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp Initialization and parameters + * + */ + + //! \cond [Initialization and parameters] \endcond + + openfpm_init(&argc,&argv); + + // Vcluster for general usage + Vcluster & v_cl = create_vcluster(); + + // The domain + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + // cut-off radius + float r_cut = 0.05; + + // ghost, big enough to contain the interaction radius + Ghost<3,float> ghost(r_cut); + + // The set of phases + openfpm::vector< vector_dist<3,float, aggregate<double,double>> > phases; + + // first phase + phases.add( vector_dist<3,float, aggregate<double,double>>(4096,box,bc,ghost) ); + + // The other 3 phases + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + + + //! \cond [Initialization and parameters] \endcond + + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Create phases ## + * + * We initialize all the phases with particle randomly positioned in the space. Completed this + * iteration we redistribute the particles using the classical map, and we synchronize the ghost + * + * \warning we cannot use the same iterator for all the phases even if the number of particles for + * each phase is the same. Consider that the number of particles (per-processor) can be + * different. The case of the initialization ("before map") is the only case where we are + * sure that the number of particles per processor is the same for each phase + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp rand dist + * + */ + + //! \cond [rand dist] \endcond + + // An iterator over the particles of the phase0 + auto it = phases.get(0).getDomainIterator(); + + // For all the particles of phase0 + while (it.isNext()) + { + // particle p + auto p = it.get(); + + // Assign the position of the particles to each phase + for (size_t i = 0 ; i < phases.size(); i++) + { + // Assign random position + phases.get(i).getPos(p)[0] = (float)rand() / RAND_MAX; + phases.get(i).getPos(p)[1] = (float)rand() / RAND_MAX; + phases.get(i).getPos(p)[2] = (float)rand() / RAND_MAX; + } + + // Next particle + ++it; + } + + + // Redistribute and sync all the phases + for (size_t i = 0 ; i < 4 ; i++) + { + phases.get(i).map(); + phases.get(i).ghost_get<>(); + } + + //! \cond [rand dist] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Multi phase Verlet-list ## + * + * In general verlet-list can be constructed from the vector itself using **getVerlerList()** + * + * \see \ref Vector_3_md_vl + * + * In the multi-phase case if we use such function on phase0 such function + * produce a Verlet list where for each particle of the phase0 we get the neighborhood + * particles within the phase0. Most of time we also want to construct Verlet-list across + * phases, for example between phase0 and phase1. Let suppose now that we want to construct + * a verlet-list that given the particles of the phase0 it return the neighborhood particles + * in phase1. In order to do this we can create a Cell-list from phase1. Once we have the + * Cell-list for phase 1 we give to **createVerlet()** + * the particle set of phase0, the Cell-list of phase1 and the cut-off radius. + * The function return a VerletList between phase0 and 1 that can be used to do computation. + * + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp create multi-phase verlet + * + */ + + //! \cond [create multi-phase verlet] \endcond + + // Get the cell list of the phase1 + auto CL_phase1 = phases.get(1).getCellList(r_cut); + + // This function create a Verlet-list between phases 0 and 1 + auto NN_ver01 = createVerlet(phases.get(0),CL_phase1,r_cut); + + //! \cond [create multi-phase verlet] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * Once we have a Verlet-list, we can do easily computation with that. We can use + * the function **getNNIterator()** to get an iterator of the neighborhood particles + * for a specified particle. In this case for each particle of the phase0 we count + * the neighborhood particles in phase1 + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp count part from phase0 to 1 + * + */ + + //! \cond [count part from phase0 to 1] \endcond + + // Get an iterator of the particles of the phase0 + it = phases.get(0).getDomainIterator(); + + // For each particle of the phase0 + while (it.isNext()) + { + // Get the particle p + auto p = it.get(); + + // reset the counter + phases.get(0).getProp<0>(p) = 0; + + // Get an iterator over the neighborhood particles for the particle p + auto Np = NN_ver01.template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q + auto q = Np.get(); + + // Count the number of particles + // Here in general we can do our computation + phases.get(0).getProp<0>(p)++; + + // Next particle + ++Np; + } + + // Next particle + ++it; + } + + //! \cond [count part from phase0 to 1] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## From one phase to all ## + * + * It is also possible to construct a Verlet-list from one phase to all the other phases. + * To do this we use the function **createCellListM<2>()** to first create a + * multi-phase cell-list. The template parameter is required to indicate how many bit + * to reserve for the phase information. + * + * \note In case of + * * 2 bit mean that you can store up to 4 phases (2^62 number of particles for each phase) + * * 3 bit mean that you can store up to 8 phases (2^61 number of particles for each phase) + * + * Once created the multiphase-cell list from the phases. We can use the function + * **createVerletM()** to create a verlet-list from one phase to all the others. + * The function requires the particle for which we are constructing the verlet list, in this case + * the phase0, the Cell-list containing all the other phases and the cut-off radius. + * + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp create multi-phase multi verlet + * + */ + + //! \cond [create multi-phase multi verlet] \endcond + + // This function create an "Empty" Multiphase Cell List from all the phases + auto CL_all = createCellListM<2>(phases,r_cut); + + // This create a Verlet-list between phase0 and all the other phases + auto NNver0_all = createVerletM<2>(phases.get(0),CL_all,r_cut); + + //! \cond [create multi-phase multi verlet] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * Compute on a multiphase verlet-list is very similar to a non multi-phase. + * The only difference is that the function **get()** is substituted by two + * other functions **getP()** and **getV()** The first return the phase from where + * it come the particle the second it return the particle-id + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp compute multi-phase multi verlet + * + */ + + //! \cond [compute multi-phase multi verlet] \endcond + + // Get an iterator for the phase0 particles + it = phases.get(0).getDomainIterator(); + + while (it.isNext()) + { + // Get the particle p + auto p = it.get(); + + // Get an interator over the neighborhood of the particle p + auto Np = NNver0_all.template getNNIterator<NO_CHECK>(p.getKey()); + + // reset the counter + phases.get(0).getProp<0>(p) = 0; + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Get the particle q near to p + auto q = Np.getP(); + + // Get from which phase it come from + auto ph_q = Np.getV(); + + // count + phases.get(0).getProp<0>(p)++; + + // Next particle + ++Np; + } + + // Next particle + ++it; + } + + //! \cond [compute multi-phase multi verlet] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Symmetric interaction case ## + * + * The same functions exist also in the case we want to construct + * symmetric-verlet list. + * + * \see \ref Vector_5_md_vl_sym For more details on how to use symmetric + * verlet-list in a real case. + * + * In general the main differences can be summarized in + * * we have to reset the **forces** or **interaction** variable(s) + * * calculate the interaction p-q and apply the result to p and q at the same time + * * merge with ghost_put the result is stored in the ghost part with the + * real particles + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp compute sym multi-phase two phase + * + */ + + //! \cond [compute sym multi-phase two phase] \endcond + + // Get the cell list of the phase1 + CL_phase1 = phases.get(1).getCellListSym(r_cut); + + // This function create a Verlet-list between phases 0 and 1 + NN_ver01 = createVerletSym(phases.get(0),CL_phase1,r_cut); + + // Get an iterator over the real and ghost particles + it = phases.get(0).getDomainAndGhostIterator(); + + // For each particles + while (it.isNext()) + { + // Get the particle p + auto p = it.get(); + + // Reset the counter + phases.get(0).getProp<0>(p) = 0; + + // Next particle + ++it; + } + + // Compute interaction from phase0 to phase1 + + // Get an iterator over the real particles of phase0 + it = phases.get(0).getDomainIterator(); + + // For each particle of the phase0 + while (it.isNext()) + { + // get particle p + auto p = it.get(); + + // Get the neighborhood of particle p + auto Np = NN_ver01.template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q of p + auto q = Np.get(); + + // increment the counter for the phase 0 and 1 + phases.get(0).getProp<0>(p)++; + phases.get(1).getProp<0>(q)++; + + // Next particle + ++Np; + } + + // Next particle + ++it; + } + + // Merge the information of the ghost with the real particles + phases.get(0).ghost_put<add_,0>(); + phases.get(1).ghost_put<add_,0>(); + + //! \cond [compute sym multi-phase two phase] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * For the case of a Verlet-list between the phase0 and all the other phases. + * The code remain very similar to the previous one the only differences is that + * we have to create a Multi-phase cell list from the vector of the phases. + * When we compute with the verlet-list list now the simple function **get** + * is substituted by the function **getP** and **getV**. In this example we are + * creating 4 multiphase symmetric verlet-list + * + * * 0 to all + * * 1 to all + * * 2 to all + * * 3 to all + * + * The computation is an all to all + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp create sym multi-phase multi verlet + * + */ + + //! \cond [create sym multi-phase multi verlet] \endcond + + // Get an iterator over the phase0 + it = phases.get(0).getDomainAndGhostIterator(); + + // For each particle of the phase 0 + while (it.isNext()) + { + // get the particle p + auto p = it.get(); + + // Reset the counter for the domain and ghost particles + phases.get(0).getProp<0>(p) = 0; + phases.get(1).getProp<0>(p) = 0; + phases.get(2).getProp<0>(p) = 0; + phases.get(3).getProp<0>(p) = 0; + + // next particle + ++it; + } + + // This function create an "Empty" Multiphase Cell List + CL_all = createCellListSymM<2>(phases,r_cut); + + // Type of the multiphase Verlet-list + typedef decltype(createVerletSymM<2>(phases.get(0),CL_all,r_cut)) verlet_type; + + // for each phase we create one Verlet-list that contain the neighborhood + // from all the phases + verlet_type NNver_all[4]; + + // Here we create a Verlet-list between each phases + + // 0 to all + NNver_all[0] = createVerletSymM<2>(phases.get(0),CL_all,r_cut); + + // 1 to all + NNver_all[1] = createVerletSymM<2>(phases.get(1),CL_all,r_cut); + + // 2 to all + NNver_all[2] = createVerletSymM<2>(phases.get(2),CL_all,r_cut); + + // 3 to all + NNver_all[3] = createVerletSymM<2>(phases.get(3),CL_all,r_cut); + + // For each phase + for (size_t i = 0 ; i < phases.size() ; i++) + { + // Get an iterator over the particles of that phase + it = phases.get(i).getDomainIterator(); + + // for each particle of the phase + while (it.isNext()) + { + // Get the particle p + auto p = it.get(); + + // Get an iterator for neighborhood of the particle p + auto Np = NNver_all[i].template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood particle + while (Np.isNext()) + { + // Get the particle q near to p + auto q = Np.getP(); + + // Get from which phase it come from + auto ph_q = Np.getV(); + + // increment the counter on both p and q + phases.get(i).getProp<0>(p)++; + phases.get(ph_q).getProp<0>(q)++; + + // Next particle + ++Np; + } + + // Next particle + ++it; + } + } + + // Merge the ghost part with the real particles + phases.get(0).ghost_put<add_,0>(); + phases.get(1).ghost_put<add_,0>(); + phases.get(2).ghost_put<add_,0>(); + phases.get(3).ghost_put<add_,0>(); + + //! \cond [create sym multi-phase multi verlet] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Multi-phase cell-list usage ## + * + * The multiphase cell-list that we constructed before to create a Verlet-list can be also used + * directly. In this case we accumulate on the property + * 0 of the phase 0 the distance of the near particles from all the phases + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp cl usage + * + */ + + //! \cond [cl usage] \endcond + + // we create a reference to phase0 particle for convenience + vector_dist<3,float, aggregate<double,double> > & current_phase = phases.get(0); + + // Get the iterator of the particles of phase 0 + auto it2 = current_phase.getIterator(); + + // For each particle ... + while (it2.isNext()) + { + // ... p + auto p = it2.get(); + + // Get the position of the particle p + Point<3,float> xp = current_phase.getPos(p); + + // Reset to zero the propety 0 + current_phase.getProp<0>(p) = 0.0; + + // Get an iterator of all the particles neighborhood of p + auto Np = CL_all.getNNIterator(CL_all.getCell(current_phase.getPos(p))); + + // For each particle near p + while (Np.isNext()) + { + // Get the particle q near to p + auto q = Np.getP(); + + // Get from which phase it come from + auto ph_q = Np.getV(); + + Point<3,float> xq = phases.get(ph_q).getPos(q); + + // we accumulate all the distances + current_phase.getProp<0>(p) = norm(xp - xq); + + ++Np; + } + + // Next particle p + ++it2; + } + + //! \cond [cl usage] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * ## Finalize ## {#finalize} + * + * At the very end of the program we have always de-initialize the library + * + * \snippet Vector/4_multiphase_celllist_verlet/main.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond + + /*! + * \page Vector_4_mp_cl Vector 4 Multi Phase cell-list + * + * # Full code # {#code} + * + * \include Vector/4_multiphase_celllist_verlet/main.cpp + * + */ +} + + + + diff --git a/example/Vector/4_reorder/Makefile b/example/Vector/4_reorder/Makefile index c5ada0a42e2a3fbefe910f8839e774e748913a69..2569b0b64d49609a916adb2b92b36a3d9c566461 100644 --- a/example/Vector/4_reorder/Makefile +++ b/example/Vector/4_reorder/Makefile @@ -28,7 +28,7 @@ md_comp_ord_test: $(OBJ_CORD) $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) run: all_test - source $$HOME/openfpm_vars; mpirun -np 4 ./md_data_ord_test; mpirun -np 4 ./md_comp_ord_test + mpirun -np 4 ./md_data_ord_test && mpirun -np 4 ./md_comp_ord_test .PHONY: clean all run all_test on_test diff --git a/example/Vector/4_reorder/main_comp_ord.cpp b/example/Vector/4_reorder/main_comp_ord.cpp index a5bc7d48fdcdb4965e9f5977c742038384a8845d..9a9a1abf48e2597408482e2c1c1abb56cb17b851 100644 --- a/example/Vector/4_reorder/main_comp_ord.cpp +++ b/example/Vector/4_reorder/main_comp_ord.cpp @@ -6,6 +6,13 @@ #include "Plot/util.hpp" #include "timer.hpp" +/*! + * \page Vector_4_reo_root Vector 4 reordering + * \subpage Vector_4_reo + * \subpage Vector_4_comp_reo + * + */ + /*! * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * diff --git a/example/Vector/4_reorder/main_expr.cpp b/example/Vector/4_reorder/main_expr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86c7e31bf41bbd94ef81c469fa90617ed261b0b1 --- /dev/null +++ b/example/Vector/4_reorder/main_expr.cpp @@ -0,0 +1,139 @@ +#include "Vector/vector_dist.hpp" +#include "Plot/GoogleChart.hpp" +#include "Operators/Vector/vector_dist_operators.hpp" + +constexpr int velocity = 0; +constexpr int force = 1; + +struct ln_potential +{ + double sigma12,sigma6; + + ln_potential(double sigma12_, double sigma6_) {sigma12 = sigma12_, sigma6 = sigma6_;} + + Point<2,double> value(const Point<3,double> & xp, const Point<3,double> xq) + { + double rn = norm2(xp - xq); + + Point<2,double> E({4.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ), + 0.0}); + + return E; + } +}; + +struct ln_force +{ + double sigma12,sigma6; + + ln_force(double sigma12_, double sigma6_) {sigma12 = sigma12_; sigma6 = sigma6_;} + + Point<3,double> value(const Point<3,double> & xp, const Point<3,double> xq) + { + Point<3,double> r = xp - xq; + double rn = norm2(r); + + return 24.0*(2.0 * sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r; + } +}; + +int main(int argc, char* argv[]) +{ + double dt = 0.0005, sigma = 0.1, r_cut = 0.3; + + double sigma6 = pow(sigma,6), sigma12 = pow(sigma,12); + + openfpm::vector<double> x; + openfpm::vector<openfpm::vector<double>> y; + + + openfpm_init(&argc,&argv); + Vcluster & vcl = create_vcluster(); + + size_t sz[3] = {10,10,10}; + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + Ghost<3,float> ghost(r_cut); + + ln_force lf(sigma12,sigma6); + ln_potential lp(sigma12,sigma6); + + vector_dist<3,double, aggregate<Point<3,double>,Point<3,double>> > vd(0,box,bc,ghost); + + auto v_force = getV<force>(vd); + auto v_velocity = getV<velocity>(vd); + auto v_pos = getV<PROP_POS>(vd); + + auto it = vd.getGridIterator(sz); + + while (it.isNext()) + { + vd.add(); + + auto key = it.get(); + + vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); + vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); + vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); + + ++it; + } + + v_force = 0; + v_velocity = 0; + + auto NN = vd.getCellList(r_cut); + + vd.updateCellList(NN); + v_force = applyKernel_in_sim(vd,NN,lf); + unsigned long int f = 0; + + // MD time stepping + for (size_t i = 0; i < 10000 ; i++) + { + assign(v_velocity, v_velocity + 0.5*dt*v_force, + v_pos, v_pos + v_velocity*dt); + + vd.map(); + vd.template ghost_get<>(); + + // calculate forces or a(tn + 1) Step 2 + vd.updateCellList(NN); + v_force = applyKernel_in_sim(vd,NN,lf); + + v_velocity = v_velocity + 0.5*dt*v_force; + + if (i % 100 == 0) + { + vd.deleteGhost(); + vd.write("particles_",f); + vd.ghost_get<>(); + + Point<2,double> E = rsum(applyKernel_in_sim(vd,NN,lp) + (v_velocity * v_velocity)/2.0,vd).get(); + + vcl.sum(E.get(0));vcl.sum(E.get(1)); + vcl.execute(); + + // we save the energy calculated at time step i c contain the time-step y contain the energy + x.add(i); + y.add({E.get(0),E.get(1),E.get(0) - E.get(1)}); + + if (vcl.getProcessUnitID() == 0) + std::cout << "Energy Total: " << E.get(0) << " Kinetic: " << E.get(1) << " Potential: " << E.get(0) - E.get(1) << std::endl; + + f++; + } + } + + GCoptions options; + options.title = std::string("Energy with time"); + options.yAxis = std::string("Energy"); + options.xAxis = std::string("iteration"); + options.lineWidth = 1.0; + + GoogleChart cg; + cg.AddLinesGraph(x,y,options); + cg.write("gc_plot2_out.html"); + + openfpm_finalize(); +} diff --git a/example/Vector/5_molecular_dynamic_sym/Makefile b/example/Vector/5_molecular_dynamic_sym/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cf0391fab74d27ace055d5904d8df2c180b2266d --- /dev/null +++ b/example/Vector/5_molecular_dynamic_sym/Makefile @@ -0,0 +1,24 @@ +include ../../example.mk + +CC=mpic++ + +LDIR = + +OBJ_DORD = main.o + +all: md_sym + +%.o: %.cpp + $(CC) -O3 -g -c --std=c++11 $(OPT) -o $@ $< $(INCLUDE_PATH) + +md_sym: $(OBJ_DORD) + $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) + +run: md_sym + mpirun -np 3 ./md_sym + +.PHONY: clean all run + +clean: + rm -f *.o *~ core md_sym + diff --git a/example/Vector/5_molecular_dynamic_sym/config.cfg b/example/Vector/5_molecular_dynamic_sym/config.cfg new file mode 100644 index 0000000000000000000000000000000000000000..1eecbac3577c765edca7f90cf5f61cfb6b9f4880 --- /dev/null +++ b/example/Vector/5_molecular_dynamic_sym/config.cfg @@ -0,0 +1,2 @@ +[pack] +files = main.cpp Makefile diff --git a/example/Vector/5_molecular_dynamic_sym/main.cpp b/example/Vector/5_molecular_dynamic_sym/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4225ae303452449bcd9ef0ac42731b6fcfc52137 --- /dev/null +++ b/example/Vector/5_molecular_dynamic_sym/main.cpp @@ -0,0 +1,505 @@ +#include "Vector/vector_dist.hpp" +#include "Decomposition/CartDecomposition.hpp" +#include "data_type/aggregate.hpp" +#include "Plot/GoogleChart.hpp" +#include "Plot/util.hpp" +#include "timer.hpp" + +/*! + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * + * # Molecular dynamic with symmetric interactions # {#md_e5_sym} + * + * In a previous example we show how to build a parallel molecular dynamic simulation. + * We also show how it was possible to achive better performance using Verlet list. + * + * \see \ref e3_md_vl + * + * In this example we show how to improve even more our code using symmetric Verlet-list. + * If we look at the form of the Lennard-Jhones potential we will see that + * calculating the force that the particle **p** produce on **q** is equivalent to the force + * that **q** produce on **p**. This mean that when we use normal verlet-list we are redundantly + * doing double calculation. In order to avoid it we will use symmetric verlet-list. Symmetric + * verlet list have their feature in store the pair **p,q** only one time. If **p** store **q** + * as neighborhood than **q** does not store **p** as neighborhood. This Mean that when we calculate + * the contribution for of **q** to **p** we have to add such contribution also to **q**. + * + * The example is exactly equivalent to the non-symmetric with few differences in **calc_forces** and + * **calc_energies** + * + * + */ + +//! \cond [constants] \endcond + +constexpr int velocity = 0; +constexpr int force = 1; + +//! \cond [constants] \endcond + +/*! + * + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * ## Calculate forces ## {#md_e5_calc_force} + * + * In this function we calculate the forces between particles. It require the vector of particles + * Cell list and sigma factor for the Lennard-Jhones potential. The function is exactly the same + * as the original + * + * \see \ref e3_md_vl_cf + * + * with the following changes + * + * + * * If we calculate the force for **p-q** we are also adding this force to **q-p** + * \snippet Vector/5_molecular_dynamic_sym/main.cpp add to q + * + * * At the end of the calculation we have to execute a ghost put + * \snippet Vector/5_molecular_dynamic_sym/main.cpp ghost_put + * + * ###Explanation### {#md_e5_sym_expl} + * + * The first point is given by the fact that if the pair is stored once, when we calculate + * the force, we have to add the contribution to both particles. The second instead is + * is given by the fact that **q** can be a ghost particles. In case **q** is a ghost particle + * we are adding the contribution to the ghost particle and not to the real one. To + * add the contribution to the real particle we have to use the function **ghost_put**. + * This function send back the information to the original processor, that will merge the + * information (in this case add_) + * + * + * \snippet Vector/5_molecular_dynamic_sym/main.cpp calc forces vl + * + */ + +//! \cond [calc forces vl] \endcond + +void calc_forces(vector_dist<3,double, aggregate<double[3],double[3]> > & vd, VerletList<3, double, FAST, shift<3, double> > & NN, double sigma12, double sigma6, double r_cut) +{ + // Reset force on the ghost + + auto itg = vd.getDomainAndGhostIterator(); + + while (itg.isNext()) + { + auto p = itg.get(); + + // Reset force + vd.getProp<force>(p)[0] = 0.0; + vd.getProp<force>(p)[1] = 0.0; + vd.getProp<force>(p)[2] = 0.0; + + ++itg; + } + + //! \cond [real and ghost] \endcond + + // Get an iterator over particles + auto it2 = vd.getDomainIterator(); + + //! \cond [real and ghost] \endcond + + // For each particle p ... + while (it2.isNext()) + { + // ... get the particle p + auto p = it2.get(); + + // Get the position xp of the particle + Point<3,double> xp = vd.getPos(p); + + // Get an iterator over the neighborhood particles of p + // Note that in case of symmetric + auto Np = NN.template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood particle ... + while (Np.isNext()) + { + // ... q + auto q = Np.get(); + + // if (p == q) skip this particle + if (q == p.getKey()) {++Np; continue;}; + + // Get the position of q + Point<3,double> xq = vd.getPos(q); + + // Get the distance between p and q + Point<3,double> r = xp - xq; + + // take the norm of this vector + double rn = norm2(r); + + if (rn > r_cut * r_cut) {++Np;continue;} + + // Calculate the force, using pow is slower + Point<3,double> f = 24.0*(2.0 *sigma12 / (rn*rn*rn*rn*rn*rn*rn) - sigma6 / (rn*rn*rn*rn)) * r; + + // we sum the force produced by q on p + vd.template getProp<force>(p)[0] += f.get(0); + vd.template getProp<force>(p)[1] += f.get(1); + vd.template getProp<force>(p)[2] += f.get(2); + + //! \cond [add to q] \endcond + + // we sum the force produced by p on q + vd.template getProp<force>(q)[0] -= f.get(0); + vd.template getProp<force>(q)[1] -= f.get(1); + vd.template getProp<force>(q)[2] -= f.get(2); + + //! \cond [add to q] \endcond + + // Next neighborhood + ++Np; + } + + // Next particle + ++it2; + } + + //! \cond [ghost_put] \endcond + + // Sum the contribution to the real particles + vd.ghost_put<add_,force>(); + + //! \cond [ghost_put] \endcond +} + +//! \cond [calc forces vl] \endcond + + +/*! + * + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * ## Calculate energy ## {#md_e5_calc_ene} + * + * For the energy we use symmetric verlet-list in the same way as we did for calc_forces. + * Because the symmetric verlet-list span each couple one time, we have to remove the division by two + * (in this case we use the original factor 4.0 of the Lennard-Jhones potential rather than 2.0). + * + * \snippet Vector/5_molecular_dynamic_sym/main.cpp calc energy vl + * + */ + +//! \cond [calc energy vl] \endcond + +double calc_energy(vector_dist<3,double, aggregate<double[3],double[3]> > & vd, VerletList<3, double, FAST, shift<3, double> > & NN, double sigma12, double sigma6, double r_cut) +{ + double E = 0.0; + + double rc = r_cut*r_cut; + double shift = 4.0 * ( sigma12 / (rc*rc*rc*rc*rc*rc) - sigma6 / ( rc*rc*rc) ); + + // Get the iterator + auto it2 = vd.getDomainIterator(); + + // For each particle ... + while (it2.isNext()) + { + // ... p + auto p = it2.get(); + + // Get the position of the particle p + Point<3,double> xp = vd.getPos(p); + + // Get an iterator over the neighborhood of the particle p + auto Np = NN.template getNNIterator<NO_CHECK>(p.getKey()); + + double Ep = E; + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q + auto q = Np.get(); + + // if p == q skip this particle + if (q == p.getKey()) {++Np; continue;}; + + // Get position of the particle q + Point<3,double> xq = vd.getPos(q); + + // take the normalized direction + double rn = norm2(xp - xq); + + if (rn >= r_cut*r_cut) {++Np;continue;} + + // potential energy (using pow is slower) + E += 4.0 * ( sigma12 / (rn*rn*rn*rn*rn*rn) - sigma6 / ( rn*rn*rn) ) - shift; + + // Next neighborhood + ++Np; + } + + // Kinetic energy of the particle given by its actual speed + E += (vd.template getProp<velocity>(p)[0]*vd.template getProp<velocity>(p)[0] + + vd.template getProp<velocity>(p)[1]*vd.template getProp<velocity>(p)[1] + + vd.template getProp<velocity>(p)[2]*vd.template getProp<velocity>(p)[2]) / 2; + + // Next Particle + ++it2; + } + + // Calculated energy + return E; +} + +//! \cond [calc energy vl] \endcond + +int main(int argc, char* argv[]) +{ + /*! + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * ## Simulation ## {#md_e5_sym_sim} + * + * The simulation is equal to the simulation explained in the example molecular dynamic + * + * \see \ref e3_md_vl + * + * The difference is that we create a symmetric Verlet-list instead of a normal one + * \snippet Vector/5_molecular_dynamic_sym/main.cpp sim verlet + * + * The rest of the code remain unchanged + * + * \snippet Vector/5_molecular_dynamic_sym/main.cpp simulation + * + */ + + //! \cond [simulation] \endcond + + double dt = 0.00025; + double sigma = 0.1; + double r_cut = 3.0*sigma; + double r_gskin = 1.3*r_cut; + double sigma12 = pow(sigma,12); + double sigma6 = pow(sigma,6); + + openfpm::vector<double> x; + openfpm::vector<openfpm::vector<double>> y; + + openfpm_init(&argc,&argv); + Vcluster & v_cl = create_vcluster(); + + // we will use it do place particles on a 10x10x10 Grid like + size_t sz[3] = {10,10,10}; + + // domain + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + // ghost, big enough to contain the interaction radius + Ghost<3,float> ghost(r_gskin); + + vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost); + + size_t k = 0; + size_t start = vd.accum(); + + auto it = vd.getGridIterator(sz); + + while (it.isNext()) + { + vd.add(); + + auto key = it.get(); + + vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); + vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); + vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); + + vd.template getLastProp<velocity>()[0] = 0.0; + vd.template getLastProp<velocity>()[1] = 0.0; + vd.template getLastProp<velocity>()[2] = 0.0; + + vd.template getLastProp<force>()[0] = 0.0; + vd.template getLastProp<force>()[1] = 0.0; + vd.template getLastProp<force>()[2] = 0.0; + + k++; + ++it; + } + + vd.map(); + vd.ghost_get<>(); + + timer tsim; + tsim.start(); + + //! \cond [sim verlet] \endcond + + // Get the Cell list structure + auto NN = vd.getVerletSym(r_gskin); + + //! \cond [sim verlet] \endcond + + // calculate forces + calc_forces(vd,NN,sigma12,sigma6,r_cut); + unsigned long int f = 0; + + int cnt = 0; + double max_disp = 0.0; + + // MD time stepping + for (size_t i = 0; i < 10000 ; i++) + { + // Get the iterator + auto it3 = vd.getDomainIterator(); + + double max_displ = 0.0; + + // integrate velicity and space based on the calculated forces (Step1) + while (it3.isNext()) + { + auto p = it3.get(); + + // here we calculate v(tn + 0.5) + vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; + vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; + vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; + + Point<3,double> disp({vd.template getProp<velocity>(p)[0]*dt,vd.template getProp<velocity>(p)[1]*dt,vd.template getProp<velocity>(p)[2]*dt}); + + // here we calculate x(tn + 1) + vd.getPos(p)[0] += disp.get(0); + vd.getPos(p)[1] += disp.get(1); + vd.getPos(p)[2] += disp.get(2); + + if (disp.norm() > max_displ) + max_displ = disp.norm(); + + ++it3; + } + + if (max_disp < max_displ) + max_disp = max_displ; + + // Because we moved the particles in space we have to map them and re-sync the ghost + if (cnt % 10 == 0) + { + vd.map(); + vd.template ghost_get<>(); + // Get the Cell list structure + vd.updateVerlet(NN,r_gskin,VL_SYMMETRIC); + } + else + { + vd.template ghost_get<>(SKIP_LABELLING); + } + + cnt++; + + // calculate forces or a(tn + 1) Step 2 + calc_forces(vd,NN,sigma12,sigma6,r_cut); + + // Integrate the velocity Step 3 + auto it4 = vd.getDomainIterator(); + + while (it4.isNext()) + { + auto p = it4.get(); + + // here we calculate v(tn + 1) + vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; + vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; + vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; + + ++it4; + } + + // After every iteration collect some statistic about the confoguration + if (i % 100 == 0) + { + // We write the particle position for visualization (Without ghost) + vd.deleteGhost(); + vd.write("particles_",f); + + // we resync the ghost + vd.ghost_get<>(); + + + // We calculate the energy + double energy = calc_energy(vd,NN,sigma12,sigma6,r_cut); + auto & vcl = create_vcluster(); + vcl.sum(energy); + vcl.max(max_disp); + vcl.execute(); + + // we save the energy calculated at time step i c contain the time-step y contain the energy + x.add(i); + y.add({energy}); + + // We also print on terminal the value of the energy + // only one processor (master) write on terminal + if (vcl.getProcessUnitID() == 0) + std::cout << "Energy: " << energy << " " << max_disp << " " << std::endl; + + max_disp = 0.0; + + f++; + } + } + + tsim.stop(); + std::cout << "Time: " << tsim.getwct() << std::endl; + + //! \cond [simulation] \endcond + + // Google charts options, it store the options to draw the X Y graph + GCoptions options; + + // Title of the graph + options.title = std::string("Energy with time"); + + // Y axis name + options.yAxis = std::string("Energy"); + + // X axis name + options.xAxis = std::string("iteration"); + + // width of the line + options.lineWidth = 1.0; + + // Object that draw the X Y graph + GoogleChart cg; + + // Add the graph + // The graph that it produce is in svg format that can be opened on browser + cg.AddLinesGraph(x,y,options); + + // Write into html format + cg.write("gc_plot2_out.html"); + + //! \cond [google chart] \endcond + + /*! + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * ## Finalize ## {#finalize_v_e5_md_sym} + * + * At the very end of the program we have always to de-initialize the library + * + * \snippet Vector/5_molecular_dynamic_sym/main.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond + + /*! + * \page Vector_5_md_vl_sym Vector 5 molecular dynamic with symmetric Verlet list + * + * ## Full code ## {#full_code_v_e5_md_sym} + * + * \include Vector/5_molecular_dynamic_sym/main.cpp + * + */ +} diff --git a/example/Vector/6_complex_usage/Makefile b/example/Vector/6_complex_usage/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..31385b0c5b98849b22cab8969db58365498defc6 --- /dev/null +++ b/example/Vector/6_complex_usage/Makefile @@ -0,0 +1,24 @@ +include ../../example.mk + +CC=mpic++ + +LDIR = + +OBJ_DORD = main.o + +all: complex_use + +%.o: %.cpp + $(CC) -O3 -g -c --std=c++11 $(OPT) -o $@ $< $(INCLUDE_PATH) + +complex_use: $(OBJ_DORD) + $(CC) -o $@ $^ $(CFLAGS) $(LIBS_PATH) $(LIBS) + +run: all + mpirun -np 3 ./complex_use + +.PHONY: clean all run all_test on_test + +clean: + rm -f *.o *~ core complex_use + diff --git a/example/Vector/6_complex_usage/config.cfg b/example/Vector/6_complex_usage/config.cfg new file mode 100644 index 0000000000000000000000000000000000000000..1eecbac3577c765edca7f90cf5f61cfb6b9f4880 --- /dev/null +++ b/example/Vector/6_complex_usage/config.cfg @@ -0,0 +1,2 @@ +[pack] +files = main.cpp Makefile diff --git a/example/Vector/6_complex_usage/main.cpp b/example/Vector/6_complex_usage/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0f9e41b7e9bbf50a91a3109b02292d3b5c4970a --- /dev/null +++ b/example/Vector/6_complex_usage/main.cpp @@ -0,0 +1,409 @@ +#include "Vector/vector_dist.hpp" +#include "data_type/aggregate.hpp" +#include "Plot/GoogleChart.hpp" +#include "Plot/util.hpp" +#include "timer.hpp" + +/*! + * \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging + * + * [TOC] + * + * # Complex usage for validation and debugging # {#e6_cp_deb} + * + * In this example we show how the flexibility of the library can be used to perform complex + * tasks for validation and debugging. We will use a lot of feature that has been explained in + * the previous examples + * + * In a previous example we show in case of symmetric interaction between particles how to symmetric + * cell list could be used to speed up the calculation. + * + * \see not present + * + * In this example we validate that both computation match, in particular because the computation depend + * from the neighborhood, we will check and validate that the neighborhood of each + * particle is equivalent with symmetric cell list and normal cell-list. + * + */ + +int main(int argc, char* argv[]) +{ + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for validation + * + * ## Initialization ## + * + * The initialization is classical we define cutoff radius, domain, boundary conditions, + * ghost part and some useful constants. We also define a struct that will contain the debug information. This structure + * contain an id that is the global id of the particle and a point that is the the position of the + * neighborhood. + * + * \see \ref e0_s_init + * + * \snippet Vector/6_complex_usage/main.cpp initialization + * + */ + + //! \cond [initialization] \endcond + + openfpm_init(&argc,&argv); + + constexpr int gid = 0; + constexpr int nn_norm = 1; + constexpr int nn_sym = 2; + + // used to define the domain + float L = 1000.0; + + // Domain + Box<3,float> box({-L,-L,-L},{L,L,L}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + // cut-off radius + float r_cut = 100.0; + + // ghost + Ghost<3,float> ghost(r_cut); + + // Point and global id + struct point_and_gid + { + // global id of the particle + size_t id; + + // Position of the neighborhood particle + Point<3,float> xq; + + // Used to reorder the neighborhood particles by id + bool operator<(const struct point_and_gid & pag) const + { + return (id < pag.id); + } + }; + + //! \cond [initialization] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Particle ## + * + * For this example we will use a particle with 3 properties + * + * * The first property is a global index for the particle unique across processors + * * The second is a vector that contain for each neighborhood the global id of the particle + * and its position + * * The last one is again a vector equivalent to the previous but is produced with the symmetric + * cell-list + * + * \snippet Vector/6_complex_usage/main.cpp particle prop + * + */ + + //! \cond [particle prop] \endcond + + // Particle properties list + typedef aggregate<size_t,openfpm::vector<point_and_gid>,openfpm::vector<point_and_gid>> part_prop; + + //! \cond [particle prop] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Distributed vector ## + * + * Here we create a distributed vector of 4096 particles. We initialize the particles + * randomly and we assign a global index to the first property of the particle + * + * The function accum return the following number + * + * \f$ \sum_{i < proc} size\_local(i) \f$ + * + * where \f$ proc \f$ is the processor where we are computing the formula and \f$ size\_local(i) \f$ + * is the number of particles the processor \f$ i \f$ has. This number is used to + * produce a global id of the particles + * + * \snippet Vector/6_complex_usage/main.cpp glob id part + * + */ + + //! \cond [glob id part] \endcond + + // Distributed vector + vector_dist<3,float, part_prop > vd(4096,box,bc,ghost); + + // used to calculate a global index for each particle + size_t start = vd.accum(); + + auto it = vd.getDomainIterator(); + + while (it.isNext()) + { + auto key = it.get(); + + vd.getPos(key)[0] = 2.0*L*((float)rand()/RAND_MAX) - L; + vd.getPos(key)[1] = 2.0*L*((float)rand()/RAND_MAX) - L; + vd.getPos(key)[2] = 2.0*L*((float)rand()/RAND_MAX) - L; + + vd.getProp<gid>(key) = key.getKey() + start; + + ++it; + } + + //! \cond [glob id part] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Redistribute ## + * + * Redistribute the particles and synchronize the ghosts. In this case we + * are only interested in synchronizing the global id property. + * + * \snippet Vector/6_complex_usage/main.cpp map and ghost + * + */ + + //! \cond [map and ghost] \endcond + + vd.map(); + + // sync the ghost + vd.ghost_get<gid>(); + + //! \cond [map and ghost] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Calculate the neighborhood of each particle ## + * + * Here we calculate the neighborhood of each particles using a simple **cell list**. + * In case the particle q has a distance from the particle p smaller than r_cut. + * We add it in the first list of neighborhood + * + * \snippet Vector/6_complex_usage/main.cpp add nn particles + * + */ + + //! \cond [add nn particles] \endcond + + auto NN = vd.getCellList(r_cut); + auto p_it = vd.getDomainIterator(); + + while (p_it.isNext()) + { + auto p = p_it.get(); + + Point<3,float> xp = vd.getPos(p); + + auto Np = NN.getNNIterator(NN.getCell(vd.getPos(p))); + + while (Np.isNext()) + { + auto q = Np.get(); + + // skip self interaction + if (p.getKey() == q) + { + ++Np; + continue; + } + + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); + + float distance = f.norm(); + + // if the distance smalle than the cut-off radius add it to the neighborhood list + if (distance < r_cut ) + { + vd.getProp<nn_norm>(p).add(); + vd.getProp<nn_norm>(p).last().xq = xq; + vd.getProp<nn_norm>(p).last().id = vd.getProp<0>(q); + } + + // Next neighborhood + ++Np; + } + + // Next particle + ++p_it; + } + + //! \cond [add nn particles] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Calculate the neighborhood of each particle with symmetric cell-list ## + * + * Here we calculate the neighborhood of each particle using instead a + * **symmetric cell list**. In case of symmetric cell-list if we find that a + * particle p is neighborhood of particle q we have to add p to the neighborhood + * of q and q to the neighborhood of p. Because q can be a ghost particle when + * we add the neighborhood p to q we have to transmit such information to the real + * owner of the particle. This can be done with the function **ghost_put**. In this + * case we use the operation **merge_** that add the already calculated neighborhood + * with the transmitted one. More in general it merge the information together. + * + * \snippet Vector/6_complex_usage/main.cpp add nn particles sym + * + */ + + //! \cond [add nn particles sym] \endcond + + auto NN2 = vd.getCellListSym(r_cut); + + auto p_it2 = vd.getDomainIterator(); + + while (p_it2.isNext()) + { + auto p = p_it2.get(); + + Point<3,float> xp = vd.getPos(p); + + auto Np = NN2.template getNNIteratorSym<NO_CHECK>(NN2.getCell(vd.getPos(p)),p.getKey(),vd.getPosVector()); + + while (Np.isNext()) + { + auto q = Np.get(); + + if (p.getKey() == q) + { + ++Np; + continue; + } + + // repulsive + + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); + + float distance = f.norm(); + + // Particle should be inside r_cut range + + if (distance < r_cut ) + { + vd.getProp<nn_sym>(p).add(); + vd.getProp<nn_sym>(q).add(); + + vd.getProp<nn_sym>(p).last().xq = xq; + vd.getProp<nn_sym>(q).last().xq = xp; + vd.getProp<nn_sym>(p).last().id = vd.getProp<0>(q); + vd.getProp<nn_sym>(q).last().id = vd.getProp<0>(p); + } + + ++Np; + } + + ++p_it2; + } + + vd.ghost_put<merge_,2>(); + + //! \cond [add nn particles sym] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for debugging + * + * ## Cheking for validation ## + * + * Here we check that the two calculated neighborhood match. In particular, + * because the order of the particles does not match, we have to first reorder + * by global-id, and than check the list. We cannot instead easily compare the + * position. The reason can be seen in this figure + * + \verbatim + + +----------------+ + | | + | 1 | + | * 2 | + | 3 * | + +<----- ghost * +<-------- real + |* <--- real |* <------- ghost + |4 |4 + | | + | | + +----------------+ + + + + \endverbatim + * + * In the case we are calculating the neighborhood of the particle \f$ + \f$ in case of normal Cell-list. + * The real particle 1,2,3 are added, while the particle 4 is added with the ghost particle coordinates. + * In the case of symmetric cell-list the real 1,2,3 are added to \f$ + \f$. The particle 4 + * instead is added by the ghost put. In particular 4 real add the particle to the \f$ + \f$ ghost particle + * and than ghost put merge the information. This mean that the symmetric add the particle 4 with the real coordinates + * of the particle 4 + * + * \snippet Vector/6_complex_usage/main.cpp checking + * + */ + + //! \cond [checking] \endcond + + auto p_it3 = vd.getDomainIterator(); + + bool ret = true; + while (p_it3.isNext()) + { + auto p = p_it3.get(); + + vd.getProp<nn_norm>(p).sort(); + vd.getProp<nn_sym>(p).sort(); + + ret &= vd.getProp<nn_norm>(p).size() == vd.getProp<nn_sym>(p).size(); + + for (size_t i = 0 ; i < vd.getProp<1>(p).size() ; i++) + { + ret &= vd.getProp<nn_norm>(p).get(i).id == vd.getProp<nn_sym>(p).get(i).id; + + if (box.isInside(vd.getProp<nn_norm>(p).get(i).xq) == true) + { + ret &= vd.getProp<nn_norm>(p).get(i).xq == vd.getProp<nn_sym>(p).get(i).xq; + } + } + + ++p_it3; + } + + if (ret != true) + { + std::cout << "ERROR" << std::endl; + exit(1); + } + + //! \cond [checking] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging + * + * ## Finalize ## + * + * At the very end of the program we have always to de-initialize the library + * + * \snippet Vector/6_complex_usage/main.cpp finalize + * + */ + + //! \cond [finalize] \endcond + + openfpm_finalize(); + + //! \cond [finalize] \endcond + + /*! + * \page Vector_6_complex_usage Vector 6 complex usage for validation and debugging + * + * # Full code # {#code} + * + * \include Vector/6_complex_usage/main.cpp + * + */ +} diff --git a/images/Makefile.am b/images/Makefile.am index 7e06aaa7635ed8ddd052d33caf2369ebb53c1462..5ddd24188f07a9aaa2ec8b92758df8830e663a82 100644 --- a/images/Makefile.am +++ b/images/Makefile.am @@ -1,24 +1,24 @@ -LINKLIBS = $(LIBHILBERT_LIB) $(PETSC_LIB) $(METIS_LIB) $(PARMETIS_LIB) $(PTHREAD_LIBS) $(OPT_LIBS) $(BOOST_LDFLAGS) $(BOOST_IOSTREAMS_LIB) $(CUDA_LIBS) +LINKLIBS = $(OPENMP_LDFLAGS) $(LIBHILBERT_LIB) $(PETSC_LIB) $(METIS_LIB) $(PARMETIS_LIB) $(PTHREAD_LIBS) $(OPT_LIBS) $(BOOST_LDFLAGS) $(BOOST_IOSTREAMS_LIB) $(CUDA_LIBS) noinst_PROGRAMS = cart_dec metis_dec dom_box vector_dist cart_dec_SOURCES = CartDecomposition_gen_vtk.cpp ../src/lib/pdata.cpp ../openfpm_devices/src/memory/HeapMemory.cpp ../openfpm_devices/src/memory/PtrMemory.cpp ../openfpm_vcluster/src/VCluster.cpp ../openfpm_devices/src/Memleak_check.cpp -cart_dec_CXXFLAGS = $(PETSC_INCLUDE) $(METIS_INCLUDE) $(PARMETIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs -cart_dec_CFLAGS = $(CUDA_CFLAGS) +cart_dec_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(PETSC_INCLUDE) $(METIS_INCLUDE) $(PARMETIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs +cart_dec_CFLAGS = $(OPENMP_CFLAGS) $(CUDA_CFLAGS) cart_dec_LDADD = $(LINKLIBS) -lparmetis -lmetis metis_dec_SOURCES = Metis_gen_vtk.cpp ../src/lib/pdata.cpp ../openfpm_devices/src/memory/HeapMemory.cpp ../openfpm_devices/src/memory/PtrMemory.cpp ../openfpm_vcluster/src/VCluster.cpp ../openfpm_devices/src/Memleak_check.cpp -metis_dec_CXXFLAGS = $(PETSC_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs -metis_dec_CFLAGS = $(CUDA_CFLAGS) +metis_dec_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(PETSC_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs +metis_dec_CFLAGS = $(OPENMP_CFLAGS) $(CUDA_CFLAGS) metis_dec_LDADD = $(LINKLIBS) -lmetis dom_box_SOURCES = domain_gen_vtk.cpp ../src/lib/pdata.cpp ../openfpm_devices/src/memory/HeapMemory.cpp ../openfpm_devices/src/memory/PtrMemory.cpp ../openfpm_vcluster/src/VCluster.cpp ../openfpm_devices/src/Memleak_check.cpp -dom_box_CXXFLAGS = $(PETSC_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs -dom_box_CFLAGS = $(CUDA_CFLAGS) +dom_box_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(PETSC_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs +dom_box_CFLAGS = $(OPENMP_CFLAGS) $(CUDA_CFLAGS) dom_box_LDADD = $(LINKLIBS) vector_dist_SOURCES = vector.cpp ../openfpm_devices/src/memory/HeapMemory.cpp ../openfpm_vcluster/src/VCluster.cpp ../openfpm_devices/src/memory/PtrMemory.cpp -vector_dist_CXXFLAGS = $(LIBHILBERT_INCLUDE) $(PETSC_INCLUDE) $(PARMETIS_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(HDF5_CPPFLAGS) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs -vector_dist_CFLAGS = $(CUDA_CFLAGS) +vector_dist_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(LIBHILBERT_INCLUDE) $(PETSC_INCLUDE) $(PARMETIS_INCLUDE) $(METIS_INCLUDE) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(HDF5_CPPFLAGS) $(BOOST_CPPFLAGS) -I../src -Wno-unused-function -Wno-unused-local-typedefs +vector_dist_CFLAGS = $(OPENMP_CFLAGS) $(CUDA_CFLAGS) vector_dist_LDADD = $(LINKLIBS) -lparmetis -lmetis .cu.o : diff --git a/install b/install index 70799d68cc492a31eb0e20e07b13b12998ae5652..b3290c2beeaea3e50fd3d156be80ac3fe76e5086 100755 --- a/install +++ b/install @@ -6,6 +6,8 @@ source script/show_solutions source script/pre_req source script/remove_old source script/set_mpi +source script/conf_PETSC + ## Check that your home is not empty @@ -19,8 +21,9 @@ fi install_req=1 i_dir=" " sq=0 +nomake=0 -while getopts :di:shc: FLAG; do +while getopts :di:smhc: FLAG; do case $FLAG in d) echo "Disable depencencies installation" @@ -38,6 +41,10 @@ while getopts :di:shc: FLAG; do echo "Fowarding options $OPTARG to configure script" configure_options=$OPTARG ;; + m) + echo "Skip make" + nomake=1 + ;; h) #show help HELP ;; @@ -166,48 +173,6 @@ fi lin_alg_dir="" lin_alg_lib="" lin_alg_inc="" -if [ -d "$i_dir/PETSC" ]; then - configure_options="$configure_options --with-petsc=$i_dir/PETSC " - lin_alg_dir="$lin_alg_dir -L$i_dir/PETSC/lib" - lin_alg_lib="$lin_alg_lib -lpetsc" - lin_alg_inc="$lin_alg_inc -I$i_dir/PETSC/include" -fi -if [ -d "$i_dir/HYPRE" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/HYPRE/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/HYPRE/include" -fi -if [ -d "$i_dir/MUMPS" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/MUMPS/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/MUMPS/include" -fi -if [ -d "$i_dir/OPENBLAS" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/OPENBLAS/lib" - lin_alg_lib="$lin_alg_lib -lopenblas" - lin_alg_inc="$lin_alg_inc -I$i_dir/OPENBLAS/include" - configure_blas_option="--with-blas=-L$i_dir/OPENBLAS/lib -lopenblas" -fi -if [ -d "$i_dir/SCALAPACK" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/SCALAPACK/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/SCALAPACK/include" -fi -if [ -d "$i_dir/SUPERLU_DIST" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/SUPERLU_DIST/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/SUPERLU_DIST/include" -fi -if [ -d "$i_dir/TRILINOS" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/TRILINOS/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/TRILINOS/include" -fi -if [ -d "$i_dir/SUITESPARSE" ]; then - lin_alg_dir="$lin_alg_dir -L$i_dir/SUITESPARSE/lib" - lin_alg_inc="$lin_alg_inc -I$i_dir/SUITESPARSE/include" - lin_alg_lib="$lin_alg_lib -lumfpack -lamd -lbtf -lcamd -lccolamd -lcholmod -lcolamd -lcxsparse -lklu -ldl -lrbio -lspqr -lsuitesparseconfig" - configure_options="$configure_options --with-suitesparse=$i_dir/SUITESPARSE " -fi -if [ -d "$i_dir/EIGEN" ]; then - configure_options=" $configure_options --with-eigen=$i_dir/EIGEN " - lin_alg_inc="$lin_alg_inc -I$i_dir/EIGEN" -fi if [ -d "$i_dir/METIS" ]; then configure_options=" $configure_options --with-metis=$i_dir/METIS " fi @@ -259,7 +224,7 @@ LIBHILBERT_installed=0 conf_err=1 if [ $install_req -eq 0 ]; then - ./configure $options $configure_options $configure_blas_option + ./configure $options $configure_options "$configure_blas_option" else while [ $conf_err -ne 0 ] do @@ -332,31 +297,31 @@ else if [ x"$inst_lin_alg" == x"y" ]; then ./script/install_EIGEN.sh $i_dir $ncore - if [ $? -eq 0 ]; then - configure_options=" $configure_options --with-eigen=$i_dir/EIGEN --with-suitesparse=$i_dir/SUITESPARSE " - configure_blas_option=" --with-blas=\"$i_dir/OPENBLAS/lib -lopenblas\" " - fi ./script/install_PETSC.sh $i_dir $ncore - if [ $? -eq 0 ]; then - configure_options=" $configure_options --with-petsc=$i_dir/PETSC " - fi fi - ./configure $options $configure_options $configure_blas_option + ### collect PETSC configuration options + conf_PETSC + + ./configure $options $configure_options "$configure_blas_option" fi ### Create example.mk install_base=$(cat install_dir) -echo "INCLUDE_PATH=-I. -I$install_base/openfpm_numerics/include -I$install_base/openfpm_pdata/include/config -I$install_base/openfpm_pdata/include -I$install_base/openfpm_data/include -I$install_base/openfpm_vcluster/include -I$install_base/openfpm_io/include -I$install_base/openfpm_devices/include -I$i_dir/METIS/include -I$i_dir/PARMETIS/include -I$i_dir/BOOST/include -I$i_dir/HDF5/include -I$i_dir/LIBHILBERT/include $lin_alg_inc" > example.mk -echo "LIBS_PATH= -L$install_base/openfpm_devices/lib -L$install_base/openfpm_pdata/lib -L$install_base/openfpm_vcluster/lib -L$i_dir/METIS/lib -L$i_dir/PARMETIS/lib -L$i_dir/BOOST/lib -L$i_dir/HDF5/lib -L$i_dir/LIBHILBERT/lib $lin_alg_dir" >> example.mk +openmp_flags="$(cat openmp_flags) $(cat openfpm_flags)" + +echo "INCLUDE_PATH= $openmp_flags -I. -I$install_base/openfpm_numerics/include -I$install_base/openfpm_pdata/include/config -I$install_base/openfpm_pdata/include -I$install_base/openfpm_data/include -I$install_base/openfpm_vcluster/include -I$install_base/openfpm_io/include -I$install_base/openfpm_devices/include -I$i_dir/METIS/include -I$i_dir/PARMETIS/include -I$i_dir/BOOST/include -I$i_dir/HDF5/include -I$i_dir/LIBHILBERT/include $lin_alg_inc" > example.mk +echo "LIBS_PATH= $openmp_flags -L$install_base/openfpm_devices/lib -L$install_base/openfpm_pdata/lib -L$install_base/openfpm_vcluster/lib -L$i_dir/METIS/lib -L$i_dir/PARMETIS/lib -L$i_dir/BOOST/lib -L$i_dir/HDF5/lib -L$i_dir/LIBHILBERT/lib $lin_alg_dir" >> example.mk echo "LIBS=-lvcluster -lofpm_pdata -lofpmmemory -lparmetis -lmetis -lboost_iostreams -lhdf5 -llibhilbert $lin_alg_lib" >> example.mk echo "LIBS_SE2=-lvcluster -lofpmmemory_se2 -lparmetis -lmetis -lboost_iostreams -lhdf5 -llibhilbert $lin_alg_lib" >> example.mk cp example.mk src/example.mk cp example.mk example/example.mk -make clean -make +if [ $nomake -eq 0 ]; then + make clean + make +fi if [ $? -ne 0 ]; then conf_err=1 diff --git a/m4/ax_libhilbert.m4 b/m4/ax_libhilbert.m4 index d83f7181d238d4bbb0cb6413c4e8e05958106f6d..fd0850a2331e0b61ccecc029a6634eb02852c3ef 100644 --- a/m4/ax_libhilbert.m4 +++ b/m4/ax_libhilbert.m4 @@ -80,7 +80,7 @@ AC_DEFUN([AX_LIB_HILBERT], [ with_libhilbert=$PETSC AC_MSG_RESULT(yes) else - with_petsc=/usr + with_libhilbert=/usr if test ! -f "$with_libhilbert/include/hilbertKey.h" ; then with_libhilbert=/usr/local if test ! -f "$with_libhilbert/include/hilbertKey.h" ; then diff --git a/m4/ax_petsc_lib.m4 b/m4/ax_petsc_lib.m4 index ed14c831b4e230d19b4bd7c9b80b37fa7dd7a098..1bd159091052c10c40e9e9317a4cca0ec579c4ec 100755 --- a/m4/ax_petsc_lib.m4 +++ b/m4/ax_petsc_lib.m4 @@ -102,8 +102,10 @@ AC_DEFUN([AX_LIB_PETSC], [ old_CC=$CC old_CFLAGS=$CFLAGS old_LDFLAGS=$LDFLAGS - CFLAGS="-I$with_petsc/include $HDF5_INCLUDE $METIS_INCLUDE " - LDFLAGS="-L$with_petsc/lib $HDF5_LDFLAGS $HDF5_LIBS $METIS_LIB -lmetis " + AX_OPENMP([CFLAGS="$OPENMP_CFLAGS" + LDFLAGS="$OPENMP_LDFLAGS"],[]) + CFLAGS="$CFLAGS -I$with_petsc/include $HDF5_INCLUDE $METIS_INCLUDE " + LDFLAGS="$LDFLAGS -L$with_petsc/lib $HDF5_LDFLAGS $HDF5_LIBS $METIS_LIB -lmetis " CC=$CXX AC_LANG_SAVE diff --git a/openfpm_devices b/openfpm_devices index aef59d58fe1e8958dd09da9672fa673063ab970e..90076f0c7ea6ac954d2b09fc8e84caa64024e8a6 160000 --- a/openfpm_devices +++ b/openfpm_devices @@ -1 +1 @@ -Subproject commit aef59d58fe1e8958dd09da9672fa673063ab970e +Subproject commit 90076f0c7ea6ac954d2b09fc8e84caa64024e8a6 diff --git a/openfpm_io b/openfpm_io index ca2becb045ef96fcf6287f8ef5da2314248bcb66..169a3037339b07e4b2d037b9a7ae27399e9c1002 160000 --- a/openfpm_io +++ b/openfpm_io @@ -1 +1 @@ -Subproject commit ca2becb045ef96fcf6287f8ef5da2314248bcb66 +Subproject commit 169a3037339b07e4b2d037b9a7ae27399e9c1002 diff --git a/openfpm_numerics b/openfpm_numerics index cd85b04542371e1ed08507f52172b10e0310a35a..a4f8379d45e361dc6ab68585d6da4d64680f5171 160000 --- a/openfpm_numerics +++ b/openfpm_numerics @@ -1 +1 @@ -Subproject commit cd85b04542371e1ed08507f52172b10e0310a35a +Subproject commit a4f8379d45e361dc6ab68585d6da4d64680f5171 diff --git a/openfpm_pdata.doc b/openfpm_pdata.doc index b16dc1c02e77632b2517229498015a101e1476d1..1375042ee7fb74340aa4414415ecafd645f56e6d 100644 --- a/openfpm_pdata.doc +++ b/openfpm_pdata.doc @@ -38,7 +38,7 @@ PROJECT_NAME = "OpenFPM_pdata" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.5.0 +PROJECT_NUMBER = 0.6.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/openfpm_vcluster b/openfpm_vcluster index 09a83aea1eb6af23477060fde84798d131ee2a69..a463ae1d10144099b2bdeccc6aa6b4de8f3bfcd8 160000 --- a/openfpm_vcluster +++ b/openfpm_vcluster @@ -1 +1 @@ -Subproject commit 09a83aea1eb6af23477060fde84798d131ee2a69 +Subproject commit a463ae1d10144099b2bdeccc6aa6b4de8f3bfcd8 diff --git a/run.sh b/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..c9766535837a838cdf668d5362936888ec807357 --- /dev/null +++ b/run.sh @@ -0,0 +1,86 @@ +#! /bin/bash + +# Make a directory in /tmp/OpenFPM_pdata + +echo "Directory: $1" +echo "Machine: $2" + +if [ "$2" == "gin" ] +then + source ~/.bashrc + module load gcc/4.9.2 + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + + source $HOME/openfpm_vars + + if [ x"$3" == x"no_test" ]; then + exit 0; + fi + + mpirun -np $3 ./src/pdata + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + +elif [ "$2" == "wetcluster" ] +then + echo "Compiling on wetcluster" + +## produce the module path + + source ~/.bashrc + module load gcc/4.9.2 + module load openmpi/1.8.1 + module load boost/1.54.0 + + source $HOME/openfpm_vars + + ## Run on the cluster + bsub -o output_run$3.%J -K -n 2 -R "span[hosts=$4]" "module load openmpi/1.8.1 ; module load gcc/4.9.2; module load boost/1.54.0; mpirun -np $3 ./src/pdata" + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi +elif [ "$2" == "taurus" ] +then + + source /etc/profile + echo "$PATH" + module load eigen/3.2.0 + module load suitesparse/4.2.1-gnu-multimkl + module load boost/1.60.0 + module load gcc/5.3.0 + module load openmpi/1.10.2-gnu + module unload bullxmpi + + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/incard/PARMETIS/lib:/home/incard/METIS/lib:/home/incard/HDF5/lib" + + source $HOME/openfpm_vars + + salloc --nodes=$4 --ntasks-per-node=$5 --time=00:15:00 --mem-per-cpu=1900 --partition=haswell bash -c "ulimit -s unlimited && mpirun -np $3 src/pdata --report_level=no" + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi + +else + source ~/.bashrc + + if [ x"$3" == x"no_test" ]; then + exit 0; + fi + + source $HOME/openfpm_vars + + mpirun -np $3 ./src/pdata + if [ $? -ne 0 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Error:\", \"color\": \"#FF0000\", \"text\":\"$2 failed to complete the openfpm_pdata test \" }] }" https://hooks.slack.com/services/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 + exit 1 ; + fi +fi + + diff --git a/script/conf_PETSC b/script/conf_PETSC new file mode 100755 index 0000000000000000000000000000000000000000..279caa26659af3c15efbcc8dcac662197b250878 --- /dev/null +++ b/script/conf_PETSC @@ -0,0 +1,48 @@ +#! /bin/bash + +function conf_PETSC() +{ +if [ -d "$i_dir/PETSC" ]; then + configure_options="$configure_options --with-petsc=$i_dir/PETSC " + lin_alg_dir="$lin_alg_dir -L$i_dir/PETSC/lib" + lin_alg_lib="$lin_alg_lib -lpetsc" + lin_alg_inc="$lin_alg_inc -I$i_dir/PETSC/include" +fi +if [ -d "$i_dir/HYPRE" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/HYPRE/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/HYPRE/include" +fi +if [ -d "$i_dir/MUMPS" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/MUMPS/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/MUMPS/include" +fi +if [ -d "$i_dir/OPENBLAS" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/OPENBLAS/lib" + lin_alg_lib="$lin_alg_lib -lopenblas" + lin_alg_inc="$lin_alg_inc -I$i_dir/OPENBLAS/include" + configure_blas_option="--with-blas=-L$i_dir/OPENBLAS/lib -lopenblas" +fi +if [ -d "$i_dir/SCALAPACK" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/SCALAPACK/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/SCALAPACK/include" +fi +if [ -d "$i_dir/SUPERLU_DIST" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/SUPERLU_DIST/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/SUPERLU_DIST/include" +fi +if [ -d "$i_dir/TRILINOS" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/TRILINOS/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/TRILINOS/include" +fi +if [ -d "$i_dir/SUITESPARSE" ]; then + lin_alg_dir="$lin_alg_dir -L$i_dir/SUITESPARSE/lib" + lin_alg_inc="$lin_alg_inc -I$i_dir/SUITESPARSE/include" + lin_alg_lib="$lin_alg_lib -lumfpack -lamd -lbtf -lcamd -lccolamd -lcholmod -lcolamd -lcxsparse -lklu -ldl -lrbio -lspqr -lsuitesparseconfig" + configure_options="$configure_options --with-suitesparse=$i_dir/SUITESPARSE " +fi +if [ -d "$i_dir/EIGEN" ]; then + configure_options=" $configure_options --with-eigen=$i_dir/EIGEN " + lin_alg_inc="$lin_alg_inc -I$i_dir/EIGEN" +fi +} + diff --git a/script/help b/script/help index e3961f3d2a475a8926c9215f230dffa2e8fc1df2..5677a2eda912df3494b6a27da447edc1dc0617bc 100755 --- a/script/help +++ b/script/help @@ -10,6 +10,7 @@ function HELP { echo -e " \033[1;34m-s\033[0m skip user input" echo -e " \033[1;34m-c\033[0m foward this options to configure" echo -e " \033[1;34m-h\033[0m Displays this help message"\\n + echo -e " \033[1;34m-m\033[0m Skip make"\\n echo -e " \033[1mExample:\033[0m ./install -i /dependencies/here -s -c\"some_options someother_option\""\\n exit 1 } diff --git a/script/install_PETSC.sh b/script/install_PETSC.sh index a420fc28b3d5bcc8f176313af06e637d0c266b0a..d4f67ab9d7176e5e3fd0266293f277ff4fc13d4a 100755 --- a/script/install_PETSC.sh +++ b/script/install_PETSC.sh @@ -46,9 +46,9 @@ if [ -d "$1/METIS" ]; then configure_options="$configure_options --with-metis=yes --with-metis-dir=$1/METIS " fi -if [ -d "$1/HDF5" ]; then - configure_options="$configure_options --with-hdf5=yes --with-hdf5-dir=$1/HDF5 " -fi +#if [ -d "$1/HDF5" ]; then +# configure_options="$configure_options --with-hdf5=yes --with-hdf5-dir=$1/HDF5 " +#fi if [ -d "$1/BOOST" ]; then configure_options="$configure_options --with-boost=yes --with-boost-dir=$1/BOOST " @@ -109,9 +109,9 @@ if [ ! -d "$1/TRILINOS" ]; then petsc_openmp="" if [ x"$dgc_compiler" == x"clang++" ]; then conf_trl_openmp="-D Trilinos_ENABLE_OpenMP=OFF" - petsc_openmp="--with-openmp=yes" else conf_trl_openmp="-D Trilinos_ENABLE_OpenMP=ON" +# petsc_openmp="--with-openmp=yes" fi cmake -D CMAKE_INSTALL_PREFIX:PATH=$1/TRILINOS -D CMAKE_BUILD_TYPE=RELEASE $conf_trl_openmp -D Trilinos_ENABLE_TESTS=OFF -D Trilinos_ENABLE_ALL_PACKAGES=ON $configure_trilinos_options ../. @@ -181,6 +181,9 @@ if [ ! -d "$1/MUMPS" ]; then $sed_command -i "/LIBBLAS\s=\s-lblas/c\LIBBLAS = -lopenblas" Makefile.inc + $sed_command -i "/INCPAR\s\+=\s\-I\/usr\/include/c\INCPAR =" Makefile.inc + $sed_command -i "/LIBPAR\s\+=\s\$(SCALAP)\s\-L\/usr\/lib\s\-lmpi/c\LIBPAR = \$(SCALAP)" Makefile.inc + make -j $2 if [ $? -eq 0 ]; then @@ -289,13 +292,16 @@ fi tar -xf petsc-lite-3.6.4.tar.gz cd petsc-3.6.4 -echo "./configure --with-cxx-dialect=C++11 --with-mpi-dir=$mpi_dir $configure_options --prefix=$1/PETSC" +echo "./configure --with-cxx-dialect=C++11 --with-mpi-dir=$mpi_dir $configure_options --prefix=$1/PETSC --with-debugging=0" -./configure --with-cxx-dialect=C++11 $petsc_openmp --with-mpi-dir=$mpi_dir $configure_options --with-mumps-lib="$MUMPS_extra_lib" --prefix=$1/PETSC +./configure --with-cxx-dialect=C++11 $petsc_openmp --with-mpi-dir=$mpi_dir $configure_options --with-mumps-lib="$MUMPS_extra_lib" --prefix=$1/PETSC --with-debugging=0 make all test make install # if empty remove the folder if [ ! "$(ls -A $1/PETSC)" ]; then rm -rf $1/PETSC +else + exit 0 fi + diff --git a/script/pre_req b/script/pre_req index cf1c39bf3d9e2bf538469240e0918f5cc167e75b..286789e23cab3c16c45713051e8a92fb34887bdf 100755 --- a/script/pre_req +++ b/script/pre_req @@ -327,6 +327,36 @@ if [ x"$MPI_valid" == x"yes" ]; then exit 1 fi fi + + #### Detect a potential dangerous situation ### + #### In which g++ is different from mpic++ ### + + output_mpi=$(mpic++ --version) + output_gcc=$(g++ --version) + + if [ x"$output_mpi" != x"$output_gcc" ]; then + echo -e "\033[91;5;1m MPI dangerous installation \033[0m" + echo -e "Performing a \033[1m \"mpic++ --version\" \033[0m, we detect that your installed mpic++ does not wrap the standard command g++" + echo "In general we strongly disencourage to override the default compiler(s), this configuration not only is not supported by OpenFPM, but can lead potentialy to several problems at system level. For the following reasons" + echo -e "\033[1m 1) All system wide dependencies become potentially useless \033[0m" + echo -e "\033[1m 2) A package maneger (apt-get or brew) installing a packege from source can potentialy generate incompatible system packages \033[0m" + echo -e "\033[1m 3) It is not easy to discover which compiler has been used to compile one dependency \033[0m" + echo -e "For just the time of the installation the installer will realign mpic++ to g++, unfortunately this could be not enough to ensure that all the dependencies has been compiled with the same compiler" + echo -e "\033[1m Installation will resume in 20 seconds \033[0m" + export OMPI_CXX=g++ + sleep 20 + fi + + output_mpi=$(mpic++ --version) + output_gcc=$(g++ --version) + + if [ x"$output_mpi" != x"$output_gcc" ]; then + echo -e "\033[91;5;1m MPI dangerous installation \033[0m" + echo -e "\033[1m The realign operation failed the installation will continue \033[0m" + sleep 10 + fi + + fi } diff --git a/src/Decomposition/ie_ghost.hpp b/src/Decomposition/ie_ghost.hpp index 4eac296ec91bfdcf4335a093eac48e096a1b818b..f61e9ac80bb4cd5c41e31b749bf78fa830af1f2f 100755 --- a/src/Decomposition/ie_ghost.hpp +++ b/src/Decomposition/ie_ghost.hpp @@ -31,11 +31,10 @@ class ie_ghost //! It store the same information of box_nn_processor_int organized by processor id openfpm::vector< Box_dom<dim,T> > proc_int_box; - // External ghost boxes for this processor, indicated with G8_0 G9_0 ... + //! External ghost boxes for this processor openfpm::vector<p_box<dim,T> > vb_ext; - // Internal ghost boxes for this processor domain, indicated with B8_0 B9_0 ..... in the figure - // below as a linear vector + //! Internal ghost boxes for this processor domain openfpm::vector<p_box<dim,T> > vb_int; //! Cell-list that store the geometrical information of the internal ghost boxes @@ -44,8 +43,10 @@ class ie_ghost //! shift vectors openfpm::vector<Point<dim,T>> shifts; - // Temporal buffers to return information for ghost_processorID + //! Temporal buffers to return temporal information for ghost_processorID openfpm::vector<std::pair<size_t,size_t>> ids_p; + + //! Temporal buffers to return temporal information openfpm::vector<size_t> ids; @@ -188,6 +189,9 @@ protected: * The geo cell list structure exist to speed up the labelling the points if they fall on some * internal ghost * + * \param domain where the cell list is defined + * \param div number of division of the cell list + * */ void Initialize_geo_cell(const Box<dim,T> & domain, const size_t (&div)[dim]) { @@ -200,7 +204,11 @@ protected: * For each sub-domain of the local processor it store the intersection between the enlarged * sub-domain of the calling processor with the adjacent processors sub-domains (External ghost box) * + * \param v_cl Virtual cluster * \param ghost margins + * \param subdomains vector of local sundomains + * \param box_nn_processor it will store for each sub-domain the near processors + * \param nn_prcs contain the sub-domains of the near processors * * \note Are the G8_0 G9_0 G9_1 G5_0 boxes in calculateGhostBoxes * \see calculateGhostBoxes @@ -296,8 +304,8 @@ protected: * \param v_cl Virtual cluster * \param ghost margins * \param sub_domains - * \param box_nn_processors sub-domains of the adjacent processors - * \param nn_prcs structure that store the adjacent processor information + * \param box_nn_processors sub-domains of the near processors + * \param nn_prcs structure that store the near processor sub-domains * \param geo_cell Cell list that store the subdomain information * * \note Are the B8_0 B9_0 B9_1 B5_0 boxes in calculateGhostBoxes @@ -508,6 +516,8 @@ public: * This function return the set of shift vectors that determine such shift, for example * in the example above the shift at position 5 will be (0,-1.0) * + * \return the shift vectors + * */ const openfpm::vector<Point<dim,T>> & getShiftVectors() { @@ -667,6 +677,8 @@ public: } /*! \brief Given the internal ghost box id, it return the internal ghost box + * + * \param b_id internal ghost box id * * \return the internal ghost box * @@ -679,6 +691,8 @@ public: /*! \brief Given the internal ghost box id, it return the near processor at witch belong * or the near processor that produced this internal ghost box * + * \param internal ghost box id + * * \return the processor id of the ghost box * */ @@ -698,6 +712,8 @@ public: } /*! \brief Given the external ghost box id, it return the external ghost box + * + * \param b_id external ghost box id * * \return the external ghost box * @@ -710,6 +726,8 @@ public: /*! \brief Given the external ghost box id, it return the near processor at witch belong * or the near processor that produced this external ghost box * + * \param b_id external ghost box id + * * \return the processor id of the external ghost box * */ @@ -721,6 +739,7 @@ public: /*! /brief Given a point it return the set of boxes in which the point fall * * \param p Point to check + * * \return An iterator with the id's of the internal boxes in which the point fall * */ @@ -757,6 +776,8 @@ public: * * \param return the processor ids (not the rank, the id in the near processor list) * + * \return a vector of pairs containinf the requested infromation + * */ template <typename id1, typename id2> inline const openfpm::vector<std::pair<size_t,size_t>> ghost_processorID_pair(Point<dim,T> & p, const int opt = MULTIPLE) { @@ -806,6 +827,8 @@ public: * * \param return the processor ids * + * \return a vector containing the requested information + * */ template <typename id> inline const openfpm::vector<size_t> ghost_processorID(Point<dim,T> & p, const int opt = MULTIPLE) { @@ -842,10 +865,12 @@ public: /*! \brief Given a position it return if the position belong to any neighborhood processor ghost * (Internal ghost) * - * \tparam id type of if to get box_id processor_id lc_processor_id + * \tparam id1 first index type to get box_id processor_id lc_processor_id + * \tparam id2 second index type to get box_id processor_id lc_processor_id + * * \param p Particle position * - * \param return the processor ids + * \return a vector of pair containing the requested information * */ template<typename id1, typename id2, typename Mem> inline const openfpm::vector<std::pair<size_t,size_t>> ghost_processorID_pair(const encapc<1,Point<dim,T>,Mem> & p, const int opt = MULTIPLE) diff --git a/src/Grid/grid_dist_id.hpp b/src/Grid/grid_dist_id.hpp index c16ae0f8fdf5843aabdeee22949c42995a31b2a1..208b654f9eb2edca1d9607b96ff49db1be20770d 100644 --- a/src/Grid/grid_dist_id.hpp +++ b/src/Grid/grid_dist_id.hpp @@ -200,7 +200,6 @@ class grid_dist_id { // Get the internal ghost boxes and transform into grid units ::Box<dim,St> ib_dom = dec.getProcessorIGhostBox(i,j); - ib_dom -= cd_sm.getOrig(); ::Box<dim,long int> ib = cd_sm.convertDomainSpaceIntoGridUnits(ib_dom,dec.periodicity()); // Check if ib is valid if not it mean that the internal ghost does not contain information so skip it @@ -321,7 +320,6 @@ class grid_dist_id { // Get the internal ghost boxes and transform into grid units ::Box<dim,St> ib_dom = dec.getLocalIGhostBox(i,j); - ib_dom -= cd_sm.getOrig(); ::Box<dim,long int> ib = cd_sm.convertDomainSpaceIntoGridUnits(ib_dom,dec.periodicity()); // Check if ib is valid if not it mean that the internal ghost does not contain information so skip it diff --git a/src/Grid/grid_dist_id_unit_test.cpp b/src/Grid/grid_dist_id_unit_test.cpp index 89f04a8d0a9654c87b3459e30553de3dba4a8cfa..08256477ec0e94d03b2c8b853f205ba6a1340919 100644 --- a/src/Grid/grid_dist_id_unit_test.cpp +++ b/src/Grid/grid_dist_id_unit_test.cpp @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE( grid_dist_id_domain_grid_unit_converter3D_test) { // Get the local hyper-cube SpaceBox<3,float> sub = dec.getSubDomain(i); - sub -= domain.getP1(); +// sub -= domain.getP1(); Box<3,size_t> g_box = g_dist.getCellDecomposer().convertDomainSpaceIntoGridUnits(sub,bc); @@ -1862,7 +1862,7 @@ BOOST_AUTO_TEST_CASE( grid_dist_id_unbound_ghost ) // Domain Box<3,float> domain3({0.0,0.0,0.0},{1.0,1.0,1.0}); - long int k = 32*32*32*create_vcluster().getProcessingUnits(); + long int k = 28*28*28*create_vcluster().getProcessingUnits(); k = std::pow(k, 1/3.); Test3D_unb_ghost(domain3,k); @@ -1873,7 +1873,7 @@ BOOST_AUTO_TEST_CASE( grid_dist_id_unbound_ghost_periodic ) // Domain Box<3,float> domain3({0.0,0.0,0.0},{1.0,1.0,1.0}); - long int k = 32*32*32*create_vcluster().getProcessingUnits(); + long int k = 25*25*25*create_vcluster().getProcessingUnits(); k = std::pow(k, 1/3.); Test3D_unb_ghost_periodic(domain3,k); diff --git a/src/Grid/grid_dist_util.hpp b/src/Grid/grid_dist_util.hpp index bba37eb0335b80bd7e99aeb03f9be68a185861d4..d16bf8bb1d073e85edd34b1a9d1778f61b823ea6 100644 --- a/src/Grid/grid_dist_util.hpp +++ b/src/Grid/grid_dist_util.hpp @@ -78,9 +78,7 @@ template<int dim, typename Decomposition> inline void create_gdb_ext(openfpm::ve // Get the local sub-domain (Grid conversion must be done with the domain P1 equivalent to 0.0) // consider that the sub-domain with point P1 equivalent to the domain P1 is a (0,0,0) in grid unit SpaceBox<Decomposition::dims, typename Decomposition::stype> sp = dec.getSubDomain(i); - sp -= cd_sm.getOrig(); SpaceBox<Decomposition::dims, typename Decomposition::stype> sp_g = dec.getSubDomainWithGhost(i); - sp_g -= cd_sm.getOrig(); // Convert from SpaceBox<dim,St> to SpaceBox<dim,long int> SpaceBox<Decomposition::dims,long int> sp_t = cd_sm.convertDomainSpaceIntoGridUnits(sp,dec.periodicity()); diff --git a/src/Grid/staggered_dist_grid_util.hpp b/src/Grid/staggered_dist_grid_util.hpp index c7d20ec6a1902d11264aa8ceeb7c67119ff368f8..938f1d9ab473645b22c4025043b49c17df9567fa 100644 --- a/src/Grid/staggered_dist_grid_util.hpp +++ b/src/Grid/staggered_dist_grid_util.hpp @@ -66,11 +66,13 @@ struct vtk_write<ele,vtk,false> template<typename T> struct extends { + //! number of elements static inline size_t mul() { return 1; } + //! number of indexes static inline size_t dim() { return 0; @@ -81,11 +83,13 @@ struct extends template<typename T,size_t N1> struct extends<T[N1]> { + //! number of elements static inline size_t mul() { return N1; } + //! number of indexes static inline size_t dim() { return 1; @@ -96,11 +100,13 @@ struct extends<T[N1]> template<typename T,size_t N1,size_t N2> struct extends<T[N1][N2]> { + //! number of elements static inline size_t mul() { return N1 * N2; } + //! number of indexes static inline size_t dim() { return 2; @@ -111,11 +117,13 @@ struct extends<T[N1][N2]> template<typename T,size_t N1,size_t N2,size_t N3> struct extends<T[N1][N2][N3]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3; } + //! number of indexes static inline size_t dim() { return 3; @@ -126,11 +134,13 @@ struct extends<T[N1][N2][N3]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4> struct extends<T[N1][N2][N3][N4]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4; } + //! number of indexes static inline size_t dim() { return 4; @@ -141,11 +151,13 @@ struct extends<T[N1][N2][N3][N4]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5> struct extends<T[N1][N2][N3][N4][N5]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5; } + //! number of indexes static inline size_t dim() { return 5; @@ -156,11 +168,13 @@ struct extends<T[N1][N2][N3][N4][N5]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5, size_t N6> struct extends<T[N1][N2][N3][N4][N5][N6]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5 * N6; } + //! number of indexes static inline size_t dim() { return 6; @@ -171,11 +185,13 @@ struct extends<T[N1][N2][N3][N4][N5][N6]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5, size_t N6, size_t N7> struct extends<T[N1][N2][N3][N4][N5][N6][N7]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5 * N6 * N7; } + //! number of indexes static inline size_t dim() { return 7; @@ -186,11 +202,13 @@ struct extends<T[N1][N2][N3][N4][N5][N6][N7]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5, size_t N6, size_t N7, size_t N8> struct extends<T[N1][N2][N3][N4][N5][N6][N7][N8]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5 * N6 * N7 * N8; } + //! number of indexes static inline size_t dim() { return 8; @@ -201,11 +219,13 @@ struct extends<T[N1][N2][N3][N4][N5][N6][N7][N8]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5, size_t N6, size_t N7, size_t N8, size_t N9> struct extends<T[N1][N2][N3][N4][N5][N6][N7][N8][N9]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5 * N6 * N7 * N8 * N9; } + //! number of indexes static inline size_t dim() { return 9; @@ -216,11 +236,13 @@ struct extends<T[N1][N2][N3][N4][N5][N6][N7][N8][N9]> template<typename T,size_t N1,size_t N2,size_t N3,size_t N4,size_t N5, size_t N6, size_t N7, size_t N8, size_t N9, size_t N10> struct extends<T[N1][N2][N3][N4][N5][N6][N7][N8][N9][N10]> { + //! number of elements static inline size_t mul() { return N1 * N2 * N3 * N4 * N5 * N6 * N7 * N8 * N9 * N10; } + //! number of indexes static inline size_t dim() { return 10; diff --git a/src/Makefile.am b/src/Makefile.am index 668590b1b95cffc95373cc48ade44603f686b72c..3ae9a4489e5d25ca3bf5f01d7c6a833b93f4d8c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,15 +1,19 @@ -LINKLIBS = $(LIBHILBERT_LIB) $(METIS_LIB) $(PTHREAD_LIBS) $(OPT_LIBS) $(BOOST_LDFLAGS) $(BOOST_IOSTREAMS_LIB) $(CUDA_LIBS) $(PETSC_LIB) $(HDF5_LDFLAGS) $(HDF5_LIBS) $(PARMETIS_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(BOOST_CHRONO_LIB) $(BOOST_TIMER_LIB) $(BOOST_SYSTEM_LIB) +LINKLIBS = $(OPENMP_LDFLAGS) $(LIBHILBERT_LIB) $(METIS_LIB) $(PTHREAD_LIBS) $(OPT_LIBS) $(BOOST_LDFLAGS) $(BOOST_IOSTREAMS_LIB) $(CUDA_LIBS) $(PETSC_LIB) $(HDF5_LDFLAGS) $(HDF5_LIBS) $(PARMETIS_LIB) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(BOOST_CHRONO_LIB) $(BOOST_TIMER_LIB) $(BOOST_SYSTEM_LIB) noinst_PROGRAMS = pdata pdata_SOURCES = main.cpp Grid/grid_dist_id_unit_test.cpp lib/pdata.cpp test_multiple_o.cpp ../openfpm_devices/src/memory/HeapMemory.cpp ../openfpm_devices/src/memory/PtrMemory.cpp ../openfpm_vcluster/src/VCluster.cpp ../openfpm_devices/src/Memleak_check.cpp +<<<<<<< HEAD pdata_CXXFLAGS = -fext-numeric-literals $(LIBHILBERT_INCLUDE) $(PETSC_INCLUDE) $(HDF5_CPPFLAGS) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(PARMETIS_INCLUDE) $(METIS_INCLUDE) $(BOOST_CPPFLAGS) $(H5PART_INCLUDE) -DPARALLEL_IO -Wno-unused-local-typedefs +======= +pdata_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(LIBHILBERT_INCLUDE) $(PETSC_INCLUDE) $(HDF5_CPPFLAGS) $(CUDA_CFLAGS) $(INCLUDES_PATH) $(PARMETIS_INCLUDE) $(METIS_INCLUDE) $(BOOST_CPPFLAGS) $(H5PART_INCLUDE) -DPARALLEL_IO -Wno-unused-local-typedefs +>>>>>>> 5f826f6afc7c06f925476a464b820e7844678371 pdata_CFLAGS = $(CUDA_CFLAGS) pdata_LDADD = $(LINKLIBS) -lparmetis -lmetis nobase_include_HEADERS = Decomposition/CartDecomposition.hpp Decomposition/CartDecomposition_ext.hpp Decomposition/common.hpp Decomposition/Decomposition.hpp Decomposition/ie_ghost.hpp \ Decomposition/nn_processor.hpp Decomposition/ie_loc_ghost.hpp Decomposition/ORB.hpp \ Graph/CartesianGraphFactory.hpp \ Grid/grid_dist_id.hpp Grid/grid_dist_id_iterator_dec.hpp Grid/grid_dist_util.hpp Grid/grid_dist_id_iterator_sub.hpp Grid/grid_dist_id_iterator.hpp Grid/grid_dist_key.hpp Grid/staggered_dist_grid.hpp Grid/staggered_dist_grid_util.hpp Grid/staggered_dist_grid_copy.hpp \ - Vector/vector_dist_comm.hpp Vector/vector_dist.hpp Vector/vector_dist_ofb.hpp Vector/vector_dist_iterator.hpp Vector/vector_dist_key.hpp \ + Vector/vector_dist_multiphase_functions.hpp Vector/vector_dist_comm.hpp Vector/vector_dist.hpp Vector/vector_dist_ofb.hpp Vector/vector_dist_iterator.hpp Vector/vector_dist_key.hpp \ config/config.h \ example.mk \ Decomposition/Distribution/metis_util.hpp Decomposition/Distribution/parmetis_dist_util.hpp Decomposition/Distribution/parmetis_util.hpp Decomposition/Distribution/MetisDistribution.hpp Decomposition/Distribution/ParMetisDistribution.hpp Decomposition/Distribution/DistParMetisDistribution.hpp dec_optimizer.hpp SubdomainGraphNodes.hpp \ @@ -18,7 +22,7 @@ nobase_include_HEADERS = Decomposition/CartDecomposition.hpp Decomposition/CartD lib_LIBRARIES = libofpm_pdata.a libofpm_pdata_a_SOURCES = lib/pdata.cpp -libofpm_pdata_a_CXXFLAGS = $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I/usr/local/include -Wno-unused-local-typedefs +libofpm_pdata_a_CXXFLAGS = $(OPENMP_CFLAGS) $(AM_CXXFLAGS) $(INCLUDES_PATH) $(BOOST_CPPFLAGS) -I/usr/local/include -Wno-unused-local-typedefs libofpm_pdata_a_CFLAGS = .cu.o : diff --git a/src/Vector/vector_dist.hpp b/src/Vector/vector_dist.hpp index 4140a9f319b41b4bb9aa34def6c1fcdac61aced5..427bb2755fea8440a7beb7f75327270d5b671a14 100644 --- a/src/Vector/vector_dist.hpp +++ b/src/Vector/vector_dist.hpp @@ -16,7 +16,6 @@ #include "Vector/vector_dist_iterator.hpp" #include "Space/Shape/Box.hpp" #include "Vector/vector_dist_key.hpp" -#include "memory/PreAllocHeapMemory.hpp" #include "memory/PtrMemory.hpp" #include "NN/CellList/CellList.hpp" #include "util/common.hpp" @@ -165,7 +164,7 @@ public: * */ vector_dist(const vector_dist<dim,St,prop,Decomposition,Memory> & v) - :vector_dist_comm<dim,St,prop,Decomposition,Memory>(v.dec),v_cl(v.v_cl) + :vector_dist_comm<dim,St,prop,Decomposition,Memory>(v.getDecomposition()),v_cl(v.v_cl) { #ifdef SE_CLASS2 check_new(this,8,VECTOR_DIST_EVENT,4); @@ -179,7 +178,7 @@ public: * \param v vector to copy * */ - vector_dist(vector_dist<dim,St,prop,Decomposition,Memory> && v) + vector_dist(vector_dist<dim,St,prop,Decomposition,Memory> && v) noexcept :v_cl(v.v_cl) { #ifdef SE_CLASS2 @@ -348,6 +347,36 @@ public: return v_prp.template get<id>(g_m - 1); } + /*! \brief Construct a cell list symmetric based on a cut of radius + * + * \tparam CellL CellList type to construct + * + * \param r_cut interation radius, or size of each cell + * + * \return the Cell list + * + */ + template<typename CellL = CellList<dim, St, FAST, shift<dim, St> > > CellL getCellListSym(St r_cut) + { + // Cell list + CellL cell_list; + + size_t pad = 0; + CellDecomposer_sm<dim,St,shift<dim,St>> cd_sm; + cl_param_calculateSym(getDecomposition().getDomain(),cd_sm,getDecomposition().getGhost(),r_cut,pad); + + // Processor bounding box + Box<dim, St> pbox = getDecomposition().getProcessorBounds(); + + // Ghost padding extension + Ghost<dim,size_t> g_ext(0); + cell_list.Initialize(cd_sm,pbox,pad); + + updateCellList(cell_list); + + return cell_list; + } + /*! \brief Construct a cell list starting from the stored particles * * \tparam CellL CellList type to construct @@ -393,21 +422,21 @@ public: */ template<typename CellL = CellList_gen<dim, St, Process_keys_lin<dim>, Mem_fast<dim,St>, shift<dim, St> > > void updateCellList(CellL & cell_list) { - // Clear the cell list from the previous particles - cell_list.clear(); - - // for each particle add the particle to the cell list - - auto it = getIterator(); + populate_cell_list(v_pos,cell_list,g_m,CL_NON_SYMMETRIC); - while (it.isNext()) - { - auto key = it.get(); - - cell_list.add(this->getPos(key), key.getKey()); + cell_list.set_gm(g_m); + } - ++it; - } + /*! \brief Update a cell list using the stored particles + * + * \tparam CellL CellList type to construct + * + * \param cell_list Cell list to update + * + */ + template<typename CellL = CellList<dim, St, FAST, shift<dim, St> > > void updateCellListSym(CellL & cell_list) + { + populate_cell_list(v_pos,cell_list,g_m,CL_SYMMETRIC); cell_list.set_gm(g_m); } @@ -482,15 +511,33 @@ public: return cell_list; } + /*! \brief for each particle get the symmetric verlet list + * + * \param r_cut cut-off radius + * + * \return the verlet list + * + */ + VerletList<dim,St,FAST,shift<dim,St> > getVerletSym(St r_cut) + { + VerletList<dim,St,FAST,shift<dim,St>> ver; + + // Processor bounding box + Box<dim, St> pbox = getDecomposition().getProcessorBounds(); + ver.InitializeSym(getDecomposition().getDomain(),pbox,getDecomposition().getGhost(),r_cut,v_pos,g_m); + + return ver; + } /*! \brief for each particle get the verlet list * * \param r_cut cut-off radius - * \param opt option like VL_SYMMETRIC and VL_NON_SYMMETRIC + * + * \return a VerletList object * */ - VerletList<dim,St,FAST,shift<dim,St> > getVerlet(St r_cut, size_t opt = VL_NON_SYMMETRIC) + VerletList<dim,St,FAST,shift<dim,St> > getVerlet(St r_cut) { VerletList<dim,St,FAST,shift<dim,St>> ver; @@ -504,7 +551,7 @@ public: // enlarge the box where the Verlet is defined bt.enlarge(g); - ver.Initialize(bt,getDecomposition().getProcessorBounds(),r_cut,v_pos,g_m,opt); + ver.Initialize(bt,getDecomposition().getProcessorBounds(),r_cut,v_pos,g_m,VL_NON_SYMMETRIC); return ver; } @@ -800,6 +847,16 @@ public: return vector_dist_comm<dim,St,prop,Decomposition,Memory>::getDecomposition(); } + /*! \brief Get the decomposition + * + * \return + * + */ + inline const Decomposition & getDecomposition() const + { + return vector_dist_comm<dim,St,prop,Decomposition,Memory>::getDecomposition(); + } + /*! \brief It move all the particles that does not belong to the local processor to the respective processor * * \tparam out of bound policy it specify what to do when the particles are detected out of bound @@ -1023,7 +1080,17 @@ public: */ void getCellListParams(St r_cut, size_t (&div)[dim],Box<dim, St> & box, Ghost<dim,St> enlarge = Ghost<dim,St>(0.0)) { - box = cl_param_calculate(div,r_cut,enlarge); + // get the processor bounding box + Box<dim, St> pbox = getDecomposition().getProcessorBounds(); + + // enlarge the processor bounding box by the ghost + Ghost<dim,St> g = getDecomposition().getGhost(); + pbox.enlarge(g); + + cl_param_calculate(pbox, div,r_cut,enlarge); + + // output the fixed domain + box = pbox; } /*! \brief It return the id of structure in the allocation list @@ -1055,6 +1122,38 @@ public: #endif return v_cl; } + + /*! \brief return the position vector of all the particles + * + * \return the particle position vector + * + */ + const openfpm::vector<Point<dim,St>> & getPosVector() const + { + return v_pos; + } + + /*! \brief It return the sum of the particles in the previous processors + * + * \return the particles number + * + */ + size_t accum() + { + openfpm::vector<size_t> accu; + + size_t sz = size_local(); + + v_cl.allGather(sz,accu); + v_cl.execute(); + + sz = 0; + + for (size_t i = 0 ; i < v_cl.getProcessUnitID() ; i++) + sz += accu.get(i); + + return sz; + } }; diff --git a/src/Vector/vector_dist_MP_unit_tests.hpp b/src/Vector/vector_dist_MP_unit_tests.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7d9eff81e52f5cbb5b5e2ad3b1951e69802ffbe0 --- /dev/null +++ b/src/Vector/vector_dist_MP_unit_tests.hpp @@ -0,0 +1,377 @@ +/* + * vector_dist_MP_unit_tests.hpp + * + * Created on: Oct 14, 2016 + * Author: i-bird + */ + +#ifndef SRC_VECTOR_VECTOR_DIST_MP_UNIT_TESTS_HPP_ +#define SRC_VECTOR_VECTOR_DIST_MP_UNIT_TESTS_HPP_ + +#include "Vector/vector_dist_multiphase_functions.hpp" + +BOOST_AUTO_TEST_SUITE( vector_dist_multiphase_test ) + +BOOST_AUTO_TEST_CASE( vector_dist_multiphase_cell_list_test ) +{ + if (create_vcluster().getProcessingUnits() > 24) + return; + + size_t sz[3] = {60,60,40}; + + // The domain + Box<3,float> box({-1000.0,-1000.0,-1000.0},{2000.0,2000.0,1000.0}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + float r_cut = 51.0; + + // ghost, big enough to contain the interaction radius + Ghost<3,float> ghost(r_cut); + + openfpm::vector< vector_dist<3,float, aggregate<double,double>> > phases; + + // first phase + phases.add( vector_dist<3,float, aggregate<double,double>>(0,box,bc,ghost) ); + + // The other 3 phases + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),0) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),0) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),0) ); + + // Fill the phases with particles + + auto g_it = phases.get(0).getGridIterator(sz); + + while (g_it.isNext()) + { + auto key = g_it.get(); + + // Add a particle to all the phases + phases.get(0).add(); + phases.get(1).add(); + phases.get(2).add(); + phases.get(3).add(); + + phases.get(0).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(0).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(0).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(1).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(1).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(1).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(2).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(2).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(2).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(3).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(3).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(3).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + ++g_it; + } + + // Sync all phases + for (size_t i = 0 ; i < 4 ; i++) + { + phases.get(i).map(); + phases.get(i).ghost_get<>(); + } + + // Get the cell list of the phase 0 and 1 + auto CL_phase0 = phases.get(0).getCellList(r_cut); + auto CL_phase1 = phases.get(1).getCellList(r_cut); + + // This function create a Verlet-list between phases 0 and 1 + auto NN_ver01 = createVerlet(phases.get(0),CL_phase1,r_cut); + + // Check NNver0_1 + + bool ret = true; + auto it = phases.get(0).getDomainIterator(); + + while (it.isNext()) + { + auto p = it.get(); + auto Np = NN_ver01.template getNNIterator<NO_CHECK>(p.getKey()); + + size_t nn_count = 0; + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q + auto q = Np.get(); + + // Count the number of particles + nn_count++; + + ++Np; + } + + ret &= nn_count == 7ul; + + ++it; + } + + BOOST_REQUIRE_EQUAL(ret,true); + + // Sync all phases + for (size_t i = 0 ; i < 4 ; i++) + { + phases.get(i).map(); + phases.get(i).ghost_get<>(); + } + + // NN_ver0_all + + // This function create an "Empty" Multiphase Cell List + auto CL_all = createCellListM<2>(phases,r_cut); + + // This create a Verlet-list between phase 0 and all the other phases + auto NNver0_all = createVerletM<2>(phases.get(0),CL_all,r_cut); + + it = phases.get(0).getDomainIterator(); + + while (it.isNext()) + { + auto p = it.get(); + auto Np = NNver0_all.template getNNIterator<NO_CHECK>(p.getKey()); + + size_t nn_cout[4] = {0,0,0,0}; + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Get the particle q near to p + auto q = Np.getP(); + + // Get from which phase it come from + auto ph_q = Np.getV(); + + nn_cout[ph_q]++; + + ++Np; + } + + ret &= nn_cout[0] == 7; + ret &= nn_cout[1] == 7; + ret &= nn_cout[2] == 7; + ret &= nn_cout[3] == 7; + + ++it; + } + + BOOST_REQUIRE_EQUAL(ret,true); +} + + +BOOST_AUTO_TEST_CASE( vector_dist_multiphase_cell_list_sym_test ) +{ + if (create_vcluster().getProcessingUnits() > 24) + return; + + size_t sz[3] = {60,60,40}; + + // The domain + Box<3,float> box({-1000.0,-1000.0,-1000.0},{2000.0,2000.0,1000.0}); + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + float r_cut = 51.0; + + // ghost, big enough to contain the interaction radius + Ghost<3,float> ghost(r_cut); + + openfpm::vector< vector_dist<3,float, aggregate<size_t>> > phases; + + // first phase + phases.add( vector_dist<3,float, aggregate<size_t>>(0,box,bc,ghost) ); + + // The other 3 phases + phases.add( vector_dist<3,float, aggregate<size_t>>(phases.get(0).getDecomposition(),0) ); + phases.add( vector_dist<3,float, aggregate<size_t>>(phases.get(0).getDecomposition(),0) ); + phases.add( vector_dist<3,float, aggregate<size_t>>(phases.get(0).getDecomposition(),0) ); + + // Fill the phases with particles + + auto g_it = phases.get(0).getGridIterator(sz); + + while (g_it.isNext()) + { + auto key = g_it.get(); + + // Add a particle to all the phases + phases.get(0).add(); + phases.get(1).add(); + phases.get(2).add(); + phases.get(3).add(); + + phases.get(0).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(0).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(0).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(1).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(1).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(1).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(2).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(2).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(2).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + phases.get(3).getLastPos()[0] = key.get(0) * g_it.getSpacing(0) + box.getLow(0); + phases.get(3).getLastPos()[1] = key.get(1) * g_it.getSpacing(1) + box.getLow(1); + phases.get(3).getLastPos()[2] = key.get(2) * g_it.getSpacing(2) + box.getLow(2); + + ++g_it; + } + + // Sync all phases + for (size_t i = 0 ; i < 4 ; i++) + { + phases.get(i).map(); + phases.get(i).ghost_get<>(); + } + + // Get the cell list of the phase 0 and 1 + auto CL_phase0 = phases.get(0).getCellListSym(r_cut); + auto CL_phase1 = phases.get(1).getCellListSym(r_cut); + + // This function create a Verlet-list between phases 0 and 1 + auto NN_ver01 = createVerletSym(phases.get(0),CL_phase1,r_cut); + + // Check NNver0_1 + + bool ret = true; + auto it = phases.get(0).getDomainIterator(); + + while (it.isNext()) + { + auto p = it.get(); + auto Np = NN_ver01.template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Neighborhood particle q + auto q = Np.get(); + + phases.get(0).getProp<0>(p)++; + phases.get(1).getProp<0>(q)++; + + ++Np; + } + + ++it; + } + + phases.get(0).ghost_put<add_,0>(); + phases.get(1).ghost_put<add_,0>(); + + it = phases.get(0).getDomainIterator(); + while (it.isNext()) + { + auto p = it.get(); + + ret &= phases.get(0).getProp<0>(p) == 7; + ret &= phases.get(1).getProp<0>(p) == 7; + + ++it; + } + + BOOST_REQUIRE_EQUAL(ret,true); + + // Sync all phases + for (size_t i = 0 ; i < 4 ; i++) + { + phases.get(i).map(); + phases.get(i).ghost_get<>(); + } + + // Reset counter on all phases + + for (size_t i = 0 ; i < phases.size() ; i++) + { + it = phases.get(i).getDomainAndGhostIterator(); + while (it.isNext()) + { + auto p = it.get(); + + phases.get(i).getProp<0>(p) = 0; + + ++it; + } + } + + // NN_ver0_all + + // This function create an "Empty" Multiphase Cell List + auto CL_all = createCellListSymM<2>(phases,r_cut); + + typedef decltype(createVerletSymM<2>(phases.get(0),CL_all,r_cut)) verlet_type; + + verlet_type NNver_all[4]; + + // This create a Verlet-list between phase all phases to all the other phases + NNver_all[0] = createVerletSymM<2>(phases.get(0),CL_all,r_cut); + NNver_all[1] = createVerletSymM<2>(phases.get(1),CL_all,r_cut); + NNver_all[2] = createVerletSymM<2>(phases.get(2),CL_all,r_cut); + NNver_all[3] = createVerletSymM<2>(phases.get(3),CL_all,r_cut); + + // all phases to all phases + + for (size_t i = 0 ; i < phases.size() ; i++) + { + it = phases.get(i).getDomainIterator(); + + while (it.isNext()) + { + auto p = it.get(); + auto Np = NNver_all[i].template getNNIterator<NO_CHECK>(p.getKey()); + + // For each neighborhood of the particle p + while (Np.isNext()) + { + // Get the particle q near to p + auto q = Np.getP(); + + // Get from which phase it come from + auto ph_q = Np.getV(); + + phases.get(i).getProp<0>(p)++; + phases.get(ph_q).getProp<0>(q)++; + + ++Np; + } + + ++it; + } + } + + phases.get(0).ghost_put<add_,0>(); + phases.get(1).ghost_put<add_,0>(); + phases.get(2).ghost_put<add_,0>(); + phases.get(3).ghost_put<add_,0>(); + + it = phases.get(0).getDomainIterator(); + while (it.isNext()) + { + auto p = it.get(); + + ret &= phases.get(0).getProp<0>(p) == 32; + ret &= phases.get(1).getProp<0>(p) == 32; + ret &= phases.get(2).getProp<0>(p) == 32; + ret &= phases.get(3).getProp<0>(p) == 32; + + ++it; + } + + BOOST_REQUIRE_EQUAL(ret,true); +} + +BOOST_AUTO_TEST_SUITE_END() + +#endif /* SRC_VECTOR_VECTOR_DIST_MP_UNIT_TESTS_HPP_ */ diff --git a/src/Vector/vector_dist_cell_list_tests.hpp b/src/Vector/vector_dist_cell_list_tests.hpp index 0b747f83b14c439fb5afbadb3525a6e40c0ba1a4..099173f2d9f9a826a567435ecf917656ae95e659 100644 --- a/src/Vector/vector_dist_cell_list_tests.hpp +++ b/src/Vector/vector_dist_cell_list_tests.hpp @@ -332,339 +332,407 @@ BOOST_AUTO_TEST_CASE( vector_dist_cl_random_vs_reorder_forces_test ) } } - -BOOST_AUTO_TEST_CASE( vector_dist_sym_cell_list_test ) +BOOST_AUTO_TEST_CASE( vector_dist_symmetric_cell_list ) { - long int k = 4096*create_vcluster().getProcessingUnits(); - - long int big_step = k / 30; - big_step = (big_step == 0)?1:big_step; - long int small_step = 21; + Vcluster & v_cl = create_vcluster(); - if (create_vcluster().getProcessingUnits() > 48) + if (v_cl.getProcessingUnits() > 24) return; - print_test( "Testing vector symmetric cell-list k<=",k); + float L = 1000.0; - // 3D test - for ( ; k > 8*big_step ; k-= (k > 2*big_step)?big_step:small_step ) - { - double r_cut = 0.1; + // set the seed + // create the random generator engine + std::srand(0); + std::default_random_engine eg; + std::uniform_real_distribution<float> ud(-L,L); - // domain - Box<3,double> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + long int k = 4096 * v_cl.getProcessingUnits(); - // Boundary conditions - size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + long int big_step = k / 4; + big_step = (big_step == 0)?1:big_step; - // ghost, big enough to contain the interaction radius - Ghost<3,float> ghost(r_cut); + print_test("Testing 3D periodic vector symmetric cell-list k=",k); + BOOST_TEST_CHECKPOINT( "Testing 3D periodic vector symmetric cell-list k=" << k ); - vector_dist<3,double, aggregate<double> > vd(k,box,bc,ghost); + Box<3,float> box({-L,-L,-L},{L,L,L}); - { - auto it = vd.getDomainIterator(); + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; - while (it.isNext()) - { - auto p = it.get(); + float r_cut = 100.0; - vd.getPos(p)[0] = (double)rand()/RAND_MAX; - vd.getPos(p)[1] = (double)rand()/RAND_MAX; - vd.getPos(p)[2] = (double)rand()/RAND_MAX; + // ghost + Ghost<3,float> ghost(r_cut); - ++it; - } + // Point and global id + struct point_and_gid + { + size_t id; + Point<3,float> xq; + + bool operator<(const struct point_and_gid & pag) const + { + return (id < pag.id); } + }; - vd.map(); - vd.ghost_get<>(); + typedef aggregate<size_t,size_t,size_t,openfpm::vector<point_and_gid>,openfpm::vector<point_and_gid>> part_prop; - // Get the Cell list structure - auto NN = vd.getCellList(r_cut); + // Distributed vector + vector_dist<3,float, part_prop > vd(k,box,bc,ghost); + size_t start = vd.init_size_accum(k); - // Get an iterator over particles - auto it2 = vd.getDomainAndGhostIterator(); + auto it = vd.getIterator(); - openfpm::vector<openfpm::vector<size_t>> idx; - idx.resize(vd.size_local_with_ghost()); + while (it.isNext()) + { + auto key = it.get(); - /////////// SYMMETRIC CASE CELL-LIST //////// + vd.getPos(key)[0] = ud(eg); + vd.getPos(key)[1] = ud(eg); + vd.getPos(key)[2] = ud(eg); - // For each particle ... - while (it2.isNext()) - { - // ... p - auto p = it2.get(); + // Fill some properties randomly - // Get the position of the particle p - Point<3,double> xp = vd.getPos(p); + vd.getProp<0>(key) = 0; + vd.getProp<1>(key) = 0; + vd.getProp<2>(key) = key.getKey() + start; - // Get an iterator over the neighborhood of the particle p symmetric - auto NpSym = NN.template getNNIteratorSym<NO_CHECK>(NN.getCell(vd.getPos(p)),p.getKey()); + ++it; + } - // For each neighborhood of the particle p - while (NpSym.isNext()) - { - // Neighborhood particle q - auto q = NpSym.get(); + vd.map(); - // if p == q skip this particle - if (q == p.getKey() ) {++NpSym; continue;}; + // sync the ghost + vd.ghost_get<0,2>(); - // Get position of the particle q - Point<3,double> xq = vd.getPos(q); + auto NN = vd.getCellList(r_cut); + auto p_it = vd.getDomainIterator(); - // take the normalized direction - double rn = norm2(xp - xq); + while (p_it.isNext()) + { + auto p = p_it.get(); - // potential energy (using pow is slower) - vd.getProp<0>(p) += rn; - vd.getProp<0>(q) += rn; + Point<3,float> xp = vd.getPos(p); - idx.get(p.getKey()).add(q); - idx.get(q).add(p.getKey()); + auto Np = NN.getNNIterator(NN.getCell(vd.getPos(p))); + while (Np.isNext()) + { + auto q = Np.get(); - // Next neighborhood - ++NpSym; + if (p.getKey() == q) + { + ++Np; + continue; } - // Next Particle - ++it2; - } + // repulsive - /////////////// NON SYMMETRIC CASE //////////////////////// + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); - openfpm::vector<openfpm::vector<size_t>> idx2; - idx2.resize(vd.size_local()); + float distance = f.norm(); - auto it = vd.getDomainIterator(); + // Particle should be inside 2 * r_cut range - // For each particle ... - while (it.isNext()) - { - // ... p - auto p = it.get(); + if (distance < r_cut ) + { + vd.getProp<0>(p)++; + vd.getProp<3>(p).add(); + vd.getProp<3>(p).last().xq = xq; + vd.getProp<3>(p).last().id = vd.getProp<2>(q); + } - // Get the position of the particle p - Point<3,double> xp = vd.getPos(p); + ++Np; + } - // Get an iterator over the neighborhood of the particle p - auto Np = NN.template getNNIterator<NO_CHECK>(NN.getCell(vd.getPos(p))); + ++p_it; + } - double Ep = 0.0; + // We now try symmetric Cell-list - // For each neighborhood of the particle p - while (Np.isNext()) - { - // Neighborhood particle q - auto q = Np.get(); + auto NN2 = vd.getCellListSym(r_cut); - // if p == q skip this particle - if (q == p.getKey()) {++Np; continue;}; + auto p_it2 = vd.getDomainIterator(); - // Get position of the particle q - Point<3,double> xq = vd.getPos(q); + while (p_it2.isNext()) + { + auto p = p_it2.get(); - // take the normalized direction - double rn = norm2(xp - xq); + Point<3,float> xp = vd.getPos(p); - idx2.get(p.getKey()).add(q); + auto Np = NN2.template getNNIteratorSym<NO_CHECK>(NN2.getCell(vd.getPos(p)),p.getKey(),vd.getPosVector()); - // potential energy (using pow is slower) - Ep += rn; + while (Np.isNext()) + { + auto q = Np.get(); - // Next neighborhood + if (p.getKey() == q) + { ++Np; + continue; } - idx.get(p.getKey()).sort(); - idx2.get(p.getKey()).sort(); + // repulsive - bool ret = true; + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); - for (size_t i = 0 ; i < idx.get(p.getKey()).size() ; i++) - ret &= idx.get(p.getKey()).get(i) == idx2.get(p.getKey()).get(i); + float distance = f.norm(); - BOOST_REQUIRE_EQUAL(ret,true); + // Particle should be inside r_cut range - BOOST_REQUIRE_CLOSE(Ep,vd.getProp<0>(p),0.01); + if (distance < r_cut ) + { + vd.getProp<1>(p)++; + vd.getProp<1>(q)++; - // Next Particle - ++it; + vd.getProp<4>(p).add(); + vd.getProp<4>(q).add(); + + vd.getProp<4>(p).last().xq = xq; + vd.getProp<4>(q).last().xq = xp; + vd.getProp<4>(p).last().id = vd.getProp<2>(q); + vd.getProp<4>(q).last().id = vd.getProp<2>(p); + } + + ++Np; } + + ++p_it2; + } + + vd.ghost_put<add_,1>(); + vd.ghost_put<merge_,4>(); + + auto p_it3 = vd.getDomainIterator(); + + bool ret = true; + while (p_it3.isNext()) + { + auto p = p_it3.get(); + + ret &= vd.getProp<1>(p) == vd.getProp<0>(p); + + vd.getProp<3>(p).sort(); + vd.getProp<4>(p).sort(); + + ret &= vd.getProp<3>(p).size() == vd.getProp<4>(p).size(); + + for (size_t i = 0 ; i < vd.getProp<3>(p).size() ; i++) + ret &= vd.getProp<3>(p).get(i).id == vd.getProp<4>(p).get(i).id; + + if (ret == false) + break; + + ++p_it3; } + + BOOST_REQUIRE_EQUAL(ret,true); } -BOOST_AUTO_TEST_CASE( vector_dist_sym_verlet_list_test ) +BOOST_AUTO_TEST_CASE( vector_dist_symmetric_verlet_list ) { - if (create_vcluster().getProcessingUnits() > 48) + Vcluster & v_cl = create_vcluster(); + + if (v_cl.getProcessingUnits() > 24) return; - long int k = 4096*create_vcluster().getProcessingUnits(); + float L = 1000.0; + + // set the seed + // create the random generator engine + std::srand(0); + std::default_random_engine eg; + std::uniform_real_distribution<float> ud(-L,L); + + long int k = 4096 * v_cl.getProcessingUnits(); - long int big_step = k / 30; + long int big_step = k / 4; big_step = (big_step == 0)?1:big_step; - long int small_step = 21; - print_test( "Testing vector symmetric verlet-list k<=",k); + print_test("Testing 3D periodic vector symmetric cell-list k=",k); + BOOST_TEST_CHECKPOINT( "Testing 3D periodic vector symmetric cell-list k=" << k ); - // 3D test - for ( ; k > 8*big_step ; k-= (k > 2*big_step)?big_step:small_step ) - { - double r_cut = 0.1; + Box<3,float> box({-L,-L,-L},{L,L,L}); - // domain - Box<3,double> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; - // Boundary conditions - size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + float r_cut = 100.0; - // ghost, big enough to contain the interaction radius - Ghost<3,float> ghost(r_cut); + // ghost + Ghost<3,float> ghost(r_cut); - vector_dist<3,double, aggregate<double> > vd(k,box,bc,ghost); + // Point and global id + struct point_and_gid + { + size_t id; + Point<3,float> xq; + bool operator<(const struct point_and_gid & pag) const { - auto it = vd.getDomainIterator(); + return (id < pag.id); + } + }; - while (it.isNext()) - { - auto p = it.get(); + typedef aggregate<size_t,size_t,size_t,openfpm::vector<point_and_gid>,openfpm::vector<point_and_gid>> part_prop; - vd.getPos(p)[0] = (double)rand()/RAND_MAX; - vd.getPos(p)[1] = (double)rand()/RAND_MAX; - vd.getPos(p)[2] = (double)rand()/RAND_MAX; + // Distributed vector + vector_dist<3,float, part_prop > vd(k,box,bc,ghost); + size_t start = vd.init_size_accum(k); - ++it; - } - } + auto it = vd.getIterator(); - vd.map(); - vd.ghost_get<>(); + while (it.isNext()) + { + auto key = it.get(); - // Get the Cell list structure - auto NN = vd.getVerlet(r_cut,VL_SYMMETRIC); - auto NNc = vd.getVerlet(r_cut); + vd.getPos(key)[0] = ud(eg); + vd.getPos(key)[1] = ud(eg); + vd.getPos(key)[2] = ud(eg); - // Get an iterator over particles - auto it2 = vd.getDomainAndGhostIterator(); + // Fill some properties randomly - openfpm::vector<openfpm::vector<size_t>> idx; - idx.resize(vd.size_local_with_ghost()); + vd.getProp<0>(key) = 0; + vd.getProp<1>(key) = 0; + vd.getProp<2>(key) = key.getKey() + start; - /////////// SYMMETRIC CASE VERLET-LIST //////// + ++it; + } - // For each particle ... - while (it2.isNext()) - { - // ... p - auto p = it2.get(); + vd.map(); - // Get the position of the particle p - Point<3,double> xp = vd.getPos(p); + // sync the ghost + vd.ghost_get<0,2>(); - // Get an iterator over the neighborhood of the particle p symmetric - auto NpSym = NN.template getNNIterator<NO_CHECK>(p.getKey()); + auto NN = vd.getVerlet(r_cut); + auto p_it = vd.getDomainIterator(); - // For each neighborhood of the particle p - while (NpSym.isNext()) - { - // Neighborhood particle q - auto q = NpSym.get(); + while (p_it.isNext()) + { + auto p = p_it.get(); - // if p == q skip this particle - if (q == p.getKey()) {++NpSym; continue;}; + Point<3,float> xp = vd.getPos(p); - // Get position of the particle q - Point<3,double> xq = vd.getPos(q); + auto Np = NN.getNNIterator(p.getKey()); - // take the normalized direction - double rn = norm2(xp - xq); + while (Np.isNext()) + { + auto q = Np.get(); - // potential energy (using pow is slower) - vd.getProp<0>(p) += rn; - vd.getProp<0>(q) += rn; + if (p.getKey() == q) + { + ++Np; + continue; + } + + // repulsive - idx.get(p.getKey()).add(q); - idx.get(q).add(p.getKey()); + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); + float distance = f.norm(); - // Next neighborhood - ++NpSym; + // Particle should be inside 2 * r_cut range + + if (distance < r_cut ) + { + vd.getProp<0>(p)++; + vd.getProp<3>(p).add(); + vd.getProp<3>(p).last().xq = xq; + vd.getProp<3>(p).last().id = vd.getProp<2>(q); } - // Next Particle - ++it2; + ++Np; } - /////////////// NON SYMMETRIC CASE VERLET-LIST //////////////////////// + ++p_it; + } - openfpm::vector<openfpm::vector<size_t>> idx2; - idx2.resize(vd.size_local()); + // We now try symmetric Cell-list - auto it = vd.getDomainIterator(); + auto NN2 = vd.getVerletSym(r_cut); - // For each particle ... - while (it.isNext()) - { - // ... p - auto p = it.get(); + auto p_it2 = vd.getDomainIterator(); - // Get the position of the particle p - Point<3,double> xp = vd.getPos(p); + while (p_it2.isNext()) + { + auto p = p_it2.get(); + + Point<3,float> xp = vd.getPos(p); - // Get an iterator over the neighborhood of the particle p - auto Np = NNc.template getNNIterator<NO_CHECK>(p.getKey()); + auto Np = NN2.template getNNIterator<NO_CHECK>(p.getKey()); - double Ep = 0.0; + while (Np.isNext()) + { + auto q = Np.get(); - // For each neighborhood of the particle p - while (Np.isNext()) + if (p.getKey() == q) { - // Neighborhood particle q - auto q = Np.get(); + ++Np; + continue; + } - // if p == q skip this particle - if (q == p.getKey()) {++Np; continue;}; + // repulsive - // Get position of the particle q - Point<3,double> xq = vd.getPos(q); + Point<3,float> xq = vd.getPos(q); + Point<3,float> f = (xp - xq); - // take the normalized direction - double rn = norm2(xp - xq); + float distance = f.norm(); - idx2.get(p.getKey()).add(q); + // Particle should be inside r_cut range - // potential energy (using pow is slower) - Ep += rn; + if (distance < r_cut ) + { + vd.getProp<1>(p)++; + vd.getProp<1>(q)++; - // Next neighborhood - ++Np; + vd.getProp<4>(p).add(); + vd.getProp<4>(q).add(); + + vd.getProp<4>(p).last().xq = xq; + vd.getProp<4>(q).last().xq = xp; + vd.getProp<4>(p).last().id = vd.getProp<2>(q); + vd.getProp<4>(q).last().id = vd.getProp<2>(p); } - idx.get(p.getKey()).sort(); - idx2.get(p.getKey()).sort(); + ++Np; + } - bool ret = true; + ++p_it2; + } - BOOST_REQUIRE_EQUAL(idx.get(p.getKey()).size(),idx2.get(p.getKey()).size()); + vd.ghost_put<add_,1>(); + vd.ghost_put<merge_,4>(); - for (size_t i = 0 ; i < idx.get(p.getKey()).size() ; i++) - { - ret &= idx.get(p.getKey()).get(i) == idx2.get(p.getKey()).get(i); - } + auto p_it3 = vd.getDomainIterator(); - BOOST_REQUIRE_EQUAL(ret,true); + bool ret = true; + while (p_it3.isNext()) + { + auto p = p_it3.get(); - BOOST_REQUIRE_CLOSE(Ep,vd.getProp<0>(p),0.01); + ret &= vd.getProp<1>(p) == vd.getProp<0>(p); - // Next Particle - ++it; - } + vd.getProp<3>(p).sort(); + vd.getProp<4>(p).sort(); + + ret &= vd.getProp<3>(p).size() == vd.getProp<4>(p).size(); + + for (size_t i = 0 ; i < vd.getProp<3>(p).size() ; i++) + ret &= vd.getProp<3>(p).get(i).id == vd.getProp<4>(p).get(i).id; + + if (ret == false) + break; + + ++p_it3; } + + BOOST_REQUIRE_EQUAL(ret,true); } diff --git a/src/Vector/vector_dist_comm.hpp b/src/Vector/vector_dist_comm.hpp index 5b3871f8e762b69229e3cfb3bddc134c585a1498..cce9b7c21d7106741fca20ca9fdc38a8b82d5dc4 100644 --- a/src/Vector/vector_dist_comm.hpp +++ b/src/Vector/vector_dist_comm.hpp @@ -11,6 +11,7 @@ #define V_SUB_UNIT_FACTOR 64 #define SKIP_LABELLING 512 +#define KEEP_PROPERTIES 512 #define NO_POSITION 1 #define WITH_POSITION 2 @@ -30,6 +31,9 @@ template<unsigned int dim, typename St, typename prop, typename Decomposition = CartDecomposition<dim,St>, typename Memory = HeapMemory> class vector_dist_comm { + //! definition of the send vector for position + typedef openfpm::vector<Point<dim, St>, Memory> send_pos_vector; + //! VCluster Vcluster & v_cl; @@ -40,74 +44,128 @@ class vector_dist_comm openfpm::vector<size_t> p_map_req; //! For each near processor, outgoing particle id - openfpm::vector<openfpm::vector<size_t>> opart; - - //! For each near processor, particle shift vector - openfpm::vector<openfpm::vector<size_t>> oshift; + //! \warning opart is assumed to be an ordered list + //! first id particle id + //! second id shift id + //! third id is the processor id + openfpm::vector<aggregate<size_t,size_t,size_t>> m_opart; - //! For each adjacent processor the size of the ghost sending buffer - openfpm::vector<size_t> ghost_prc_sz; + //! Per processor ordered particles id for ghost_get (see prc_g_opart) + //! For each processor the internal vector store the id of the + //! particles that must be communicated to the other processors + openfpm::vector<openfpm::vector<aggregate<size_t,size_t>>> g_opart; - //! Sending buffer for the ghost particles properties - BHeapMemory g_prp_mem; + // processor rank list of g_opart + openfpm::vector<size_t> prc_g_opart; //! Sending buffer for the ghost particles position - BHeapMemory g_pos_mem; + openfpm::vector<send_pos_vector> g_pos_send; - //! For each adjacent processor it store from which processor come from - openfpm::vector<size_t> prc_recv; + //! It store the list of processor that communicate with us (local processor) + //! from the last ghost get + openfpm::vector<size_t> prc_recv_get; - //! the same as prc_recv but for put + //! the same as prc_recv_get but for put openfpm::vector<size_t> prc_recv_put; - //! Number of received elements - openfpm::vector<size_t> n_recv_ele; + //! the same as prc_recv_get but for map + openfpm::vector<size_t> prc_recv_map; - //! For each adjacent processor it store the size of the receiving message in byte - openfpm::vector<size_t> recv_sz; + //! It store the size of the elements added for each processor that communicate with us (local processor) + //! from the last ghost get + openfpm::vector<size_t> recv_sz_get; - //! The same as recv_sz but for put + //! The same as recv_sz_get but for put openfpm::vector<size_t> recv_sz_put; - //! For each adjacent processor it store the received message for ghost get - openfpm::vector<BHeapMemory> recv_mem_gg; - - //! For each processor it store the received message for global map - openfpm::vector<BHeapMemory> recv_mem_gm; + //! The same as recv_sz_get but for map + openfpm::vector<size_t> recv_sz_map; //! Local ghost marker (across the ghost particles it mark from where we have the) //! replicated ghost particles that are local size_t lg_m; - /*! \brief It store for each processor the position and properties vector of the particles - * - * This structure is used in the map function - * - */ - struct pos_prop + //! process the particle with properties + struct proc_without_prp { - //! position vector - openfpm::vector<Point<dim, St>, PreAllocHeapMemory<2>, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin, openfpm::grow_policy_identity> pos; - //! properties vector - openfpm::vector<prop, PreAllocHeapMemory<2>, typename memory_traits_lin<prop>::type, memory_traits_lin, openfpm::grow_policy_identity> prp; + template<typename T1, typename T2> inline static void proc(size_t lbl, size_t cnt, size_t id, T1 & v_prp, T2 & m_prp) + { + m_prp.get(lbl).set(cnt, v_prp.get(id)); + } }; - /*! \brief for each processor store 2 vector containing the sending buffers + template<typename prp_object, int ... prp> + struct proc_with_prp + { + template<typename T1, typename T2> inline static void proc(size_t lbl, size_t cnt, size_t id, T1 & v_prp, T2 & m_prp) + { + // source object type + typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src; + // destination object type + typedef encapc<1, prp_object, typename openfpm::vector<prp_object>::layout_type> encap_dst; + + // Copy only the selected properties + object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(id), m_prp.get(lbl).get(cnt)); + } + }; + + //! It process one particle + template<typename proc_class, typename T1, typename T2, typename T3, typename T4> inline void process_map_particle(size_t i, long int & end, long int & id_end, T1 & m_pos, T2 & m_prp, T3 & v_pos, T4 & v_prp, openfpm::vector<size_t> & cnt) + { + long int prc_id = m_opart.template get<2>(i); + size_t id = m_opart.template get<0>(i); + + if (prc_id >= 0) + { + size_t lbl = p_map_req.get(prc_id); + + m_pos.get(lbl).set(cnt.get(lbl), v_pos.get(id)); + proc_class::proc(lbl,cnt.get(lbl),id,v_prp,m_prp); + + cnt.get(lbl)++; + + // swap the particle + long int id_valid = get_end_valid(end,id_end); + + if (id_valid > 0 && (long int)id < id_valid) + { + v_pos.set(id,v_pos.get(id_valid)); + v_prp.set(id,v_prp.get(id_valid)); + } + } + else + { + // swap the particle + long int id_valid = get_end_valid(end,id_end); + + if (id_valid > 0 && (long int)id < id_valid) + { + v_pos.set(id,v_pos.get(id_valid)); + v_prp.set(id,v_prp.get(id_valid)); + } + } + } + + /*! \brief Return a valid particle starting from end and tracing back + * + * \param end actual opart particle pointer + * \param actual end particle point * - * This structure is used in the map_list function + * \return a valid particle * */ - template <typename sel_prop> - struct pos_prop_sel + inline size_t get_end_valid(long int & end, long int & end_id) { - //! position vector - openfpm::vector<Point<dim, St>, PreAllocHeapMemory<2>, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin, openfpm::grow_policy_identity> pos; - //! properties vector - openfpm::vector<sel_prop, PreAllocHeapMemory<2>, typename memory_traits_lin<sel_prop>::type, memory_traits_lin, openfpm::grow_policy_identity> prp; - }; + end_id--; - //! definition of the send vector for position - typedef openfpm::vector<Point<dim, St>, ExtPreAlloc<Memory>, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin , openfpm::grow_policy_identity> send_pos_vector; + while (end >= 0 && end_id >= 0 && (long int)m_opart.template get<0>(end) == end_id) + { + end_id--; + end--; + } + + return end_id; + } //! Flags that indicate that the function createShiftBox() has been called bool is_shift_box_created = false; @@ -191,8 +249,7 @@ class vector_dist_comm // add this particle shifting its position v_pos.add(p); - v_prp.add(); - v_prp.last() = v_prp.get(key); + v_prp.get(lg_m+i) = v_prp.get(key); } } @@ -309,7 +366,8 @@ class vector_dist_comm // Create the shift boxes createShiftBox(); - lg_m = v_prp.size(); + if (!(opt & SKIP_LABELLING)) + lg_m = v_prp.size(); if (box_f.size() == 0) return; @@ -329,29 +387,26 @@ class vector_dist_comm * \param prAlloc_pos Memory object for the send buffer * */ - void fill_send_ghost_pos_buf(openfpm::vector<Point<dim, St>> & v_pos,openfpm::vector<send_pos_vector> & g_pos_send, ExtPreAlloc<Memory> * prAlloc_pos) + void fill_send_ghost_pos_buf(openfpm::vector<Point<dim, St>> & v_pos,openfpm::vector<send_pos_vector> & g_pos_send) { // get the shift vectors const openfpm::vector<Point<dim, St>> & shifts = dec.getShiftVectors(); // create a number of send buffers equal to the near processors - g_pos_send.resize(ghost_prc_sz.size()); + g_pos_send.resize(g_opart.size()); for (size_t i = 0; i < g_pos_send.size(); i++) { - // set the preallocated memory to ensure contiguity - g_pos_send.get(i).setMemory(*prAlloc_pos); - // resize the sending vector (No allocation is produced) - g_pos_send.get(i).resize(ghost_prc_sz.get(i)); + g_pos_send.get(i).resize(g_opart.get(i).size()); } // Fill the send buffer - for (size_t i = 0; i < opart.size(); i++) + for (size_t i = 0; i < g_opart.size(); i++) { - for (size_t j = 0; j < opart.get(i).size(); j++) + for (size_t j = 0; j < g_opart.get(i).size(); j++) { - Point<dim, St> s = v_pos.get(opart.get(i).get(j)); - s -= shifts.get(oshift.get(i).get(j)); + Point<dim, St> s = v_pos.get(g_opart.get(i).template get<0>(j)); + s -= shifts.get(g_opart.get(i).template get<1>(j)); g_pos_send.get(i).set(j, s); } } @@ -369,27 +424,24 @@ class vector_dist_comm * \param g_m ghost marker * */ - template<typename send_vector, typename prp_object, int ... prp> void fill_send_ghost_put_prp_buf(openfpm::vector<prop> & v_prp, openfpm::vector<send_vector> & g_send_prp, ExtPreAlloc<Memory> * prAlloc_prp, size_t & g_m) + template<typename send_vector, typename prp_object, int ... prp> void fill_send_ghost_put_prp_buf(openfpm::vector<prop> & v_prp, openfpm::vector<send_vector> & g_send_prp, size_t & g_m) { // create a number of send buffers equal to the near processors // from which we received - g_send_prp.resize(prc_recv.size()); + g_send_prp.resize(prc_recv_get.size()); for (size_t i = 0; i < g_send_prp.size(); i++) { - // set the preallocated memory to ensure contiguity - g_send_prp.get(i).setMemory(*prAlloc_prp); - // resize the sending vector (No allocation is produced) - g_send_prp.get(i).resize(n_recv_ele.get(i)); + g_send_prp.get(i).resize(recv_sz_get.get(i)); } size_t accum = g_m; // Fill the send buffer - for (size_t i = 0; i < prc_recv.size(); i++) + for (size_t i = 0; i < prc_recv_get.size(); i++) { size_t j2 = 0; - for (size_t j = accum; j < accum + n_recv_ele.get(i); j++) + for (size_t j = accum; j < accum + recv_sz_get.get(i); j++) { // source object type typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src; @@ -402,7 +454,7 @@ class vector_dist_comm j2++; } - accum = accum + n_recv_ele.get(i); + accum = accum + recv_sz_get.get(i); } } @@ -417,23 +469,20 @@ class vector_dist_comm * \param prAlloc_prp Memory object for the send buffer * */ - template<typename send_vector, typename prp_object, int ... prp> void fill_send_ghost_prp_buf(openfpm::vector<prop> & v_prp, openfpm::vector<send_vector> & g_send_prp, ExtPreAlloc<Memory> * prAlloc_prp) + template<typename send_vector, typename prp_object, int ... prp> void fill_send_ghost_prp_buf(openfpm::vector<prop> & v_prp, openfpm::vector<send_vector> & g_send_prp) { // create a number of send buffers equal to the near processors - g_send_prp.resize(ghost_prc_sz.size()); + g_send_prp.resize(g_opart.size()); for (size_t i = 0; i < g_send_prp.size(); i++) { - // set the preallocated memory to ensure contiguity - g_send_prp.get(i).setMemory(*prAlloc_prp); - // resize the sending vector (No allocation is produced) - g_send_prp.get(i).resize(ghost_prc_sz.get(i)); + g_send_prp.get(i).resize(g_opart.get(i).size()); } // Fill the send buffer - for (size_t i = 0; i < opart.size(); i++) + for (size_t i = 0; i < g_opart.size(); i++) { - for (size_t j = 0; j < opart.get(i).size(); j++) + for (size_t j = 0; j < g_opart.get(i).size(); j++) { // source object type typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src; @@ -441,7 +490,7 @@ class vector_dist_comm typedef encapc<1, prp_object, typename openfpm::vector<prp_object>::layout_type> encap_dst; // Copy only the selected properties - object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(opart.get(i).get(j)), g_send_prp.get(i).get(j)); + object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(g_opart.get(i).template get<0>(j)), g_send_prp.get(i).get(j)); } } } @@ -455,49 +504,37 @@ class vector_dist_comm * \param pb send buffer * */ - void fill_send_map_buf(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp,openfpm::vector<size_t> & prc_r, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<pos_prop> & pb) + void fill_send_map_buf(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<openfpm::vector<Point<dim,St>>> & m_pos, openfpm::vector<openfpm::vector<prop>> & m_prp) { - pb.resize(prc_r.size()); + m_prp.resize(prc_sz_r.size()); + m_pos.resize(prc_sz_r.size()); + openfpm::vector<size_t> cnt(prc_sz_r.size()); - for (size_t i = 0; i < prc_r.size(); i++) + for (size_t i = 0; i < prc_sz_r.size() ; i++) { - // Create the size required to store the particles position and properties to communicate - size_t s1 = openfpm::vector<Point<dim, St>, HeapMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin, openfpm::grow_policy_identity>::calculateMem(prc_sz_r.get(i), 0); - size_t s2 = openfpm::vector<prop, HeapMemory, typename memory_traits_lin<prop>::type, memory_traits_lin, openfpm::grow_policy_identity>::calculateMem(prc_sz_r.get(i), 0); - - // Preallocate the memory - size_t sz[2] = { s1, s2 }; - PreAllocHeapMemory<2> * mem = new PreAllocHeapMemory<2>(sz); - - // Set the memory allocator - pb.get(i).pos.setMemory(*mem); - pb.get(i).prp.setMemory(*mem); - // set the size and allocate, using mem warant that pos and prp is contiguous - pb.get(i).pos.resize(prc_sz_r.get(i)); - pb.get(i).prp.resize(prc_sz_r.get(i)); + m_pos.get(i).resize(prc_sz_r.get(i)); + m_prp.get(i).resize(prc_sz_r.get(i)); + cnt.get(i) = 0; } - // Run through all the particles and fill the sending buffer - - for (size_t i = 0; i < opart.size(); i++) - { - auto it = opart.get(i).getIterator(); - size_t lbl = p_map_req.get(i); - - while (it.isNext()) - { - size_t key = it.get(); - size_t id = opart.get(i).get(key); + // end vector point + long int id_end = v_pos.size(); - pb.get(lbl).pos.set(key, v_pos.get(id)); - pb.get(lbl).prp.set(key, v_prp.get(id)); + // end opart point + long int end = m_opart.size()-1; - ++it; - } + // Run through all the particles and fill the sending buffer + for (size_t i = 0; i < m_opart.size(); i++) + { + process_map_particle<proc_without_prp>(i,end,id_end,m_pos,m_prp,v_pos,v_prp,cnt); } + + v_pos.resize(v_pos.size() - m_opart.size()); + v_prp.resize(v_prp.size() - m_opart.size()); } + /*! \brief allocate and fill the send buffer for the map function * * \param v_pos vector of particle positions @@ -507,54 +544,34 @@ class vector_dist_comm * \param pb send buffer * */ - template<typename prp_object,int ... prp> void fill_send_map_buf_list(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc_r, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<pos_prop_sel<prp_object>> & pb) + template<typename prp_object,int ... prp> void fill_send_map_buf_list(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc_sz_r, openfpm::vector<openfpm::vector<Point<dim,St>>> & m_pos, openfpm::vector<openfpm::vector<prp_object>> & m_prp) { - pb.resize(prc_r.size()); + m_prp.resize(prc_sz_r.size()); + m_pos.resize(prc_sz_r.size()); + openfpm::vector<size_t> cnt(prc_sz_r.size()); - for (size_t i = 0; i < prc_r.size(); i++) + for (size_t i = 0; i < prc_sz_r.size(); i++) { - // Create the size required to store the particles position and properties to communicate - size_t s1 = openfpm::vector<Point<dim, St>, HeapMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin, openfpm::grow_policy_identity>::calculateMem(prc_sz_r.get(i), 0); - size_t s2 = openfpm::vector<prp_object, HeapMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin, openfpm::grow_policy_identity>::calculateMem(prc_sz_r.get(i), 0); - - // Preallocate the memory - size_t sz[2] = { s1, s2 }; - PreAllocHeapMemory<2> * mem = new PreAllocHeapMemory<2>(sz); - - // Set the memory allocator - pb.get(i).pos.setMemory(*mem); - pb.get(i).prp.setMemory(*mem); - // set the size and allocate, using mem warant that pos and prp is contiguous - pb.get(i).pos.resize(prc_sz_r.get(i)); - pb.get(i).prp.resize(prc_sz_r.get(i)); + m_pos.get(i).resize(prc_sz_r.get(i)); + m_prp.get(i).resize(prc_sz_r.get(i)); + cnt.get(i) = 0; } - // Run through all the particles and fill the sending buffer + // end vector point + long int id_end = v_pos.size(); - for (size_t i = 0; i < opart.size(); i++) - { - auto it = opart.get(i).getIterator(); - size_t lbl = p_map_req.get(i); - - while (it.isNext()) - { - size_t key = it.get(); - size_t id = opart.get(i).get(key); - - pb.get(lbl).pos.set(key, v_pos.get(id)); - - // source object type - typedef encapc<1, prop, typename openfpm::vector<prop>::layout_type> encap_src; - // destination object type - typedef encapc<1, prp_object, typename openfpm::vector<prp_object>::layout_type> encap_dst; - - // Copy only the selected properties - object_si_d<encap_src, encap_dst, OBJ_ENCAP, prp...>(v_prp.get(id), pb.get(lbl).prp.get(key)); + // end opart point + long int end = m_opart.size()-1; - ++it; - } + // Run through all the particles and fill the sending buffer + for (size_t i = 0; i < m_opart.size(); i++) + { + process_map_particle<proc_with_prp<prp_object,prp...>>(i,end,id_end,m_pos,m_prp,v_pos,v_prp,cnt); } + + v_pos.resize(v_pos.size() - m_opart.size()); + v_prp.resize(v_prp.size() - m_opart.size()); } /*! \brief Label particles for mappings @@ -565,12 +582,10 @@ class vector_dist_comm * \param opart id of the particles to send * */ - template<typename obp> void labelParticleProcessor(openfpm::vector<Point<dim, St>> & v_pos,openfpm::vector<openfpm::vector<size_t>> & lbl_p, openfpm::vector<size_t> & prc_sz, openfpm::vector<size_t> & opart) + template<typename obp> void labelParticleProcessor(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<aggregate<size_t,size_t,size_t>> & lbl_p, openfpm::vector<size_t> & prc_sz) { // reset lbl_p - lbl_p.resize(v_cl.getProcessingUnits()); - for (size_t i = 0; i < lbl_p.size(); i++) - lbl_p.get(i).clear(); + lbl_p.clear(); // resize the label buffer prc_sz.resize(v_cl.getProcessingUnits()); @@ -599,12 +614,15 @@ class vector_dist_comm if ((long int) p_id != -1) { prc_sz.get(p_id)++; - lbl_p.get(p_id).add(key); - opart.add(key); + lbl_p.add(); + lbl_p.last().template get<0>() = key; + lbl_p.last().template get<2>() = p_id; } else { - opart.add(key); + lbl_p.add(); + lbl_p.last().template get<0>() = key; + lbl_p.last().template get<2>() = p_id; } } @@ -614,297 +632,6 @@ class vector_dist_comm } } - /*! \brief This function process the received data for the properties and populate the ghost - * - * \tparam send_vector type used to send data - * \tparam prp_object object containing only the properties to send - * \tparam prp set of properties to send - * - * \param v_prp vector of particle properties - * \param g_m ghost marker - * - */ - template<typename send_vector, typename prp_object, int ... prp> void process_received_ghost_prp(openfpm::vector<prop> & v_prp, size_t & g_m) - { - n_recv_ele.resize(recv_mem_gg.size()); - - // Mark the ghost part - g_m = v_prp.size(); - - // Process the received data (recv_mem_gg != 0 if you have data) - for (size_t i = 0; i < dec.getNNProcessors() && recv_mem_gg.size() != 0; i++) - { - // calculate the number of received elements - size_t n_ele = recv_sz.get(i) / sizeof(prp_object); - - // add the received particles to the vector - PtrMemory * ptr1 = new PtrMemory(recv_mem_gg.get(i).getPointer(), recv_sz.get(i)); - - // create vector representation to a piece of memory already allocated - openfpm::vector<prp_object, PtrMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin , openfpm::grow_policy_identity> v2; - - v2.setMemory(*ptr1); - - // resize with the number of elements and store the number - // or received elements - v2.resize(n_ele); - n_recv_ele.get(i) = n_ele; - - // Add the ghost particle - v_prp.template add_prp<prp_object, PtrMemory, openfpm::grow_policy_identity, prp...>(v2); - } - } - - - /*! \brief This function process the received data from ghost put - * - * \tparam op operation to do - * \tparam send_vector type used to send data - * \tparam prp_object object containing only the properties to send - * \tparam prp set of properties to send - * - * \param v_prp vector of particle properties - * \param g_m ghost marker - * - */ - template<template<typename,typename> class op, typename send_vector, typename prp_object, int ... prp> void process_received_put_ghost_prp(openfpm::vector<prop> & v_prp, size_t g_m) - { - // Process the received data (recv_mem_gg != 0 if you have data) - for (size_t i = 0; i < recv_sz_put.size(); i++) - { - // calculate the number of received elements - size_t n_ele = recv_sz_put.get(i) / sizeof(prp_object); - - // add the received particles to the vector - PtrMemory * ptr1 = new PtrMemory(recv_mem_gg.get(i).getPointer(), recv_sz_put.get(i)); - - // create vector representation to a piece of memory already allocated - openfpm::vector<prp_object, PtrMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin , openfpm::grow_policy_identity> v2; - - v2.setMemory(*ptr1); - - // resize with the number of elements - v2.resize(n_ele); - - // Add the ghost particle - v_prp.template merge_prp<op,prp_object, PtrMemory, openfpm::grow_policy_identity, prp...>(v2,opart.get(i)); - } - - // process also the local replicated particles - - size_t i2 = 0; - -#ifdef SE_CLASS1 - - if (v_prp.size() - lg_m != o_part_loc.size()) - std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " v_prp.size() - lg_m = " << v_prp.size() - lg_m << " != " << o_part_loc.size() << std::endl; - -#endif - - for (size_t i = lg_m ; i < v_prp.size() ; i++) - { - auto dst = v_prp.get(o_part_loc.template get<0>(i2)); - auto src = v_prp.get(i); - copy_cpu_encap_encap_op_prp<op,decltype(v_prp.get(0)),decltype(v_prp.get(0)),prp...> cp(src,dst); - - boost::mpl::for_each_ref< boost::mpl::range_c<int,0,sizeof...(prp)> >(cp); - - i2++; - } - } - - /*! \brief This function process the received data for the properties and populate the ghost - * - * \param v_pos vector of particle positions - * - */ - void process_received_ghost_pos(openfpm::vector<Point<dim, St>> & v_pos) - { - // Process the received data (recv_mem_gg != 0 if you have data) - for (size_t i = 0; i < dec.getNNProcessors() && recv_mem_gg.size() != 0; i++) - { - // calculate the number of received elements - size_t n_ele = recv_sz.get(i) / sizeof(Point<dim, St> ); - - // add the received particles to the vector - PtrMemory * ptr1 = new PtrMemory(recv_mem_gg.get(i).getPointer(), recv_sz.get(i)); - - // create vector representation to a piece of memory already allocated - - openfpm::vector<Point<dim, St>, PtrMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin , openfpm::grow_policy_identity> v2; - - v2.setMemory(*ptr1); - - // resize with the number of elements - v2.resize(n_ele); - - // Add the ghost particle - v_pos.template add<PtrMemory, openfpm::grow_policy_identity>(v2); - } - } - - /*! \brief Process the received particles - * - * \param v_pos vector of particle positions - * \param v_prp vector of particle properties - * \param out_part list of the out-going particles - * - */ - void process_received_map(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp,openfpm::vector<size_t> & out_part) - { - size_t o_p_id = 0; - - for (size_t i = 0; i < recv_mem_gm.size(); i++) - { - // Get the number of elements - - size_t n_ele = recv_mem_gm.get(i).size() / (sizeof(Point<dim, St> ) + sizeof(prop)); - - // Pointer of the received positions for each near processor - void * ptr_pos = (unsigned char *) recv_mem_gm.get(i).getPointer(); - // Pointer of the received properties for each near processor - void * ptr_prp = (unsigned char *) recv_mem_gm.get(i).getPointer() + n_ele * sizeof(Point<dim, St> ); - - PtrMemory * ptr1 = new PtrMemory(ptr_pos, n_ele * sizeof(Point<dim, St> )); - PtrMemory * ptr2 = new PtrMemory(ptr_prp, n_ele * sizeof(prop)); - - // create vector representation to a piece of memory already allocated - - openfpm::vector<Point<dim, St>, PtrMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin ,openfpm::grow_policy_identity> vpos; - openfpm::vector<prop, PtrMemory, typename memory_traits_lin<prop>::type, memory_traits_lin ,openfpm::grow_policy_identity> vprp; - - vpos.setMemory(*ptr1); - vprp.setMemory(*ptr2); - - vpos.resize(n_ele); - vprp.resize(n_ele); - - // Add the received particles to v_pos and v_prp - - size_t j = 0; - for (; j < vpos.size() && o_p_id < out_part.size(); j++, o_p_id++) - { - v_pos.set(out_part.get(o_p_id), vpos.get(j)); - v_prp.set(out_part.get(o_p_id), vprp.get(j)); - } - - for (; j < vpos.size(); j++) - { - v_pos.add(); - v_pos.set(v_pos.size() - 1, vpos.get(j)); - v_prp.add(); - v_prp.set(v_prp.size() - 1, vprp.get(j)); - } - } - - // remove the (out-going particles) in the vector - - v_pos.remove(out_part, o_p_id); - v_prp.remove(out_part, o_p_id); - } - - /*! \brief Process the received particles - * - * \param v_pos vector of particle positions - * \param v_prp vector of particle properties - * \param out_part list of the out-going particles - * - */ - template<typename prp_object , int ... prp> void process_received_map_list(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & out_part) - { - size_t o_p_id = 0; - - for (size_t i = 0; i < recv_mem_gm.size(); i++) - { - // Get the number of elements - - size_t n_ele = recv_mem_gm.get(i).size() / (sizeof(Point<dim, St> ) + sizeof(prp_object)); - - // Pointer of the received positions for each near processor - void * ptr_pos = (unsigned char *) recv_mem_gm.get(i).getPointer(); - // Pointer of the received properties for each near processor - void * ptr_prp = (unsigned char *) recv_mem_gm.get(i).getPointer() + n_ele * sizeof(Point<dim, St> ); - - PtrMemory * ptr1 = new PtrMemory(ptr_pos, n_ele * sizeof(Point<dim, St> )); - PtrMemory * ptr2 = new PtrMemory(ptr_prp, n_ele * sizeof(prp_object)); - - // create vector representation to a piece of memory already allocated - - openfpm::vector<Point<dim, St>, PtrMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin ,openfpm::grow_policy_identity> vpos; - openfpm::vector<prp_object, PtrMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin ,openfpm::grow_policy_identity> vprp; - - vpos.setMemory(*ptr1); - vprp.setMemory(*ptr2); - - vpos.resize(n_ele); - vprp.resize(n_ele); - - // Add the received particles to v_pos and v_prp - - size_t j = 0; - for (; j < vpos.size() && o_p_id < out_part.size(); j++, o_p_id++) - { - v_pos.set(out_part.get(o_p_id), vpos.get(j)); - v_prp.template set_o<decltype(vprp.get(j)), prp... >(out_part.get(o_p_id), vprp.get(j)); - } - - for (; j < vpos.size(); j++) - { - v_pos.add(); - v_pos.set(v_pos.size() - 1, vpos.get(j)); - v_prp.template set_o<decltype(vprp.get(j)), prp... >(v_prp.size() - 1, vprp.get(j)); - } - } - - // remove the (out-going particles) in the vector - - v_pos.remove(out_part, o_p_id); - v_prp.remove(out_part, o_p_id); - } - - /*! \brief Calculate send buffers total size and allocation - * - * \tparam prp_object object containing only the properties to send - * - * \param v_pos vector of particle positions - * \param v_prp vector of particle properties - * \param size_byte_prp total size for the property buffer - * \param size_byte_pos total size for the position buffer - * - */ - template<typename prp_object> void calc_send_ghost_buf(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, size_t & size_byte_prp, size_t & size_byte_pos) - { - // Calculate the total size required for the sending buffer - for (size_t i = 0; i < ghost_prc_sz.size(); i++) - { - size_t alloc_ele = openfpm::vector<prp_object, HeapMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin , openfpm::grow_policy_identity>::calculateMem(ghost_prc_sz.get(i), 0); - size_byte_prp += alloc_ele; - - alloc_ele = openfpm::vector<Point<dim, St>, HeapMemory, typename memory_traits_lin<Point<dim, St>>::type, memory_traits_lin, openfpm::grow_policy_identity>::calculateMem(ghost_prc_sz.get(i), 0); - size_byte_pos += alloc_ele; - } - } - - /*! \brief Calculate send buffers total size and allocation - * - * \tparam prp_object object containing only the properties to send - * - * \param v_pos vector of particle positions - * \param v_prp vector of particle properties - * \param size_byte_prp total size for the property buffer - * \param size_byte_pos total size for the position buffer - * - */ - template<typename prp_object> void calc_send_ghost_put_buf(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, size_t & size_byte_prp, size_t & size_byte_pos) - { - // Calculate the total size required for the sending buffer - for (size_t i = 0; i < recv_sz.size(); i++) - { - size_t alloc_ele = openfpm::vector<prp_object, HeapMemory, typename memory_traits_lin<prp_object>::type, memory_traits_lin , openfpm::grow_policy_identity>::calculateMem(n_recv_ele.get(i), 0); - size_byte_prp += alloc_ele; - } - } - /*! \brief Label the particles * * It count the number of particle to send to each processors and save its ids @@ -916,19 +643,12 @@ class vector_dist_comm * \param g_m ghost marker * */ - void labelParticlesGhost(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, size_t & g_m) + void labelParticlesGhost(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, openfpm::vector<size_t> & prc, size_t & g_m) { - // Buffer that contain the number of elements to send for each processor - ghost_prc_sz.clear(); - ghost_prc_sz.resize(dec.getNNProcessors()); - // Buffer that contain for each processor the id of the particle to send - opart.clear(); - opart.resize(dec.getNNProcessors()); - - // Buffer that contain for each processor the id of the shift vector - oshift.clear(); - oshift.resize(dec.getNNProcessors()); + g_opart.clear(); + g_opart.resize(dec.getNNProcessors()); + prc_g_opart.clear(); // Iterate over all particles auto it = v_pos.getIteratorTo(g_m); @@ -946,77 +666,29 @@ class vector_dist_comm size_t p_id = vp_id.get(i).first; // add particle to communicate - ghost_prc_sz.get(p_id)++; - opart.get(p_id).add(key); - oshift.get(p_id).add(vp_id.get(i).second); + g_opart.get(p_id).add(); + g_opart.get(p_id).last().template get<0>() = key; + g_opart.get(p_id).last().template get<1>() = vp_id.get(i).second; } ++it; } - } - - /*! \brief Call-back to allocate buffer to receive incoming elements (particles) - * - * \param msg_i message size required to receive from i - * \param total_msg message size to receive from all the processors - * \param total_p the total number of processor want to communicate with you - * \param i processor id - * \param ri request id (it is an id that goes from 0 to total_p, and is unique - * every time message_alloc is called) - * \param ptr void pointer parameter for additional data to pass to the call-back - * - */ - static void * msg_alloc_ghost_put(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, void * ptr) - { - vector_dist_comm<dim, St, prop, Decomposition, Memory> * v = static_cast<vector_dist_comm<dim, St, prop, Decomposition, Memory> *>(ptr); - - v->recv_sz_put.resize(v->dec.getNNProcessors()); - v->recv_mem_gg.resize(v->dec.getNNProcessors()); - v->prc_recv_put.resize(v->dec.getNNProcessors()); - - // Get the local processor id - size_t lc_id = v->dec.ProctoID(i); - - // resize the receive buffer - v->recv_mem_gg.get(lc_id).resize(msg_i); - v->recv_sz_put.get(lc_id) = msg_i; - - // save the processor id - v->prc_recv_put.get(lc_id) = i; - - return v->recv_mem_gg.get(lc_id).getPointer(); - } - - /*! \brief Call-back to allocate buffer to receive incoming elements (particles) - * - * \param msg_i message size required to receive from i - * \param total_msg message size to receive from all the processors - * \param total_p the total number of processor want to communicate with you - * \param i processor id - * \param ri request id (it is an id that goes from 0 to total_p, and is unique - * every time message_alloc is called) - * \param ptr void pointer parameter for additional data to pass to the call-back - * - */ - static void * msg_alloc_ghost_get(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, void * ptr) - { - vector_dist_comm<dim, St, prop, Decomposition, Memory> * v = static_cast<vector_dist_comm<dim, St, prop, Decomposition, Memory> *>(ptr); - - v->recv_sz.resize(v->dec.getNNProcessors()); - v->recv_mem_gg.resize(v->dec.getNNProcessors()); - v->prc_recv.resize(v->dec.getNNProcessors()); - - // Get the local processor id - size_t lc_id = v->dec.ProctoID(i); - // resize the receive buffer - v->recv_mem_gg.get(lc_id).resize(msg_i); - v->recv_sz.get(lc_id) = msg_i; + // remove all zero entry and construct prc (the list of the sending processors) + openfpm::vector<openfpm::vector<aggregate<size_t,size_t>>> g_opart_f; - // save the processor id - v->prc_recv.get(lc_id) = i; + // count the non zero element + for (size_t i = 0 ; i < g_opart.size() ; i++) + { + if (g_opart.get(i).size() != 0) + { + g_opart_f.add(); + g_opart.get(i).swap(g_opart_f.last()); + prc.add(dec.IDtoProc(i)); + } + } - return v->recv_mem_gg.get(lc_id).getPointer(); + g_opart.swap(g_opart_f); } /*! \brief Call-back to allocate buffer to receive incoming elements (particles) @@ -1045,13 +717,25 @@ class vector_dist_comm public: + /*! \brief Copy Constructor + * + * \param v vector to copy + * + */ + vector_dist_comm(const vector_dist_comm<dim,St,prop,Decomposition,Memory> & v) + :v_cl(create_vcluster()),dec(create_vcluster()),lg_m(0) + { + this->operator=(v); + } + + /*! \brief Constructor * * \param dec Domain decompositon * */ vector_dist_comm(const Decomposition & dec) - :v_cl(create_vcluster()),dec(dec) + :v_cl(create_vcluster()),dec(dec),lg_m(0) { } @@ -1071,7 +755,7 @@ public: * */ vector_dist_comm() - :v_cl(create_vcluster()),dec(create_vcluster()) + :v_cl(create_vcluster()),dec(create_vcluster()),lg_m(0) { } @@ -1126,68 +810,51 @@ public: template<int ... prp> inline void ghost_get_(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, size_t & g_m, size_t opt = WITH_POSITION) { // Unload receive buffer - for (size_t i = 0 ; i < recv_sz.size() ; i++) - recv_sz.get(i) = 0; + for (size_t i = 0 ; i < recv_sz_get.size() ; i++) + recv_sz_get.get(i) = 0; // Sending property object typedef object<typename object_creator<typename prop::type, prp...>::type> prp_object; // send vector for each processor - typedef openfpm::vector<prp_object, ExtPreAlloc<Memory>, typename memory_traits_lin<prp_object>::type, memory_traits_lin, openfpm::grow_policy_identity> send_vector; + typedef openfpm::vector<prp_object> send_vector; + + if (!(opt & NO_POSITION)) + v_pos.resize(g_m); // reset the ghost part - v_pos.resize(g_m); - v_prp.resize(g_m); + + if (!(opt & SKIP_LABELLING)) + v_prp.resize(g_m); // Label all the particles if ((opt & SKIP_LABELLING) == false) - labelParticlesGhost(v_pos,v_prp,g_m); - - // Calculate memory and allocation for the send buffers - - // Total size - size_t size_byte_prp = 0; - size_t size_byte_pos = 0; - - calc_send_ghost_buf<prp_object>(v_pos,v_prp,size_byte_prp, size_byte_pos); - - // Create memory for the send buffer - - g_prp_mem.resize(size_byte_prp); - if (opt != NO_POSITION) - g_pos_mem.resize(size_byte_pos); - - // Create and fill send buffer for particle properties - - ExtPreAlloc<Memory> * prAlloc_prp = new ExtPreAlloc<Memory>(size_byte_prp, g_prp_mem); + labelParticlesGhost(v_pos,v_prp,prc_g_opart,g_m); + // Send and receive ghost particle information openfpm::vector<send_vector> g_send_prp; - fill_send_ghost_prp_buf<send_vector, prp_object, prp...>(v_prp,g_send_prp, prAlloc_prp); + fill_send_ghost_prp_buf<send_vector, prp_object, prp...>(v_prp,g_send_prp); // Create and fill the send buffer for the particle position + if (!(opt & NO_POSITION)) + fill_send_ghost_pos_buf(v_pos,g_pos_send); + + prc_recv_get.clear(); + recv_sz_get.clear(); - ExtPreAlloc<Memory> * prAlloc_pos; - openfpm::vector<send_pos_vector> g_pos_send; - if (opt != NO_POSITION) + if (opt & SKIP_LABELLING) { - prAlloc_pos = new ExtPreAlloc<Memory>(size_byte_pos, g_pos_mem); - fill_send_ghost_pos_buf(v_pos,g_pos_send, prAlloc_pos); + op_ssend_gg_recv_merge opm(g_m); + v_cl.SSendRecvP_op<op_ssend_gg_recv_merge,send_vector,decltype(v_prp),prp...>(g_send_prp,v_prp,prc_g_opart,opm,prc_recv_get,recv_sz_get); } + else + v_cl.SSendRecvP<send_vector,decltype(v_prp),prp...>(g_send_prp,v_prp,prc_g_opart,prc_recv_get,recv_sz_get); - // Create processor list - openfpm::vector<size_t> prc; - for (size_t i = 0; i < opart.size(); i++) - prc.add(dec.IDtoProc(i)); - - // Send/receive the particle properties information - v_cl.sendrecvMultipleMessagesNBX(prc, g_send_prp, msg_alloc_ghost_get, this); - process_received_ghost_prp<send_vector, prp_object, prp...>(v_prp,g_m); - - if (opt != NO_POSITION) + if (!(opt & NO_POSITION)) { - // Send/receive the particle properties information - v_cl.sendrecvMultipleMessagesNBX(prc, g_pos_send, msg_alloc_ghost_get, this); - process_received_ghost_pos(v_pos); + prc_recv_get.clear(); + recv_sz_get.clear(); + v_cl.SSendRecv(g_pos_send,v_pos,prc_g_opart,prc_recv_get,recv_sz_get); } add_loc_particles_bc(v_pos,v_prp,g_m,opt); @@ -1213,9 +880,6 @@ public: { typedef KillParticle obp; - // outgoing particles-id - openfpm::vector<size_t> out_part; - // Processor communication size openfpm::vector<size_t> prc_sz(v_cl.getProcessingUnits()); @@ -1227,7 +891,7 @@ public: v_prp.resize(g_m); // Contain the processor id of each particle (basically where they have to go) - labelParticleProcessor<obp>(v_pos,opart, prc_sz, out_part); + labelParticleProcessor<obp>(v_pos,m_opart, prc_sz); // Calculate the sending buffer size for each processor, put this information in // a contiguous buffer @@ -1248,34 +912,15 @@ public: // Sending property object typedef object<typename object_creator<typename prop::type, prp...>::type> prp_object; - // Allocate the send buffers - - openfpm::vector<pos_prop_sel<prp_object>> pb; - - // fill the send buffers - fill_send_map_buf_list<prp_object,prp...>(v_pos,v_prp,prc_r, prc_sz_r, pb); - - // Create the set of pointers - openfpm::vector<void *> ptr(prc_r.size()); - for (size_t i = 0; i < prc_r.size(); i++) - { - ptr.get(i) = pb.get(i).pos.getPointer(); - } - - // convert the particle number to buffer size - for (size_t i = 0; i < prc_sz_r.size(); i++) - { - prc_sz_r.get(i) = prc_sz_r.get(i) * (sizeof(prp_object) + sizeof(Point<dim, St> )); - } - - // Send and receive the particles - - recv_mem_gm.clear(); - v_cl.sendrecvMultipleMessagesNBX(prc_sz_r.size(), (size_t *) prc_sz_r.getPointer(), (size_t *) prc_r.getPointer(), (void **) ptr.getPointer(), vector_dist_comm::message_alloc_map, this, NEED_ALL_SIZE); + //! position vector + openfpm::vector<openfpm::vector<Point<dim, St>>> m_pos; + //! properties vector + openfpm::vector<openfpm::vector<prp_object>> m_prp; - // Process the incoming particles + fill_send_map_buf_list<prp_object,prp...>(v_pos,v_prp,prc_sz_r, m_pos, m_prp); - process_received_map_list<prp_object, prp...>(v_pos,v_prp,out_part); + v_cl.SSendRecv(m_pos,v_pos,prc_r,prc_recv_map,recv_sz_map); + v_cl.SSendRecvP<openfpm::vector<prp_object>,decltype(v_prp),prp...>(m_prp,v_prp,prc_r,prc_recv_map,recv_sz_map); // mark the ghost part @@ -1297,9 +942,6 @@ public: */ template<typename obp = KillParticle> void map_(openfpm::vector<Point<dim, St>> & v_pos, openfpm::vector<prop> & v_prp, size_t & g_m) { - // outgoing particles-id - openfpm::vector<size_t> out_part; - // Processor communication size openfpm::vector<size_t> prc_sz(v_cl.getProcessingUnits()); @@ -1311,7 +953,7 @@ public: v_prp.resize(g_m); // Contain the processor id of each particle (basically where they have to go) - labelParticleProcessor<obp>(v_pos,opart, prc_sz, out_part); + labelParticleProcessor<obp>(v_pos,m_opart, prc_sz); // Calculate the sending buffer size for each processor, put this information in // a contiguous buffer @@ -1329,34 +971,15 @@ public: } } - // Allocate the send buffers - - openfpm::vector<pos_prop> pb; - - // fill the send buffers - fill_send_map_buf(v_pos,v_prp,prc_r, prc_sz_r, pb); - - // Create the set of pointers - openfpm::vector<void *> ptr(prc_r.size()); - for (size_t i = 0; i < prc_r.size(); i++) - { - ptr.get(i) = pb.get(i).pos.getPointer(); - } - - // convert the particle number to buffer size - for (size_t i = 0; i < prc_sz_r.size(); i++) - { - prc_sz_r.get(i) = prc_sz_r.get(i) * (sizeof(prop) + sizeof(Point<dim, St> )); - } - - // Send and receive the particles - - recv_mem_gm.clear(); - v_cl.sendrecvMultipleMessagesNBX(prc_sz_r.size(), (size_t *) prc_sz_r.getPointer(), (size_t *) prc_r.getPointer(), (void **) ptr.getPointer(), vector_dist_comm::message_alloc_map, this, NEED_ALL_SIZE); + //! position vector + openfpm::vector<openfpm::vector<Point<dim, St>>> m_pos; + //! properties vector + openfpm::vector<openfpm::vector<prop>> m_prp; - // Process the incoming particles + fill_send_map_buf(v_pos,v_prp, prc_sz_r, m_pos, m_prp); - process_received_map(v_pos,v_prp,out_part); + v_cl.SSendRecv(m_pos,v_pos,prc_r,prc_recv_map,recv_sz_map); + v_cl.SSendRecv(m_prp,v_prp,prc_r,prc_recv_map,recv_sz_map); // mark the ghost part @@ -1373,6 +996,16 @@ public: return dec; } + /*! \brief Get the decomposition + * + * \return + * + */ + inline const Decomposition & getDecomposition() const + { + return dec; + } + /*! \brief Copy a vector * * \param vc vector to copy @@ -1396,7 +1029,7 @@ public: */ vector_dist_comm<dim,St,prop,Decomposition,Memory> & operator=(vector_dist_comm<dim,St,prop,Decomposition,Memory> && vc) { - dec.swap(vc.dec); + dec = vc.dec; return *this; } @@ -1417,30 +1050,36 @@ public: typedef object<typename object_creator<typename prop::type, prp...>::type> prp_object; // send vector for each processor - typedef openfpm::vector<prp_object, ExtPreAlloc<Memory>, typename memory_traits_lin<prp_object>::type, memory_traits_lin, openfpm::grow_policy_identity> send_vector; + typedef openfpm::vector<prp_object> send_vector; - // Calculate memory and allocation for the send buffers + openfpm::vector<send_vector> g_send_prp; + fill_send_ghost_put_prp_buf<send_vector, prp_object, prp...>(v_prp,g_send_prp,g_m); - // Total size - size_t size_byte_prp = 0; - size_t size_byte_pos = 0; + // Send and receive ghost particle information + op_ssend_recv_merge<op> opm(g_opart); + v_cl.SSendRecvP_op<op_ssend_recv_merge<op>,send_vector,decltype(v_prp),prp...>(g_send_prp,v_prp,prc_recv_get,opm,prc_recv_put,recv_sz_put); - calc_send_ghost_put_buf<prp_object>(v_pos,v_prp,size_byte_prp, size_byte_pos); + // process also the local replicated particles - // Create memory for the send buffer + size_t i2 = 0; - g_prp_mem.resize(size_byte_prp); - // Create and fill send buffer for particle properties + if (lg_m < v_prp.size() && v_prp.size() - lg_m != o_part_loc.size()) + { + std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " Local ghost particles = " << v_prp.size() - lg_m << " != " << o_part_loc.size() << std::endl; + std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " Check that you did a ghost_get before a ghost_put" << std::endl; + } - ExtPreAlloc<Memory> * prAlloc_prp = new ExtPreAlloc<Memory>(size_byte_prp, g_prp_mem); - openfpm::vector<send_vector> g_send_prp; - fill_send_ghost_put_prp_buf<send_vector, prp_object, prp...>(v_prp,g_send_prp, prAlloc_prp,g_m); + for (size_t i = lg_m ; i < v_prp.size() ; i++) + { + auto dst = v_prp.get(o_part_loc.template get<0>(i2)); + auto src = v_prp.get(i); + copy_cpu_encap_encap_op_prp<op,decltype(v_prp.get(0)),decltype(v_prp.get(0)),prp...> cp(src,dst); - // Send/receive the particle properties information - v_cl.sendrecvMultipleMessagesNBX(prc_recv, g_send_prp, msg_alloc_ghost_put, this); - process_received_put_ghost_prp<op,send_vector, prp_object, prp...>(v_prp,g_m); + boost::mpl::for_each_ref< boost::mpl::range_c<int,0,sizeof...(prp)> >(cp); + i2++; + } } }; diff --git a/src/Vector/vector_dist_complex_prp_unit_test.hpp b/src/Vector/vector_dist_complex_prp_unit_test.hpp new file mode 100644 index 0000000000000000000000000000000000000000..253259a8557d0c5dc697eb9448e8e8a03f24fea0 --- /dev/null +++ b/src/Vector/vector_dist_complex_prp_unit_test.hpp @@ -0,0 +1,231 @@ +/* + * vector_dist_complex_prp_unit_test.hpp + * + * Created on: Sep 18, 2016 + * Author: i-bird + */ + +#ifndef SRC_VECTOR_VECTOR_DIST_COMPLEX_PRP_UNIT_TEST_HPP_ +#define SRC_VECTOR_VECTOR_DIST_COMPLEX_PRP_UNIT_TEST_HPP_ + + +BOOST_AUTO_TEST_CASE( vector_dist_periodic_complex_prp_test_use_3d ) +{ + Vcluster & v_cl = create_vcluster(); + + if (v_cl.getProcessingUnits() > 48) + return; + + // set the seed + // create the random generator engine + std::srand(v_cl.getProcessUnitID()); + std::default_random_engine eg; + std::uniform_real_distribution<float> ud(0.0f, 1.0f); + + long int k = 124288 * v_cl.getProcessingUnits(); + + long int big_step = k / 4; + big_step = (big_step == 0)?1:big_step; + + print_test_v( "Testing 3D vector full complex prp vector k<=",k); + + // 3D test + for ( ; k >= 2 ; k-= decrement(k,big_step) ) + { + BOOST_TEST_CHECKPOINT( "Testing 3D full complex prp vector k=" << k ); + + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + + // Boundary conditions + size_t bc[3]={NON_PERIODIC,NON_PERIODIC,NON_PERIODIC}; + + // factor + float factor = pow(create_vcluster().getProcessingUnits()/2.0f,1.0f/3.0f); + + // ghost + Ghost<3,float> ghost(0.05 / factor); + + // ghost2 (a little bigger because of round off error) + Ghost<3,float> ghost2(0.05001 / factor); + + // Distributed vector + vector_dist<3,float, aggregate<openfpm::vector<float>,grid_cpu<3,aggregate<double,double[3]>> > > vd(k,box,bc,ghost); + + auto it = vd.getIterator(); + + while (it.isNext()) + { + auto key = it.get(); + + vd.getPos(key)[0] = ud(eg); + vd.getPos(key)[1] = ud(eg); + vd.getPos(key)[2] = ud(eg); + + // initalize vector property and grid + + vd.template getProp<0>(key).add(vd.getPos(key)[0]); + vd.template getProp<0>(key).add(vd.getPos(key)[1]); + vd.template getProp<0>(key).add(vd.getPos(key)[2]); + + vd.template getProp<0>(key).add(vd.getPos(key)[0]+vd.getPos(key)[1]); + vd.template getProp<0>(key).add(vd.getPos(key)[1]+vd.getPos(key)[2]); + vd.template getProp<0>(key).add(vd.getPos(key)[0]+vd.getPos(key)[2]); + + // Grid + size_t sz[] = {3,3,3}; + vd.template getProp<1>(key).resize(sz); + + vd.template getProp<1>(key).template get<0>({0,0,0}) = vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({0,0,1}) = vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({0,0,2}) = vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({0,1,0}) = 2.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({0,1,1}) = 2.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({0,1,2}) = 2.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({0,2,0}) = 3.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({0,2,1}) = 3.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({0,2,2}) = 3.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({1,0,0}) = 4.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({1,0,1}) = 4.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({1,0,2}) = 4.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({1,1,0}) = 5.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({1,1,1}) = 5.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({1,1,2}) = 5.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({1,2,0}) = 6.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({1,2,1}) = 6.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({1,2,2}) = 6.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({2,0,0}) = 7.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({2,0,1}) = 7.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({2,0,2}) = 7.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({2,1,0}) = 8.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({2,1,1}) = 8.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({2,1,2}) = 8.0*vd.getPos(key)[2]; + + vd.template getProp<1>(key).template get<0>({2,2,0}) = 9.0*vd.getPos(key)[0]; + vd.template getProp<1>(key).template get<0>({2,2,1}) = 9.0*vd.getPos(key)[1]; + vd.template getProp<1>(key).template get<0>({2,2,2}) = 9.0*vd.getPos(key)[2]; + + ++it; + } + + vd.map(); + + // sync the ghost + vd.ghost_get<0,1>(); + + // Domain + ghost + Box<3,float> dom_ext = box; + dom_ext.enlarge(ghost2); + + // Iterate on all particles domain + ghost + size_t l_cnt = 0; + size_t nl_cnt = 0; + size_t n_out = 0; + + auto it2 = vd.getIterator(); + count_local_n_local<3,vector_dist<3,float, aggregate<openfpm::vector<float>,grid_cpu<3,aggregate<double,double[3]>>>> >(vd,it2,bc,box,dom_ext,l_cnt,nl_cnt,n_out); + + // No particles should be out of domain + ghost + BOOST_REQUIRE_EQUAL(n_out,0ul); + + // Ghost must populated because we synchronized them + if (k > 524288) + { + BOOST_REQUIRE(nl_cnt != 0); + BOOST_REQUIRE(l_cnt > nl_cnt); + } + + // Sum all the particles inside the domain + v_cl.sum(l_cnt); + v_cl.execute(); + BOOST_REQUIRE_EQUAL(l_cnt,(size_t)k); + + l_cnt = 0; + nl_cnt = 0; + + // Iterate only on the ghost particles + auto itg = vd.getGhostIterator(); + count_local_n_local<3, vector_dist<3,float, aggregate<openfpm::vector<float>,grid_cpu<3,aggregate<double,double[3]>>>> >(vd,itg,bc,box,dom_ext,l_cnt,nl_cnt,n_out); + + // No particle on the ghost must be inside the domain + BOOST_REQUIRE_EQUAL(l_cnt,0ul); + + // Ghost must be populated + if (k > 524288) + { + BOOST_REQUIRE(nl_cnt != 0); + } + + // check that the particles contain the correct information + + bool ret = true; + auto it3 = vd.getDomainAndGhostIterator(); + + while (it3.isNext()) + { + auto key = it3.get(); + + ret &= vd.template getProp<0>(key).size() == 6; + + ret &= vd.template getProp<0>(key).get(0) == vd.getPos(key)[0]; + ret &= vd.template getProp<0>(key).get(1) == vd.getPos(key)[1]; + ret &= vd.template getProp<0>(key).get(2) == vd.getPos(key)[2]; + + ret &= vd.template getProp<0>(key).get(3) == vd.getPos(key)[0]+vd.getPos(key)[1]; + ret &= vd.template getProp<0>(key).get(4) == vd.getPos(key)[1]+vd.getPos(key)[2]; + ret &= vd.template getProp<0>(key).get(5) == vd.getPos(key)[0]+vd.getPos(key)[2]; + +// BOOST_REQUIRE_EQUAL(vd.template getProp<0>(key).get(0),vd.getPos(key)[0]); + + ret &= vd.template getProp<1>(key).size() == 3*3*3; + ret &= vd.template getProp<1>(key).template get<0>({0,0,0}) == vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({0,0,1}) == vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({0,0,2}) == vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({0,1,0}) == 2.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({0,1,1}) == 2.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({0,1,2}) == 2.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({0,2,0}) == 3.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({0,2,1}) == 3.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({0,2,2}) == 3.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({1,0,0}) == 4.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({1,0,1}) == 4.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({1,0,2}) == 4.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({1,1,0}) == 5.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({1,1,1}) == 5.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({1,1,2}) == 5.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({1,2,0}) == 6.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({1,2,1}) == 6.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({1,2,2}) == 6.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({2,0,0}) == 7.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({2,0,1}) == 7.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({2,0,2}) == 7.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({2,1,0}) == 8.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({2,1,1}) == 8.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({2,1,2}) == 8.0*vd.getPos(key)[2]; + + ret &= vd.template getProp<1>(key).template get<0>({2,2,0}) == 9.0*vd.getPos(key)[0]; + ret &= vd.template getProp<1>(key).template get<0>({2,2,1}) == 9.0*vd.getPos(key)[1]; + ret &= vd.template getProp<1>(key).template get<0>({2,2,2}) == 9.0*vd.getPos(key)[2]; + + ++it3; + } + + BOOST_REQUIRE_EQUAL(ret,true); + } +} + + +#endif /* SRC_VECTOR_VECTOR_DIST_COMPLEX_PRP_UNIT_TEST_HPP_ */ diff --git a/src/Vector/vector_dist_multiphase_functions.hpp b/src/Vector/vector_dist_multiphase_functions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a3c6e32bd51a19a6d4fddb68b1f75d398401963 --- /dev/null +++ b/src/Vector/vector_dist_multiphase_functions.hpp @@ -0,0 +1,126 @@ +/* + * vector_dist_multiphase_functions.hpp + * + * Created on: Oct 14, 2016 + * Author: i-bird + */ + +#ifndef SRC_VECTOR_VECTOR_DIST_MULTIPHASE_FUNCTIONS_HPP_ +#define SRC_VECTOR_VECTOR_DIST_MULTIPHASE_FUNCTIONS_HPP_ + +#include "NN/CellList/CellListM.hpp" +#include "NN/VerletList/VerletListM.hpp" + +template<typename Vector,typename CL, typename T> VerletList<Vector::dims,typename Vector::stype,FAST,shift<Vector::dims,typename Vector::stype>> createVerlet(Vector & v, CL & cl, T r_cut) +{ + VerletList<Vector::dims,typename Vector::stype,FAST,shift<Vector::dims,typename Vector::stype>> ver; + + ver.Initialize(cl,r_cut,v.getPosVector(),v.size_local()); + + return ver; +} + +template<unsigned int sh_byte, typename Vector,typename CL, typename T> VerletListM<Vector::dims,typename Vector::stype,sh_byte,shift<Vector::dims,typename Vector::stype>> createVerletM(Vector & v, CL & cl, T r_cut) +{ + VerletListM<Vector::dims,typename Vector::stype,sh_byte,shift<Vector::dims,typename Vector::stype>> ver; + + ver.Initialize(cl,r_cut,v.getPosVector(),v.size_local()); + + return ver; +} + +template<unsigned int nbit, typename Vector, typename T> CellListM<Vector::dims,typename Vector::stype,nbit> createCellListM(openfpm::vector<Vector> & phases, T r_cut) +{ + size_t div[3]; + Box<Vector::dims,typename Vector::stype> box_cl; + + CellListM<Vector::dims,typename Vector::stype,nbit> NN; + if (phases.size() == 0) + return NN; + + box_cl = phases.get(0).getDecomposition().getProcessorBounds(); + phases.get(0).getCellListParams(r_cut,div,box_cl); + + NN.Initialize(box_cl,div); + + // for all the phases i + for (size_t i = 0; i < phases.size() ; i++) + { + // iterate across all the particle of the phase i + auto it = phases.get(i).getDomainAndGhostIterator(); + while (it.isNext()) + { + auto key = it.get(); + + // Add the particle of the phase i to the cell list + NN.add(phases.get(i).getPos(key), key.getKey(), i); + + ++it; + } + } + + return NN; +} + + +/////// Symmetric version + +template<typename Vector,typename CL, typename T> VerletList<Vector::dims,typename Vector::stype,FAST,shift<Vector::dims,typename Vector::stype>> createVerletSym(Vector & v, CL & cl, T r_cut) +{ + VerletList<Vector::dims,typename Vector::stype,FAST,shift<Vector::dims,typename Vector::stype>> ver; + + ver.Initialize(cl,r_cut,v.getPosVector(),v.size_local()); + + return ver; +} + +template<unsigned int sh_byte, typename Vector,typename CL, typename T> VerletListM<Vector::dims,typename Vector::stype,sh_byte,shift<Vector::dims,typename Vector::stype>> createVerletSymM(Vector & v, CL & cl, T r_cut) +{ + VerletListM<Vector::dims,typename Vector::stype,sh_byte,shift<Vector::dims,typename Vector::stype>> ver; + + ver.Initialize(cl,r_cut,v.getPosVector(),v.size_local(),VL_SYMMETRIC); + + return ver; +} + +template<unsigned int nbit, typename Vector, typename T> CellListM<Vector::dims,typename Vector::stype,nbit> createCellListSymM(openfpm::vector<Vector> & phases, T r_cut) +{ + Box<Vector::dims,typename Vector::stype> box_cl; + + CellListM<Vector::dims,typename Vector::stype,nbit> NN; + if (phases.size() == 0) + return NN; + + // Calculate the Cell list division for this CellList + CellDecomposer_sm<Vector::dims,typename Vector::stype,shift<Vector::dims,typename Vector::stype>> cd_sm; + + size_t pad = 0; + cl_param_calculateSym(phases.get(0).getDecomposition().getDomain(),cd_sm,phases.get(0).getDecomposition().getGhost(),r_cut,pad); + + // Processor bounding box + Box<Vector::dims, typename Vector::stype> pbox = phases.get(0).getDecomposition().getProcessorBounds(); + + // Ghost padding extension + Ghost<Vector::dims,size_t> g_ext(0); + NN.Initialize(cd_sm,pbox,pad); + + // for all the phases i + for (size_t i = 0; i < phases.size() ; i++) + { + // iterate across all the particle of the phase i + auto it = phases.get(i).getDomainAndGhostIterator(); + while (it.isNext()) + { + auto key = it.get(); + + // Add the particle of the phase i to the cell list + NN.add(phases.get(i).getPos(key), key.getKey(), i); + + ++it; + } + } + + return NN; +} + +#endif /* SRC_VECTOR_VECTOR_DIST_MULTIPHASE_FUNCTIONS_HPP_ */ diff --git a/src/Vector/vector_dist_unit_test.hpp b/src/Vector/vector_dist_unit_test.hpp index bcec71e3006c4291adb7578bceff9a24353b2d4a..89b67b77e7f873ca2164bd05718cbdcea11773df 100644 --- a/src/Vector/vector_dist_unit_test.hpp +++ b/src/Vector/vector_dist_unit_test.hpp @@ -180,9 +180,14 @@ void Test2D_ghost(Box<2,float> & box) //! [Redistribute the particles and sync the ghost properties] + vd.write("debug_before"); + // redistribute the particles according to the decomposition vd.map(); + vd.write("debug_after"); + vd.getDecomposition().write("debug_decomposition"); + auto v_it2 = vd.getIterator(); while (v_it2.isNext()) @@ -1234,8 +1239,6 @@ BOOST_AUTO_TEST_CASE( vector_dist_cell_verlet_test ) vd.ghost_get<0>(); - vd.write("Debug_output"); - // calculate the distance of the first, second and third neighborhood particle // Consider that they are on a regular grid @@ -1432,12 +1435,12 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); // Boundary conditions - size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + size_t bc[3]={NON_PERIODIC,NON_PERIODIC,NON_PERIODIC}; // ghost Ghost<3,float> ghost(0.1); - typedef aggregate<float> part_prop; + typedef aggregate<float,float,float> part_prop; // Distributed vector vector_dist<3,float, part_prop > vd(k,box,bc,ghost); @@ -1455,6 +1458,8 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) // Fill some properties randomly vd.getProp<0>(key) = 0.0; + vd.getProp<1>(key) = vd.getPos(key)[0]; + vd.getProp<2>(key) = vd.getPos(key)[0]*vd.getPos(key)[0]; ++it; } @@ -1462,22 +1467,21 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) vd.map(); // sync the ghost - vd.ghost_get<0>(); + vd.ghost_get<0,1,2>(); - openfpm::vector<size_t> list_idx; - openfpm::vector<size_t> list_idx2; - - auto it3 = vd.getGhostIterator(); - while (it3.isNext()) + bool ret = true; + auto it2 = vd.getGhostIterator(); + while (it2.isNext()) { - auto key = it3.get(); + auto key = it2.get(); - list_idx.add(key.getKey()); + ret &= vd.getProp<1>(key) == vd.getPos(key)[0]; + ret &= vd.getProp<2>(key) == vd.getPos(key)[0] * vd.getPos(key)[0]; - ++it3; + ++it2; } - list_idx.sort(); + BOOST_REQUIRE_EQUAL(ret,true); for (size_t i = 0 ; i < 10 ; i++) { @@ -1487,7 +1491,6 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) { auto key = it.get(); - vd.getPos(key)[0] = ud(eg); vd.getPos(key)[1] = ud(eg); vd.getPos(key)[2] = ud(eg); @@ -1500,7 +1503,6 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) vd.ghost_get<0>(SKIP_LABELLING); - list_idx2.clear(); auto it2 = vd.getGhostIterator(); bool ret = true; @@ -1508,40 +1510,36 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) { auto key = it2.get(); - list_idx2.add(key.getKey()); ret &= vd.getProp<0>(key) == i; + ret &= vd.getProp<1>(key) == vd.getPos(key)[0]; + ret &= vd.getProp<2>(key) == vd.getPos(key)[0] * vd.getPos(key)[0]; ++it2; } - BOOST_REQUIRE_EQUAL(ret,true); - BOOST_REQUIRE_EQUAL(list_idx.size(),list_idx2.size()); - - list_idx2.sort(); - - ret = true; - for (size_t i = 0 ; i < list_idx.size() ; i++) - ret &= list_idx.get(i) == list_idx2.get(i); - BOOST_REQUIRE_EQUAL(ret,true); } vd.map(); - vd.ghost_get<0>(); + vd.ghost_get<0,1,2>(); - list_idx.clear(); + // shift the particle position by 1.0 - auto it4 = vd.getGhostIterator(); - while (it4.isNext()) + it = vd.getGhostIterator(); + while (it.isNext()) { - auto key = it4.get(); + // Particle p + auto p = it.get(); - list_idx.add(key.getKey()); + // we shift down he particles + vd.getPos(p)[0] = 10.0; - ++it4; - } + // we shift + vd.getPos(p)[1] = 17.0; - list_idx.sort(); + // next particle + ++it; + } for (size_t i = 0 ; i < 10 ; i++) { @@ -1551,42 +1549,37 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_with_ghost_buffering ) { auto key = it.get(); - vd.getPos(key)[0] = ud(eg); vd.getPos(key)[1] = ud(eg); vd.getPos(key)[2] = ud(eg); // Fill some properties randomly vd.getProp<0>(key) = i; + vd.getProp<1>(key) = vd.getPos(key)[0]; + vd.getProp<2>(key) = vd.getPos(key)[0]*vd.getPos(key)[0]; ++it; } - vd.ghost_get<0>(SKIP_LABELLING); + vd.ghost_get<0>(SKIP_LABELLING | NO_POSITION); - list_idx2.clear(); auto it2 = vd.getGhostIterator(); bool ret = true; while (it2.isNext()) { - auto key = it2.get(); + // Particle p + auto p = it.get(); - list_idx2.add(key.getKey()); - ret &= vd.getProp<0>(key) == i; + ret &= vd.getPos(p)[0] == 10.0; + // we shift + ret &= vd.getPos(p)[1] == 17.0; + + // next particle ++it2; } - BOOST_REQUIRE_EQUAL(ret,true); - BOOST_REQUIRE_EQUAL(list_idx.size(),list_idx2.size()); - - list_idx2.sort(); - - ret = true; - for (size_t i = 0 ; i < list_idx.size() ; i++) - ret &= list_idx.get(i) == list_idx2.get(i); - BOOST_REQUIRE_EQUAL(ret,true); } } @@ -1613,13 +1606,16 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) // 3D test for ( ; k >= 2 ; k-= (k > 2*big_step)?big_step:small_step ) { + float r_cut = 1.3 / k; + float r_g = 1.5 / k; + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); // Boundary conditions size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; // ghost - Ghost<3,float> ghost(1.3/(k)); + Ghost<3,float> ghost(r_g); typedef aggregate<float> part_prop; @@ -1651,7 +1647,7 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) vd.ghost_get<0>(); { - auto NN = vd.getCellList(1.3/k); + auto NN = vd.getCellList(r_cut); float a = 1.0f*k*k; // run trough all the particles + ghost @@ -1675,8 +1671,8 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) float dist = xp.distance(xq); - if (dist < 1.0/k) - vd.getProp<0>(q) += a*(-dist*dist+1.0/k/k); + if (dist < r_cut) + vd.getProp<0>(q) += a*(-dist*dist+r_cut*r_cut); ++Np; } @@ -1707,8 +1703,18 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) BOOST_REQUIRE_EQUAL(ret,true); } + auto itp = vd.getDomainAndGhostIterator(); + while (itp.isNext()) + { + auto key = itp.get(); + + vd.getProp<0>(key) = 0.0; + + ++itp; + } + { - auto NN = vd.getCellList(1.3/k); + auto NN = vd.getCellList(r_cut); float a = 1.0f*k*k; // run trough all the particles + ghost @@ -1732,8 +1738,8 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) float dist = xp.distance(xq); - if (dist < 1.0/k) - vd.getProp<0>(q) += a*(-dist*dist+1.0/k/k); + if (dist < r_cut) + vd.getProp<0>(q) += a*(-dist*dist+r_cut*r_cut); ++Np; } @@ -1766,8 +1772,56 @@ BOOST_AUTO_TEST_CASE( vector_dist_ghost_put ) } } +BOOST_AUTO_TEST_CASE( vector_of_vector_dist ) +{ + Vcluster & v_cl = create_vcluster(); + + if (v_cl.getProcessingUnits() > 48) + return; + + // Boundary conditions + size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; + + // Box + Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); + + // ghost + Ghost<3,float> ghost(0.1); + + openfpm::vector< vector_dist<3,float, aggregate<double,double>> > phases; + + // first phase + phases.add( vector_dist<3,float, aggregate<double,double>>(4096,box,bc,ghost) ); + + // The other 3 phases + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + phases.add( vector_dist<3,float, aggregate<double,double>>(phases.get(0).getDecomposition(),4096) ); + + phases.get(0).map(); + phases.get(0).ghost_get<>(); + phases.get(1).map(); + phases.get(1).ghost_get<>(); + phases.get(2).map(); + phases.get(2).ghost_get<>(); + phases.get(3).map(); + phases.get(3).ghost_get<>(); + + size_t cnt = 0; + + for (size_t i = 0 ; i < phases.size() ; i++) + cnt += phases.get(i).size_local(); + + v_cl.sum(cnt); + v_cl.execute(); + + BOOST_REQUIRE_EQUAL(cnt,4*4096ul); +} + + #include "vector_dist_cell_list_tests.hpp" #include "vector_dist_NN_tests.hpp" +#include "vector_dist_complex_prp_unit_test.hpp" BOOST_AUTO_TEST_SUITE_END() diff --git a/src/debug.hpp b/src/debug.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d550941bfda0f57d0ba31de964b2c3671604e4bd --- /dev/null +++ b/src/debug.hpp @@ -0,0 +1,36 @@ +/* + * debug.hpp + * + * Created on: Oct 7, 2016 + * Author: i-bird + */ + +#ifndef SRC_DEBUG_HPP_ +#define SRC_DEBUG_HPP_ + +#include "Vector/map_vector.hpp" +#include "Space/Shape/Point.hpp" + +Point<3,float> getPosPoint3f(openfpm::vector<Point<3,float>> & pos, size_t i) +{ + return Point<3,float>(pos.get(i)); +} + +Point<3,double> getPosPoint3d(openfpm::vector<Point<3,double>> & pos, size_t i) +{ + return Point<3,double>(pos.get(i)); +} + +Point<2,float> getPosPoint2f(openfpm::vector<Point<2,float>> & pos, size_t i) +{ + return Point<2,float>(pos.get(i)); +} + +Point<2,double> getPosPoint2d(openfpm::vector<Point<2,double>> & pos, size_t i) +{ + return Point<2,double>(pos.get(i)); +} + + + +#endif /* SRC_DEBUG_HPP_ */ diff --git a/src/main.cpp b/src/main.cpp index 38a88d937269940f14d9282b2a8c655dda788382..c60b455f760aa5c64e8c240c5e273acc34046d6e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ int main(int argc, char* argv[]) return boost::unit_test::unit_test_main( &init_unit_test, argc, argv ); } +#include "debug.hpp" #include "Grid/grid_dist_id.hpp" #include "Point_test.hpp" #include "Decomposition/CartDecomposition.hpp" @@ -48,4 +49,5 @@ int main(int argc, char* argv[]) #include "Graph/DistGraphFactory.hpp" #include "Decomposition/nn_processor_unit_test.hpp" #include "Grid/staggered_grid_dist_unit_test.hpp" +#include "Vector/vector_dist_MP_unit_tests.hpp" //#include "antoniol_test_isolation.hpp" diff --git a/success.sh b/success.sh new file mode 100755 index 0000000000000000000000000000000000000000..abb68fea7dd668b0041f35c8387d1e84bcdfe8f9 --- /dev/null +++ b/success.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +if [ $1 -eq 1 ]; then + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Info:\", \"color\": \"#00FF00\", \"text\":\"$2 completed succeffuly the $3 tests with $4\" }] }" https://hooks.slack.com/services/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 +else + curl -X POST --data "payload={\"icon_emoji\": \":jenkins:\", \"username\": \"jenkins\" , \"attachments\":[{ \"title\":\"Info:\", \"color\": \"#00FF00\", \"text\":\"$2 completed succeffuly the $3 tests \" }] }" https://hooks.slack.com/services/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 +fi + +