diff --git a/.cproject b/.cproject new file mode 100644 index 00000000000..6133cfedb98 --- /dev/null +++ b/.cproject @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + -k -j12 + check + false + true + true + + + make + -k -j12 + check processors="4" + false + true + true + + + make + -k -j12 + clean + false + true + true + + + make + -k -j12 + distcheck + false + true + true + + + make + -k -j12 + distclean + false + true + false + + + make + -k -j12 + doc + false + true + true + + + make + -k -j12 + all + false + true + true + + + make + -k + all + false + false + true + + + + diff --git a/.gitignore b/.gitignore index 3cb0dae5cbc..b83a7281b30 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ tools/es_mpiexec src/libEspresso.a Espresso Espresso.install +build.eclipse # Espresso output *.end diff --git a/.project b/.project new file mode 100644 index 00000000000..67e6cff74df --- /dev/null +++ b/.project @@ -0,0 +1,55 @@ + + + ESPResSo + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/net.sourceforge.texlipse.builder.TexlipseBuilder.launch + + + + + org.python.pydev.PyDevBuilder + + + + + + net.sourceforge.texlipse.builder.TexlipseNature + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.python.pydev.pythonNature + + + + 1401874441371 + + 30 + + org.eclipse.ui.ide.multiFilter + 1.0-projectRelativePath-matches-false-false-build.eclipse/espresso-* + + + + diff --git a/.settings/org.eclipse.cdt.codan.core.prefs b/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 00000000000..77386c23cbe --- /dev/null +++ b/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,67 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} diff --git a/.settings/org.eclipse.cdt.ui.prefs b/.settings/org.eclipse.cdt.ui.prefs new file mode 100644 index 00000000000..4ee12a4ba78 --- /dev/null +++ b/.settings/org.eclipse.cdt.ui.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +formatter_settings_version=1 diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 00000000000..11bfbcd5d3a --- /dev/null +++ b/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,3 @@ +content-types/enabled=true +content-types/org.eclipse.cdt.core.cxxSource/file-extensions=cu +eclipse.preferences.version=1 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..223535f9492 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,36 @@ +language: cpp + +before_install: + - sudo apt-get update + - sudo apt-get install tcl-dev #cython python-numpy + - if [ "$with_mpi" != false ]; then sudo apt-get install libopenmpi-dev openmpi-bin; fi + - if [ "$with_fftw" != false ]; then sudo apt-get install libfftw3-dev; fi + +env: + - myconfig=default + - myconfig=maxset + - myconfig=molcut + - myconfig=rest1 + - myconfig=rest2 + - make_check=false myconfig=nocheck-maxset + - with_fftw=false with_mpi=false myconfig=maxset + +compiler: + - gcc + +matrix: + include: + - compiler: clang + env: with-mpi=false myconfig=default + - compiler: clang + env: with-mpi=false myconfig=maxset + - compiler: clang + env: with-mpi=false myconfig=molcut + - compiler: clang + env: with-mpi=false myconfig=rest1 + - compiler: clang + env: with-mpi=false myconfig=rest2 + - compiler: clang + env: with-mpi=false make_check=false myconfig=nocheck-maxset + +script: ./maintainer/travis/build.sh diff --git a/AUTHORS b/AUTHORS index a53315a6b7c..27a9eff8cb1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -12,6 +12,7 @@ Core developers --------------- Axel Arnold Olaf Lenz (maintainer) +Florian Weik Stefan Kesselheim Bernward Mann (deceased 2006) @@ -26,44 +27,61 @@ Alexander Schlaich Arjit Maitra Ben Reynwar (formerly: Reynolds) Christoph Schneider +David Schwörer Dmitro Galperin Dmytro Antypov Dominic Röhm +Elena Minina Florian Fahrenberger (formerly: Rühle) -Florian Weik Florian Häußermann Francesca Lugli Frank Mühlbach Georg Rempfer Gizem Inci Gregoria Illya -Igor Pasichny +Hamid Zaheri +Henri Menke +Igor Pasichnyk Ira Cooke +Ivan Cimrak +Iveta Jancigova Joan Josep Cerdà Jon Halverson +Joost de Graaf +Josh Berryman Kai Grass Kai Kratzer +Kai Szuttor Karen Johnston Konrad Breitsprecher +Lukas Fischer Marcello Sega +Markus Gusenbauer Matej Praprotnik Mehmet Sayar Mehmet Süzen +Michael Kuron Mingyang Hu Muhammad Anwar Nils Binz -Owen Hickey +Owen A. Hickey-Moriarty +Patrick Diggins +Pedro Ojeda Pedro Sanchez Peter Kosovan +Pierre de Buyl Rudolf Weeber Sandeep Tyagi Sathish K. Sukumaran Sela Samin Shervin Raafatnia Simon Poblete +Stephan Gekle +Stefan Medina Thomas Spura Timo Schürg Tobias Richter +Tobias Steinle Tristan Bereau Ulf Schiller Vagelis Harmandaris @@ -75,3 +93,4 @@ Special thanks -------------- Special thanks to Henrik Skov Midtiby for providing a GPL version of todonotes.sty. + diff --git a/INSTALL b/INSTALL index 16345a68700..36fe7af876f 100644 --- a/INSTALL +++ b/INSTALL @@ -43,7 +43,7 @@ without any warranty. LICENSE ------- -Copyright (C) 2010,2011,2012,2013 The ESPResSo project +Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/Makefile.am b/Makefile.am index 0e49a19b2ad..b169b0bf629 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. @@ -16,7 +16,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -SUBDIRS = config src . scripts tools testsuite doc +DIST_SUBDIRS = config src . scripts tools testsuite doc +SUBDIRS = config src . +if TCL +SUBDIRS += scripts +endif +SUBDIRS += tools testsuite doc ACLOCAL_AMFLAGS = -I config AUTOMAKE_OPTIONS = gnu subdir-objects dist-xz @@ -25,21 +30,36 @@ AUTOMAKE_OPTIONS = gnu subdir-objects dist-xz # by any other means EXTRA_DIST = bootstrap.sh samples packages $(extra) +CLEANFILES = + +if TCL all-local: Espresso -CLEANFILES = Espresso +CLEANFILES += Espresso if !DEVEL_SRC Espresso: FORCE - test -e Espresso || $(LN_S) src/Espresso . + test -L Espresso || $(LN_S) src/tcl/Espresso . else Espresso: version.txt - test -e Espresso || $(LN_S) src/Espresso . + test -L Espresso || $(LN_S) src/tcl/Espresso . +endif +endif + +if PYTHON_INTERFACE +all-local: espresso-python pypresso +espresso-python: FORCE + test -L espressomd || $(LN_S) src/python/espressomd espressomd +pypresso: FORCE + test -L pypresso || $(LN_S) src/python/pypresso pypresso + +CLEANFILES += pypresso espresso endif # Sample myconfig generation -myconfig-sample.hpp: +myconfig-sample.hpp: ./config.status myconfig-sample.hpp -CLEANFILES += myconfig-sample.hpp +DISTCLEANFILES = myconfig-sample.hpp + # config.status deps in configure.ac # Handle version @@ -79,7 +99,6 @@ else endif doc doxygen: FORCE - cd src; $(MAKE) --print-directory $@ cd doc; $(MAKE) --print-directory $@ FORCE: diff --git a/NEWS b/NEWS index 210d930d9f4..35c5d052029 100644 --- a/NEWS +++ b/NEWS @@ -2,40 +2,133 @@ = ESPRESSO NEWS = ================= +ESPResSo 3.4 +============ + +New user-visible features +------------------------- + +* New quartic bonded interaction +* New bonded coulomb interaction +* Lees Edwards boundaries for sheer stuff + +Known bugs +---------- + +User-visible changes +-------------------- + +Changes visible for developers +------------------------------ + + ESPResSo 3.3 ============ New user-visible features ------------------------- +* SHANCHEN: a bicomponent lattice Boltzmann fluid, with support for rigid + boundaries and coupling to particle dynamics. + +* ELECTROKINETICS: An algorithm to treat species of ions on a mean-field + level. Implementation takes advantage of a GPU. + +* MMM1D_GPU: The mmm1d electrostatics algorithm is now available as GPU version. + * Support of P3M on GPU. +* Provide the preliminary Python interface. Configure with + --with-python-interface. + * Allow the p3m to dump the mesh in x, y, and z (before it only dumped -the mesh in x). This allows for the dumping of the p3m in blockfile -format in the case of non-cubic boxes. It will also now be possible to -tune the settings of a non-cubic mesh. + the mesh in x). This allows for the dumping of the p3m in blockfile + format in the case of non-cubic boxes. It will also now be possible + to tune the settings of a non-cubic mesh. * Stomatocyte lb-boundary and constraint implemented. * MEMD electrostatics can now handle spatially varying dielectrc constants. -* New command time_integration to get the runtime of the integration loop. +* Pore constraint / lbboundary can have a two outer radii now to create nozzles. + +* Slitpore constraint and dielectric for IL based supercaps implemented. + +* New command time_integration to get the runtime of the integration + loop. + +* New harmonic well that runs on the GPU. + +Known bugs +---------- + +* The implementation of dielectric contrasts in conjunction with ELC + seems to have an error. Please do not use it if you do not know + exactly what you are doing until we have fixe the problem. User-visible changes -------------------- -* Generic LJ can now turned into an soft potential. +* Added new arguments "recalc_forces" and "reuse_forces" to the + command "integrate". These arguments can be used to enforce or + suppress the recalculation of the forces at the beginning of the + call to "integrate". This is important for doing checkpoints, where + the forces have to be stored and reloaded. + +* Removed command "invalidate_system". + +* Comfixed now works with periodic boundary conditions. + +* The pressure contribution due to rigid bodies constructed by means of the + virtual sites relative mechanism is included, both for pressure and stress + tensor. Note that the corresponding contribution for rigid bonds is still + not implemented. + +* The configure option "--with-myconfig" has been removed. Instead, + the configure variable "MYCONFIG" can be set to give the name of a + myconfig file. + +* Generic LJ can now be turned into a soft potential. * Renamed torque to torque_{lab,body}, improved torque handling in blockfiles. Clearer distinction between the reference frames for torque and angular momentum. +* Lattice-Boltzmann now has a additional 3-point coupling scheme. + +* The noise type in thermalized Lattice-Boltzmann is now selectable via Tcl. + +* Interaction with a wall can be restricted to the outside. + +* Removed compiler switch GRANDCANONICAL. + +* Removed outdated ADRESS code. + +* external_potential tabulated to include arbitrary potentials applied to all + particles. + +* thermostat inter_dpd ignore_fixed_particles 1 allows the user to swith on DPD + with fixed particles. + +* New Observable concept that includes running averages and other observables + with history + + Changes visible for developers ------------------------------ +* Feature GHOSTS_HAVE_BONDS allows for ghost particles to also store the bonds. + * The code has been switched to using a C++ compiler. +* Introduced object-oriented interfaces for forces/constraints/external fields: + SystemInterface and Actor. + +* Improved Lattice structure + +* Generic TclAppend function + ESPResSo 3.2 ============ @@ -150,7 +243,6 @@ New user-visible features * Added new feature LANGEVIN_PER_PARTICLE that allows to set the Langevin parameters temperature and gamma per particle. - * Added new constraint and LB boundary condition "rhomboid". * Lattice-Boltzmann: @@ -403,7 +495,7 @@ Changes visible for developers For older changes to ESPResSo, see ./old/RELEASE_NOTES. ======================================================================== -Copyright (C) 2010,2011,2012,2013 The ESPResSo project +Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright diff --git a/README b/README index ab45508b28c..a6b10fe715b 100644 --- a/README +++ b/README @@ -181,7 +181,7 @@ testsuite/thermostat.data testsuite/thermostat_rot.data testsuite/uwerr.data -"Copyright (C) 2010,2011,2012,2013 The ESPResSo project +"Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/Readme.md b/Readme.md new file mode 100644 index 00000000000..9a9f7b05397 --- /dev/null +++ b/Readme.md @@ -0,0 +1,212 @@ +# ESPResSo + +This is the Molecular Dynamics software ESPResSo ("Extensible +Simulation Package for the Research on Soft Matter Systems"). + +ESPResSo is a highly versatile software package for performing and +analyzing scientific Molecular Dynamics many-particle simulations of +"coarse-grained" bead-spring models as they are used in soft-matter +research in physics, chemistry and molecular biology. It can be used +to simulate systems as for example polymers, liquid crystals, +colloids, ferrofluids and biological systems such as DNA and lipid +membranes. + +In "coarse-grained" models, a whole group of atoms or molecules are +treated as a single bead. Although many details are coarse-grained +away in these models, they can often predict qualitative properties, +such as for example the scaling behavior of a system, and can give +insight into theoretical models. Due to the drastic reduction of +degrees of freedom, coarse-graining allows to investigate systems +which would be out of reach of the commonly used atom-based +simulations, due to the large time- and length scales of the studied +processes. + +ESPResSo is capable of doing classical Molecular dynamics simulations +of many types of systems in different statistical ensembles (NVE, NVT, +NPT) and non-equilibrium situations, using standard potentials such as +the Lennard-Jones or Morse potential. It contains many advanced +simulation algorithms, which take into account hydrodynamic (lattice +Boltzmann) and electrostatic interactions (P3M, ELC, MMMxD). Rigid +bodies can be modelled by virtual site interactions, and it can +integrate rotationally non-invariant particles. + +ESPResSo is free, open-source software (GPL). It is parallelized and +can be employed on desktop machines, convenience clusters as well as +on supercomputers with hundreds of CPUs. The parallel code is +controlled via the scripting language Tcl, which gives the software +its great flexibility and allows for many unconventional simulation +protocols, as are often required when studying coarse-grained models. + +ESPResSo is used in scientific working groups all over the world both +as a production platform as well as a research platform for developing +new algorithms and methods and designing new models for coarse-grained +simulations. It is mainly developed at the Institute for +Computational Physics of the University of Stuttgart, but has +contributors from all over the world. + + +## Documentation + +You can find documentation on how to compile, use and develop ESPResSo +on the homepage at [http://espressomd.org](http://espressomd.org). + +ESPResSo is intended to be used by people that have proper knowledge +of simulation techniques and know how to use them. We do not take +responsibility if you use ESPResSo to create and publish bogus +results. You have been warned! + +## PLEASE CITE US! + +If you use ESPResSo and obtain scientific results that you publish, we +would ask you to acknowledge the usage of ESPResSo by referencing + + Hans-Jörg Limbach, Axel Arnold, Bernward A. Mann and Christian + Holm. + "ESPResSo - An Extensible Simulation Package for Research on + Soft Matter Systems". + Comput. Phys. Commun. 174(9) (704-727), 2006. + +For a BibTeX record, please refer to the key "espresso" in +doc/ug/citations.bib. + +A number of algorithms in ESPResSo are fairly advanced and unique to +ESPResSo. The authors of these contributions kindly ask you to cite the +relevant publications, as indicated in the ESPResSo User's Guide +(see http://espressomd.org or doc/ug/ug.pdf). For your convenience, the +BibTeX records are compiled in doc/ug/citations.bib. + +## Licence + +The following files are licensed and copyrighted as indicated below: + +``` +doc/dg/figs/bond_angle.fig +doc/dg/figs/datastorage.gif +doc/dg/figs/dihedral_angle.fig +doc/dg/figs/directions.fig +doc/dg/figs/elc_errordist.gif +doc/dg/figs/ghost_cells.fig +doc/dg/figs/ghost_communication.fig +doc/dg/figs/linked_cells.fig +doc/dg/figs/logo.png +doc/dg/figs/move_to_p_buf.fig +doc/dg/figs/particles.fig +doc/ug/figures/diamond.png +doc/ug/figures/dihedral-angle.fig +doc/ug/figures/dihedral-angle.pdf +doc/ug/figures/fullerene.png +doc/ug/figures/hbond.fig +doc/ug/figures/hbond.pdf +doc/ug/figures/logo.png +doc/ug/figures/maggs-charge-assignment.pdf +doc/ug/figures/maggs-initial-scheme.pdf +doc/ug/figures/maggs-rotation.pdf +doc/ug/figures/nacl-rdf.pdf +doc/ug/figures/salt.png +doc/tutorials/tut2/figures/data/neutral-rho.data +doc/tutorials/tut2/figures/data/nonneutral-rho.data +doc/tutorials/tut2/figures/data/rdf_from_melt_00.data +doc/tutorials/tut2/figures/data/rdf_from_melt_10.data +doc/tutorials/tut2/figures/data/rdf_from_melt_11.data +doc/tutorials/tut2/figures/data/rdf_lj_00.data +doc/tutorials/tut2/figures/nacl-rdf.pdf +doc/tutorials/tut2/figures/nacl.plot +doc/tutorials/tut2/figures/neutral-rho.pdf +doc/tutorials/tut2/figures/nonneutral-rho.pdf +doc/tutorials/tut2/figures/salt.png +packages/mbtools/doc/colloid_model.jpg +packages/mbtools/doc/cylinder_membrane.jpg +packages/mbtools/doc/flat_membrane.jpg +packages/mbtools/doc/protein_model.jpg +packages/mbtools/doc/sphere_membrane.jpg +packages/mbtools/doc/torus_membrane.jpg +packages/mbtools/doc/wrapped_colloid_densitymap.jpg +packages/mbtools/examples/forcetables/9_095_11.tab +packages/mbtools/examples/forcetables/n9_c140_22.tab +packages/mbtools/examples/forcetables/n9_c160_22.tab +packages/mbtools/examples/forcetables/sr_e10_c25.tab +samples/adress/bond_tetra.tab +samples/adress/cg_ic_tetra.tab +samples/adress/cg_tetra.tab +samples/adress/thermo_force.tab +samples/maggs_correct_rdf.dat +samples/object-in-fluid/object-in-fluidUG/figures/arealocal.eps +samples/object-in-fluid/object-in-fluidUG/figures/bending.eps +samples/object-in-fluid/object-in-fluidUG/figures/bloodCell.eps +samples/object-in-fluid/object-in-fluidUG/figures/stretching.eps +samples/object-in-fluid/object-in-fluidUG/figures/volume.eps +testsuite/analysis_system.data.00.gz +testsuite/analysis_system.data.01.gz +testsuite/analysis_system.data.02.gz +testsuite/analysis_system.data.03.gz +testsuite/analysis_system.data.04.gz +testsuite/analysis_system.data.05.gz +testsuite/analysis_system.data.06.gz +testsuite/analysis_system.data.07.gz +testsuite/analysis_system.data.08.gz +testsuite/analysis_system.data.09.gz +testsuite/analysis_system.data.10.gz +testsuite/analysis_system.data.chk +testsuite/angle_cosine.data +testsuite/angle_cossquare.data +testsuite/angle_harmonic.data +testsuite/comfixed_system.data +testsuite/comforce_system.data +testsuite/constraints_system.data +testsuite/dh_system.data +testsuite/el2d_system.data +testsuite/el2d_system_die.data +testsuite/gb_system.data +testsuite/lb_system.data +testsuite/lj-cos_system.data +testsuite/lj_system.data +testsuite/maggs_correct_rdf.data +testsuite/mass_system.data +testsuite/mdlc_expected_energy.data +testsuite/mdlc_expected_force_torque.data +testsuite/mdlc_system.data +testsuite/mmm1d_system.data +testsuite/npt_lj_system.data +testsuite/object_in_fluid_system-final.data +testsuite/object_in_fluid_system-init.data +testsuite/object_in_fluid_system-nodes.data +testsuite/object_in_fluid_system-triangles.data +testsuite/p3m_magnetostatics2_expected.data +testsuite/p3m_magnetostatics2_system.data +testsuite/p3m_magnetostatics.data +testsuite/p3m_system.data +testsuite/p3m_wall_system.data +testsuite/pe_micelle.data +testsuite/tabulated_system.data +testsuite/thermostat.data +testsuite/thermostat_rot.data +testsuite/uwerr.data +``` + +> "Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project +> Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 +> Max-Planck-Institute for Polymer Research, Theory Group +> +> This file is part of ESPResSo. +> +> ESPResSo is free software: you can redistribute it and/or modify it +> under the terms of the GNU General Public License as published by the +> Free Software Foundation, either version 3 of the License, or (at your +> option) any later version. +> +> ESPResSo is distributed in the hope that it will be useful, but +> WITHOUT ANY WARRANTY; without even the implied warranty of +> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +> General Public License for more details. +> +> You should have received a copy of the GNU General Public License +> along with this program. If not, see ." + +This file is licensed as follows: + +> Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project +> +> Copying and distribution of this file, with or without modification, +> are permitted in any medium without royalty provided the copyright +> notice and this notice are preserved. This file is offered as-is, +>without any warranty. diff --git a/config/Espresso.m4 b/config/Espresso.m4 index 50847711207..5aaeeb4b9ae 100644 --- a/config/Espresso.m4 +++ b/config/Espresso.m4 @@ -1,5 +1,5 @@ dnl -*- mode: autoconf -*- -dnl Copyright (C) 2010,2011,2012,2013 The ESPResSo project +dnl Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project dnl Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 dnl Max-Planck-Institute for Polymer Research, Theory Group dnl @@ -56,7 +56,7 @@ AC_DEFUN([ES_ADDPATH_CHECK_HEADER],[ ])],[es_adp_found=yes],[]) if test .$es_adp_found = .no; then - for path in $4 /sw/include /usr/include /usr/local/include /opt/include; do + for path in $4 /sw/include /opt/local/include /usr/include /usr/local/include /opt/include; do CPPFLAGS="$es_save_CPPFLAGS -I$path" AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include <$1> diff --git a/config/Makefile.am b/config/Makefile.am index 89a9d83c45d..f32e4604c60 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # @@ -16,8 +16,5 @@ # along with this program. If not, see . # EXTRA_DIST = \ - gen_featureconfig.py \ - gen_doxyconfig.py \ gen_sampleconfig.py \ - featuredefs.py \ genversion.sh diff --git a/config/ax_count_cpus.m4 b/config/ax_count_cpus.m4 index d4f3d290f4f..2bcbdf84cf0 100644 --- a/config/ax_count_cpus.m4 +++ b/config/ax_count_cpus.m4 @@ -15,6 +15,7 @@ # # LICENSE # +# Copyright (C) 2014 The ESPResSo project # Copyright (c) 2012 Brian Aker # Copyright (c) 2008 Michael Paul Bailey # Copyright (c) 2008 Christophe Tournayre diff --git a/config/ax_cxx_var_prettyfunc.m4 b/config/ax_cxx_var_prettyfunc.m4 new file mode 100644 index 00000000000..9afc52594dc --- /dev/null +++ b/config/ax_cxx_var_prettyfunc.m4 @@ -0,0 +1,92 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_var_prettyfunc.html +# =========================================================================== +# +# SYNPOSIS +# +# AX_CXX_VAR_PRETTYFUNC +# +# DESCRIPTION +# +# This function tries to determine the best C++ macro/identifier +# that contains the current function name. Depending on the +# compiler, this may be __PRETTY_FUNCTION__ (GCC), __FUNCSIG__ +# (MSVC), __func__ (C++ standard), __FUNCTION__ (fallback). +# +# The function will define HAVE_PRETTYFUNC if a macro exists, +# and define __PRETTYFUNC__ to the best possible macro. When +# HAVE_PRETTYFUNC is not defined, __PRETTYFUNC__ will contain the +# constant string "<>". +# +# LICENSE +# +# Copyright (c) 2014 Olaf Lenz +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 1 + +AC_DEFUN([AX_CXX_VAR_PRETTYFUNC], +[ +# try to find best __FUNCTION__ variant + +AC_CACHE_CHECK([whether $CXX can get a pretty function name], ac_cv_cxx_var_prettyfunc, + ac_cv_cxx_var_prettyfunc=no + + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(,[const char *s = __PRETTY_FUNCTION__])], + [ ac_cv_cxx_var_prettyfunc=__PRETTY_FUNCTION__ ]) + + AS_IF([test "x$ac_cv_cxx_var_prettyfunc" = "xno"], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(,[const char *s = __FUNCSIG__])], + [ ac_cv_cxx_var_prettyfunc=__FUNCSIG__ ]) + ]) + + AS_IF([test "x$ac_cv_cxx_var_prettyfunc" = "xno"], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(,[const char *s = __func__])], + [ ac_cv_cxx_var_prettyfunc=__func__ ]) + ]) + + AS_IF([test "x$ac_cv_cxx_var_prettyfunc" = "xno"], [ + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(,[const char *s = __FUNCTION__])], + [ ac_cv_cxx_var_prettyfunc=__FUNCTION__ ]) + ]) +) + + +AS_IF([test "x$ac_cv_cxx_var_prettyfunc" != "xno"], [ + AC_DEFINE(HAVE_PRETTYFUNC,, [Whether __PRETTY_FUNCTION__ has a useful value.]) + AC_DEFINE_UNQUOTED(__PRETTYFUNC__,$ac_cv_cxx_var_prettyfunc, + [contains the function wherein the macro is called]) +],[ + AC_DEFINE(__PRETTYFUNC__,"<>") +]) + +])dnl diff --git a/config/ax_prog_cc_mpi.m4 b/config/ax_prog_cc_mpi.m4 deleted file mode 100644 index a1c22a1bd8f..00000000000 --- a/config/ax_prog_cc_mpi.m4 +++ /dev/null @@ -1,141 +0,0 @@ -dnl -*- mode: autoconf -*- -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_mpi.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_CC_MPI([MPI-WANTED-TEST[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]]) -# -# DESCRIPTION -# -# This macro tries to find out how to compile C programs that use MPI -# (Message Passing Interface), a standard API for parallel process -# communication (see http://www-unix.mcs.anl.gov/mpi/). -# The macro has to be used instead of the standard macro AC_PROG_CC -# and will replace the standard variable CC with the found compiler. -# -# MPI-WANTED-TEST is used to test whether MPI is actually wanted by -# the user. If the test fails, the macro will not try to find MPI -# and call AC_MPI_CC instead. If the test is omitted, the macro will -# try to found MPI and fail if it is not found. -# -# When MPI is found, ACTION-IF-FOUND will be executed, otherwise -# ACTION-IF-NOT-FOUND is executed. If ACTION-IF-FOUND is not set, -# the macro will define HAVE_MPI. -# -# EXAMPLE -# -# # If --with-mpi=auto is used, try to find MPI, but use standard C -# compiler if it is not found. -# # If --with-mpi=yes is used, try to find MPI and fail if it isn't -# # found. -# # If --with-mpi=no is used, use a standard C compiler instead. -# AC_ARG_WITH(mpi, [AS_HELP_STRING([--with-mpi], -# [compile with MPI (parallelization) support. If none is found, -# MPI is not used. Default: auto]) -# ],,[with_mpi=auto]) -# -# AX_PROG_CC_MPI([test x"$with_mpi" != xno],[use_mpi=yes],[ -# use_mpi=no -# if test x"$with_mpi" = xyes; then -# AC_MSG_FAILURE([MPI compiler requested, but couldn't use MPI.]) -# else -# AC_MSG_WARN([No MPI compiler found, won't use MPI.]) -# fi -# ]) -# -# LICENSE -# -# Copyright (C) 2012,2013 The ESPResSo project -# Copyright (c) 2010,2011 Olaf Lenz -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 1 - -AC_DEFUN([AX_PROG_CC_MPI], [ -AC_PREREQ(2.50) dnl for AC_LANG_CASE - -# Check for compiler -# Needs to be split off into an extra macro to ensure right expansion -# order. -AC_REQUIRE([_AX_PROG_CC_MPI],[_AX_PROG_CC_MPI([$1])]) - -AS_IF([test x"$_ax_prog_mpicc_mpi_wanted" = xno], - [ ax_prog_mpicc_mpi_found=no ], - [ - # test whether MPI_Init is available in a library - AC_SEARCH_LIBS(MPI_Init, [mpi mpich], - [ ax_prog_mpicc_mpi_found=yes ], - [ ax_prog_mpicc_mpi_found=no ]) - - # Check for header - AS_IF([test x"$ax_only_mpi_found" = xyes], [ - AC_MSG_CHECKING([for mpi.h]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ])], - [ AC_MSG_RESULT(yes)], - [ AC_MSG_RESULT(no) - ax_prog_mpicc_mpi_found=no - ]) - ]) -]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -AS_IF([test x"$ax_prog_mpicc_mpi_found" = xyes], [ - ifelse([$2],,[AC_DEFINE(HAVE_MPI,1,[Define if you have the MPI library.])],[$2]) - : -],[ - $3 - : -]) - -])dnl AX_PROG_CC_MPI - -dnl _AX_PROG_CC_MPI is an internal macro required by AX_PROG_CC_MPI. -dnl To ensure the right expansion order, the main function AX_PROG_CC_MPI -dnl has to be split into two parts. -AC_DEFUN([_AX_PROG_CC_MPI], [ - AC_ARG_VAR(MPICC,[MPI C compiler command]) - ifelse([$1],,[_ax_prog_mpicc_mpi_wanted=yes],[ - AC_MSG_CHECKING([whether to compile using MPI]) - if $1; then - _ax_prog_mpicc_mpi_wanted=yes - else - _ax_prog_mpicc_mpi_wanted=no - fi - AC_MSG_RESULT($_ax_prog_mpicc_mpi_wanted) - ]) - if test x"$_ax_prog_mpicc_mpi_wanted" = xyes; then - if test -z "$CC" && test -n "$MPICC"; then - CC="$MPICC" - else - AC_CHECK_TOOLS([CC], [mpicc hcc mpxlc_r mpxlc mpcc cmpicc]) - fi - fi - AC_PROG_CC -])dnl _AX_PROG_CC_MPI diff --git a/config/ax_prog_cxx_mpi.m4 b/config/ax_prog_cxx_mpi.m4 index a0053abf43f..28c982bef04 100644 --- a/config/ax_prog_cxx_mpi.m4 +++ b/config/ax_prog_cxx_mpi.m4 @@ -44,6 +44,7 @@ # # LICENSE # +# Copyright (C) 2014 The ESPResSo project # Copyright (c) 2010,2011 Olaf Lenz # # This program is free software: you can redistribute it and/or modify it @@ -72,7 +73,7 @@ # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. -#serial 1 +#serial 2 AC_DEFUN([AX_PROG_CXX_MPI], [ AC_PREREQ(2.50) @@ -87,24 +88,22 @@ AS_IF([test x"$_ax_prog_cxx_mpi_mpi_wanted" = xno], [ AC_LANG_PUSH([C++]) - # test whether MPI::Init is available + # test whether MPI_Init() is available # We do not use AC_SEARCH_LIBS here, as it caches its outcome and # thus disallows corresponding calls in the other AX_PROG_*_MPI # macros. for lib in NONE mpi mpich; do save_LIBS=$LIBS if test x"$lib" = xNONE; then - AC_MSG_CHECKING([for function MPI::Init]) + AC_MSG_CHECKING([for function MPI_Init]) else - AC_MSG_CHECKING([for function MPI::Init in -l$lib]) + AC_MSG_CHECKING([for function MPI_Init in -l$lib]) LIBS="-l$lib $LIBS" fi AC_LINK_IFELSE([ AC_LANG_PROGRAM([ -namespace MPI { -char Init(); -}; -using MPI::Init;],[MPI::Init;])], +extern "C" { void MPI_Init(); } +],[MPI_Init();])], [ _ax_prog_cxx_mpi_mpi_found=yes ], [ _ax_prog_cxx_mpi_mpi_found=no ]) AC_MSG_RESULT($_ax_prog_cxx_mpi_mpi_found) diff --git a/config/ax_python_devel.m4 b/config/ax_python_devel.m4 new file mode 100644 index 00000000000..1dae176e890 --- /dev/null +++ b/config/ax_python_devel.m4 @@ -0,0 +1,337 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON_DEVEL([version]) +# +# DESCRIPTION +# +# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it +# in your configure.ac. +# +# This macro checks for Python and tries to get the include path to +# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS) +# output variables. It also exports $(PYTHON_EXTRA_LIBS) and +# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code. +# +# You can search for some particular version of Python by passing a +# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please +# note that you *have* to pass also an operator along with the version to +# match, and pay special attention to the single quotes surrounding the +# version number. Don't use "PYTHON_VERSION" for this: that environment +# variable is declared as precious and thus reserved for the end-user. +# +# This macro should work for all versions of Python >= 2.1.0. As an end +# user, you can disable the check for the python version by setting the +# PYTHON_NOVERSIONCHECK environment variable to something else than the +# empty string. +# +# If you need to use this macro for an older Python version, please +# contact the authors. We're always open for feedback. +# +# LICENSE +# +# Copyright (C) 2014 The ESPResSo project +# Copyright (c) 2009 Sebastian Huber +# Copyright (c) 2009 Alan W. Irwin +# Copyright (c) 2009 Rafael Laboissiere +# Copyright (c) 2009 Andrew Collier +# Copyright (c) 2009 Matteo Settenvini +# Copyright (c) 2009 Horst Knorr +# Copyright (c) 2013 Daniel Mullner +# Copyright (c) 2013 Axel Arnold +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 17 + +AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL]) +AC_DEFUN([AX_PYTHON_DEVEL],[ + # + # Allow the use of a (user set) custom python version + # + AC_ARG_VAR([PYTHON_VERSION],[The installed Python + version to use, for example '2.3'. This string + will be appended to the Python interpreter + canonical name.]) + + AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]]) + if test -z "$PYTHON"; then + AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path]) + PYTHON_VERSION="" + fi + + # + # if the macro parameter ``version'' is set, honour it + # otherwise, we need at least 2.1.0 for this to work + # + if test -n "$1"; then + version='2.1.0' + else + version='$1' + fi + AC_MSG_CHECKING([for a version of Python $1]) + ac_supports_python_ver=`$PYTHON -c "import sys; \ + ver = sys.version.split ()[[0]]; \ + print (ver $1)"` + if test "$ac_supports_python_ver" = "True"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([this package requires Python $1. +If you have it installed, but it isn't the default Python +interpreter in your system path, please pass the PYTHON_VERSION +variable to configure. See ``configure --help'' for reference. +]) + PYTHON_VERSION="" + fi + + # get the flags to compile against python + ######################################### + + # first try python-config, following the python manual + _AC_PYTHON_DEVEL_FROM_PYTHONCONFIG + AS_IF([test "$PYTHONCONFIG" != "no"], [ + _AC_CHECK_PYTHON_DEVEL_CONSISTENCY + ],) + + # try again using distutils, if that failed + AS_IF([test "$pythonexists" != "yes"], [ + _AC_PYTHON_CHECK_DISTUTILS + _AC_PYTHON_DEVEL_FROM_DISTUTILS + _AC_CHECK_PYTHON_DEVEL_CONSISTENCY + + if test ! "x$pythonexists" = "xyes"; then + AC_MSG_FAILURE([ + Could not link test program to Python neither using distutils nor + python-config. Maybe the main Python library has been + installed in some non-standard library path. If so, pass it to configure, + via the LDFLAGS environment variable. + Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib" + ============================================================================ + ERROR! + You probably have to install the development version of the Python package + for your distribution. The exact name of this package varies among them. + ============================================================================ + ]) + fi + ]) + + AC_SUBST([PYTHON_SITE_PKG]) + AC_SUBST([PYTHON_CPPFLAGS]) + AC_SUBST([PYTHON_LDFLAGS]) + AC_SUBST(PYTHON_EXTRA_LDFLAGS) + AC_SUBST(PYTHON_EXTRA_LIBS) + + # + # all done! + # +]) + +AC_DEFUN([_AC_CHECK_PYTHON_DEVEL_CONSISTENCY],[ + # check to see if everything compiles alright + # + AC_MSG_CHECKING([consistency of all components of python development environment]) + # save current global flags + ac_save_LIBS="$LIBS" + ac_save_CPPFLAGS="$CPPFLAGS" + LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS" + CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" + AC_LANG_PUSH([C]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[#include ]], + [[Py_Initialize();]]) + ],[pythonexists=yes],[pythonexists=no]) + AC_LANG_POP([C]) + # turn back to default flags + CPPFLAGS="$ac_save_CPPFLAGS" + LIBS="$ac_save_LIBS" + AC_MSG_RESULT([$pythonexists]) +]) + +AC_DEFUN([_AC_PYTHON_DEVEL_FROM_PYTHONCONFIG],[ + + AC_PATH_PROG([PYTHONCONFIG],[python[$PYTHON_VERSION]-config],no) + + if test "$PYTHONCONFIG" != no; then + # no splitting of LDFLAGS with python-config + PYTHON_CPPFLAGS=`$PYTHONCONFIG --cflags` + PYTHON_LDFLAGS=`$PYTHONCONFIG --ldflags` + PYTHON_EXTRA_LDFLAGS= + PYTHON_EXTRA_LIBS=`$PYTHONCONFIG --libs` + fi +]) + +AC_DEFUN([_AC_PYTHON_CHECK_DISTUTILS],[ + # + # Check if you have distutils, else fail + # + AC_MSG_CHECKING([for the distutils Python package]) + ac_distutils_result=`$PYTHON -c "import distutils" 2>&1` + if test -z "$ac_distutils_result"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([cannot import Python module "distutils". +Please check your Python installation. The error was: +$ac_distutils_result]) + PYTHON_VERSION="" + fi + + # + # Check for site packages + # + AC_MSG_CHECKING([for Python site-packages path]) + if test -z "$PYTHON_SITE_PKG"; then + PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_lib(0,0));"` + fi + AC_MSG_RESULT([$PYTHON_SITE_PKG]) +]) + +AC_DEFUN([_AC_PYTHON_DEVEL_FROM_DISTUTILS],[ + # + # Check for Python include path + # + AC_MSG_CHECKING([for Python include path]) + if test -z "$PYTHON_CPPFLAGS"; then + python_path=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_inc ());"` + plat_python_path=`$PYTHON -c "import distutils.sysconfig; \ + print (distutils.sysconfig.get_python_inc (plat_specific=1));"` + if test -n "${python_path}"; then + if test "${plat_python_path}" != "${python_path}"; then + python_path="-I$python_path -I$plat_python_path" + else + python_path="-I$python_path" + fi + fi + PYTHON_CPPFLAGS=$python_path + fi + AC_MSG_RESULT([$PYTHON_CPPFLAGS]) + + # + # Check for Python library path + # + AC_MSG_CHECKING([for Python library path]) + if test -z "$PYTHON_LDFLAGS"; then + # (makes two attempts to ensure we've got a version number + # from the interpreter) + ac_python_version=`cat</dev/null + if test $? -eq 0; + then + AC_MSG_RESULT(yes) + eval AS_TR_CPP(HAVE_PYMOD_$1)=yes + else + AC_MSG_RESULT(no) + eval AS_TR_CPP(HAVE_PYMOD_$1)=no + # + if test -n "$2" + then + AC_MSG_ERROR(failed to find required module $1) + exit 1 + fi + fi +]) diff --git a/testsuite/configs/check_myconfig_complete.py b/config/check_myconfig_complete.py similarity index 74% rename from testsuite/configs/check_myconfig_complete.py rename to config/check_myconfig_complete.py index 8779323790c..248afecb15a 100644 --- a/testsuite/configs/check_myconfig_complete.py +++ b/config/check_myconfig_complete.py @@ -1,4 +1,5 @@ -# Copyright (C) 2012 Olaf Lenz +# Copyright (C) 2014 The ESPResSo project +# Copyright (C) 2012,2013 Olaf Lenz # # This file is part of ESPResSo. # @@ -17,16 +18,17 @@ # # Check whether all features used in the code are defined # +from __future__ import print_function import sys, os, re, fileinput -sys.path.append(os.path.join(sys.path[0], '..', '..', 'config')) +sys.path.append(os.path.join(sys.path[0], '..', 'src')) import featuredefs if len(sys.argv) < 3: - print "Usage: %s DEFFILE [FILE...]" % sys.argv[0] + print("Usage: %s DEFFILE [FILE...]" % sys.argv[0]) exit(2) -print "Checking for completeness of features in test configurations..." +print("Checking for completeness of features in test configurations...") fdefs = featuredefs.defs(sys.argv[1]) @@ -42,8 +44,8 @@ unused = unused.difference(fdefs.notestfeatures) if len(unused) > 0: for feature in unused: - print "check_myconfig_complete: %s is not used" % feature + print("check_myconfig_complete: %s is not used" % feature) else: - print "check_myconfig_complete: All features are used!" + print("check_myconfig_complete: All features are used!") diff --git a/config/compile b/config/compile index 106fd91e0ca..2fdcd9e5883 100755 --- a/config/compile +++ b/config/compile @@ -3,7 +3,7 @@ scriptversion=2005-05-14.22 -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # Written by Tom Tromey . # diff --git a/config/config.guess b/config/config.guess index b79252d6b10..de8e6dd2c4a 100755 --- a/config/config.guess +++ b/config/config.guess @@ -1,12 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2013-06-10' +timestamp='2012-02-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -20,17 +22,19 @@ timestamp='2013-06-10' # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. # -# Originally written by Per Bothner. +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD -# -# Please send patches with a ChangeLog entry to config-patches@gnu.org. - me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +54,9 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -132,26 +138,15 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in -Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu - - eval $set_cc_for_build - cat <<-EOF > $dummy.c - #include - #if defined(__UCLIBC__) - LIBC=uclibc - #elif defined(__dietlibc__) - LIBC=dietlibc - #else - LIBC=gnu - #endif - EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` - ;; +case "${UNAME_MACHINE}" in + i?86) + test -z "$VENDOR" && VENDOR=pc + ;; + *) + test -z "$VENDOR" && VENDOR=unknown + ;; esac +test -f /etc/SuSE-release -o -f /.buildenv && VENDOR=suse # Note: order is significant - the case branches are not exclusive. @@ -215,25 +210,21 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} - exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + echo ${UNAME_MACHINE_ARCH}-${VENDOR}-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + echo ${UNAME_MACHINE}-${VENDOR}-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + echo ${UNAME_MACHINE}-${VENDOR}-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} + echo powerpc-${VENDOR}-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + echo ${UNAME_MACHINE}-${VENDOR}-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in @@ -301,13 +292,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 + echo m68k-${VENDOR}-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos + echo ${UNAME_MACHINE}-${VENDOR}-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos + echo ${UNAME_MACHINE}-${VENDOR}-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition @@ -321,8 +312,8 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-${VENDOR}-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp @@ -430,7 +421,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} + echo m68k-${VENDOR}-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} @@ -741,9 +732,9 @@ EOF exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + echo ${UNAME_MACHINE}-${VENDOR}-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + echo ${UNAME_MACHINE}-${VENDOR}-osf1 fi exit ;; parisc*:Lites*:*:*) @@ -803,26 +794,23 @@ EOF echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} + echo sparc-${VENDOR}-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + echo ${UNAME_MACHINE}-${VENDOR}-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo x86_64-${VENDOR}-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_PROCESSOR}-${VENDOR}-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; - *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 - exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; @@ -842,10 +830,10 @@ EOF echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} + echo x86_64-${VENDOR}-interix${UNAME_RELEASE} exit ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} + echo ia64-${VENDOR}-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) @@ -864,31 +852,31 @@ EOF echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin + echo x86_64-${VENDOR}-cygwin exit ;; p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin + echo powerpcle-${VENDOR}-cygwin exit ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + echo powerpcle-${VENDOR}-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-${VENDOR}-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in @@ -901,54 +889,59 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnueabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build @@ -967,63 +960,54 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + test x"${CPU}" != x && { echo "${CPU}-${VENDOR}-linux-gnu"; exit; } ;; - or1k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; or32:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} + echo sparc-${VENDOR}-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} + echo hppa64-${VENDOR}-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) echo hppa1.1-${VENDOR}-linux-gnu ;; + PA8*) echo hppa2.0-${VENDOR}-linux-gnu ;; + *) echo hppa-${VENDOR}-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} + echo powerpc64-${VENDOR}-linux-gnu exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} - exit ;; - ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} - exit ;; - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} + echo powerpc-${VENDOR}-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} + echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-${VENDOR}-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1045,16 +1029,16 @@ EOF echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop + echo ${UNAME_MACHINE}-${VENDOR}-stop exit ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos + echo ${UNAME_MACHINE}-${VENDOR}-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} + echo i386-${VENODR}-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp @@ -1074,7 +1058,7 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + echo ${UNAME_MACHINE}-${VENDOR}-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then @@ -1113,7 +1097,7 @@ EOF if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + echo i860-${VENODR}-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) @@ -1150,19 +1134,19 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} + echo m68k-${VENDOR}-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} + echo sparc-${VENDOR}-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} + echo rs6000-${VENDOR}-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} + echo powerpc-${VENDOR}-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} @@ -1212,7 +1196,7 @@ EOF if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-${VENDOR}-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. @@ -1227,9 +1211,6 @@ EOF BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; @@ -1256,21 +1237,19 @@ EOF exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc - fi - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi - fi + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) @@ -1287,7 +1266,7 @@ EOF NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; - NSE-*:NONSTOP_KERNEL:*:*) + NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1311,13 +1290,13 @@ EOF else UNAME_MACHINE="$cputype" fi - echo ${UNAME_MACHINE}-unknown-plan9 + echo ${UNAME_MACHINE}-${VENDOR}-plan9 exit ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 + echo pdp10-${VENDOR}-tops10 exit ;; *:TENEX:*:*) - echo pdp10-unknown-tenex + echo pdp10-${VENDOR}-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 @@ -1326,16 +1305,16 @@ EOF echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 + echo pdp10-${VENDOR}-tops20 exit ;; *:ITS:*:*) - echo pdp10-unknown-its + echo pdp10-${VENDOR}-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + echo ${UNAME_MACHINE}-${VENDOR}-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` @@ -1357,10 +1336,13 @@ EOF echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx + echo ${UNAME_MACHINE}-${VENDOR}-esx exit ;; esac +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + eval $set_cc_for_build cat >$dummy.c <. @@ -20,12 +26,11 @@ timestamp='2013-04-24' # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). +# the same distribution terms that you use for the rest of that program. -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -68,7 +73,9 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -116,7 +123,7 @@ esac maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) @@ -149,7 +156,7 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) + -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; @@ -252,10 +259,8 @@ case $basic_machine in | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | be32 | be64 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ @@ -268,7 +273,7 @@ case $basic_machine in | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ @@ -286,17 +291,16 @@ case $basic_machine in | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ + | nios | nios2 \ | ns16k | ns32k \ | open8 \ - | or1k | or32 \ + | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ @@ -366,7 +370,7 @@ case $basic_machine in | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ @@ -385,8 +389,7 @@ case $basic_machine in | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ @@ -404,13 +407,12 @@ case $basic_machine in | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ @@ -786,13 +788,9 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; - microblaze*) + microblaze) basic_machine=microblaze-xilinx ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; mingw32) basic_machine=i386-pc os=-mingw32 @@ -1021,11 +1019,7 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) + rdos) basic_machine=i386-pc os=-rdos ;; @@ -1352,21 +1346,21 @@ case $os in -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ + | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ @@ -1498,6 +1492,9 @@ case $os in -aros*) os=-aros ;; + -kaos*) + os=-kaos + ;; -zvmoe) os=-zvmoe ;; @@ -1546,9 +1543,6 @@ case $basic_machine in c4x-* | tic4x-*) os=-coff ;; - hexagon-*) - os=-elf - ;; tic54x-*) os=-coff ;; @@ -1589,9 +1583,6 @@ case $basic_machine in mips*-*) os=-elf ;; - or1k-*) - os=-elf - ;; or32-*) os=-coff ;; diff --git a/config/cuda.m4 b/config/cuda.m4 new file mode 100644 index 00000000000..01873500cc0 --- /dev/null +++ b/config/cuda.m4 @@ -0,0 +1,103 @@ +dnl -*- mode: autoconf -*- +dnl Copyright (C) 2013,2014 The ESPResSo project +dnl +dnl This file is part of ESPResSo. +dnl +dnl ESPResSo is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl ESPResSo is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program. If not, see . +dnl +dnl CUDA support for libtool +dnl +AC_DEFUN([AC_PROG_CUDA], + [LT_LANG(CUDA)]) + +AC_DEFUN([LT_PROG_CUDA], + [AC_ARG_VAR(NVCC,[NVIDIA CUDA compiler command]) + AC_ARG_VAR(NVCCFLAGS,[special compiler flags for the NVIDIA CUDA compiler]) + + AC_PATH_PROG(NVCC, nvcc, no, [$PATH:$cuda_path/bin]) + + # MAC nvcc stays 32 bit, even if the rest is 64 bit + case $target in + x86_64-apple-darwin*) + NVCCFLAGS="$NVCCFLAGS -m64";; + esac +]) + +# _LT_LANG_CUDA_CONFIG([TAG]) +# -------------------------- +# Analogue to _LT_LANG_GCJ_CONFIG for CUDA +AC_DEFUN([_LT_LANG_CUDA_CONFIG], + [AC_REQUIRE([LT_PROG_CUDA]) + AC_LANG_PUSH(C++) + + # CUDA file extensions + ac_ext=cu + objext=o + _LT_TAGVAR(objext, $1)=$objext + + # Code to be used in simple compile tests + lt_simple_compile_test_code="static __device__ __constant__ int var;" + + # Code to be used in simple link tests + lt_simple_link_test_code="#include + int main() { cudaGetDevice(0); }" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + + # nvcc interface is not gcc-like (but can steer gcc) + GCC=no + CC=$NVCC + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_TAGVAR(LD, $1)="$LD" + _LT_CC_BASENAME([$compiler]) + + # CUDA did not exist at the time GCC didn't implicitly link libc in. + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + _LT_TAGVAR(reload_flag, $1)=$reload_flag + _LT_TAGVAR(reload_cmds, $1)=$reload_cmds + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + # building shared with nvcc not there in libtool + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Xcompiler -static' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC' + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi + + AC_LANG_POP + + GCC=$lt_save_GCC + CC="$lt_save_CC" +]) diff --git a/config/depcomp b/config/depcomp index 4ebd5b3a2f2..08ffb634daa 100755 --- a/config/depcomp +++ b/config/depcomp @@ -1,9 +1,10 @@ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects -scriptversion=2013-05-30.07; # UTC +scriptversion=2012-03-27.16; # UTC -# Copyright (C) 1999-2013 Free Software Foundation, Inc. +# Copyright (C) 2014 The ESPResSo project +# Copyright (C) 1999-2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -27,9 +28,9 @@ scriptversion=2013-05-30.07; # UTC case $1 in '') - echo "$0: No command. Try '$0 --help' for more information." 1>&2 - exit 1; - ;; + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] @@ -56,65 +57,11 @@ EOF ;; esac -# Get the directory component of the given path, and save it in the -# global variables '$dir'. Note that this directory component will -# be either empty or ending with a '/' character. This is deliberate. -set_dir_from () -{ - case $1 in - */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; - *) dir=;; - esac -} - -# Get the suffix-stripped basename of the given path, and save it the -# global variable '$base'. -set_base_from () -{ - base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` -} - -# If no dependency file was actually created by the compiler invocation, -# we still have to create a dummy depfile, to avoid errors with the -# Makefile "include basename.Plo" scheme. -make_dummy_depfile () -{ - echo "#dummy" > "$depfile" -} - -# Factor out some common post-processing of the generated depfile. -# Requires the auxiliary global variable '$tmpdepfile' to be set. -aix_post_process_depfile () -{ - # If the compiler actually managed to produce a dependency file, - # post-process it. - if test -f "$tmpdepfile"; then - # Each line is of the form 'foo.o: dependency.h'. - # Do two passes, one to just change these to - # $object: dependency.h - # and one to simply output - # dependency.h: - # which is needed to avoid the deleted-header problem. - { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" - sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" - } > "$depfile" - rm -f "$tmpdepfile" - else - make_dummy_depfile - fi -} - # A tabulation character. tab=' ' # A newline character. nl=' ' -# Character ranges might be problematic outside the C locale. -# These definitions help. -upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ -lower=abcdefghijklmnopqrstuvwxyz -digits=0123456789 -alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 @@ -128,9 +75,6 @@ tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" -# Avoid interferences from the environment. -gccflag= dashmflag= - # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case @@ -142,32 +86,32 @@ if test "$depmode" = hp; then fi if test "$depmode" = dashXmstdout; then - # This is just like dashmstdout with a different argument. - dashmflag=-xM - depmode=dashmstdout + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then - # This is just like msvisualcpp but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvisualcpp + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then - # This is just like msvc7 but w/o cygpath translation. - # Just convert the backslash-escaped backslashes to single forward - # slashes to satisfy depend.m4 - cygpath_u='sed s,\\\\,/,g' - depmode=msvc7 + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 fi if test "$depmode" = xlc; then - # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. - gccflag=-qmakedep=gcc,-MF - depmode=gcc + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. + gccflag=-qmakedep=gcc,-MF + depmode=gcc fi case "$depmode" in @@ -190,7 +134,8 @@ gcc3) done "$@" stat=$? - if test $stat -ne 0; then + if test $stat -eq 0; then : + else rm -f "$tmpdepfile" exit $stat fi @@ -198,17 +143,13 @@ gcc3) ;; gcc) -## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. -## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. -## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like -## -MM, not -M (despite what the docs say). Also, it might not be -## supported by the other compilers which use the 'gcc' depmode. +## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then @@ -216,14 +157,15 @@ gcc) fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? - if test $stat -ne 0; then + if test $stat -eq 0; then : + else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" - # The second -e expression handles DOS-style file names with drive - # letters. + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. @@ -232,15 +174,15 @@ gcc) ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. + tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" + sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; @@ -258,7 +200,8 @@ sgi) "$@" -MDupdate "$tmpdepfile" fi stat=$? - if test $stat -ne 0; then + if test $stat -eq 0; then : + else rm -f "$tmpdepfile" exit $stat fi @@ -266,6 +209,7 @@ sgi) if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" + # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in @@ -273,15 +217,19 @@ sgi) # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ - | tr "$nl" ' ' >> "$depfile" + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr "$nl" ' ' >> "$depfile" echo >> "$depfile" + # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ - >> "$depfile" + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" else - make_dummy_depfile + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; @@ -299,8 +247,9 @@ aix) # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. - set_dir_from "$object" - set_base_from "$object" + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u @@ -313,7 +262,9 @@ aix) "$@" -M fi stat=$? - if test $stat -ne 0; then + + if test $stat -eq 0; then : + else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi @@ -322,113 +273,65 @@ aix) do test -f "$tmpdepfile" && break done - aix_post_process_depfile - ;; - -tcc) - # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 - # FIXME: That version still under development at the moment of writing. - # Make that this statement remains true also for stable, released - # versions. - # It will wrap lines (doesn't matter whether long or short) with a - # trailing '\', as in: - # - # foo.o : \ - # foo.c \ - # foo.h \ - # - # It will put a trailing '\' even on the last line, and will use leading - # spaces rather than leading tabs (at least since its commit 0394caf7 - # "Emit spaces for -MD"). - "$@" -MD -MF "$tmpdepfile" - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile" - exit $stat + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependent.h'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" fi - rm -f "$depfile" - # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. - # We have to change lines of the first kind to '$object: \'. - sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" - # And for each line of the second kind, we have to emit a 'dep.h:' - # dummy dependency, to avoid the deleted-header problem. - sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; -## The order of this option in the case statement is important, since the -## shell code in configure will try each of these formats in the order -## listed in this file. A plain '-MD' option would be understood by many -## compilers, so we must ensure this comes after the gcc and icc options. -pgcc) - # Portland's C compiler understands '-MD'. - # Will always output deps to 'file.d' where file is the root name of the - # source file under compilation, even if file resides in a subdirectory. - # The object file name does not affect the name of the '.d' file. - # pgcc 10.2 will output +icc) + # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. + # However on + # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h - # and will wrap long lines using '\' : + # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... - set_dir_from "$object" - # Use the source, not the object, to determine the base name, since - # that's sadly what pgcc will do too. - set_base_from "$source" - tmpdepfile=$base.d - - # For projects that build the same source file twice into different object - # files, the pgcc approach of using the *source* file root name can cause - # problems in parallel builds. Use a locking strategy to avoid stomping on - # the same $tmpdepfile. - lockdir=$base.d-lock - trap " - echo '$0: caught signal, cleaning up...' >&2 - rmdir '$lockdir' - exit 1 - " 1 2 13 15 - numtries=100 - i=$numtries - while test $i -gt 0; do - # mkdir is a portable test-and-set. - if mkdir "$lockdir" 2>/dev/null; then - # This process acquired the lock. - "$@" -MD - stat=$? - # Release the lock. - rmdir "$lockdir" - break - else - # If the lock is being held by a different process, wait - # until the winning process is done or we timeout. - while test -d "$lockdir" && test $i -gt 0; do - sleep 1 - i=`expr $i - 1` - done - fi - i=`expr $i - 1` - done - trap - 1 2 13 15 - if test $i -le 0; then - echo "$0: failed to acquire lock after $numtries attempts" >&2 - echo "$0: check lockdir '$lockdir'" >&2 - exit 1 - fi - - if test $stat -ne 0; then + # tcc 0.9.26 (FIXME still under development at the moment of writing) + # will emit a similar output, but also prepend the continuation lines + # with horizontal tabulation characters. + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" - # Each line is of the form `foo.o: dependent.h', - # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Each line is of the form 'foo.o: dependent.h', + # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. # Do two passes, one to just change these to - # `$object: dependent.h' and one to simply `dependent.h:'. - sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ - | sed -e 's/$/ :/' >> "$depfile" + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ + < "$tmpdepfile" > "$depfile" + sed ' + s/[ '"$tab"'][ '"$tab"']*/ /g + s/^ *// + s/ *\\*$// + s/^[^:]*: *// + /^$/d + /:$/d + s/$/ :/ + ' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; @@ -439,8 +342,9 @@ hp2) # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. - set_dir_from "$object" - set_base_from "$object" + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d @@ -451,7 +355,8 @@ hp2) "$@" +Maked fi stat=$? - if test $stat -ne 0; then + if test $stat -eq 0; then : + else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi @@ -461,61 +366,76 @@ hp2) test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then - sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ - s/^ *// - s/ \\*$// - s/$/:/ - p - }' "$tmpdepfile" >> "$depfile" + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" else - make_dummy_depfile + echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) - # The Tru64 compiler uses -MD to generate dependencies as a side - # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. - # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put - # dependencies in 'foo.d' instead, so we check for that too. - # Subdirectories are respected. - set_dir_from "$object" - set_base_from "$object" - - if test "$libtool" = yes; then - # Libtool generates 2 separate objects for the 2 libraries. These - # two compilations output dependencies in $dir.libs/$base.o.d and - # in $dir$base.o.d. We have to check for both files, because - # one of the two compilations can be disabled. We should prefer - # $dir$base.o.d over $dir.libs/$base.o.d because the latter is - # automatically cleaned when .libs/ is deleted, while ignoring - # the former would cause a distcleancheck panic. - tmpdepfile1=$dir$base.o.d # libtool 1.5 - tmpdepfile2=$dir.libs/$base.o.d # Likewise. - tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 - "$@" -Wc,-MD - else - tmpdepfile1=$dir$base.d - tmpdepfile2=$dir$base.d - tmpdepfile3=$dir$base.d - "$@" -MD - fi - - stat=$? - if test $stat -ne 0; then - rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - exit $stat - fi - - for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" - do - test -f "$tmpdepfile" && break - done - # Same post-processing that is required for AIX mode. - aix_post_process_depfile - ;; + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; msvc7) if test "$libtool" = yes; then @@ -526,7 +446,8 @@ msvc7) "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" - if test $stat -ne 0; then + if test "$stat" = 0; then : + else rm -f "$tmpdepfile" exit $stat fi @@ -552,7 +473,6 @@ $ { G p }' >> "$depfile" - echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; @@ -604,14 +524,13 @@ dashmstdout) # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | - sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" + sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process this sed invocation - # correctly. Breaking it into two sed invocations is a workaround. - tr ' ' "$nl" < "$tmpdepfile" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" + tr ' ' "$nl" < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; @@ -664,12 +583,10 @@ makedepend) # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" - # Some versions of the HPUX 10.20 sed can't process the last invocation - # correctly. Breaking it into two sed invocations is a workaround. - sed '1,2d' "$tmpdepfile" \ - | tr ' ' "$nl" \ - | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ - | sed -e 's/$/ :/' >> "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; @@ -705,10 +622,10 @@ cpp) esac done - "$@" -E \ - | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ - | sed '$ s: \\$::' > "$tmpdepfile" + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" @@ -740,15 +657,15 @@ msvisualcpp) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") - set fnord "$@" - shift - shift - ;; + set fnord "$@" + shift + shift + ;; *) - set fnord "$@" "$arg" - shift - shift - ;; + set fnord "$@" "$arg" + shift + shift + ;; esac done "$@" -E 2>/dev/null | diff --git a/config/gen_doxyconfig.py b/config/gen_doxyconfig.py deleted file mode 100644 index eb80f7d1bcc..00000000000 --- a/config/gen_doxyconfig.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2013 The ESPResSo project -# Copyright (C) 2012 Olaf Lenz -# -# This file is part of ESPResSo. -# -# ESPResSo is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# ESPResSo is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# This script generates the file doxyconfigure.h (used by doxygen) -# -import sys, featuredefs, time - -if len(sys.argv) != 3: - print >> sys.stderr, "Usage: %s DEFFILE HFILE" % sys.argv[0] - exit(2) - -deffilename, hfilename = sys.argv[1:3] - -print "Reading definitions from " + deffilename + "..." -defs = featuredefs.defs(deffilename) -print "Done." - -print "Writing " + hfilename + "..." -hfile = file(hfilename, 'w'); - -hfile.write("""/* -WARNING: This file was autogenerated by - - %s on %s - - Do not modify it or your changes will be overwritten! - Modify features.def instead. - - This file is needed so that doxygen will generate documentation for - all functions of all features. -*/ -#ifndef _DOXYCONFIG_H -#define _DOXYCONFIG_H - -""" % (sys.argv[0], time.asctime())) - -for feature in defs.features: - hfile.write('#define ' + feature + '\n') - -hfile.write(""" -#endif /* of _DOXYCONFIG_H */""") -hfile.close() -print "Done." - diff --git a/config/gen_sampleconfig.py b/config/gen_sampleconfig.py index 41fecccfe03..2951537dac6 100644 --- a/config/gen_sampleconfig.py +++ b/config/gen_sampleconfig.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -19,10 +19,16 @@ # This script appends the sample list of features to the file # myconfig-sample.h. # -import sys, featuredefs, time, string, fileinput +from __future__ import print_function +import time, string, fileinput +import inspect, sys, os +# find featuredefs.py +moduledir = os.path.dirname(inspect.getfile(inspect.currentframe())) +sys.path.append(os.path.join(moduledir, '..', 'src')) +import featuredefs if len(sys.argv) != 2: - print >> sys.stderr, "Usage: %s DEFFILE" % sys.argv[0] + print("Usage: {} DEFFILE".format(sys.argv[0]), file=sys.stderr) exit(2) deffilename = sys.argv[1] @@ -39,17 +45,17 @@ # Handle empty and comment lines if len(line) == 0: - print + print() continue elif line.startswith('#'): continue elif line.startswith('//') or line.startswith('/*'): - print line + print(line) continue # Tokenify line feature = line.split(None, 1)[0] if feature in defs.features and feature not in featuresdone: - print '//#define %s' % feature + print('//#define %s' % feature) featuresdone.add(feature) diff --git a/config/genversion.sh b/config/genversion.sh index 100afd8ad42..2c2c546216a 100755 --- a/config/genversion.sh +++ b/config/genversion.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2011,2012 Olaf Lenz # # This program is free software: you can redistribute it and/or modify @@ -47,11 +47,11 @@ fi VERSIONFILE=version.txt # try to use git describe --dirty -if VERSION=`git describe --dirty --match=?\.?\.? 2> /dev/null`; then +if VERSION=`git describe --dirty --match=?\.* 2> /dev/null`; then test -z "$DIST" && VERSION=$VERSION-git # try to use git without --dirty -elif VERSION=`git describe --match=?\.?\.? 2> /dev/null`-maybedirty; then +elif VERSION=`git describe --match=?\.* 2> /dev/null`-maybedirty; then test -z "$DIST" && VERSION=$VERSION-git # otherwise use the versionfile diff --git a/config/header.txt b/config/header.txt index e326a2747b5..d13469910f9 100644 --- a/config/header.txt +++ b/config/header.txt @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/config/missing b/config/missing index cdea514931f..690a25e377b 100755 --- a/config/missing +++ b/config/missing @@ -1,10 +1,11 @@ #! /bin/sh -# Common wrapper for a few potentially missing GNU programs. +# Common stub for a few missing GNU programs while installing. -scriptversion=2012-06-26.16; # UTC +scriptversion=2012-01-06.18; # UTC -# Copyright (C) 1996-2013 Free Software Foundation, Inc. -# Originally written by Fran,cois Pinard , 1996. +# Copyright (C) 2014 The ESPResSo project +# Copyright (C) 1996-2012 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,33 +30,61 @@ if test $# -eq 0; then exit 1 fi -case $1 in +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' - --is-lightweight) - # Used by our autoconf macros to check whether the available missing - # script is modern enough. - exit 0 - ;; +# In the cases where this matters, 'missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi - --run) - # Back-compat with the calling convention used by older automake. - shift - ;; +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... -Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due -to PROGRAM being missing or too old. +Handle 'PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails Supported PROGRAM values: - aclocal autoconf autoheader autom4te automake makeinfo - bison yacc flex lex help2man + aclocal touch file 'aclocal.m4' + autoconf touch file 'configure' + autoheader touch file 'config.h.in' + autom4te touch the output file, or create a stub one + automake touch all 'Makefile.in' files + bison create 'y.tab.[ch]', if possible, from existing .[ch] + flex create 'lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create 'lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create 'y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. @@ -70,141 +99,228 @@ Send bug reports to ." ;; -*) - echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "$0: Unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac -# Run the given program, remember its exit status. -"$@"; st=$? - -# If it succeeded, we are done. -test $st -eq 0 && exit 0 - -# Also exit now if we it failed (or wasn't found), and '--version' was -# passed; such an option is passed most likely to detect whether the -# program is present and works. -case $2 in --version|--help) exit $st;; esac - -# Exit code 63 means version mismatch. This often happens when the user -# tries to use an ancient version of a tool on a file that requires a -# minimum version. -if test $st -eq 63; then - msg="probably too old" -elif test $st -eq 127; then - # Program was missing. - msg="missing on your system" -else - # Program was found and executed, but failed. Give up. - exit $st -fi +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running '$TOOL --version' or '$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified 'acinclude.m4' or '${configure_ac}'. You might want + to install the Automake and Perl packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified '${configure_ac}'. You might want to install the + Autoconf and GNU m4 packages. Grab them from any GNU + archive site." + touch configure + ;; -perl_URL=http://www.perl.org/ -flex_URL=http://flex.sourceforge.net/ -gnu_software_URL=http://www.gnu.org/software - -program_details () -{ - case $1 in - aclocal|automake) - echo "The '$1' program is part of the GNU Automake package:" - echo "<$gnu_software_URL/automake>" - echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" - echo "<$gnu_software_URL/autoconf>" - echo "<$gnu_software_URL/m4/>" - echo "<$perl_URL>" - ;; - autoconf|autom4te|autoheader) - echo "The '$1' program is part of the GNU Autoconf package:" - echo "<$gnu_software_URL/autoconf/>" - echo "It also requires GNU m4 and Perl in order to run:" - echo "<$gnu_software_URL/m4/>" - echo "<$perl_URL>" - ;; - esac -} - -give_advice () -{ - # Normalize program name to check for. - normalized_program=`echo "$1" | sed ' - s/^gnu-//; t - s/^gnu//; t - s/^g//; t'` - - printf '%s\n' "'$1' is $msg." - - configure_deps="'configure.ac' or m4 files included by 'configure.ac'" - case $normalized_program in - autoconf*) - echo "You should only need it if you modified 'configure.ac'," - echo "or m4 files included by it." - program_details 'autoconf' - ;; - autoheader*) - echo "You should only need it if you modified 'acconfig.h' or" - echo "$configure_deps." - program_details 'autoheader' - ;; - automake*) - echo "You should only need it if you modified 'Makefile.am' or" - echo "$configure_deps." - program_details 'automake' - ;; - aclocal*) - echo "You should only need it if you modified 'acinclude.m4' or" - echo "$configure_deps." - program_details 'aclocal' - ;; - autom4te*) - echo "You might have modified some maintainer files that require" - echo "the 'automa4te' program to be rebuilt." - program_details 'autom4te' - ;; - bison*|yacc*) - echo "You should only need it if you modified a '.y' file." - echo "You may want to install the GNU Bison package:" - echo "<$gnu_software_URL/bison/>" - ;; - lex*|flex*) - echo "You should only need it if you modified a '.l' file." - echo "You may want to install the Fast Lexical Analyzer package:" - echo "<$flex_URL>" - ;; - help2man*) - echo "You should only need it if you modified a dependency" \ - "of a man page." - echo "You may want to install the GNU Help2man package:" - echo "<$gnu_software_URL/help2man/>" + autoheader*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified 'acconfig.h' or '${configure_ac}'. You might want + to install the Autoconf and GNU m4 packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files ;; - makeinfo*) - echo "You should only need it if you modified a '.texi' file, or" - echo "any other file indirectly affecting the aspect of the manual." - echo "You might want to install the Texinfo package:" - echo "<$gnu_software_URL/texinfo/>" - echo "The spurious makeinfo call might also be the consequence of" - echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" - echo "want to install GNU make:" - echo "<$gnu_software_URL/make/>" - ;; - *) - echo "You might have modified some files without having the proper" - echo "tools for further handling them. Check the 'README' file, it" - echo "often tells you about the needed prerequisites for installing" - echo "this package. You may also peek at any GNU archive site, in" - echo "case some other package contains this missing '$1' program." - ;; - esac -} - -give_advice "$1" | sed -e '1s/^/WARNING: /' \ - -e '2,$s/^/ /' >&2 - -# Propagate the correct exit status (expected to be 127 for a program -# not found, 63 for a program that failed due to version mismatch). -exit $st + + automake*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified 'Makefile.am', 'acinclude.m4' or '${configure_ac}'. + You might want to install the Automake and Perl packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: '$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get '$1' as part of Autoconf from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: '$1' $msg. You should only need it if + you modified a '.y' file. You may need the Bison package + in order for those modifications to take effect. You can get + Bison from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified a '.l' file. You may need the Flex package + in order for those modifications to take effect. You can get + Flex from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + Help2man package in order for those modifications to take + effect. You can get Help2man from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: '$1' is $msg. You should only need it if + you modified a '.texi' or '.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy 'make' (AIX, + DU, IRIX). You might want to install the Texinfo package or + the GNU make package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: '$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the 'README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing '$1' program." + exit 1 + ;; +esac + +exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) diff --git a/configure.ac b/configure.ac index 4f9ac9036c8..143fb166a21 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2006,2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # Copyright (C) 2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group @@ -25,7 +25,7 @@ AC_INIT([ESPResSo],[ESPRESSO_VERSION],[espressomd-users@nongnu.org]) AC_PREREQ([2.59]) -AC_CONFIG_SRCDIR([src/initialize.cpp]) +AC_CONFIG_SRCDIR([src/features.def]) AC_CONFIG_AUX_DIR(config) AC_CONFIG_MACRO_DIR(config) AC_PREFIX_DEFAULT($HOME/Espresso) @@ -33,11 +33,12 @@ AC_CANONICAL_HOST AC_CANONICAL_TARGET # Initialize automake -AM_INIT_AUTOMAKE([1.11 gnu subdir-objects dist-xz]) +# tar-ustar is needed for filenames longer than 99 chars +AM_INIT_AUTOMAKE([1.11 gnu tar-ustar subdir-objects dist-xz]) AM_MAINTAINER_MODE # silent rules, backwards compatiblity -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # Are we in an unpacked dist or in the git repo? AC_MSG_CHECKING([whether we are using development sources]) @@ -116,18 +117,22 @@ AC_SUBST(ESPRESSO_MPIEXEC) ################################## #### COMPILER CHARACTERISTICS #### ################################## +# try to find best __FUNCTION__ variant +AX_CXX_VAR_PRETTYFUNC() + +# set the optimization flags # never overwrite users CXXFLAGS if test "${CXXFLAGS+set}" != set; then - # test for -O5 - AC_MSG_CHECKING([whether the compiler accepts -O5]) + # test for -O3 + AC_MSG_CHECKING([whether the compiler accepts -O3]) saved_CXXFLAGS=$CXXFLAGS - CXXFLAGS="-O5 $CXXFLAGS" + CXXFLAGS="-O3 $CXXFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],[ AC_MSG_RESULT(yes);try_add_flag_res=yes ],[ AC_MSG_RESULT(no); CXXFLAGS=$saved_CXXFLAGS; try_add_flag_res=no ]) - + ################################## # test for -Wall AC_MSG_CHECKING([whether the compiler accepts -Wall]) @@ -150,15 +155,15 @@ cat < /dev/null 2>&1; then - PYTHON="$PYTHON -B" - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - fi -fi cat <.dylib is - in one of the library paths set by LDFLAGS, or that you set the appropriate - apple gcc -framework option in CPPFLAGS and LDFLAGS.]) ;; - *) AC_MSG_FAILURE([ -******************************************************************************** -* Could not link against the (static) Tcl library (libtcl*.a). * -* Please add the library path to LDFLAGS (e.g. configure LDFLAGS=-L/usr/lib)! * -******************************************************************************** -]) ;; - esac -fi - -case $target_os in - *linux*) # path used by *buntu - extrapaths=/usr/include/$version ;; -esac - -if test .$use_tcl != .none; then - ES_ADDPATH_CHECK_HEADER(tcl.h, [], - [AC_MSG_FAILURE([ -******************************************************************************** -* Could not find the Tcl header files (tcl.h). * -* Please add the include path to CPPFLAGS * -* (e.g. configure CPPFLAGS=-I/usr/include)! * -******************************************************************************** -])], $extrapaths) -fi - -if test .$use_tcl = .; then - use_tcl=none -fi - -AM_CONDITIONAL(TCL, [test .$use_tcl != .none]) - -################################## -# check for tk -AC_ARG_WITH(tk, - AS_HELP_STRING([--with-tk=VERSION],[whether to use Tk, and which version to use]), - [], [with_tk=no]) -dnl with_tk=no don't use Tk -dnl with_tk=yes try to find a working Tk version, bail out if none is found -dnl otherwise use the specified version -if test .$with_tk != .no; then - # test for X11 - AC_PATH_XTRA - saved_CPPFLAGS=$CPPFLAGS - saved_LDFLAGS=$LDFLAGS - saved_LIBS=$LIBS - CPPFLAGS="$CPPFLAGS $X_CXXFLAGS" - LDFLAGS="$LDFLAGS $X_LIBS" - LIBS="$LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" - AC_LINK_IFELSE([AC_LANG_CALL([],[XOpenDisplay])],[x11_works=yes],[x11_works=no]) - if test $x11_works = no; then - AC_MSG_WARN([could not link against X11, hoping Tk works without]) - CPPFLAGS=$saved_CPPFLAGS - LDFLAGS=$saved_LDFLAGS - LIBS=$saved_LIBS - fi - # now test whether Tk can be found - if test .$with_tk = .yes; then - for version in $TK_VERSION tk8.5 tk8.4 tk8.3 tk8.2 tk; do - ES_ADDPATH_CHECK_LIB($version, Tk_Init, [use_tk=$version], []) - if test .$use_tk != .; then break; fi - done - else - ES_ADDPATH_CHECK_LIB($with_tk, Tk_Init, [use_tk=$with_tk], []) - fi - if test .$use_tk = .; then - case $target_os in - *darwin*) AC_MSG_ERROR( -[If you have Tk installed, make sure that either libtcl.dylib is - in one of the library paths set by LDFLAGS, or that you set the appropriate - apple gcc -framework option in CPPFLAGS and LDFLAGS.]) ;; - *) AC_MSG_FAILURE([Tk library $with_tk not found]) ;; - esac - fi - if test .$use_tk = .tk; then - if test .$use_tcl != .tcl; then - AC_MSG_WARN([You are using a generic Tk version, but a defined Tcl version. This may cause problems. -Try --with-tcl=tcl to also use a generic Tcl version, which may fit better.]) - fi - fi - case $target_os in - *linux*) # path used by *buntu - extrapaths="/usr/include/$version /usr/include/$use_tcl" ;; - (*) ;; - esac - ES_ADDPATH_CHECK_HEADER(tk.h, [], - [AC_MSG_ERROR([Tk headers not found. Please add the include path to CPPFLAGS (e.g. configure CPPFLAGS=-I/usr/include/tcl8.4).]) - ] - ,$extrapaths) - AC_DEFINE_UNQUOTED(TK,$use_tk,[Whether to use Tk]) -else - use_tk=none -fi - ################################## # check for FFTW # with_fftw=no don't use FFTW @@ -363,9 +225,9 @@ AC_ARG_WITH([fftw], AC_MSG_RESULT($with_fftw) AS_IF([test x$with_fftw = xno], [fftw_found=no], - [ AC_SEARCH_LIBS(fftw_plan_many_dft, [fftw3], [fftw_found=yes], [fftw_found=no]) + [ ES_ADDPATH_CHECK_LIB(fftw3, fftw_plan_many_dft, [fftw_found=yes], [fftw_found=no],) AS_IF([test x$fftw_found = xyes], - [AC_CHECK_HEADER([fftw3.h],, [fftw_found=no])]) + [ES_ADDPATH_CHECK_HEADER([fftw3.h],, [fftw_found=no],)]) ]) AS_IF([test x$fftw_found = xno],[ @@ -382,14 +244,14 @@ AS_IF([test x$fftw_found = xyes],[ ################################## # check for CUDA AC_MSG_CHECKING([whether to use CUDA]) - AC_ARG_WITH([cuda], AS_HELP_STRING([--with-cuda@<:@=DIR@:>@], [specify where CUDA is installed. The cuda compiler can also be specified by setting the NVCC environment variable. The CUDA library and header can be manually specified by using CPPFLAGS, LDFLAGS and LIBS. [guess]]), , - with_cuda=guess) AC_MSG_RESULT($with_cuda) + with_cuda=guess) +AC_MSG_RESULT($with_cuda) AS_IF([test x$with_cuda = xguess || test x$with_cuda = xyes],[ cuda_path=/usr/local/cuda @@ -402,16 +264,13 @@ cuda_ok=no AS_IF([test x$with_cuda != xno],[ cuda_ok=yes + + # save current libs in case CUDA is not enabled at the end save_LIBS=$LIBS save_LDFLAGS=$LDFLAGS - save_CXX=$CXX - save_CXXFLAGS=$CXXFLAGS # NVCC - AC_ARG_VAR(NVCC,[NVIDIA CUDA compiler command]) - AC_ARG_VAR(NVCCFLAGS,[special compiler flags for the NVIDIA CUDA compiler]) - - AC_PATH_PROG(NVCC, nvcc, no, [$PATH:$cuda_path/bin]) + AC_PROG_CUDA AS_IF([test x$NVCC = xno],[ AS_IF([test x$with_cuda = xyes],[ @@ -421,14 +280,8 @@ AS_IF([test x$with_cuda != xno],[ ]) ]) - # MAC nvcc stays 32 bit, even if the rest is 64 bit - case $target in - x86_64-apple-darwin*) - NVCCFLAGS="$NVCCFLAGS -m64";; - esac - # since we link with mpic++, we need to find the cuda libraries manually - ES_ADDPATH_CHECK_LIB(cudart, cudaGetDevice, [LIBS="$LIBS -lcudart"], [ + ES_ADDPATH_CHECK_LIB(cudart, cudaGetDevice, [], [ cuda_ok=no AS_IF([test x$with_cuda = xyes],[ @@ -438,7 +291,7 @@ AS_IF([test x$with_cuda != xno],[ ]) ], [$cuda_path/lib $cuda_path/lib64]) - ES_ADDPATH_CHECK_LIB(cufft, cufftPlan3d, [LIBS="$LIBS -lcufft"], [ + ES_ADDPATH_CHECK_LIB(cufft, cufftPlan3d, [], [ cuda_ok=no AS_IF([test x$with_cuda = xyes],[ @@ -451,20 +304,25 @@ AS_IF([test x$with_cuda != xno],[ # NVCC compile check AC_MSG_CHECKING([whether CUDA compiles]) - # if no other compute capability is defined by the user, we require at least 1.1 + # if no other compute capability is defined by the user, we default to 2.0 case "$NVCCFLAGS" in *-arch=*) ;; - *) NVCCFLAGS="$NVCCFLAGS --ptxas-options=-v -gencode arch=compute_11,code=compute_11 -gencode arch=compute_20,code=compute_20" + *) NVCCFLAGS="$NVCCFLAGS --ptxas-options=-v -gencode arch=compute_20,code=compute_20" esac # use nvcc # autoconf currently doesn't allow to define new languages like cuda, this is a workaround - save_CXX=$CXX - save_CXXFLAGS=$CXXFLAGS - + save_noncuda_CXX=$CXX + save_noncuda_CXXFLAGS=$CXXFLAGS + save_noncuda_LDFLAGS=$LDFLAGS + save_noncuda_LIBS=$LIBS + CXX=$NVCC CXXFLAGS="$NVCCFLAGS -x cu" + # libtool linking options likely break NVCC linking, sort out all but simple -L options + AS_IF([test -n "$LDFLAGS"],[ LDFLAGS="-Xlinker `echo $LDFLAGS | sed -e ['s|-[^L][^ ]*||g' -e 's|[ ][ ]*|,|g']`" ]) + AS_IF([test -n "$LIBS" ],[ LIBS="-Xlinker `echo $LIBS | sed ['s|[ ][ ]*|,|g']`"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include ],[cudaGetDevice(0);])], [ AC_MSG_RESULT(yes) @@ -481,26 +339,44 @@ AS_IF([test x$with_cuda != xno],[ # NVCC compile check AC_MSG_CHECKING([whether CUDA runs]) - AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ],[int no; cudaGetDeviceCount(&no);])], [ + AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ],[ + int no; + cudaGetDeviceCount(&no); + if (no == 0) return 1; + ])], [ AC_MSG_RESULT(yes) ],[ - cuda_ok=no AC_MSG_RESULT(no) AS_IF([test x$with_cuda = xyes],[ - AC_MSG_FAILURE([cannot run CUDA code. Look at config.log for more details.]) + cuda_running=no + AC_MSG_WARN([cannot run CUDA code. Look at config.log for more details. Still compiling since explicitely requested.]) ],[ + cuda_ok=no AC_MSG_WARN([cannot run CUDA code. Some features will not be available!]) ]) ],[ AC_MSG_RESULT([unknown (cross-compiling)]) ]) - - CXX=$save_CXX - CXXFLAGS=$save_CXXFLAGS + + CXX=$save_noncuda_CXX + CXXFLAGS=$save_noncuda_CXXFLAGS + LDFLAGS=$save_noncuda_LDFLAGS + LIBS=$save_noncuda_LIBS AS_IF([test x$cuda_ok == xyes], [ + # NVCC doesn't work with llvm's libc++ so we need to also + # compile the rest with libstdc++, if nvcc-compiled code is + # used + AC_MSG_CHECKING([whether the compiler accepts -stdlib=libstdc++]) + saved_CXXFLAGS=$CXXFLAGS + CXXFLAGS="-stdlib=libstdc++ $CXXFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],[ AC_MSG_RESULT(yes) ],[ + AC_MSG_RESULT(no); CXXFLAGS=$saved_CXXFLAGS + ]) + AC_DEFINE(CUDA,[],[Whether CUDA is available]) ],[ + # reset standard compiler options LIBS=$save_LIBS LDFLAGS=$save_LDFLAGS ]) @@ -508,6 +384,197 @@ AS_IF([test x$with_cuda != xno],[ AM_CONDITIONAL(CUDA, [test x$cuda_ok == xyes]) +cat < /dev/null 2>&1; then + PYTHON="$PYTHON -B" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi +fi + +AC_MSG_CHECKING([whether the python interface is wanted]) +AC_ARG_WITH([python-interface], AS_HELP_STRING([--with-python-interface], + [specify whether or not to use python [guess]]), + [], [with_python_interface=guess]) +AC_MSG_RESULT($with_python_interface) +dnl with_python_interface=yes try to find a working PYTHON devel version, +dnl bail out if none is found +dnl with_python_interface=guess try to find a working PYTHON devel version, +dnl with_python_interface=no do not use python interface + +AS_IF([test .$with_python_interface != .no], [ + AX_PYTHON_DEVEL([>= '2.5']) + + AC_ARG_VAR(CYTHON,[Specify the cython tool to use]) + AC_PATH_PROG(CYTHON,cython,no) + AS_IF([test .$CYTHON = .no], + [build_python_interface=no], + [build_python_interface=yes]) + + AX_PYTHON_MODULE(numpy, required) + AC_MSG_CHECKING([for numpy include path]) + NUMPY_INCLUDE="`$PYTHON -c 'import numpy; import sys; sys.stdout.write(numpy.get_include())'`" #` + PYTHON_CPPFLAGS="$PYTHON_CPPFLAGS -I$NUMPY_INCLUDE" + AC_MSG_RESULT([$NUMPY_INCLUDE]) + + AS_IF([test .$with_python_interface = .yes && test .$build_python_interface = .no], + [AC_MSG_FAILURE([Cannot build python interface!])]) + AC_DEFINE(PYTHON_DEV,[],[Whether Python is available]) +]) +AM_CONDITIONAL(PYTHON_INTERFACE, [test .$build_python_interface = .yes]) +# export libtool objdir, so that we can link the .so files to the dir itself +AC_SUBST(objdir) + +cat <.dylib is + in one of the library paths set by LDFLAGS, or that you set the appropriate + apple gcc -framework option in CPPFLAGS and LDFLAGS.]) ;; + *) AC_MSG_FAILURE([ +******************************************************************************** +* Could not link against the (static) Tcl library (libtcl*.a). * +* Please add the library path to LDFLAGS (e.g. configure LDFLAGS=-L/usr/lib)! * +******************************************************************************** +]) ;; + esac +fi + +case $target_os in + *darwin*) extrapaths=/Library/Frameworks/Tcl.framework/Headers ;; + *linux*) # path used by *buntu + extrapaths=/usr/include/$version ;; +esac + +if test .$use_tcl != .none; then + ES_ADDPATH_CHECK_HEADER(tcl.h, [], + [AC_MSG_FAILURE([ +******************************************************************************** +* Could not find the Tcl header files (tcl.h). * +* Please add the include path to CPPFLAGS * +* (e.g. configure CPPFLAGS=-I/usr/include)! * +******************************************************************************** +])], $extrapaths) +fi + +if test .$use_tcl = .; then + use_tcl=none +fi + +AM_CONDITIONAL(TCL, [test .$use_tcl != .none]) + +################################## +# check for tk + +AC_MSG_CHECKING([whether to use Tk]) +AC_ARG_WITH(tk, + AS_HELP_STRING([--with-tk=VERSION],[whether to use Tk, and which version to use]), + [], [with_tk=no]) +AC_MSG_RESULT($with_tcl) + +dnl with_tk=no don't use Tk +dnl with_tk=yes try to find a working Tk version, bail out if none is found +dnl otherwise use the specified version +if test .$with_tk != .no; then + # test for X11 + AC_PATH_XTRA + saved_CPPFLAGS=$CPPFLAGS + saved_LDFLAGS=$LDFLAGS + saved_LIBS=$LIBS + CPPFLAGS="$CPPFLAGS $X_CXXFLAGS" + LDFLAGS="$LDFLAGS $X_LIBS" + LIBS="$LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" + AC_LINK_IFELSE([AC_LANG_CALL([],[XOpenDisplay])],[x11_works=yes],[x11_works=no]) + if test $x11_works = no; then + AC_MSG_WARN([could not link against X11, hoping Tk works without]) + CPPFLAGS=$saved_CPPFLAGS + LDFLAGS=$saved_LDFLAGS + LIBS=$saved_LIBS + fi + # now test whether Tk can be found + if test .$with_tk = .yes; then + for version in $TK_VERSION tk8.5 tk8.4 tk8.3 tk8.2 tk; do + ES_ADDPATH_CHECK_LIB($version, Tk_Init, [use_tk=$version], []) + if test .$use_tk != .; then break; fi + done + else + ES_ADDPATH_CHECK_LIB($with_tk, Tk_Init, [use_tk=$with_tk], []) + fi + if test .$use_tk = .; then + case $target_os in + *darwin*) AC_MSG_ERROR( +[If you have Tk installed, make sure that either libtcl.dylib is + in one of the library paths set by LDFLAGS, or that you set the appropriate + apple gcc -framework option in CPPFLAGS and LDFLAGS.]) ;; + *) AC_MSG_FAILURE([Tk library $with_tk not found]) ;; + esac + fi + if test .$use_tk = .tk; then + if test .$use_tcl != .tcl; then + AC_MSG_WARN([You are using a generic Tk version, but a defined Tcl version. This may cause problems. +Try --with-tcl=tcl to also use a generic Tcl version, which may fit better.]) + fi + fi + case $target_os in + *darwin*) extrapaths=/Library/Frameworks/Tk.framework/Headers ;; + *linux*) # path used by *buntu + extrapaths="/usr/include/$version /usr/include/$use_tcl" ;; + (*) ;; + esac + ES_ADDPATH_CHECK_HEADER(tk.h, [], + [AC_MSG_ERROR([Tk headers not found. Please add the include path to CPPFLAGS (e.g. configure CPPFLAGS=-I/usr/include/tcl8.4).]) + ] + ,$extrapaths) + AC_DEFINE_UNQUOTED(TK,$use_tk,[Whether to use Tk]) +else + use_tk=none +fi + cat <@]) +AC_MSG_CHECKING([whether the variable MYCONFIG is set]) +AS_IF([test "x$MYCONFIG" != "x"], [ + AC_MSG_RESULT(yes) + AC_MSG_CHECKING([whether file $MYCONFIG exists]) + if ! test -f $MYCONFIG; then + AC_MSG_RESULT(no) + AC_MSG_ERROR([MYCONFIG file $MYCONFIG does not exist!]) + fi +],[ + AC_MSG_RESULT(no) + MYCONFIG="myconfig.hpp" +]) +AM_CONDITIONAL(MYCONFIG, [test x$MYCONFIG != xmyconfig.hpp]) ################################## # Number of CPUs @@ -567,10 +641,12 @@ AC_CONFIG_FILES([ config/Makefile config/myconfig-sample-header.hpp src/Makefile + src/core/Makefile + src/tcl/Makefile + src/python/espressomd/Makefile tools/Makefile scripts/Makefile testsuite/Makefile - testsuite/configs/Makefile doc/Makefile doc/logo/Makefile doc/ug/Makefile @@ -579,12 +655,15 @@ AC_CONFIG_FILES([ doc/tutorials/Makefile doc/tutorials/01-lennard_jones/Makefile doc/tutorials/02-charged_system/Makefile + doc/tutorials/03-object_in_fluid/Makefile doc/latexit.sh ]) AC_CONFIG_FILES([testsuite/runtest.sh], [chmod 755 testsuite/runtest.sh]) AC_CONFIG_FILES([tools/es_mpiexec], [chmod 755 tools/es_mpiexec]) +AC_CONFIG_FILES([src/python/pypresso], + [chmod 755 src/python/pypresso]) AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ['$(top_srcdir)/src/features.def $(top_srcdir)/config/gen_sampleconfig.py']) AC_CONFIG_COMMANDS([myconfig-sample.hpp], @@ -602,59 +681,86 @@ cat < %% %% This program is free software: you can redistribute it and/or modify diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index a826c755949..b9353ee76b0 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -1,4 +1,6 @@ -# Doxyfile 1.7.3 +# Doxyfile 1.8.2 + +@INCLUDE = $(BUILDDIR)/doxy-features # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -22,8 +24,9 @@ DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. PROJECT_NAME = $(PACKAGE) @@ -33,10 +36,9 @@ PROJECT_NAME = $(PACKAGE) PROJECT_NUMBER = -# 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 quick idea about the purpose of the -# project. Keep the description short. +# 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 quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = "Extensible Simulation Package for Soft Matter Research" @@ -126,7 +128,9 @@ FULL_PATH_NAMES = NO # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the -# path to strip. +# path to strip. Note that you specify absolute paths here, but also +# relative paths, which will be relative from the directory where doxygen is +# started. STRIP_FROM_PATH = @@ -167,7 +171,7 @@ QT_AUTOBRIEF = NO # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. -MULTILINE_CPP_IS_BRIEF = NO +MULTILINE_CPP_IS_BRIEF = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it @@ -195,6 +199,13 @@ TAB_SIZE = 8 ALIASES = +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list @@ -222,16 +233,33 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. - -EXTENSION_MAPPING = cu=C +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, +# and language is one of the parsers supported by doxygen: IDL, Java, +# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, +# C++. For instance to make doxygen treat .inc files as Fortran files (default +# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note +# that for custom extensions you also need to set FILE_PATTERNS otherwise the +# files are not read by doxygen. + +EXTENSION_MAPPING = cu=C++ + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented classes, +# or namespaces to their corresponding documentation. Such a link can be +# prevented in individual cases by by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. + +AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should @@ -253,12 +281,7 @@ CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. +# For Microsoft's IDL there are propget and propput attributes to indicate getter and setter methods for a property. Setting this option to YES (the default) will make doxygen replace the get and set methods by a property in the documentation. This will only work if the methods are indeed getting or setting a simple type. If this is not the case, or you want to show the methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES @@ -277,6 +300,22 @@ DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct @@ -299,10 +338,21 @@ TYPEDEF_HIDES_STRUCT = NO # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols +# corresponding to a cache size of 2^16 = 65536 symbols. SYMBOL_CACHE_SIZE = 0 +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -319,6 +369,11 @@ EXTRACT_ALL = YES EXTRACT_PRIVATE = NO +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. @@ -453,12 +508,11 @@ SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will -# reject a match between the prototype and the implementation of a -# member function even if there is only one candidate or it is obvious -# which candidate to choose by doing a simple string match. By -# disabling STRICT_PROTO_MATCHING doxygen will still accept a match -# between prototype and implementation in such cases. +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO @@ -507,12 +561,6 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = YES - # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. @@ -538,13 +586,23 @@ FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file +# output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -606,8 +664,7 @@ WARN_LOGFILE = # with spaces. INPUT = $(SRCDIR)/src \ - $(SRCDIR)/doc/doxygen \ - background_errors.dox + $(SRCDIR)/doc/doxygen # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -627,7 +684,9 @@ INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.h \ *.c \ - *.cu \ + *.hpp \ + *.cpp \ + *.cu \ *.dox # The RECURSIVE tag can be used to turn specify whether or not subdirectories @@ -636,13 +695,15 @@ FILE_PATTERNS = *.h \ RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should +# The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. -EXCLUDE = acconfig.h +EXCLUDE = acconfig.hpp -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. @@ -654,7 +715,7 @@ EXCLUDE_SYMLINKS = NO # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = src/myconfig-final.h +EXCLUDE_PATTERNS = src/myconfig-final.hpp # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -744,7 +805,7 @@ INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = NO @@ -790,7 +851,7 @@ VERBATIM_HEADERS = YES # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. -ALPHABETICAL_INDEX = NO +ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns @@ -828,7 +889,14 @@ HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a -# standard header. +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = @@ -840,15 +908,34 @@ HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# fine-tune the look of the HTML output. If left blank doxygen will +# generate a default style sheet. Note that it is recommended to use +# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this +# tag will in the future become obsolete. HTML_STYLESHEET = +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional +# user-defined cascading style sheet that is included after the standard +# style sheets created by doxygen. Using this option one can overrule +# certain style aspects. This is preferred over using HTML_STYLESHEET +# since it does not replace the standard style sheet and is therefor more +# robust against future updates. Doxygen will copy the style sheet file to +# the output directory. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images +# Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, @@ -878,19 +965,22 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# page has loaded. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. -HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 @@ -919,9 +1009,9 @@ DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely +# identify the documentation publisher. This should be a reverse domain-name +# style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher @@ -1043,18 +1133,14 @@ GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [0,1..20]) -# that doxygen will group on one line in the generated HTML documentation. -# Note that a value of 0 will completely suppress the enum values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated @@ -1062,13 +1148,17 @@ ENUM_VALUES_PER_LINE = 4 # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES -# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, -# and Class Hierarchy pages using a tree view instead of an ordered list. +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. -USE_INLINE_TREES = NO +ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree @@ -1101,23 +1191,28 @@ FORMULA_TRANSPARENT = YES # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you also need to install MathJax separately and +# output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO -# When MathJax is enabled you need to specify the location relative to -# the HTML output directory using the MATHJAX_RELPATH option. The -# destination directory should contain the MathJax.js script. For -# instance, if the mathjax directory is located at the same level as -# the HTML output directory, then MATHJAX_RELPATH should be -# ../mathjax. The default value points to the mathjax.org site, so you -# can quickly see the result without installing MathJax, but it is -# strongly recommended to install a local copy of MathJax before -# deployment. +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using @@ -1191,6 +1286,13 @@ EXTRA_PACKAGES = LATEX_HEADER = +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references @@ -1224,6 +1326,12 @@ LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1255,7 +1363,7 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's +# Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. @@ -1400,7 +1508,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. +# pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES @@ -1415,7 +1523,7 @@ INCLUDE_PATH = $(INCLUDEDIR) # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = myconfig-sample.h +INCLUDE_FILE_PATTERNS = *.h *.hpp # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of @@ -1425,14 +1533,17 @@ INCLUDE_FILE_PATTERNS = myconfig-sample.h # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = DOXYGEN_RUN FFTW CUDA TK +# PREDEFINED = \ +# DOXYGEN_RUN \ +# FFTW \ +# CUDA \ +# TK -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES -# then this tag can be used to specify a list of macro names that -# should be expanded. The macro definition that is found in the -# sources will be used. Use the PREDEFINED tag if you want to use a -# different macro definition that overrules the definition found in -# the source code. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. EXPAND_AS_DEFINED = @@ -1447,22 +1558,18 @@ SKIP_FUNCTION_MACROS = YES # Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. TAGFILES = @@ -1530,13 +1637,12 @@ HAVE_DOT = $(HAVE_DOT) DOT_NUM_THREADS = 0 -# By default doxygen will write a font called Helvetica to the output -# directory and reference it in all dot files that doxygen generates. -# When you want a differently looking font you can specify the font name -# using DOT_FONTNAME. You need to make sure dot is able to find the font, -# which can be done by putting it in a standard location or by setting the -# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory -# containing the font. +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. DOT_FONTNAME = Helvetica @@ -1545,17 +1651,16 @@ DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 -# By default doxygen will tell dot to use the output directory to look for the -# FreeSans.ttf font (which doxygen will put there itself). If you specify a -# different font using DOT_FONTNAME you can set the path where dot -# can find it using this tag. +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES @@ -1577,6 +1682,15 @@ GROUP_GRAPHS = YES UML_LOOK = NO +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. @@ -1617,7 +1731,7 @@ CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. @@ -1625,10 +1739,21 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, svg, gif or svg. -# If left blank png will be used. +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. -DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = YES # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. @@ -1655,7 +1780,7 @@ MSCFILE_DIRS = # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 100 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable @@ -1673,7 +1798,7 @@ MAX_DOT_GRAPH_DEPTH = 0 # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). -DOT_TRANSPARENT = NO +DOT_TRANSPARENT = YES # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am index 6920ad0182d..095faf2dbed 100644 --- a/doc/doxygen/Makefile.am +++ b/doc/doxygen/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. @@ -17,52 +17,66 @@ # along with this program. If not, see . # EXTRA_DIST = \ - background_errors.sh background_errors.awk \ + gen_doxyconfig.py \ Doxyfile \ - figs/bond_angle.fig \ - figs/bond_angle.gif \ - figs/datastorage.gif \ - figs/dihedral_angle.fig \ - figs/dihedral_angle.gif \ - figs/dihedral_angle.pdf \ - figs/directions.fig \ - figs/directions.gif \ - figs/elc_errordist.gif \ - figs/ghost_cells.fig \ - figs/ghost_cells.gif \ - figs/ghost_communication.fig \ - figs/ghost_communication.gif \ - figs/linked_cells.fig \ - figs/linked_cells.gif \ - figs/logo.png \ - figs/move_to_p_buf.fig \ - figs/move_to_p_buf.gif \ - figs/particles.fig \ - figs/particles.gif + figs/bond_angle.fig \ + figs/bond_angle.gif \ + figs/datastorage.gif \ + figs/dihedral_angle.fig \ + figs/dihedral_angle.gif \ + figs/dihedral_angle.pdf \ + figs/directions.fig \ + figs/directions.gif \ + figs/elc_errordist.gif \ + figs/ghost_cells.fig \ + figs/ghost_cells.gif \ + figs/ghost_communication.fig \ + figs/ghost_communication.gif \ + figs/linked_cells.fig \ + figs/linked_cells.gif \ + figs/logo.png \ + figs/move_to_p_buf.fig \ + figs/move_to_p_buf.gif \ + figs/particles.fig \ + figs/particles.gif .PHONY: doc doxygen doc: doxygen -doxygen: if HAVE_DOXYGEN - SRCDIR=$(srcdir) AWK=$(AWK)\ - $(SHELL) $(srcdir)/background_errors.sh $(top_srcdir)/src/*.c $(top_srcdir)/src/*.h +if HAVE_PYTHON +doxy-features: + $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_doxyconfig.py \ + $(top_srcdir)/src/features.def doxy-features + +doxygen-html: doxy-features + $(AM_V_GEN)\ ESPRESSO_VERSION=`cd $(top_srcdir); sh config/genversion.sh` \ PACKAGE="ESPResSo $$ESPRESSO_VERSION" \ - SRCDIR=$(top_srcdir) INCLUDEDIR=$(top_builddir) \ - HAVE_DOT=$(HAVE_DOT) DOT_PATH=$(DOT_PATH) \ + SRCDIR="$(abs_top_srcdir)" \ + BUILDDIR="$(builddir)" \ + HAVE_DOT="$(HAVE_DOT)" DOT_PATH="$(DOT_PATH)" \ $(DOXYGEN) $(srcdir)/Doxyfile @echo "***************************************************************************" @echo "* The code documentation is now accessible at" @echo "* file://`pwd`/html/index.html" @echo "***************************************************************************" + +doxygen: doxygen-html + else +doxygen: + @echo "Python was not found in your PATH." + @echo "Can't build the code documentation without python." + @echo "Install python and rerun configure." +endif +else +doxygen: @echo "doxygen was not found in your PATH." - @echo "Can't build the code documentation without doxygen." + @echo "Can't build the code documentation without doxygen and python." @echo "Install doxygen and rerun configure." endif -MOSTLYCLEANFILES = background_errors.doxygen background_errors.sorted background_errors.unsorted clean-local: -rm -rf html diff --git a/doc/doxygen/background_errors.awk b/doc/doxygen/background_errors.awk deleted file mode 100644 index 2f99a8e771a..00000000000 --- a/doc/doxygen/background_errors.awk +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (C) 2012,2013 The ESPResSo project -# Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Axel Arnold -# -# This file is part of ESPResSo. -# -# ESPResSo is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# ESPResSo is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Parse the ERROR_SPRINTF lines -/\ *ERROR_SPRINTF.*/ { - # skip define of ERROR_SPRINTF - if($0 == "#define ERROR_SPRINTF sprintf") - nextfile; - out = ""; - count = split($0,s,/\{/); - c = 2; - while(c <= count){ - out = out s[c]; - c = c+1; - } - errcode = substr(out,match(out,/[0-9]{3}/),3); - if(para_match($0) != 0){ - getline; - c = match($0,/[a-zA-Z0-9]/); - out = out substr($0,c,length-c+1); - out = substr(out,1,length(out)-2); - } else { - out = substr(out,1,length(out)-2); - } - filename = FILENAME; - gsub(/.*\//,"",filename); - print "
  • " errcode ": " filename ": " fname "() : \" {" out "
  • "; -} - -# Parse all other lines for the function name -/.*/ { - if(FNR == 1){ - i = 0; - j = 0; - cflag = 0; - } - nocomments(); - i = i + split(" " $0 " ",tmp,/\{/); - i = i - split(" " $0 " ",tmp,/\}/); - if(i == 1 && j == 0) { - if(match($0,/[a-zA-Z0-9_]+\(.*\).*\{/) == 0) - $0 = buf $0; - if(match($0,/[a-zA-Z0-9_]+\(.*\).*\{/) == 0) - $0 = buf1 $0; - x = match($0,/\(/); - $0 = substr($0,1,x-1); - x = split($0,s); - fname = s[x]; - if(match(fname,/\*/) == 1) - fname = substr(fname,2,length(fname)-1); - } - buf1= buf; - buf = $0; - j = i; -} - -# ignore comment lines -function nocomments(){ - tmp0 = ""; - spos = match($0,/\/\*/) - eposold = 0 - epos = match($0,/\*\//) - while(spos > 0 || epos > 0){ - if((spos < epos && spos > 0) || epos == 0){ - if(cflag == 0){ - tmp0 = tmp0 substr($0,eposold+1,spos-eposold-1) - cflag = 1 - } - sub(/\/\*/,"XX",$0) - spos = match($0,/\/\*/) - } - else{ - if(cflag == 1){ - cflag = 0 - eposold = epos+1 - } - sub(/\*\//,"YY",$0) - epos = match($0,/\*\//) - } - } - if(cflag == 0) - tmp0 = tmp0 substr($0,eposold+1,length-eposold) - $0 = tmp0 -} - -function para_match(s){ - return (split(s,a,"(") - split(s,b,")")); -} diff --git a/doc/doxygen/gen_doxyconfig.py b/doc/doxygen/gen_doxyconfig.py new file mode 100644 index 00000000000..eec761206bc --- /dev/null +++ b/doc/doxygen/gen_doxyconfig.py @@ -0,0 +1,59 @@ +# Copyright (C) 2013,2014 The ESPResSo project +# Copyright (C) 2012 Olaf Lenz +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script generates the file doxy-features +# +from __future__ import print_function +import inspect, sys, os +# find featuredefs.py +moduledir = os.path.dirname(inspect.getfile(inspect.currentframe())) +sys.path.append(os.path.join(moduledir, '..', '..', 'src')) +import featuredefs +import time + +if len(sys.argv) != 3: + print("Usage: {} DEFFILE DOXYCONFIG".format(sys.argv[0]), file=sys.stderr) + exit(2) + +deffilename, configfilename = sys.argv[1:3] + +print("Reading definitions from {}...".format(deffilename)) +defs = featuredefs.defs(deffilename) +print("Done.") + +print("Writing {}...".format(configfilename)) +configfile = file(configfilename, 'w'); + +configfile.write("""# WARNING: This file was autogenerated by +# +# {} +# on {} +# Do not modify it or your changes will be overwritten! +# Modify features.def instead. +# +# This file is needed so that doxygen will generate documentation for +# all functions of all features. +PREDEFINED = \\ +""".format(sys.argv[0], time.asctime())) + +for feature in sorted(defs.features): + configfile.write(" {} \\\n".format(feature)) + +configfile.close() +print("Done.") + diff --git a/doc/doxygen/main.dox b/doc/doxygen/main.dox index ef7ace73195..489f52f869d 100644 --- a/doc/doxygen/main.dox +++ b/doc/doxygen/main.dox @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -46,9 +46,9 @@ homepage. The DG explains The script is interpreted on one node, the master node, whereas the other nodes wait for the master node to issue specific actions, i. e. a client-server model is utilized. More details can be found in -\ref communication.h "communication.h". During the actual integration, +\ref communication.hpp "communication.hpp". During the actual integration, however, the communication is done synchronously. For more details -see \ref integrate.c "integrate.c". +see \ref integrate.cpp "integrate.cpp". \section Copyright and License of the Code Documentation Copyright (C) 2010,2011,2012 The ESPResSo project diff --git a/doc/latexit.sh.in b/doc/latexit.sh.in index 88573fb4d1f..5def13f9b7b 100644 --- a/doc/latexit.sh.in +++ b/doc/latexit.sh.in @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2010,2011,2012 Olaf Lenz # # This file is part of ESPResSo. diff --git a/doc/logo/Makefile.am b/doc/logo/Makefile.am index 94d3d9befa0..541187fd9b5 100644 --- a/doc/logo/Makefile.am +++ b/doc/logo/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2011 Olaf Lenz # # This file is part of ESPResSo. diff --git a/doc/logo/cup.vmd b/doc/logo/cup.vmd index a032e56660c..94fba744975 100644 --- a/doc/logo/cup.vmd +++ b/doc/logo/cup.vmd @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright diff --git a/doc/logo/cup_espresso.tcl b/doc/logo/cup_espresso.tcl index e7279921b29..835479b3647 100755 --- a/doc/logo/cup_espresso.tcl +++ b/doc/logo/cup_espresso.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/logo/generate_animation.sh b/doc/logo/generate_animation.sh index 6543e860276..1a78d2b5da3 100755 --- a/doc/logo/generate_animation.sh +++ b/doc/logo/generate_animation.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2012,2013 Olaf Lenz # # This file is part of ESPResSo. diff --git a/doc/logo/generate_pixmaps.sh b/doc/logo/generate_pixmaps.sh index b44d0982782..76053a21883 100755 --- a/doc/logo/generate_pixmaps.sh +++ b/doc/logo/generate_pixmaps.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2012,2013 Olaf Lenz # # This file is part of ESPResSo. diff --git a/doc/misc/description.txt b/doc/misc/description.txt index 8eab071257d..88097ed0857 100644 --- a/doc/misc/description.txt +++ b/doc/misc/description.txt @@ -1,4 +1,4 @@ -Copyright (C) 2012,2013 The ESPResSo project +Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/doc/misc/python.tex b/doc/misc/python.tex index e8507872ca2..0ee70bf7ca9 100644 --- a/doc/misc/python.tex +++ b/doc/misc/python.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2011,2012,2013 The ESPResSo project +% Copyright (C) 2011,2012,2013,2014 The ESPResSo project % % This file is part of ESPResSo. % diff --git a/doc/tutorials/01-lennard_jones/01-lennard_jones.tex b/doc/tutorials/01-lennard_jones/01-lennard_jones.tex index 748262bc7c2..e319f55a270 100644 --- a/doc/tutorials/01-lennard_jones/01-lennard_jones.tex +++ b/doc/tutorials/01-lennard_jones/01-lennard_jones.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -394,7 +394,8 @@ \subsection{Comparisons and looping} {\small\vspace{0,2cm} \begin{lstlisting}[numbers=none] -set i 0 foreach j $x {\ +set i 0 +foreach j $x {\ puts "$j is item number $i in list x"; incr i} \end{lstlisting}\vspace{0,2cm} } @@ -418,7 +419,7 @@ \subsection{Comparisons and looping} llength $x ; # get the size of list x (number of elements) lappend x 5 ; # add a new member end of list puts "x is {$x}" ; # print list again -set $x [linsert $x 3 3a] ; # insert an element "3a" at index 3 +set x [linsert $x 3 3a] ; # insert an element "3a" at index 3 puts "x is {$x}" ; # print list again \end{lstlisting} }\vspace{0,2cm} diff --git a/doc/tutorials/01-lennard_jones/Makefile.am b/doc/tutorials/01-lennard_jones/Makefile.am index 99c88887612..5da07156598 100644 --- a/doc/tutorials/01-lennard_jones/Makefile.am +++ b/doc/tutorials/01-lennard_jones/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. diff --git a/doc/tutorials/01-lennard_jones/scripts/blockfile_read.tcl b/doc/tutorials/01-lennard_jones/scripts/blockfile_read.tcl index 75f77131f42..542762219b9 100755 --- a/doc/tutorials/01-lennard_jones/scripts/blockfile_read.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/blockfile_read.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/scripts/lj_functions.tcl b/doc/tutorials/01-lennard_jones/scripts/lj_functions.tcl index 04ce09e1b06..1b8c56f8c43 100755 --- a/doc/tutorials/01-lennard_jones/scripts/lj_functions.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/lj_functions.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/scripts/lj_tutorial.tcl b/doc/tutorials/01-lennard_jones/scripts/lj_tutorial.tcl index f62a86ede72..38233fd2bcf 100755 --- a/doc/tutorials/01-lennard_jones/scripts/lj_tutorial.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/lj_tutorial.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/scripts/msd.tcl b/doc/tutorials/01-lennard_jones/scripts/msd.tcl index 94b5589e101..50d609fe16b 100755 --- a/doc/tutorials/01-lennard_jones/scripts/msd.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/msd.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/scripts/rdf.tcl b/doc/tutorials/01-lennard_jones/scripts/rdf.tcl index 3772c1a4fec..32fa80149d5 100755 --- a/doc/tutorials/01-lennard_jones/scripts/rdf.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/rdf.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/scripts/vacf.tcl b/doc/tutorials/01-lennard_jones/scripts/vacf.tcl index 2b03f49a80e..d892790b729 100755 --- a/doc/tutorials/01-lennard_jones/scripts/vacf.tcl +++ b/doc/tutorials/01-lennard_jones/scripts/vacf.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/blockfile_read.tcl b/doc/tutorials/01-lennard_jones/solutions/blockfile_read.tcl index 75f77131f42..542762219b9 100755 --- a/doc/tutorials/01-lennard_jones/solutions/blockfile_read.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/blockfile_read.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/lj_functions.tcl b/doc/tutorials/01-lennard_jones/solutions/lj_functions.tcl index 04ce09e1b06..1b8c56f8c43 100755 --- a/doc/tutorials/01-lennard_jones/solutions/lj_functions.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/lj_functions.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/lj_tutorial.tcl b/doc/tutorials/01-lennard_jones/solutions/lj_tutorial.tcl index 5502419e06c..b5d70306fb5 100755 --- a/doc/tutorials/01-lennard_jones/solutions/lj_tutorial.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/lj_tutorial.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/msd.tcl b/doc/tutorials/01-lennard_jones/solutions/msd.tcl index 623940a8ea3..410d37dbb39 100755 --- a/doc/tutorials/01-lennard_jones/solutions/msd.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/msd.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/rdf.tcl b/doc/tutorials/01-lennard_jones/solutions/rdf.tcl index 3772c1a4fec..32fa80149d5 100755 --- a/doc/tutorials/01-lennard_jones/solutions/rdf.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/rdf.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/vacf.tcl b/doc/tutorials/01-lennard_jones/solutions/vacf.tcl index 3e2d76e44dc..0efe3255976 100755 --- a/doc/tutorials/01-lennard_jones/solutions/vacf.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/vacf.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/01-lennard_jones/solutions/vacf_vec.tcl b/doc/tutorials/01-lennard_jones/solutions/vacf_vec.tcl index d0d9cfed647..8a617a2945d 100755 --- a/doc/tutorials/01-lennard_jones/solutions/vacf_vec.tcl +++ b/doc/tutorials/01-lennard_jones/solutions/vacf_vec.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/02-charged_system/02-charged_system.tex b/doc/tutorials/02-charged_system/02-charged_system.tex index 13b9c4b90a2..c80e08f7e10 100644 --- a/doc/tutorials/02-charged_system/02-charged_system.tex +++ b/doc/tutorials/02-charged_system/02-charged_system.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -395,6 +395,50 @@ \section{Analysis} was one of the main reasons why we decided to use a script language for controlling the simulation core. +\section{Using the MEMD algorithm} + +\es{} provides a variety of different electrostatics solvers. So far, +we have been introduced to P$^3$M, but in this section we will try +something new. A fairly recent addition to the family of electrostatics +solvers is the "Maxwell Equations Molecular Dynamics" (MEMD) algorithm. +To use it, two parameters have to be set: A mesh size, and a method +parameter called \verb|f_mass|, which can be estimated following the +formula in the \es{} user guide. In this example, a good estimate for +the mesh size is 12, but this can be varied, affecting speed and +accuracy of the algorithm. + +The MEMD algorithm relies on a very precise spatial distribution of +the particles across processors, and will therefore currently not work +with Verlet lists. Since those are switched on by default, they will +have to be turned off manually. + +\begin{tclcode} + cellsystem domain_decomposition -no_verlet_list +\end{tclcode} + + +Other than that, you will have to replace the setup of the P$^3$M +interaction with an according MEMD call. + +\begin{tclcode} + set memd_mesh 12 + set f_mass [expr 100.0*pow( ([setmd time_step]*$memd_mesh/$box_l),2.0)] + inter coulomb 10.0 memd $f_mass $memd_mesh +\end{tclcode} + + +Be sure to comment out the P$^3$M part of your script, otherwise +you will have both algorithms running at the same time, resulting +in twice the electrostatic force. In the example script included +within the \es{} code, there is already an \verb|if|-construct +provided and you can switch between the methods at the very top +of the script. + +You can copy the results from your completed tasks so far to a different +filename (e.g.~\verb|rdf_p3m.data|) for comparison. Then, just +run the simulation and analysis again, and compare the speed and +resulting radial distribution function of the two methods. + \section{Partially periodic boundary conditions} \begin{figure}[t] diff --git a/doc/tutorials/02-charged_system/Makefile.am b/doc/tutorials/02-charged_system/Makefile.am index 960de222d11..98de59ded40 100644 --- a/doc/tutorials/02-charged_system/Makefile.am +++ b/doc/tutorials/02-charged_system/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. diff --git a/doc/tutorials/02-charged_system/figures/nacl.plot b/doc/tutorials/02-charged_system/figures/nacl.plot index 8d1e901618f..d981858ba54 100644 --- a/doc/tutorials/02-charged_system/figures/nacl.plot +++ b/doc/tutorials/02-charged_system/figures/nacl.plot @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # # This file is part of ESPResSo. # diff --git a/doc/tutorials/02-charged_system/scripts/analyze.tcl b/doc/tutorials/02-charged_system/scripts/analyze.tcl index 8f034c13838..aac67c85487 100644 --- a/doc/tutorials/02-charged_system/scripts/analyze.tcl +++ b/doc/tutorials/02-charged_system/scripts/analyze.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/tutorials/02-charged_system/scripts/analyze_rho.tcl b/doc/tutorials/02-charged_system/scripts/analyze_rho.tcl index 1c1bfb6eaee..4bb3afe5684 100644 --- a/doc/tutorials/02-charged_system/scripts/analyze_rho.tcl +++ b/doc/tutorials/02-charged_system/scripts/analyze_rho.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/tutorials/02-charged_system/scripts/replay.tcl b/doc/tutorials/02-charged_system/scripts/replay.tcl index e5d15c72786..8e6fbc65e31 100644 --- a/doc/tutorials/02-charged_system/scripts/replay.tcl +++ b/doc/tutorials/02-charged_system/scripts/replay.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/tutorials/02-charged_system/scripts/sim.tcl b/doc/tutorials/02-charged_system/scripts/sim.tcl index b5a74b536c7..ed35bfd3185 100644 --- a/doc/tutorials/02-charged_system/scripts/sim.tcl +++ b/doc/tutorials/02-charged_system/scripts/sim.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # @@ -17,13 +17,22 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -set n_part 200; set density 0.7 +# + +# Set system parameters +set n_part 200 +set density 0.7 set box_l [expr pow($n_part/$density,1./3.)] +# Select electrostatics method +set method "p3m" +#set method "memd" + +# Setup system geometry in Espresso setmd box_l $box_l $box_l $box_l setmd periodic 1 1 1 +# Place particles set q 1; set type 0 for {set i 0} { $i < $n_part } {incr i} { set posx [expr $box_l*[t_random]] @@ -33,16 +42,42 @@ for {set i 0} { $i < $n_part } {incr i} { part $i pos $posx $posy $posz q $q type $type } +# Simulation parameters setmd time_step 0.01; setmd skin 0.3 +# Thermostat set temp 1; set gamma 1 thermostat langevin $temp $gamma + +# Lennard-Jones interactions set sig 1.0; set cut [expr 1.12246*$sig] set eps 1.0; set shift [expr 0.25*$eps] inter 0 0 lennard-jones $eps $sig $cut $shift 0 inter 1 0 lennard-jones $eps $sig $cut $shift 0 inter 1 1 lennard-jones $eps $sig $cut $shift 0 -puts [inter coulomb 10.0 p3m tunev2 accuracy 1e-3 mesh 32] + + +# Check if electrostatics method is clear... +if { ![ info exists method ] } { + puts "Please select an electrostatics method in the script." + exit +} + +# Distinguish between different methods +if { $method == "p3m" } { + puts [inter coulomb 10.0 p3m tunev2 accuracy 1e-3 mesh 32] +} elseif { $method == "memd" } { + # MEMD need no Verlet lists! + cellsystem domain_decomposition -no_verlet_list + set memd_mesh 12 + set f_mass [expr 100.0*pow( ([setmd time_step]*$memd_mesh/$box_l) , 2.0 ) ] + puts "memd parameters: mesh=$memd_mesh, f_mass=$f_mass" + puts [inter coulomb 10.0 memd $f_mass $memd_mesh] +} else { + puts "Electrostatics method must be one of 'memd' or 'p3m'." + exit +} + set p3m_params [inter coulomb] foreach f $p3m_params { eval inter $f } diff --git a/doc/tutorials/02-charged_system/scripts/sim_charged_walls.tcl b/doc/tutorials/02-charged_system/scripts/sim_charged_walls.tcl index bc2671f630a..ee6d0003adf 100644 --- a/doc/tutorials/02-charged_system/scripts/sim_charged_walls.tcl +++ b/doc/tutorials/02-charged_system/scripts/sim_charged_walls.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/tutorials/02-charged_system/scripts/sim_walls.tcl b/doc/tutorials/02-charged_system/scripts/sim_walls.tcl index 13f9dc6a7ab..afa9336a25e 100644 --- a/doc/tutorials/02-charged_system/scripts/sim_walls.tcl +++ b/doc/tutorials/02-charged_system/scripts/sim_walls.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/doc/tutorials/03-object_in_fluid/03-object_in_fluid.tex b/doc/tutorials/03-object_in_fluid/03-object_in_fluid.tex new file mode 100755 index 00000000000..bb2bb1d3ad0 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/03-object_in_fluid.tex @@ -0,0 +1,338 @@ +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project +% Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 +% Max-Planck-Institute for Polymer Research, Theory Group +% +% This file is part of ESPResSo. +% +% ESPResSo is free software: you can redistribute it and/or modify it +% under the terms of the GNU General Public License as published by the +% Free Software Foundation, either version 3 of the License, or (at your +% option) any later version. +% +% ESPResSo is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . +% +\documentclass[ +a4paper, % paper size +11pt, % font size +twoside, % two sided +footsepline, % add a line to separate the footer +headsepline, % add a line to separate the header +headexclude, % header does not belong to the text +footexclude, % footer does not belong to the text +pagesize, % set the pagesize in a DVI document +]{scrartcl} + +\include{common} +\usepackage[export]{adjustbox} + +\begin{document} +\esptitlehead +\title{Tutorial: Object in fluid +\ifdefined\esversion +\thanks{For \es \esversion} +\fi +} + +\maketitle +\tableofcontents + +\section{Introduction} + +This tutorial introduces some of the features of \es\ module Object in fluid (OIF). Even though \es\ was not primarily intended to work with closed objects, it appears very suitable when one wants to model closed objects with elastic properties, especially if they are immersed in a moving fluid. Here we offer a step by step Tcl tutorial that will show you how to use this module. The resulting code can be run using \verb|Espresso | from the \es source directory. It produces .vtk files that can then be visualized using Paraview.\\ + +The OIF module was developed for simulations of red blood cells flowing through microfluidic devices and therefore the elasticity features were designed with this application in mind. However, they are completely tunable and can be modified easily to allow the user model any elastic object moving in fluid flow. + +\begin{figure}[htbp] + \hfill + \begin{minipage}[t]{.32\textwidth} + + \includegraphics[width=4.3cm,right]{figures/1.png} + + \end{minipage} + \hfill + \begin{minipage}[t]{.32\textwidth} + \begin{center} + \includegraphics[width=4.2cm]{figures/2.png} + \end{center} + \end{minipage} + \hfill + \begin{minipage}[t]{.32\textwidth} + + \includegraphics[width=4.2cm,left]{figures/3.png} + + \end{minipage} + \hfill +\end{figure} + +\section{Basic set up} + +In order to be able to work with elastic objects, one needs to configure \es with the following options in myconfig.hpp:\\ +\#define LB (or \#define LB\_GPU)\\ +\#define LB\_BOUNDARIES (or \#define LB\_BOUNDARIES\_GPU)\\ +\#define EXTERNAL\_FORCES\\ +\#define MASS\\ +\#define CONSTRAINTS\\ +\#define BOND\_ANGLE\\ +\#define VOLUME\_FORCE\\ +\#define AREA\_FORCE\_GLOBAL\\ + +To create an elastic object, we also need a triangulation of the surface of this object. Sample sphere and red blood cell are provided in the directory scripts/input. User can create her own in gmsh, salome or any other meshing software. The required format is as follows:\\ + +The file \verb|some_nodes.dat| should contain triplets of floats (one triplet per line), where each triplet represents the x, y and z coordinates of one node of the surface triangulation. No additional information should be written in this file, so this means that the number of lines equals the number of surface nodes. The coordinates of the nodes should be specified in such a way that the approximate center of mass of the object corresponds to the origin (0,0,0). This is for convenience when placing the objects at desired locations later.\\ + +The file \verb|some_triangles.dat| should also contain triplets of numbers, this time integers. These refer to the IDs of the nodes in the \verb|some_nodes.dat| file and specify which three nodes form a triangle together. Please, note that the nodes' IDs start at 0, i.e. the node written in the first line of \verb|some_nodes.dat| has ID 0, the node in the second line, has ID 1, etc.\\ + +We can start our script by specifying these files:\\ +\begin{tclcode} + set fileNodes "input/cell_nodes.dat" + set fileTriangles "input/cell_triangles.dat" +\end{tclcode} +\vspace{0 mm} + +And continue with setting up some molecular dynamics parameters of the simulation engine:\\ +\begin{tclcode} + setmd time_step 0.1 + setmd skin 0.4 + thermostat off +\end{tclcode} +\vspace{0 mm} + +The skin depth \verb|skin| is a parameter for the link--cell system, which tunes its performance, but will not be discussed here in detail. The one important thing a user needs to know about it is that it has to be strictly less than half the grid size.\\ + +Next we need to specify the simulation box:\\ +\begin{tclcode} + set boxX 50 + set boxY 22 + set boxZ 20 + setmd box_l $boxX $boxY $boxZ +\end{tclcode} +\vspace{0 mm} + +and define the walls and boundaries. For clarity, these have been placed in a separate file \verb|boundaries.tcl|, which we'll go over in the next subsection. The source code of this boundaries script is included using the command\\ +\begin{tclcode} + source boundaries.tcl +\end{tclcode} +\vspace{0 mm} + +but note, that the boundaries could have been specified directly at this point.\\ + +Now comes the initialization of OIF module using\\ +\begin{tclcode} + oif_init +\end{tclcode} +\vspace{0 mm} + +This command creates all the global variables and lists needed for templates and objects that will come afterwards. Elastic objects cannot be created directly. Each one has to correspond to a template that has been created first. The advantage of this approach is clear when creating many objects of the same type that only differ by e.g. position or rotation, because in such case it significantly speeds up the creation of objects that are just copies of the same template. The following command creates a template\\ +\begin{tclcode} + oif_create_template template-id 0 nodes-file $fileNodes \ + triangles-file $fileTriangles stretch 3.0 3.0 3.0 \ + ks 0.05 kb 0.01 kal 0.01 kag 0.01 kv 10.0 +\end{tclcode} +\vspace{0 mm} + +Each template has to have a unique ID specified using keyword \verb|template-id|. The IDs should start at 0 and increase consecutively. Another two mandatory arguments are \verb|nodes-file| and \verb|triangles-file| that specify data files with desired triangulation. All other arguments are optional: \verb|stretch| defines stretching in x, y, z direction and \verb|ks, kb, kal, kag, kv| specify the elastic properties of the object (stretching, bending, local area conservation, global area conservation, volume conservation respectively). The keywords can come in any order.\\ + +Once we have the template, we can start creating objects:\\ +\begin{tclcode} + oif_add_object object-id 0 template-id 0 origin 5 15 5 \ + rotate 0 0 [expr $pi/2] part-type 0 mass 1 + oif_add_object object-id 1 template-id 0 origin 5 5 15 \ + rotate 0 0 0 part-type 1 mass 1 +\end{tclcode} +\vspace{0 mm} + +Each object has to have a unique ID specified using keyword \verb|object-id|. The IDs should start at 0 and increase consecutively. Another three mandatory arguments are \verb|template-id|, \verb|origin| and \verb|part-type|. \verb|template-id| specifies which template will be used for this object. \verb|origin| gives placement of object's center in the simulation box. And \verb|part-type| assigns the particle type to all nodes of the given object. It is generally a good idea to specify a different \verb|part-type| for different objects since it can be then used to set up interactions among objects. The optional arguments are \verb|rotate| and \verb|mass|. Rotate takes three arguments - angles in radians - that determine how much the object is rotated around the x, y, z axes. (Note: if you want to use the variable \verb|$pi|, you need to specify it beforehand, i.e. \verb|set pi 3.14159265359|). The optional keyword \verb|mass| takes one value and this mass will be assigned to each surface node of the object.\\ + +The interactions among objects are specified using\\ +\begin{tclcode} + inter 0 1 soft-sphere 0.005 2.0 0.3 0.0 +\end{tclcode} +\vspace{0 mm} + +where after \verb|inter| come the particle types of the two objects and \verb|soft-sphere| with four parameters stands for the "bouncy" interactions between the objects, once they come sufficiently close. (There are also other interaction types available in \es.) Similar interaction is defined with the boundaries:\\ +\begin{tclcode} + inter 0 10 soft-sphere 0.0001 1.2 0.1 0.0 + inter 1 10 soft-sphere 0.0001 1.2 0.1 0.0 +\end{tclcode} +\vspace{0 mm} + +Here 10 (the second number after keyword \verb|inter|) is the the type of all boundaries and obstacles. + +Finally, we specify the fluid, either by\\ +\begin{tclcode} + lbfluid grid 1 dens 1.0 visc 1.5 tau 0.1 friction 0.5 +\end{tclcode} +\vspace{0 mm} + +or\\ + \begin{tclcode} + lbfluid gpu grid 1 dens 1.0 visc 1.5 tau 0.1 friction 0.5 +\end{tclcode} +\vspace{0 mm} + +depending on the available computational resources. (The GPU computation can be two orders of magnitude faster than the CPU.)\\ + +\subsection*{Specification of boundaries} +As was previously mentioned, all the boundaries and obstacles are conveniently grouped in separate file \verb|boundaries.tcl|. This file contains two output procedures - one writes a rhomboid, another a cylinder into a .vtk file for later visualization. Below these procedures, one can specify the geometry of the channel. Here we only go over rhomboids and cylinders, but note that other boundary types are available in \es.\\ + +The rhomboid is a 3D structure specified by one corner and three vectors originating from this corner. It can be a box and in that case the three vectors give the length, width and height. However, there is no requirement that the vectors are perpendicular (to each other or to the walls). It is a standard \es command.\\ + +Cylinder is specified by its center, radius, normal vector, and length. The length is the distance from center to either base, therefore it is only half the total "height". Note: the included \verb|boundaries.tcl| script can only output cylinder with (0,0,1) normal. \\ + +\begin{figure}[htbp] + \hfill + \begin{minipage}[t]{.22\textwidth} + \includegraphics[width=2.3cm,right]{figures/cylinder.png} + %\caption{Cylinder dimensions} + \end{minipage} + \hfill + \begin{minipage}[t]{.45\textwidth} + \begin{center} + \includegraphics[width=5.2cm]{figures/rhomboid.png} + %\caption{Rhomboid dimensions} + \end{center} + \end{minipage} + \hfill + \begin{minipage}[t]{.3\textwidth} + \includegraphics[width=4cm,left]{figures/channel.png} + %\caption{Channel geometry} + \end{minipage} + \hfill +\end{figure} + +Each wall and obstacle has to be specified separately as a fluid boundary and as a particle constraint. The former enters the simulation as a boundary condition for the fluid, the latter serves for particle-boundary interactions. Sample cylinder and rhomboid can then be defined as follows:\\ + \begin{tclcode} +# obstacle cylinder1 +set cX 16; set cY 17; set cZ 10; +set nX 0; set nY 0; set nZ 1; +set L 9 +set r 3 +set cylFile "output/cylinder1.vtk" +set n 20 +output_vtk_cylinder $cX $cY $cZ $nX $nY $nZ $r $L $n $cylFile +constraint cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r \ +length $L direction 1 type 10 +lbboundary cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r \ +length $L direction 1 + \end{tclcode} +\vspace{0 mm} + + \begin{tclcode} +# obstacle rhomboid1 +set corX 25; set corY 1; set corZ 1; +set aX 5; set aY 0; set aZ 0; +set bX 0; set bY 20; set bZ 0; +set cX 0; set cY 0; set cZ 10; +set rhomFile "output/rhomboid1.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ \ +$cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ \ +c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ \ +c $cX $cY $cZ direction 1 + \end{tclcode} + \vspace{0 mm} + +Note that the cylinder also has an input parameter \verb|n|. This specifies number of rectangular faces on the side. The \verb|direction 1| determines that the fluid is on the "outside".\\ + +To create a rectangular channel, there are two possibilities. Either the walls are specified as the \verb|lbboundary wall| and \verb|constraint wall| with normal and distance from origin. Alternatively, the channel can be built using four flat rhomboids as can be seen in the picture above.\\ + +Another way how to work with boundaries, is to set them up using \verb|lbboundary| and \verb|constraint|, make sure each boundary has a different type (the object-boundary interactions have to be modified accordingly) and then following command can be used for output of all of them at once:\\ + \begin{tclcode} +lbfluid print vtk boundary "boundary.vtk" + \end{tclcode} + \vspace{0 mm} + +The differences in visualization in these two approaches are discussed later in this tutorial. + +\section{Running the simulation} +One last thing needed before we can proceed to the main part of the simulation code, is to get the fluid moving. This can be done by setting the velocity of the individual \verb|lbnodes| on one side of the channel and letting the flow develop, but this is not a very convenient setup because it has to be done at every integration step and the tcl-C communication slows down the computation. The alternative is to set up a wall/rhomboid with velocity. This does not mean that the physical boundary is moving, but rather that it transfers specified momentum onto the fluid. This can be done using the command\\ +\begin{tclcode} +lbboundary rhomboid velocity 0.01 0 0 corner 0 1 1 a 1 1 1 \ +b 0 [expr $boxY-1] 1 c 0 1 [expr $boxZ-1] direction 1 + \end{tclcode} + \vspace{0 mm} + +Now we can integrate the system:\\ +\begin{tclcode} +set steps 200 +set counter 0 +while { $counter<150} { + set cycle [expr $counter*$steps] + puts "cycle $cycle" + integrate $steps + incr counter +} + \end{tclcode} + \vspace{0 mm} + +The script will print out a cycle number every 200 MD steps. + +\section{Writing out data} + +We have already discussed how to output the walls and obstacles for later visualization, but we also need output for fluid and objects. The fluid output is done using the standard \es command\\ +\begin{tclcode} + lbfluid print vtk velocity "output/fluid$cycle.vtk" + \end{tclcode} + \vspace{0 mm} + + and for object output we have\\ + \begin{tclcode} + oif_object_output object-id 0 vtk-pos "output/output_file.vtk" + \end{tclcode} + \vspace{0 mm} + +This will save the positions of all surface nodes into the .vtk output file. The modified integration loop now looks like this:\\ +\begin{tclcode} +while { $counter<150} { + set cycle [expr $counter*$steps] + puts "cycle $cycle" + lbfluid print vtk velocity "output/fluid$cycle.vtk" + oif_object_output object-id 0 vtk-pos "output/cell0_$cycle.vtk" + oif_object_output object-id 1 vtk-pos "output/cell1_$cycle.vtk" + integrate $steps + incr counter +} + \end{tclcode} + \vspace{0 mm} + + where each object has its own output file and a new file is written every \verb|$steps| steps. + +\section{Visualization} +For visualization we suggest the free software Paraview. All .vtk files (boundaries, fluid, objects at all time steps) can be loaded at the same time. The loading is a two step process, because only after pressing the Apply button, are the files actually imported. Using the eye icon to the left of file names, one can turn on and off the individual objects and/or boundaries. It is also possible to do this when one imports all the boundaries from a single .vtk file (created using command \verb|lbfluid print vtk| \verb|boundary| \verb|"boundary.vtk"|), however only when each boundary had been assigned a unique type number and is then selected in the bottom left menu by this number.\\ + +Fluid can be visualized using Filters/Alphabetical/Glyph (or other options from this menu. Please, refer to the Paraview user's guide for more details).\\ + +Note, that Paraview does not automatically reload the data if they have been changed in the input folder, but a useful thing to know is that the created filters can be "recycled". Once you delete the old data, load the new data and right-click on the existing filters, you can re-attach them to the new data.\\ + +It is a good idea to output and visualize the boundaries and objects just prior to running the actual simulation, to make sure that the geometry is correct and no objects intersect with any boundaries. This would cause "particle out of range" error and crash the simulation.\\ + +\section{Other available OIF commands} + +The OIF commands that we have covered so far are\\ + \begin{tclcode} +oif_init +oif_create_template +oif_add_object +oif_object_output + \end{tclcode} + \vspace{0 mm} + +Here we want to describe the rest of the currently available OIF commands and note that there are more still being added. We would be pleased to hear from you about any suggestions on further functionality.\\ + +\verb|oif_info| prints out information about all global variables, currently available templates and added objects.\\ + +\verb|oif_mesh_analyze| takes two mandatory arguments: \verb|nodes-file nodes.dat| and \verb|triangles-file triangles.dat|. Their required format is discussed at the beginning of this document, in Basic set up section. The three optional arguments: \verb|orientation|, \verb|repair| and \verb|flip| determine what will be done with the mesh. \verb|orientation| checks whether all triangles of the surface mesh are properly oriented, \verb|repair| corrects the orientation of those that are not and \verb|flip| flips the orientation of all triangles in the triangulation.\\ + +\verb|oif_object_analyze| has only one mandatory argument, \verb|object-id 0|, and the optional arguments specify what function will be performed. \verb|origin| outputs the location of the center of the object, \verb|pos-bounds b-name| computes the six extremal coordinates of the object. More precisely, runs through the all mesh points and remembers the minimal and maximal x-coordinate, y-coordinate and z-coordinate. If \verb|b-name| is the name of one of these: \verb|z-min, z-max, x-min, x-max, y-min, y-max| then the procedure returns one number according to the value of \verb|b-name|. If b-name is \verb|all|, then the procedure returns a list of six numbers, namely Xmin, Xmax, Ymin, Ymax, Zmin, Zmax. \verb|volume| outputs the volume of the object, \verb|surface-area| outputs the surface of the object and \verb|velocity| outputs the average velocity of the object by calculating the average velocity of object's mesh points.\\ + +\verb|oif_object_set| also has only one mandatory argument \verb|object-id 0|. The optional arguments are: \verb|force valX valY valZ|, which sets the force vector (valX,valY,valZ) to all mesh nodes of the object. Setting is done using \es command \verb|part $i set| \verb|ext_force $valX $valY $valZ|. Note, that this command sets the external force in each integration step. So if you want to use the external force only in one iteration, you need to set zero external force in the following integration step. \verb|origin posX posY posZ| moves the object in such a way that the origin has coordinates posX posY posZ. \verb|mesh-nodes "mesh-nodes.dat"| deforms the object in such a way that its origin stays unchanged, however the relative positions of the mesh points are taken from file mesh-nodes.dat. (The file mesh-nodes.dat should contain the coordinates of the mesh points with the origin's location at (0,0,0).) The command also checks whether number of lines in the mesh-nodes.dat file is the same as the corresponding value from oif\_nparticles. \verb|kill-motion| stops all the particles in the object (analogue to the \verb|kill_motion| command in \es).\\ + +More information can be found in the OIF documentation and on our website www.cell-in-fluid.weebly.com. +\end{document} diff --git a/doc/tutorials/03-object_in_fluid/Makefile.am b/doc/tutorials/03-object_in_fluid/Makefile.am new file mode 100644 index 00000000000..5aedea67f09 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/Makefile.am @@ -0,0 +1,60 @@ +# Copyright (C) 2014 Olaf Lenz +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +BASENAME=03-object_in_fluid +EXTRA_DIST=$(BASENAME).pdf \ + scripts/boundaries.tcl \ + scripts/simulation.tcl \ + scripts/input/cell_nodes.dat \ + scripts/input/cell_triangles.dat \ + scripts/input/sphere_nodes.dat \ + scripts/input/sphere_triangles.dat + +if DEVEL_SRC +tutorial_TEXFILES=$(BASENAME).tex + +tutorial_FIGURES = \ + figures/1.png \ + figures/2.png \ + figures/3.png \ + figures/channel.png \ + figures/cylinder.png \ + figures/rhomboid.png + +tutorial_FILES = \ + $(tutorial_TEXFILES) \ + $(tutorial_FIGURES) + +.PHONY: doc $(BASENAME).pdf + +doc: tutorials +tutorials: $(BASENAME).pdf +$(BASENAME).pdf: $(tutorial_FILES) ../common/common.tex +if HAVE_LATEX + sh ../../latexit.sh $(srcdir):$(srcdir)/../common $(BASENAME) +else + @echo "No complete LaTeX-installation was not found in your PATH." + @echo "Can't build the tutorial without pdflatex, makeindex and bibtex." + @echo "Install these and rerun configure." +endif + +CLEANFILES = $(BASENAME).pdf +MOSTLYCLEANFILES = \ + *.aux *.aux.bak\ + $(BASENAME).idx $(BASENAME).idx.bak $(BASENAME).ilg $(BASENAME).ind \ + $(BASENAME).log $(BASENAME).out $(BASENAME).toc \ + $(BASENAME).blg $(BASENAME).bbl +endif diff --git a/doc/tutorials/03-object_in_fluid/figures/1.png b/doc/tutorials/03-object_in_fluid/figures/1.png new file mode 100755 index 00000000000..6ad71a0d069 Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/1.png differ diff --git a/doc/tutorials/03-object_in_fluid/figures/2.png b/doc/tutorials/03-object_in_fluid/figures/2.png new file mode 100755 index 00000000000..edf1298cc41 Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/2.png differ diff --git a/doc/tutorials/03-object_in_fluid/figures/3.png b/doc/tutorials/03-object_in_fluid/figures/3.png new file mode 100755 index 00000000000..cf445ca4d62 Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/3.png differ diff --git a/doc/tutorials/03-object_in_fluid/figures/channel.png b/doc/tutorials/03-object_in_fluid/figures/channel.png new file mode 100755 index 00000000000..c20cf824a4d Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/channel.png differ diff --git a/doc/tutorials/03-object_in_fluid/figures/cylinder.png b/doc/tutorials/03-object_in_fluid/figures/cylinder.png new file mode 100755 index 00000000000..4c228f904af Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/cylinder.png differ diff --git a/doc/tutorials/03-object_in_fluid/figures/rhomboid.png b/doc/tutorials/03-object_in_fluid/figures/rhomboid.png new file mode 100755 index 00000000000..99bbc768f73 Binary files /dev/null and b/doc/tutorials/03-object_in_fluid/figures/rhomboid.png differ diff --git a/doc/tutorials/03-object_in_fluid/scripts/boundaries.tcl b/doc/tutorials/03-object_in_fluid/scripts/boundaries.tcl new file mode 100644 index 00000000000..5d50bec0144 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/boundaries.tcl @@ -0,0 +1,244 @@ +# Copyright (C) 2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +proc output_vtk_rhomboid { args } { + + # expected parameters: + # corX, corY, corZ - corner + # aX, aY, aZ - length vector + # bX, bY, bZ - width vector + # cX, cY, cZ - height vector + # rhomFile - file to write into + + set corX [lindex $args 0] + set corY [lindex $args 1] + set corZ [lindex $args 2] + set aX [lindex $args 3] + set aY [lindex $args 4] + set aZ [lindex $args 5] + set bX [lindex $args 6] + set bY [lindex $args 7] + set bZ [lindex $args 8] + set cX [lindex $args 9] + set cY [lindex $args 10] + set cZ [lindex $args 11] + set rhomFile [lindex $args 12] + + # write output + set f [open $rhomFile "w"] + + puts $f "# vtk DataFile Version 3.0" + puts $f "Data" + puts $f "ASCII" + puts $f "DATASET POLYDATA" + puts $f "POINTS 8 float" + + puts $f "$corX $corY $corZ" + puts $f "[expr $corX + $aX] [expr $corY + $aY] [expr $corZ + $aZ]" + puts $f "[expr $corX + $aX + $bX] [expr $corY + $aY + $bY] [expr $corZ + $aZ + $bZ]" + puts $f "[expr $corX + $bX] [expr $corY + $bY] [expr $corZ + $bZ]" + + puts $f "[expr $corX + $cX] [expr $corY + $cY] [expr $corZ + $cZ]" + puts $f "[expr $corX + $aX + $cX] [expr $corY + $aY + $cY] [expr $corZ + $aZ + $cZ]" + puts $f "[expr $corX + $aX + $bX + $cX] [expr $corY + $aY + $bY + $cY] [expr $corZ + $aZ + $bZ + $cZ]" + puts $f "[expr $corX + $bX + $cX] [expr $corY + $bY + $cY] [expr $corZ + $bZ + $cZ]" + + puts $f "POLYGONS 6 30" + puts $f "4 0 1 2 3" + puts $f "4 4 5 6 7" + puts $f "4 0 1 5 4" + puts $f "4 2 3 7 6" + puts $f "4 0 4 7 3" + puts $f "4 1 2 6 5" + + close $f +} + +#--------------------------------------------------------------------------------------------------------------- +proc output_vtk_cylinder { args } { + + # expected parameters: + # cX, cY, cZ - center + # nX, nY, nZ - normal vector, for now only [0,0,1] + # L - half cylinder length + # r - radius + # n - number of faces on the circumference (the higher the number, the smoother the cylinder) + # cylFile - file to write into + + set cX [lindex $args 0] + set cY [lindex $args 1] + set cZ [lindex $args 2] + set nX [lindex $args 3] + set nY [lindex $args 4] + set nZ [lindex $args 5] + set r [lindex $args 6] + set L [lindex $args 7] + set n [lindex $args 8] + set cylFile [lindex $args 9] + + # write output + set f [open $cylFile "w"] + + set check_normal 1 + if { $nX != 0.0 } { set check_normal 0 } + if { $nY != 0.0 } { set check_normal 0 } + if { $nZ == 0.0 } { set check_normal 0 } + if { $check_normal == 0 } { + puts "This type of cylinder is not supported yet." + } else { + if { $nZ != 1.0 } { set nZ 1.0 } + + # set points on the circumference + set pi 3.14159265359 + set alpha [expr 2*$pi/$n] + set points [expr 2*$n] + + # get center P1 of bottom circle + set p1X [expr $cX-$L*$nX] + set p1Y [expr $cY-$L*$nY] + set p1Z [expr $cZ-$L*$nZ] + + puts $f "# vtk DataFile Version 3.0" + puts $f "Data" + puts $f "ASCII" + puts $f "DATASET POLYDATA" + puts $f "POINTS $points float" + + for {set i 0} {$i < $n} {incr i} { + puts $f "[expr $p1X+$r*cos($i*$alpha)] [expr $p1Y+$r*sin($i*$alpha)] $p1Z" + } + + for {set i 0} {$i < $n} {incr i} { + puts $f "[expr $p1X+$r*cos($i*$alpha)] [expr $p1Y+$r*sin($i*$alpha)] [expr $p1Z+2*$L*$nZ]" + } + + puts $f "POLYGONS [expr $n+2] [expr 5*$n+($n+1)*2]" + + # writing the bottom "circle" + puts -nonewline $f "$n " + for {set i 0} {$i < [expr $n-1]} {incr i} { + puts -nonewline $f "$i " + } + puts $f "[expr $n-1]" + + # writing the top "circle" + puts -nonewline $f "$n " + for {set i 0} {$i < [expr $n-1]} {incr i} { + puts -nonewline $f "[expr $i+$n] " + } + puts $f "[expr 2*$n-1]" + + # writing the side rectangles + for {set i 0} {$i < [expr $n-1]} {incr i} { + puts $f "4 $i [expr $i+1] [expr $i+$n+1] [expr $i+$n]" + } + puts $f "4 [expr $n-1] 0 $n [expr 2*$n-1]" + + close $f + } +} + +#----------------------------------------------------------------------------------------------------- +# define your own walls and boundaries here +# +# remember that +# output_vtk_* writes boundary for visualisation later +# constraint sets up boundary for objects +# and lbboundary sets up boundary for fluid + +# wall - bottom +set corX 0; set corY 0; set corZ 0; +set aX $boxX; set aY 0; set aZ 0; +set bX 0; set bY $boxY; set bZ 0; +set cX 0; set cY 0; set cZ 1; +set rhomFile "output/wallbottom.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + +# wall - top +set corX 0; set corY 0; set corZ [expr $boxZ - 1]; +set aX $boxX; set aY 0; set aZ 0; +set bX 0; set bY $boxY; set bZ 0; +set cX 0; set cY 0; set cZ 1; +set rhomFile "output/walltop.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + +# wall - front side +set corX 0; set corY 0; set corZ 1; +set aX $boxX; set aY 0; set aZ 0; +set bX 0; set bY 1; set bZ 0; +set cX 0; set cY 0; set cZ [expr $boxZ - 2]; +set rhomFile "output/wallfront.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + +# wall - back side +set corX 0; set corY [expr $boxY - 1]; set corZ 1; +set aX $boxX; set aY 0; set aZ 0; +set bX 0; set bY 1; set bZ 0; +set cX 0; set cY 0; set cZ [expr $boxZ - 2]; +set rhomFile "output/wallback.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + + +# obstacle rhomboid1 +set corX 10; set corY 1; set corZ 1; +set aX 8; set aY 0; set aZ 0; +set bX 0; set bY 4; set bZ 0; +set cX 0; set cY 0; set cZ 18; +set rhomFile "output/rhomboid1.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + +# obstacle cylinder1 +set cX 16; set cY 17; set cZ 10; +set nX 0; set nY 0; set nZ 1; +set L 9 +set r 3 +set cylFile "output/cylinder1.vtk" +set n 20 +output_vtk_cylinder $cX $cY $cZ $nX $nY $nZ $r $L $n $cylFile +constraint cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r length $L direction 1 type 10 +lbboundary cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r length $L direction 1 + +# obstacle rhomboid2 +set corX 25; set corY 1; set corZ 1; +set aX 5; set aY 0; set aZ 0; +set bX 0; set bY 20; set bZ 0; +set cX 0; set cY 0; set cZ 10; +set rhomFile "output/rhomboid2.vtk" +output_vtk_rhomboid $corX $corY $corZ $aX $aY $aZ $bX $bY $bZ $cX $cY $cZ $rhomFile +constraint rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 type 10 +lbboundary rhomboid corner $corX $corY $corZ a $aX $aY $aZ b $bX $bY $bZ c $cX $cY $cZ direction 1 + +# obstacle cylinder2 +set cX 37; set cY 10; set cZ 10; +set nX 0; set nY 0; set nZ 1; +set L 9 +set r 3 +set cylFile "output/cylinder2.vtk" +set n 20 +output_vtk_cylinder $cX $cY $cZ $nX $nY $nZ $r $L $n $cylFile +constraint cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r length $L direction 1 type 10 +lbboundary cylinder center $cX $cY $cZ axis $nX $nY $nZ radius $r length $L direction 1 diff --git a/doc/tutorials/03-object_in_fluid/scripts/input/cell_nodes.dat b/doc/tutorials/03-object_in_fluid/scripts/input/cell_nodes.dat new file mode 100644 index 00000000000..9bf051cb7c1 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/input/cell_nodes.dat @@ -0,0 +1,400 @@ + 1.00000 0.00000 0.00017 + 0.99262 0.00000 0.12129 + 0.99266 0.00000 -0.12096 + 0.95106 0.16995 0.00000 + 0.95106 -0.16995 0.00000 + 0.94356 0.16995 0.11920 + 0.94356 -0.16995 0.11920 + 0.94356 0.16995 -0.11920 + 0.94356 -0.16995 -0.11920 + 0.97063 0.00000 0.24059 + 0.97070 0.00000 -0.24028 + 0.92118 0.16995 0.23652 + 0.92118 -0.16995 0.23652 + 0.92118 0.16995 -0.23652 + 0.92118 -0.16995 -0.23652 + 0.80902 0.30474 0.00018 + 0.80902 -0.30474 0.00018 + 0.93437 0.00000 0.35630 + 0.93448 0.00000 -0.35601 + 0.79991 0.30474 -0.12108 + 0.79991 -0.30474 -0.12108 + 0.79985 0.30474 0.12142 + 0.79985 -0.30474 0.12142 + 0.88427 0.16995 0.35011 + 0.88427 -0.16995 0.35011 + 0.88427 0.16995 -0.35011 + 0.88427 -0.16995 -0.35011 + 0.77274 0.30474 -0.23954 + 0.77274 -0.30474 -0.23954 + 0.77264 0.30474 0.23986 + 0.77264 -0.30474 0.23986 + 0.88440 0.00000 0.46674 + 0.88453 0.00000 -0.46648 + 0.58778 0.30944 0.00072 + 0.58778 -0.30944 0.00072 + 0.83342 0.16995 0.45817 + 0.83342 -0.16995 0.45817 + 0.83342 0.16995 -0.45817 + 0.83342 -0.16995 -0.45817 + 0.72816 0.30474 -0.35255 + 0.72816 -0.30474 -0.35255 + 0.72802 0.30474 0.35284 + 0.72802 -0.30474 0.35284 + 0.57475 0.30944 -0.12310 + 0.57475 -0.30944 -0.12310 + 0.57447 0.30944 0.12442 + 0.57447 -0.30944 0.12442 + 0.82145 0.00000 0.57028 + 0.82161 0.00000 -0.57005 + 0.53601 0.30944 -0.24121 + 0.53601 -0.30944 -0.24121 + 0.53549 0.30944 0.24236 + 0.53549 -0.30944 0.24236 + 0.44556 0.25003 -0.09326 + 0.44556 -0.25003 -0.09326 + 0.58856 0.30747 -0.34170 + 0.58856 -0.30747 -0.34170 + 0.58844 0.30747 0.34193 + 0.58844 -0.30747 0.34193 + 0.44090 0.24824 0.09592 + 0.44090 -0.24824 0.09592 + 0.76942 0.16995 0.55902 + 0.76942 -0.16995 0.55902 + 0.76942 0.16995 -0.55902 + 0.76942 -0.16995 -0.55902 + 0.66720 0.30474 -0.45755 + 0.66720 -0.30474 -0.45755 + 0.66703 0.30474 0.45780 + 0.66703 -0.30474 0.45780 + 0.47343 0.30944 -0.34837 + 0.47343 -0.30944 -0.34837 + 0.47273 0.30944 0.34931 + 0.47273 -0.30944 0.34931 + 0.74647 0.00000 0.66542 + 0.74665 0.00000 -0.66521 + 0.30902 0.18452 0.00000 + 0.30902 -0.18452 0.00000 + 0.36597 0.24798 -0.26295 + 0.36597 -0.24798 -0.26295 + 0.36563 0.24797 0.26339 + 0.36563 -0.24797 0.26339 + 0.69329 0.16995 0.65104 + 0.69329 -0.16995 0.65104 + 0.69329 0.16995 -0.65104 + 0.69329 -0.16995 -0.65104 + 0.28549 0.18452 0.11826 + 0.28549 -0.18452 0.11826 + 0.28549 0.18452 -0.11826 + 0.28549 -0.18452 -0.11826 + 0.59125 0.30474 -0.55221 + 0.59125 -0.30474 -0.55221 + 0.59105 0.30474 0.55242 + 0.59105 -0.30474 0.55242 + 0.38990 0.30944 -0.43986 + 0.38990 -0.30944 -0.43986 + 0.38908 0.30944 0.44058 + 0.38908 -0.30944 0.44058 + 0.66058 0.00000 0.75076 + 0.66077 0.00000 -0.75059 + 0.21851 0.18452 0.21851 + 0.21851 -0.18452 0.21851 + 0.21851 0.18452 -0.21851 + 0.21851 -0.18452 -0.21851 + 0.16751 0.14801 -0.02766 + 0.16751 -0.14801 -0.02766 + 0.60623 0.16995 0.73280 + 0.60623 -0.16995 0.73280 + 0.60623 0.16995 -0.73280 + 0.60623 -0.16995 -0.73280 + 0.50184 0.30474 0.63456 + 0.50184 -0.30474 0.63456 + 0.50205 0.30474 -0.63439 + 0.50205 -0.30474 -0.63439 + 0.13233 0.15270 0.13307 + 0.13233 -0.15270 0.13307 + 0.23292 0.24653 -0.38200 + 0.23292 -0.24653 -0.38200 + 0.23255 0.24653 0.38222 + 0.23255 -0.24653 0.38222 + 0.10127 0.15129 -0.15154 + 0.10127 -0.15129 -0.15154 + 0.28923 0.30944 -0.51170 + 0.28923 -0.30944 -0.51170 + 0.28837 0.30944 0.51219 + 0.28837 -0.30944 0.51219 + 0.56503 0.00000 0.82507 + 0.56524 0.00000 -0.82493 + 0.11826 0.18452 0.28549 + 0.11826 -0.18452 0.28549 + 0.11826 0.18452 -0.28549 + 0.11826 -0.18452 -0.28549 + 0.50960 0.16995 0.80300 + 0.50960 -0.16995 0.80300 + 0.50960 0.16995 -0.80300 + 0.50960 -0.16995 -0.80300 + 0.40140 0.30474 0.70242 + 0.40140 -0.30474 0.70242 + 0.40162 0.30474 -0.70229 + 0.40162 -0.30474 -0.70229 + 0.00000 0.10350 0.00000 + 0.00000 -0.10350 0.00000 + 0.46125 0.00000 0.88727 + 0.46146 0.00000 -0.88716 + 0.08622 0.24233 -0.42945 + 0.08622 -0.24233 -0.42945 + 0.08583 0.24233 0.42954 + 0.08583 -0.24233 0.42954 + 0.17598 0.30944 -0.56082 + 0.17598 -0.30944 -0.56082 + 0.17512 0.30944 0.56109 + 0.17512 -0.30944 0.56109 + 0.40494 0.16995 0.86054 + 0.40494 -0.16995 0.86054 + 0.40494 0.16995 -0.86054 + 0.40494 -0.16995 -0.86054 + 0.00000 0.18452 0.30902 + 0.00000 -0.18452 0.30902 + 0.00000 0.18452 -0.30902 + 0.00000 -0.18452 -0.30902 + 0.29201 0.30474 0.75448 + 0.29201 -0.30474 0.75448 + 0.29224 0.30474 -0.75439 + 0.29224 -0.30474 -0.75439 + -0.07038 0.14689 0.14977 + -0.07038 -0.14689 0.14977 + -0.07504 0.14811 -0.15272 + -0.07504 -0.14811 -0.15272 + -0.10802 0.13182 0.00000 + -0.10802 -0.13182 0.00000 + 0.35077 0.00000 0.93646 + 0.35097 0.00000 -0.93638 + 0.05519 0.30944 -0.58519 + 0.05519 -0.30944 -0.58519 + 0.05439 0.30944 0.58526 + 0.05439 -0.30944 0.58526 + 0.29389 0.16995 0.90451 + 0.29389 -0.16995 0.90451 + 0.29389 0.16995 -0.90451 + 0.29389 -0.16995 -0.90451 + -0.11826 0.18452 0.28549 + -0.11826 -0.18452 0.28549 + -0.11826 0.18452 -0.28549 + -0.11826 -0.18452 -0.28549 + 0.17615 0.30474 0.78961 + 0.17615 -0.30474 0.78961 + 0.17637 0.30474 -0.78956 + 0.17637 -0.30474 -0.78956 + -0.06741 0.24653 -0.44229 + -0.06741 -0.24653 -0.44229 + -0.06771 0.24654 0.44226 + -0.06771 -0.24654 0.44226 + -0.17500 0.15518 -0.09072 + -0.17500 -0.15518 -0.09072 + -0.17509 -0.15521 0.09077 + -0.17509 0.15521 0.09077 + -0.20942 0.15841 0.00000 + -0.20942 -0.15841 0.00000 + 0.23519 0.00000 0.97195 + 0.23540 0.00000 -0.97190 + -0.00342 -0.30746 0.68107 + -0.00342 0.30746 0.68107 + -0.00326 -0.30746 -0.68105 + -0.00326 0.30746 -0.68105 + -0.21851 0.18452 0.21851 + -0.21851 -0.18452 0.21851 + -0.21851 0.18452 -0.21851 + -0.21851 -0.18452 -0.21851 + 0.17821 0.16995 0.93421 + 0.17821 -0.16995 0.93421 + -0.06779 0.30944 -0.58386 + -0.06779 -0.30944 -0.58386 + 0.17821 0.16995 -0.93421 + 0.17821 -0.16995 -0.93421 + -0.06849 0.30944 0.58378 + -0.06849 -0.30944 0.58378 + 0.05641 0.30474 0.80705 + 0.05641 -0.30474 0.80705 + 0.05661 0.30474 -0.80703 + 0.05661 -0.30474 -0.80703 + -0.28549 0.18452 0.11826 + -0.28549 -0.18452 0.11826 + -0.28549 0.18452 -0.11826 + -0.28549 -0.18452 -0.11826 + -0.23507 0.24797 -0.38444 + -0.23507 -0.24797 -0.38444 + -0.23530 0.24798 0.38433 + -0.23530 -0.24798 0.38433 + -0.30902 0.18452 0.00000 + -0.30902 -0.18452 0.00000 + 0.11623 0.00000 0.99322 + 0.11643 0.00000 -0.99320 + 0.05972 0.16995 0.94918 + 0.05972 -0.16995 0.94918 + 0.05972 0.16995 -0.94918 + 0.05972 -0.16995 -0.94918 + -0.18757 0.30944 -0.55705 + -0.18757 -0.30944 -0.55705 + -0.18814 0.30944 0.55686 + -0.18814 -0.30944 0.55686 + -0.06452 0.30474 0.80644 + -0.06452 -0.30474 0.80644 + -0.06433 0.30474 -0.80645 + -0.06433 -0.30474 -0.80645 + -0.00437 0.00000 0.99999 + -0.00419 0.00000 -0.99999 + -0.40262 0.22646 0.00000 + -0.40262 -0.22646 0.00000 + -0.37335 0.25105 -0.26441 + -0.37355 0.25103 0.26404 + -0.37355 -0.25103 0.26404 + -0.37330 -0.25232 -0.26933 + -0.29896 0.30944 -0.50608 + -0.29896 -0.30944 -0.50608 + -0.29939 0.30944 0.50582 + -0.29939 -0.30944 0.50582 + -0.05972 0.16995 0.94918 + -0.05972 -0.16995 0.94918 + -0.05972 0.16995 -0.94918 + -0.05972 -0.16995 -0.94918 + -0.18394 0.30474 0.78783 + -0.18394 -0.30474 0.78783 + -0.18377 0.30474 -0.78787 + -0.18377 -0.30474 -0.78787 + -0.44692 0.25385 -0.12373 + -0.44696 0.25386 0.12363 + -0.44696 -0.25386 0.12363 + -0.44695 -0.25396 -0.12457 + -0.39718 0.30944 -0.43329 + -0.39718 -0.30944 -0.43329 + -0.39747 0.30944 0.43303 + -0.39747 -0.30944 0.43303 + -0.12487 0.00000 0.99217 + -0.12470 0.00000 -0.99220 + -0.17821 0.16995 0.93421 + -0.17821 -0.16995 0.93421 + -0.17821 0.16995 -0.93421 + -0.17821 -0.16995 -0.93421 + -0.49535 0.26802 0.00000 + -0.49535 -0.26802 0.00000 + -0.29918 0.30474 0.75166 + -0.29918 -0.30474 0.75166 + -0.29904 0.30474 -0.75172 + -0.29904 -0.30474 -0.75172 + -0.47807 0.30944 -0.34197 + -0.47807 -0.30944 -0.34197 + -0.47823 0.30944 0.34174 + -0.47823 -0.30944 0.34174 + -0.24349 0.00000 0.96990 + -0.24334 0.00000 -0.96994 + -0.53832 0.30944 0.23600 + -0.53832 -0.30944 0.23600 + -0.53826 0.30944 -0.23616 + -0.53826 -0.30944 -0.23616 + -0.29389 0.16995 0.90451 + -0.29389 -0.16995 0.90451 + -0.29389 0.16995 -0.90451 + -0.29389 -0.16995 -0.90451 + -0.40769 0.30474 0.69878 + -0.40769 -0.30474 0.69878 + -0.40758 0.30474 -0.69885 + -0.40758 -0.30474 -0.69885 + -0.57532 0.30944 0.12043 + -0.57532 -0.30944 0.12043 + -0.57530 0.30944 -0.12049 + -0.57530 -0.30944 -0.12049 + -0.58779 0.30944 0.00000 + -0.58779 -0.30944 0.00000 + -0.35851 0.00000 0.93352 + -0.35838 0.00000 -0.93358 + -0.59131 0.30744 0.33913 + -0.59131 -0.30744 0.33913 + -0.59127 0.30744 -0.33917 + -0.59127 -0.30744 -0.33917 + -0.40494 0.16995 0.86054 + -0.40494 -0.16995 0.86054 + -0.40494 0.16995 -0.86054 + -0.40494 -0.16995 -0.86054 + -0.50706 0.30474 0.63039 + -0.50706 -0.30474 0.63039 + -0.50698 0.30474 -0.63046 + -0.50698 -0.30474 -0.63046 + -0.46828 0.00000 0.88358 + -0.46816 0.00000 -0.88364 + -0.59511 0.30474 0.54805 + -0.59511 -0.30474 0.54805 + -0.59505 0.30474 -0.54811 + -0.59505 -0.30474 -0.54811 + -0.50960 0.16995 0.80300 + -0.50960 -0.16995 0.80300 + -0.50960 0.16995 -0.80300 + -0.50960 -0.16995 -0.80300 + -0.69840 0.30709 0.00000 + -0.69840 -0.30709 0.00000 + -0.66990 0.30474 0.45359 + -0.66990 -0.30474 0.45359 + -0.66986 0.30474 -0.45365 + -0.66986 -0.30474 -0.45365 + -0.57118 0.00000 0.82082 + -0.57109 0.00000 -0.82089 + -0.60623 0.16995 0.73280 + -0.60623 -0.16995 0.73280 + -0.60623 0.16995 -0.73280 + -0.60623 -0.16995 -0.73280 + -0.72979 0.30474 0.34916 + -0.72979 -0.30474 0.34916 + -0.72977 0.30474 -0.34920 + -0.72977 -0.30474 -0.34920 + -0.77350 0.30474 0.23707 + -0.77350 -0.30474 0.23707 + -0.77349 0.30474 -0.23710 + -0.77349 -0.30474 -0.23710 + -0.69329 0.16995 0.65104 + -0.69329 -0.16995 0.65104 + -0.69329 0.16995 -0.65104 + -0.69329 -0.16995 -0.65104 + -0.66575 0.00000 0.74617 + -0.66568 0.00000 -0.74624 + -0.80010 0.30474 0.11981 + -0.80010 -0.30474 0.11981 + -0.80009 0.30474 -0.11982 + -0.80009 -0.30474 -0.11982 + -0.80902 0.30474 0.00000 + -0.80902 -0.30474 0.00000 + -0.76942 0.16995 0.55902 + -0.76942 -0.16995 0.55902 + -0.76942 0.16995 -0.55902 + -0.76942 -0.16995 -0.55902 + -0.75062 0.00000 0.66073 + -0.75057 0.00000 -0.66080 + -0.88004 0.23735 0.00000 + -0.88004 -0.23735 0.00000 + -0.83342 0.16995 0.45817 + -0.83342 -0.16995 0.45817 + -0.83342 0.16995 -0.45817 + -0.83342 -0.16995 -0.45817 + -0.82457 0.00000 0.56576 + -0.82453 0.00000 -0.56581 + -0.88427 0.16995 0.35011 + -0.88427 -0.16995 0.35011 + -0.88427 0.16995 -0.35011 + -0.88427 -0.16995 -0.35011 + -0.88655 0.00000 0.46263 + -0.88652 0.00000 -0.46268 + -0.92118 0.16995 0.23652 + -0.92118 -0.16995 0.23652 + -0.92118 0.16995 -0.23652 + -0.92118 -0.16995 -0.23652 + -0.94356 0.16995 0.11920 + -0.94356 -0.16995 0.11920 + -0.94356 0.16995 -0.11920 + -0.94356 -0.16995 -0.11920 + -0.95106 0.16995 0.00000 + -0.95106 -0.16995 0.00000 + -0.93567 0.00000 0.35287 + -0.93566 0.00000 -0.35291 + -0.97125 0.00000 0.23806 + -0.97125 0.00000 -0.23808 + -0.99279 0.00000 0.11986 + -0.99279 0.00000 -0.11987 + -1.00000 0.00000 0.00000 diff --git a/doc/tutorials/03-object_in_fluid/scripts/input/cell_triangles.dat b/doc/tutorials/03-object_in_fluid/scripts/input/cell_triangles.dat new file mode 100644 index 00000000000..2a521f6367e --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/input/cell_triangles.dat @@ -0,0 +1,796 @@ + 175 151 169 + 295 315 308 + 313 293 307 + 153 177 170 + 35 23 31 + 373 379 382 + 377 371 381 + 25 37 32 + 383 377 393 + 13 25 18 + 23 11 17 + 379 385 394 + 327 313 321 + 133 153 142 + 151 131 141 + 315 329 322 + 365 373 376 + 61 35 47 + 371 363 375 + 37 63 48 + 339 327 337 + 107 133 126 + 131 105 125 + 329 341 338 + 81 61 73 + 353 365 368 + 363 351 367 + 63 83 74 + 351 339 355 + 105 81 97 + 83 107 98 + 341 353 356 + 207 175 197 + 275 295 288 + 293 273 287 + 177 211 198 + 255 231 243 + 233 257 244 + 391 387 397 + 3 7 2 + 5 3 1 + 389 391 398 + 387 383 395 + 7 13 10 + 11 5 9 + 385 389 396 + 231 207 229 + 257 275 272 + 273 255 271 + 211 233 230 + 397 399 391 + 399 398 391 + 395 397 387 + 398 396 389 + 393 395 383 + 396 394 385 + 381 393 377 + 394 382 379 + 375 381 371 + 382 376 373 + 367 375 363 + 376 368 365 + 355 367 351 + 368 356 353 + 337 355 339 + 356 338 341 + 321 337 327 + 338 322 329 + 307 321 313 + 322 308 315 + 287 307 293 + 308 288 295 + 271 287 273 + 288 272 275 + 243 271 255 + 272 244 257 + 229 243 231 + 244 230 233 + 197 229 207 + 230 198 211 + 169 197 175 + 198 170 177 + 141 169 151 + 170 142 153 + 125 141 131 + 142 126 133 + 97 125 105 + 126 98 107 + 73 97 81 + 98 74 83 + 47 73 61 + 74 48 63 + 31 47 35 + 48 32 37 + 17 31 23 + 32 18 25 + 9 17 11 + 18 10 13 + 1 9 5 + 10 2 7 + 0 1 3 + 2 0 3 + 391 369 387 + 369 361 357 + 315 295 281 + 151 175 159 + 177 153 161 + 293 313 279 + 379 373 345 + 23 35 41 + 37 25 39 + 371 377 343 + 25 13 27 + 377 383 347 + 385 379 349 + 11 23 29 + 153 133 137 + 313 327 297 + 329 315 299 + 131 151 135 + 373 365 335 + 35 61 67 + 63 37 65 + 363 371 333 + 133 107 111 + 327 339 317 + 341 329 319 + 105 131 109 + 365 353 325 + 61 81 91 + 83 63 89 + 351 363 323 + 353 341 325 + 107 83 89 + 81 105 91 + 339 351 323 + 295 275 261 + 175 207 183 + 211 177 185 + 273 293 259 + 257 233 217 + 231 255 215 + 7 3 15 + 391 389 369 + 3 5 15 + 13 7 19 + 383 387 357 + 389 385 359 + 5 11 21 + 275 257 241 + 207 231 215 + 233 211 217 + 255 273 239 + 359 361 369 + 357 347 383 + 349 359 385 + 347 343 377 + 345 349 379 + 343 333 371 + 335 345 373 + 333 323 363 + 325 335 365 + 323 317 339 + 319 325 341 + 317 297 327 + 299 319 329 + 297 279 313 + 281 299 315 + 279 259 293 + 261 281 295 + 259 239 273 + 241 261 275 + 239 215 255 + 217 241 257 + 215 183 207 + 185 217 211 + 183 159 175 + 161 185 177 + 159 135 151 + 137 161 153 + 135 109 131 + 111 137 133 + 109 91 105 + 89 111 107 + 91 67 61 + 65 89 63 + 67 41 35 + 39 65 37 + 41 29 23 + 27 39 25 + 29 21 11 + 19 27 13 + 21 15 5 + 15 19 7 + 387 369 357 + 369 389 359 + 361 331 357 + 331 305 301 + 331 361 359 + 347 357 301 + 359 349 303 + 343 347 289 + 349 345 291 + 333 343 309 + 345 335 311 + 323 333 285 + 335 325 283 + 317 323 269 + 325 319 267 + 297 317 253 + 319 299 251 + 259 279 237 + 281 261 235 + 239 259 213 + 261 241 209 + 215 239 200 + 241 217 202 + 183 215 173 + 217 185 171 + 159 183 149 + 185 161 147 + 303 305 331 + 135 159 123 + 161 137 121 + 109 135 123 + 137 111 121 + 91 109 95 + 111 89 93 + 67 91 71 + 301 289 347 + 89 65 69 + 41 67 57 + 65 39 55 + 291 303 349 + 29 41 51 + 39 27 49 + 21 29 45 + 27 19 43 + 15 21 33 + 19 15 33 + 289 285 309 + 309 285 333 + 289 309 343 + 283 291 311 + 283 311 335 + 311 291 345 + 285 269 323 + 267 283 325 + 269 253 317 + 251 267 319 + 253 237 297 + 235 251 281 + 281 251 299 + 237 213 259 + 209 235 261 + 213 173 200 + 200 173 215 + 213 200 239 + 171 209 202 + 171 202 217 + 202 209 241 + 173 149 183 + 147 171 185 + 149 123 159 + 121 147 161 + 297 237 279 + 123 95 109 + 93 121 111 + 95 71 91 + 69 93 89 + 71 51 57 + 57 51 41 + 71 57 67 + 49 69 55 + 49 55 39 + 55 69 65 + 51 45 29 + 43 49 27 + 45 33 21 + 33 43 19 + 357 331 301 + 331 359 303 + 305 277 301 + 277 305 303 + 277 245 264 + 245 277 263 + 245 227 219 + 264 245 219 + 277 264 301 + 245 263 221 + 263 277 303 + 203 179 225 + 99 85 79 + 101 129 115 + 205 221 247 + 219 203 248 + 127 99 117 + 87 101 77 + 181 205 223 + 155 127 145 + 75 87 53 + 157 181 187 + 179 155 189 + 85 75 59 + 129 157 143 + 221 227 245 + 289 301 264 + 303 291 263 + 285 289 248 + 291 283 247 + 269 285 248 + 283 267 247 + 253 269 225 + 267 251 223 + 237 253 225 + 251 235 223 + 213 237 189 + 235 209 187 + 173 213 189 + 209 171 187 + 149 173 145 + 171 147 143 + 123 149 117 + 147 121 115 + 95 123 117 + 121 93 115 + 71 95 79 + 93 69 77 + 51 71 79 + 69 49 77 + 45 51 59 + 49 43 53 + 33 45 59 + 43 33 53 + 225 179 189 + 115 129 143 + 79 85 59 + 247 221 263 + 181 223 187 + 87 77 53 + 127 117 145 + 219 248 264 + 205 247 223 + 99 79 117 + 101 115 77 + 203 225 248 + 155 145 189 + 157 187 143 + 59 75 53 + 247 263 291 + 264 248 289 + 59 53 33 + 189 145 173 + 143 187 171 + 117 79 95 + 223 247 267 + 77 115 93 + 248 225 269 + 225 189 237 + 115 143 147 + 79 59 51 + 187 223 235 + 145 117 149 + 53 77 49 + 227 195 219 + 195 167 194 + 167 195 191 + 167 139 163 + 139 167 165 + 221 205 191 + 129 101 119 + 85 99 113 + 179 203 163 + 205 181 165 + 101 87 119 + 99 127 113 + 203 219 194 + 181 157 165 + 87 75 103 + 227 221 195 + 157 129 119 + 75 85 113 + 155 179 163 + 194 167 163 + 194 163 203 + 195 194 219 + 167 191 165 + 165 191 205 + 191 195 221 + 139 165 119 + 163 139 113 + 127 155 113 + 87 103 119 + 155 163 113 + 103 75 113 + 119 103 139 + 103 113 139 + 119 165 157 + 176 169 152 + 296 308 316 + 314 307 294 + 154 170 178 + 36 31 24 + 374 382 380 + 378 381 372 + 26 32 38 + 384 393 378 + 14 18 26 + 24 17 12 + 380 394 386 + 328 321 314 + 134 142 154 + 152 141 132 + 316 322 330 + 366 376 374 + 62 47 36 + 372 375 364 + 38 48 64 + 340 337 328 + 108 126 134 + 132 125 106 + 330 338 342 + 82 73 62 + 354 368 366 + 364 367 352 + 64 74 84 + 352 355 340 + 106 97 82 + 84 98 108 + 342 356 354 + 208 197 176 + 276 288 296 + 294 287 274 + 178 198 212 + 256 243 232 + 234 244 258 + 392 397 388 + 4 2 8 + 6 1 4 + 390 398 392 + 388 395 384 + 8 10 14 + 12 9 6 + 386 396 390 + 232 229 208 + 258 272 276 + 274 271 256 + 212 230 234 + 397 392 399 + 399 392 398 + 395 388 397 + 398 390 396 + 393 384 395 + 396 386 394 + 381 378 393 + 394 380 382 + 375 372 381 + 382 374 376 + 367 364 375 + 376 366 368 + 355 352 367 + 368 354 356 + 337 340 355 + 356 342 338 + 321 328 337 + 338 330 322 + 307 314 321 + 322 316 308 + 287 294 307 + 308 296 288 + 271 274 287 + 288 276 272 + 243 256 271 + 272 258 244 + 229 232 243 + 244 234 230 + 197 208 229 + 230 212 198 + 169 176 197 + 198 178 170 + 141 152 169 + 170 154 142 + 125 132 141 + 142 134 126 + 97 106 125 + 126 108 98 + 73 82 97 + 98 84 74 + 47 62 73 + 74 64 48 + 31 36 47 + 48 38 32 + 17 24 31 + 32 26 18 + 9 12 17 + 18 14 10 + 1 6 9 + 10 8 2 + 0 4 1 + 2 4 0 + 392 388 370 + 370 358 362 + 362 360 370 + 316 282 296 + 152 160 176 + 178 162 154 + 294 280 314 + 380 346 374 + 24 42 36 + 38 40 26 + 372 344 378 + 26 28 14 + 378 348 384 + 386 350 380 + 12 30 24 + 154 138 134 + 314 298 328 + 330 300 316 + 132 136 152 + 374 336 366 + 36 68 62 + 64 66 38 + 364 334 372 + 134 112 108 + 328 318 340 + 342 320 330 + 106 110 132 + 366 326 354 + 62 92 82 + 84 90 64 + 352 324 364 + 354 326 342 + 108 90 84 + 82 92 106 + 340 324 352 + 296 262 276 + 176 184 208 + 212 186 178 + 274 260 294 + 258 218 234 + 232 216 256 + 8 16 4 + 392 370 390 + 4 16 6 + 14 20 8 + 384 358 388 + 390 360 386 + 6 22 12 + 276 242 258 + 208 216 232 + 234 218 212 + 256 240 274 + 358 384 348 + 350 386 360 + 348 378 344 + 346 380 350 + 344 372 334 + 336 374 346 + 334 364 324 + 326 366 336 + 324 340 318 + 320 342 326 + 318 328 298 + 300 330 320 + 298 314 280 + 282 316 300 + 280 294 260 + 262 296 282 + 260 274 240 + 242 276 262 + 240 256 216 + 218 258 242 + 216 208 184 + 186 212 218 + 184 176 160 + 162 178 186 + 160 152 136 + 138 154 162 + 136 132 110 + 112 134 138 + 110 106 92 + 90 108 112 + 92 62 68 + 66 64 90 + 68 36 42 + 40 38 66 + 42 24 30 + 28 26 40 + 30 12 22 + 20 14 28 + 22 6 16 + 16 8 20 + 388 358 370 + 370 360 390 + 362 358 332 + 332 302 306 + 332 360 362 + 348 302 358 + 360 304 350 + 344 290 348 + 350 292 346 + 334 310 344 + 346 312 336 + 324 286 334 + 336 284 326 + 318 270 324 + 326 268 320 + 298 254 318 + 320 252 300 + 260 238 280 + 282 236 262 + 240 214 260 + 262 210 242 + 216 199 240 + 242 201 218 + 184 174 216 + 218 172 186 + 160 150 184 + 186 148 162 + 304 332 306 + 136 124 160 + 162 122 138 + 110 124 136 + 138 122 112 + 92 96 110 + 112 94 90 + 68 72 92 + 302 348 290 + 90 70 66 + 42 58 68 + 66 56 40 + 292 350 304 + 30 52 42 + 40 50 28 + 22 46 30 + 28 44 20 + 16 34 22 + 20 34 16 + 290 310 286 + 310 334 286 + 290 344 310 + 284 312 292 + 284 336 312 + 312 346 292 + 286 324 270 + 268 326 284 + 270 318 254 + 252 320 268 + 254 298 238 + 236 282 252 + 282 300 252 + 238 260 214 + 210 262 236 + 214 199 174 + 199 216 174 + 214 240 199 + 172 201 210 + 172 218 201 + 201 242 210 + 174 184 150 + 148 186 172 + 150 160 124 + 122 162 148 + 298 280 238 + 124 110 96 + 94 112 122 + 96 92 72 + 70 90 94 + 72 58 52 + 58 42 52 + 72 68 58 + 50 56 70 + 50 40 56 + 56 66 70 + 52 30 46 + 44 28 50 + 46 22 34 + 34 20 44 + 358 302 332 + 332 304 360 + 306 302 278 + 278 304 306 + 278 265 246 + 246 220 228 + 228 222 246 + 265 220 246 + 278 302 265 + 204 226 180 + 100 80 86 + 102 116 130 + 206 250 222 + 220 249 204 + 128 118 100 + 88 78 102 + 182 224 206 + 156 146 128 + 76 54 88 + 158 188 182 + 180 190 156 + 86 60 76 + 130 144 158 + 290 265 302 + 304 266 292 + 286 249 290 + 292 250 284 + 270 249 286 + 284 250 268 + 254 226 270 + 268 224 252 + 238 226 254 + 252 224 236 + 214 190 238 + 236 188 210 + 174 190 214 + 210 188 172 + 150 146 174 + 172 144 148 + 124 118 150 + 148 116 122 + 96 118 124 + 122 116 94 + 72 80 96 + 94 78 70 + 52 80 72 + 70 78 50 + 46 60 52 + 50 54 44 + 34 60 46 + 44 54 34 + 226 190 180 + 116 144 130 + 80 60 86 + 250 266 222 + 250 292 266 + 182 188 224 + 88 54 78 + 128 146 118 + 220 265 249 + 206 224 250 + 100 118 80 + 102 78 116 + 204 249 226 + 156 190 146 + 158 144 188 + 60 54 76 + 304 278 266 + 278 246 266 + 246 222 266 + 265 290 249 + 60 34 54 + 190 174 146 + 144 172 188 + 118 96 80 + 224 268 250 + 78 94 116 + 249 270 226 + 226 238 190 + 116 148 144 + 80 52 60 + 188 236 224 + 146 150 118 + 54 50 78 + 228 220 196 + 196 193 168 + 168 192 196 + 168 164 140 + 140 166 168 + 222 192 206 + 130 120 102 + 86 114 100 + 180 164 204 + 206 166 182 + 102 120 88 + 100 114 128 + 204 193 220 + 182 166 158 + 88 104 76 + 228 196 222 + 158 120 130 + 76 114 86 + 156 164 180 + 193 164 168 + 193 204 164 + 196 220 193 + 168 166 192 + 166 206 192 + 192 222 196 + 140 120 166 + 164 114 140 + 128 114 156 + 88 120 104 + 156 114 164 + 104 114 76 + 120 140 104 + 104 140 114 + 120 158 166 diff --git a/doc/tutorials/03-object_in_fluid/scripts/input/sphere_nodes.dat b/doc/tutorials/03-object_in_fluid/scripts/input/sphere_nodes.dat new file mode 100644 index 00000000000..5d307c282f6 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/input/sphere_nodes.dat @@ -0,0 +1,393 @@ +4.000000e+00 0.000000e+00 0.000000e+00 +0.000000e+00 4.000000e+00 0.000000e+00 +0.000000e+00 0.000000e+00 4.000000e+00 +-4.000000e+00 2.449213e-16 0.000000e+00 +-4.898425e-16 -4.000000e+00 0.000000e+00 +0.000000e+00 0.000000e+00 -4.000000e+00 +7.809111e-01 0.000000e+00 3.923031e+00 +1.531079e+00 0.000000e+00 3.695376e+00 +2.222436e+00 0.000000e+00 3.325775e+00 +2.828427e+00 0.000000e+00 2.828427e+00 +3.325775e+00 0.000000e+00 2.222437e+00 +3.695375e+00 0.000000e+00 1.531079e+00 +3.923031e+00 0.000000e+00 7.809112e-01 +3.923031e+00 7.809111e-01 0.000000e+00 +3.695376e+00 1.531079e+00 0.000000e+00 +3.325775e+00 2.222436e+00 0.000000e+00 +2.828427e+00 2.828427e+00 0.000000e+00 +2.222437e+00 3.325775e+00 0.000000e+00 +1.531079e+00 3.695375e+00 0.000000e+00 +7.809112e-01 3.923031e+00 0.000000e+00 +0.000000e+00 3.923031e+00 7.809111e-01 +0.000000e+00 3.695376e+00 1.531079e+00 +0.000000e+00 3.325775e+00 2.222436e+00 +0.000000e+00 2.828427e+00 2.828427e+00 +0.000000e+00 2.222437e+00 3.325775e+00 +0.000000e+00 1.531079e+00 3.695375e+00 +0.000000e+00 7.809112e-01 3.923031e+00 +-7.809111e-01 3.923031e+00 0.000000e+00 +-1.531079e+00 3.695376e+00 0.000000e+00 +-2.222436e+00 3.325775e+00 0.000000e+00 +-2.828427e+00 2.828427e+00 0.000000e+00 +-3.325775e+00 2.222437e+00 0.000000e+00 +-3.695375e+00 1.531079e+00 0.000000e+00 +-3.923031e+00 7.809112e-01 0.000000e+00 +-3.923031e+00 2.402085e-16 7.809111e-01 +-3.695376e+00 2.262690e-16 1.531079e+00 +-3.325775e+00 2.036382e-16 2.222436e+00 +-2.828427e+00 1.731855e-16 2.828427e+00 +-2.222437e+00 1.360805e-16 3.325775e+00 +-1.531079e+00 9.374846e-17 3.695375e+00 +-7.809112e-01 4.781544e-17 3.923031e+00 +-3.923031e+00 -7.809111e-01 0.000000e+00 +-3.695376e+00 -1.531079e+00 0.000000e+00 +-3.325775e+00 -2.222436e+00 0.000000e+00 +-2.828427e+00 -2.828427e+00 0.000000e+00 +-2.222437e+00 -3.325775e+00 0.000000e+00 +-1.531079e+00 -3.695375e+00 0.000000e+00 +-7.809112e-01 -3.923031e+00 0.000000e+00 +-4.804169e-16 -3.923031e+00 7.809111e-01 +-4.525380e-16 -3.695376e+00 1.531079e+00 +-4.072765e-16 -3.325775e+00 2.222436e+00 +-3.463710e-16 -2.828427e+00 2.828427e+00 +-2.721610e-16 -2.222437e+00 3.325775e+00 +-1.874969e-16 -1.531079e+00 3.695375e+00 +-9.563088e-17 -7.809112e-01 3.923031e+00 +7.809111e-01 -3.923031e+00 0.000000e+00 +1.531079e+00 -3.695376e+00 0.000000e+00 +2.222436e+00 -3.325775e+00 0.000000e+00 +2.828427e+00 -2.828427e+00 0.000000e+00 +3.325775e+00 -2.222437e+00 0.000000e+00 +3.695375e+00 -1.531079e+00 0.000000e+00 +3.923031e+00 -7.809112e-01 0.000000e+00 +7.809111e-01 0.000000e+00 -3.923031e+00 +1.531079e+00 0.000000e+00 -3.695376e+00 +2.222436e+00 0.000000e+00 -3.325775e+00 +2.828427e+00 0.000000e+00 -2.828427e+00 +3.325775e+00 0.000000e+00 -2.222437e+00 +3.695375e+00 0.000000e+00 -1.531079e+00 +3.923031e+00 0.000000e+00 -7.809112e-01 +0.000000e+00 3.923031e+00 -7.809111e-01 +0.000000e+00 3.695376e+00 -1.531079e+00 +0.000000e+00 3.325775e+00 -2.222436e+00 +0.000000e+00 2.828427e+00 -2.828427e+00 +0.000000e+00 2.222437e+00 -3.325775e+00 +0.000000e+00 1.531079e+00 -3.695375e+00 +0.000000e+00 7.809112e-01 -3.923031e+00 +-3.923031e+00 2.402085e-16 -7.809111e-01 +-3.695376e+00 2.262690e-16 -1.531079e+00 +-3.325775e+00 2.036382e-16 -2.222436e+00 +-2.828427e+00 1.731855e-16 -2.828427e+00 +-2.222437e+00 1.360805e-16 -3.325775e+00 +-1.531079e+00 9.374846e-17 -3.695375e+00 +-7.809112e-01 4.781544e-17 -3.923031e+00 +-4.804169e-16 -3.923031e+00 -7.809111e-01 +-4.525380e-16 -3.695376e+00 -1.531079e+00 +-4.072765e-16 -3.325775e+00 -2.222436e+00 +-3.463710e-16 -2.828427e+00 -2.828427e+00 +-2.721610e-16 -2.222437e+00 -3.325775e+00 +-1.874969e-16 -1.531079e+00 -3.695375e+00 +-9.563088e-17 -7.809112e-01 -3.923031e+00 +1.894854e+00 2.438120e+00 2.542621e+00 +1.704344e+00 1.876629e+00 3.094139e+00 +1.266904e+00 1.589526e+00 3.445037e+00 +3.772757e+00 1.137329e+00 6.714737e-01 +1.104442e+00 3.772531e+00 7.322286e-01 +2.343466e+00 1.619107e+00 2.808317e+00 +2.278902e+00 7.554233e-01 3.197192e+00 +1.213682e+00 2.982021e+00 2.373729e+00 +3.109551e+00 2.451983e+00 5.198051e-01 +2.445957e+00 2.597821e+00 1.807927e+00 +1.718495e+00 2.983532e+00 2.035984e+00 +1.851154e+00 3.462550e+00 7.558510e-01 +6.071574e-01 1.955790e+00 3.430865e+00 +5.621668e-01 3.779217e+00 1.165981e+00 +3.759272e+00 6.327164e-01 1.199336e+00 +6.513418e-01 1.198689e+00 3.756737e+00 +1.400636e+00 7.484204e-01 3.669645e+00 +1.118821e+00 2.416356e+00 2.984902e+00 +2.870560e+00 8.977746e-01 2.636720e+00 +4.909150e-01 3.505724e+00 1.848146e+00 +1.291576e+00 3.442122e+00 1.575918e+00 +5.732813e-01 3.002874e+00 2.571644e+00 +1.889620e+00 1.382830e+00 3.242777e+00 +3.919135e+00 5.346171e-01 5.117257e-01 +3.482453e+00 1.830013e+00 7.103406e-01 +3.378556e+00 6.859136e-01 2.022787e+00 +2.927272e+00 1.954846e+00 1.899603e+00 +3.421874e+00 1.441956e+00 1.487081e+00 +4.703272e-01 2.516754e+00 3.064392e+00 +2.957761e+00 1.493075e+00 2.241056e+00 +2.021612e+00 3.158533e+00 1.391136e+00 +3.122297e+00 4.373653e-01 2.449965e+00 +3.061355e+00 2.274672e+00 1.205686e+00 +2.568992e+00 2.947271e+00 8.419584e-01 +4.935165e-01 3.920371e+00 5.403548e-01 +2.552751e+00 2.053710e+00 2.294481e+00 +1.902304e+00 3.891480e-01 3.487965e+00 +5.713833e-01 5.496422e-01 3.910774e+00 +-2.803402e+00 2.207545e+00 1.807417e+00 +-2.099985e+00 1.565474e+00 3.023115e+00 +-1.363141e+00 2.103006e+00 3.117372e+00 +-3.500096e+00 1.337346e+00 1.400095e+00 +-1.541026e+00 3.067214e+00 2.053559e+00 +-6.262644e-01 1.092081e+00 3.792816e+00 +-3.774834e+00 1.131828e+00 6.687780e-01 +-1.889804e+00 3.242206e+00 1.383919e+00 +-1.336915e+00 1.398428e+00 3.500926e+00 +-1.899860e+00 2.402970e+00 2.572125e+00 +-1.257690e+00 2.721341e+00 2.647749e+00 +-2.532174e+00 7.649893e-01 2.998291e+00 +-2.346521e+00 2.642036e+00 1.874213e+00 +-1.216509e+00 3.458547e+00 1.599542e+00 +-2.536861e+00 1.982283e+00 2.373675e+00 +-3.423768e+00 1.915117e+00 7.742512e-01 +-7.838044e-01 3.148339e+00 2.337332e+00 +-1.142079e+00 6.886843e-01 3.768595e+00 +-3.778175e+00 5.766649e-01 1.163430e+00 +-3.376469e+00 7.792642e-01 1.995428e+00 +-6.861429e-01 3.769627e+00 1.140025e+00 +-3.158925e+00 1.948181e+00 1.491543e+00 +-7.090569e-01 2.517315e+00 3.023185e+00 +-1.265744e+00 3.712649e+00 7.788963e-01 +-2.954341e+00 2.610697e+00 6.537937e-01 +-5.518353e-01 3.525513e+00 1.794971e+00 +-2.896120e+00 2.423958e+00 1.317808e+00 +-3.089989e+00 1.597968e+00 1.974395e+00 +-2.521811e+00 3.054240e+00 5.127586e-01 +-2.488667e+00 2.934563e+00 1.093003e+00 +-5.493375e-01 3.914162e+00 5.424736e-01 +-3.920832e+00 5.026320e-01 5.276556e-01 +-5.112628e-01 5.070701e-01 3.922109e+00 +-2.791110e+00 1.249421e+00 2.578193e+00 +-7.062452e-01 1.829761e+00 3.483330e+00 +-2.987207e+00 5.721610e-01 2.590055e+00 +-2.035189e+00 3.374565e+00 6.664262e-01 +-1.852423e+00 7.604300e-01 3.460953e+00 +-2.207545e+00 -2.803402e+00 1.807417e+00 +-1.565474e+00 -2.099985e+00 3.023115e+00 +-2.103006e+00 -1.363141e+00 3.117372e+00 +-1.337346e+00 -3.500096e+00 1.400095e+00 +-3.067214e+00 -1.541026e+00 2.053559e+00 +-1.092081e+00 -6.262644e-01 3.792816e+00 +-1.131828e+00 -3.774834e+00 6.687780e-01 +-3.242206e+00 -1.889804e+00 1.383919e+00 +-1.398428e+00 -1.336915e+00 3.500926e+00 +-2.402970e+00 -1.899860e+00 2.572125e+00 +-2.721341e+00 -1.257690e+00 2.647749e+00 +-7.649893e-01 -2.532174e+00 2.998291e+00 +-2.642036e+00 -2.346521e+00 1.874213e+00 +-3.458547e+00 -1.216509e+00 1.599542e+00 +-1.982283e+00 -2.536861e+00 2.373675e+00 +-1.915117e+00 -3.423768e+00 7.742512e-01 +-3.148339e+00 -7.838044e-01 2.337332e+00 +-6.886843e-01 -1.142079e+00 3.768595e+00 +-5.766649e-01 -3.778175e+00 1.163430e+00 +-7.792642e-01 -3.376469e+00 1.995428e+00 +-3.769627e+00 -6.861429e-01 1.140025e+00 +-1.948181e+00 -3.158925e+00 1.491543e+00 +-2.517315e+00 -7.090569e-01 3.023185e+00 +-3.712649e+00 -1.265744e+00 7.788963e-01 +-2.610697e+00 -2.954341e+00 6.537937e-01 +-3.525513e+00 -5.518353e-01 1.794971e+00 +-2.423958e+00 -2.896120e+00 1.317808e+00 +-1.597968e+00 -3.089989e+00 1.974395e+00 +-3.054240e+00 -2.521811e+00 5.127586e-01 +-2.934563e+00 -2.488667e+00 1.093003e+00 +-3.914162e+00 -5.493375e-01 5.424736e-01 +-5.026320e-01 -3.920832e+00 5.276556e-01 +-5.070701e-01 -5.112628e-01 3.922109e+00 +-1.249421e+00 -2.791110e+00 2.578193e+00 +-1.829761e+00 -7.062452e-01 3.483330e+00 +-5.721610e-01 -2.987207e+00 2.590055e+00 +-3.374565e+00 -2.035189e+00 6.664262e-01 +-7.604300e-01 -1.852423e+00 3.460953e+00 +1.795535e+00 -2.920995e+00 2.059895e+00 +2.059999e+00 -1.481755e+00 3.091943e+00 +3.279759e+00 -1.335256e+00 1.859787e+00 +3.536872e+00 -1.480828e+00 1.138916e+00 +1.521236e+00 -1.912615e+00 3.166518e+00 +1.130687e+00 -3.233759e+00 2.064652e+00 +3.782088e+00 -1.156482e+00 5.625638e-01 +6.592869e-01 -1.039867e+00 3.802726e+00 +1.128112e+00 -3.779322e+00 6.464092e-01 +2.742903e+00 -1.444477e+00 2.527605e+00 +2.115196e+00 -2.227741e+00 2.561583e+00 +1.400128e+00 -1.255191e+00 3.530337e+00 +1.331660e+00 -2.649562e+00 2.684126e+00 +1.908751e+00 -3.431406e+00 7.543102e-01 +6.341436e-01 -3.028220e+00 2.529020e+00 +7.883196e-01 -2.430908e+00 3.075553e+00 +3.473460e+00 -1.877956e+00 6.111823e-01 +3.732273e+00 -7.410055e-01 1.228485e+00 +1.942094e+00 -8.253110e-01 3.397307e+00 +3.477505e+00 -5.303094e-01 1.891615e+00 +7.661470e-01 -1.760618e+00 3.507463e+00 +1.371126e+00 -3.471119e+00 1.439100e+00 +6.035457e-01 -3.784885e+00 1.129707e+00 +6.255508e-01 -3.487150e+00 1.848246e+00 +3.022251e+00 -2.546547e+00 5.847712e-01 +2.579939e+00 -2.853689e+00 1.095189e+00 +2.511531e+00 -3.066367e+00 4.870977e-01 +2.059163e+00 -3.094702e+00 1.477136e+00 +2.641355e+00 -8.302566e-01 2.885769e+00 +5.071048e-01 -3.921603e+00 5.160746e-01 +3.917757e+00 -5.402530e-01 5.189075e-01 +2.424698e+00 -2.604973e+00 1.826138e+00 +2.781142e+00 -2.023617e+00 2.041532e+00 +3.084175e+00 -2.168104e+00 1.336558e+00 +3.104700e+00 -7.118799e-01 2.415350e+00 +5.293112e-01 -4.606326e-01 3.924763e+00 +1.329724e+00 -5.296436e-01 3.728749e+00 +1.735562e+00 3.048014e+00 -1.922915e+00 +1.305414e+00 3.469395e+00 -1.502979e+00 +1.798713e+00 1.155291e+00 -3.380708e+00 +1.233134e+00 5.758579e-01 -3.756085e+00 +3.779509e+00 1.079701e+00 -7.334144e-01 +2.406790e+00 2.780186e+00 -1.574106e+00 +1.983735e+00 3.263740e+00 -1.187875e+00 +3.452674e+00 1.856573e+00 -7.896939e-01 +5.421156e-01 2.494953e+00 -3.071813e+00 +2.517589e+00 1.346143e+00 -2.801508e+00 +2.392386e+00 6.545226e-01 -3.133620e+00 +1.473417e+00 2.764007e+00 -2.487680e+00 +3.522618e+00 1.312920e+00 -1.366227e+00 +9.344768e-01 3.257081e+00 -2.125461e+00 +3.761524e+00 5.772544e-01 -1.215900e+00 +9.699098e-01 1.266094e+00 -3.668140e+00 +3.093864e+00 1.471639e+00 -2.064350e+00 +3.079085e+00 2.483935e+00 -5.527143e-01 +6.325733e-01 3.780067e+00 -1.132326e+00 +1.253388e+00 3.731593e+00 -6.969211e-01 +1.862575e+00 4.792319e-01 -3.499484e+00 +3.448914e+00 7.166009e-01 -1.890294e+00 +1.487472e+00 1.793177e+00 -3.251342e+00 +2.556994e+00 2.985280e+00 -7.294241e-01 +7.313388e-01 1.936548e+00 -3.420318e+00 +2.995461e+00 7.912778e-01 -2.528066e+00 +7.389885e-01 2.873244e+00 -2.679871e+00 +2.990056e+00 2.389490e+00 -1.161915e+00 +1.230124e+00 2.360920e+00 -2.985448e+00 +1.818633e+00 2.225888e+00 -2.781545e+00 +3.919423e+00 4.914396e-01 -5.506946e-01 +5.942955e-01 3.549865e+00 -1.734348e+00 +3.219477e+00 1.866263e+00 -1.466593e+00 +1.959795e+00 3.438905e+00 -5.353617e-01 +2.415444e+00 1.954043e+00 -2.519345e+00 +2.033127e+00 1.717196e+00 -2.986229e+00 +2.737902e+00 2.219829e+00 -1.890679e+00 +5.377519e-01 3.917268e+00 -5.260557e-01 +2.135028e+00 2.539836e+00 -2.233767e+00 +5.116662e-01 7.108174e-01 -3.895340e+00 +-2.803402e+00 2.207545e+00 -1.807417e+00 +-2.099985e+00 1.565474e+00 -3.023115e+00 +-1.363141e+00 2.103006e+00 -3.117372e+00 +-3.500096e+00 1.337346e+00 -1.400095e+00 +-1.541026e+00 3.067214e+00 -2.053559e+00 +-6.262644e-01 1.092081e+00 -3.792816e+00 +-3.774834e+00 1.131828e+00 -6.687780e-01 +-1.889804e+00 3.242206e+00 -1.383919e+00 +-1.336915e+00 1.398428e+00 -3.500926e+00 +-1.899860e+00 2.402970e+00 -2.572125e+00 +-1.257690e+00 2.721341e+00 -2.647749e+00 +-2.532174e+00 7.649893e-01 -2.998291e+00 +-2.346521e+00 2.642036e+00 -1.874213e+00 +-1.216509e+00 3.458547e+00 -1.599542e+00 +-2.536861e+00 1.982283e+00 -2.373675e+00 +-3.423768e+00 1.915117e+00 -7.742512e-01 +-7.838044e-01 3.148339e+00 -2.337332e+00 +-1.142079e+00 6.886843e-01 -3.768595e+00 +-3.778175e+00 5.766649e-01 -1.163430e+00 +-3.376469e+00 7.792642e-01 -1.995428e+00 +-6.861429e-01 3.769627e+00 -1.140025e+00 +-3.158925e+00 1.948181e+00 -1.491543e+00 +-7.090569e-01 2.517315e+00 -3.023185e+00 +-1.265744e+00 3.712649e+00 -7.788963e-01 +-2.954341e+00 2.610697e+00 -6.537937e-01 +-5.518353e-01 3.525513e+00 -1.794971e+00 +-2.896120e+00 2.423958e+00 -1.317808e+00 +-3.089989e+00 1.597968e+00 -1.974395e+00 +-2.521811e+00 3.054240e+00 -5.127586e-01 +-2.488667e+00 2.934563e+00 -1.093003e+00 +-5.493375e-01 3.914162e+00 -5.424736e-01 +-3.920832e+00 5.026320e-01 -5.276556e-01 +-5.112628e-01 5.070701e-01 -3.922109e+00 +-2.791110e+00 1.249421e+00 -2.578193e+00 +-7.062452e-01 1.829761e+00 -3.483330e+00 +-2.987207e+00 5.721610e-01 -2.590055e+00 +-2.035189e+00 3.374565e+00 -6.664262e-01 +-1.852423e+00 7.604300e-01 -3.460953e+00 +-1.570453e+00 -2.100102e+00 -3.020453e+00 +-2.099664e+00 -1.363321e+00 -3.119542e+00 +-1.338350e+00 -3.500008e+00 -1.399354e+00 +-3.067878e+00 -1.552183e+00 -2.044149e+00 +-1.092077e+00 -6.263561e-01 -3.792804e+00 +-1.131943e+00 -3.774808e+00 -6.687200e-01 +-3.730096e+00 -1.168653e+00 -8.480656e-01 +-3.291597e+00 -1.785079e+00 -1.406405e+00 +-1.398130e+00 -1.336659e+00 -3.501142e+00 +-2.403074e+00 -1.901667e+00 -2.570692e+00 +-2.709438e+00 -1.245706e+00 -2.665558e+00 +-7.687068e-01 -2.532073e+00 -2.997502e+00 +-2.657537e+00 -2.319311e+00 -1.886069e+00 +-3.435465e+00 -1.065821e+00 -1.749721e+00 +-1.972411e+00 -2.605948e+00 -2.305941e+00 +-1.829031e+00 -3.467277e+00 -7.901029e-01 +-3.094484e+00 -7.485042e-01 -2.418425e+00 +-6.889896e-01 -1.142044e+00 -3.768556e+00 +-5.767202e-01 -3.778173e+00 -1.163412e+00 +-7.810603e-01 -3.376683e+00 -1.994416e+00 +-2.137047e+00 -3.014331e+00 -1.531891e+00 +-2.495662e+00 -7.009861e-01 -3.042765e+00 +-3.392898e+00 -1.995080e+00 -6.974808e-01 +-1.527532e+00 -3.111629e+00 -1.995927e+00 +-3.005806e+00 -2.567486e+00 -5.769942e-01 +-2.877050e+00 -2.501969e+00 -1.209109e+00 +-5.026668e-01 -3.920830e+00 -5.276404e-01 +-5.070718e-01 -5.112746e-01 -3.922107e+00 +-1.825157e+00 -7.048900e-01 -3.485991e+00 +-1.260338e+00 -2.789080e+00 -2.575073e+00 +-5.751112e-01 -2.987235e+00 -2.589450e+00 +-2.533967e+00 -3.009639e+00 -7.071854e-01 +-7.619421e-01 -1.852408e+00 -3.460657e+00 +-3.757472e+00 -5.376977e-01 -1.243318e+00 +-3.503600e+00 -4.794512e-01 -1.854765e+00 +-3.915144e+00 -5.010026e-01 -5.789481e-01 +2.038209e+00 -2.693023e+00 -2.142660e+00 +2.060668e+00 -1.481789e+00 -3.091481e+00 +3.305494e+00 -1.329959e+00 -1.817608e+00 +3.538110e+00 -1.476612e+00 -1.140532e+00 +1.521236e+00 -1.912615e+00 -3.166518e+00 +1.342350e+00 -3.156562e+00 -2.057340e+00 +3.782097e+00 -1.156474e+00 -5.625042e-01 +6.593780e-01 -1.039973e+00 -3.802684e+00 +1.106854e+00 -3.781071e+00 -6.764234e-01 +2.740095e+00 -1.537685e+00 -2.475260e+00 +2.090785e+00 -2.119853e+00 -2.670674e+00 +1.433143e+00 -1.240783e+00 -3.522198e+00 +1.336528e+00 -2.650154e+00 -2.681121e+00 +1.900919e+00 -3.435687e+00 -7.546614e-01 +6.380061e-01 -3.029047e+00 -2.527172e+00 +7.898274e-01 -2.431194e+00 -3.074968e+00 +3.474443e+00 -1.875816e+00 -6.123156e-01 +5.701324e-01 -3.785781e+00 -1.141215e+00 +3.732323e+00 -7.409966e-01 -1.228342e+00 +2.123914e+00 -6.977133e-01 -3.313686e+00 +3.482950e+00 -5.297323e-01 -1.881704e+00 +1.283908e+00 -3.537658e+00 -1.354816e+00 +7.663934e-01 -1.760657e+00 -3.507394e+00 +6.040160e-01 -3.479031e+00 -1.869635e+00 +3.022950e+00 -2.545619e+00 -5.852553e-01 +2.573444e+00 -2.877956e+00 -1.046010e+00 +2.509183e+00 -3.068500e+00 -4.855800e-01 +1.954280e+00 -3.136923e+00 -1.529606e+00 +2.644809e+00 -8.515097e-01 -2.876707e+00 +2.592202e+00 -2.533079e+00 -1.692289e+00 +4.960999e-01 -3.921830e+00 -5.245320e-01 +3.917761e+00 -5.402503e-01 -5.188667e-01 +2.923650e+00 -1.957738e+00 -1.902190e+00 +3.126751e+00 -2.140957e+00 -1.280024e+00 +2.506927e+00 -2.213752e+00 -2.194033e+00 +3.113086e+00 -7.318979e-01 -2.399109e+00 +5.293383e-01 -4.606590e-01 -3.924758e+00 +1.362841e+00 -5.096747e-01 -3.719130e+00 diff --git a/doc/tutorials/03-object_in_fluid/scripts/input/sphere_triangles.dat b/doc/tutorials/03-object_in_fluid/scripts/input/sphere_triangles.dat new file mode 100644 index 00000000000..a9321d1aa77 --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/input/sphere_triangles.dat @@ -0,0 +1,782 @@ +93 14 13 +95 91 90 +9 8 96 +101 94 18 +105 26 25 +12 11 104 +99 90 100 +19 18 94 +25 24 102 +25 102 105 +105 102 92 +101 18 17 +16 15 98 +90 97 100 +92 106 105 +22 21 109 +109 21 103 +111 23 22 +112 106 92 +113 0 12 +113 93 13 +13 0 113 +14 93 114 +107 111 97 +113 12 104 +93 113 104 +111 22 109 +91 95 112 +112 92 91 +112 95 96 +15 14 114 +114 98 15 +108 9 96 +96 95 108 +110 94 101 +103 94 110 +110 100 97 +103 110 109 +90 91 107 +107 97 90 +102 107 92 +107 91 92 +103 21 20 +109 110 97 +111 109 97 +118 24 23 +118 111 107 +23 111 118 +119 108 95 +110 101 120 +120 100 110 +102 24 118 +102 118 107 +108 119 115 +11 10 115 +115 104 11 +104 115 117 +121 10 9 +121 108 115 +115 10 121 +9 108 121 +16 98 123 +124 1 19 +20 1 124 +19 94 124 +114 122 98 +103 20 124 +103 124 94 +99 122 116 +17 16 123 +123 101 17 +99 100 120 +95 90 125 +99 116 125 +125 90 99 +8 7 126 +126 7 106 +126 96 8 +119 95 125 +119 125 116 +123 120 101 +99 120 123 +123 98 122 +99 123 122 +119 116 117 +117 116 122 +119 117 115 +93 104 117 +114 93 117 +114 117 122 +6 2 127 +127 2 26 +105 106 127 +127 26 105 +106 7 6 +6 127 106 +112 96 126 +112 126 106 +133 25 26 +33 32 134 +137 130 129 +138 137 132 +130 137 138 +132 137 140 +140 135 132 +132 135 141 +142 137 129 +143 134 32 +131 134 143 +145 40 39 +145 136 133 +35 34 146 +147 36 35 +148 20 21 +142 128 140 +137 142 140 +147 35 146 +146 134 131 +144 22 23 +144 138 132 +141 144 132 +143 32 31 +149 131 143 +139 38 37 +136 129 130 +131 147 146 +138 144 150 +150 144 23 +31 30 152 +152 143 31 +153 141 148 +148 21 153 +144 141 153 +128 142 155 +155 149 128 +156 30 29 +158 1 20 +27 1 158 +159 3 33 +34 3 159 +26 2 160 +40 145 160 +160 2 40 +162 24 25 +25 133 162 +152 30 156 +133 26 160 +133 160 145 +150 23 24 +153 21 22 +144 153 22 +149 155 131 +128 149 154 +154 140 128 +140 154 157 +159 146 34 +134 146 159 +159 33 134 +158 20 148 +143 152 154 +154 149 143 +161 142 129 +129 139 161 +161 155 142 +135 140 157 +141 135 151 +141 151 148 +148 151 158 +163 139 37 +163 147 161 +161 139 163 +164 157 156 +156 29 164 +164 29 28 +151 164 28 +164 151 135 +157 164 135 +157 154 152 +157 152 156 +36 163 37 +147 163 36 +162 136 130 +133 136 162 +131 155 147 +147 155 161 +165 129 136 +139 129 165 +150 24 162 +130 138 150 +130 150 162 +165 145 39 +165 39 38 +136 145 165 +38 139 165 +151 28 27 +158 151 27 +171 39 40 +47 46 172 +175 168 167 +176 175 170 +168 175 176 +170 175 178 +178 173 170 +170 173 179 +180 175 167 +181 172 46 +169 172 181 +183 54 53 +183 174 171 +49 48 184 +185 50 49 +186 34 35 +180 166 178 +175 180 178 +185 49 184 +184 172 169 +182 36 37 +182 176 170 +179 182 170 +181 46 45 +187 169 181 +177 52 51 +174 167 168 +169 185 184 +176 182 188 +188 182 37 +45 44 190 +190 181 45 +191 179 186 +186 35 191 +182 179 191 +166 180 193 +193 187 166 +194 44 43 +196 3 34 +41 3 196 +197 4 47 +48 4 197 +40 2 198 +54 183 198 +198 2 54 +200 38 39 +39 171 200 +190 44 194 +171 40 198 +171 198 183 +188 37 38 +191 35 36 +182 191 36 +187 193 169 +166 187 192 +192 178 166 +178 192 195 +197 184 48 +172 184 197 +197 47 172 +196 34 186 +181 190 192 +192 187 181 +199 180 167 +167 177 199 +199 193 180 +173 178 195 +179 173 189 +179 189 186 +186 189 196 +201 177 51 +201 185 199 +199 177 201 +202 195 194 +194 43 202 +202 43 42 +189 202 42 +202 189 173 +195 202 173 +195 192 190 +195 190 194 +50 201 51 +185 201 50 +200 174 168 +171 174 200 +169 193 185 +185 193 199 +203 167 174 +177 167 203 +188 38 200 +168 176 188 +168 188 200 +203 183 53 +203 53 52 +174 183 203 +52 177 203 +189 42 41 +196 189 41 +61 60 210 +205 213 214 +214 208 205 +216 214 204 +208 214 216 +218 50 51 +220 210 60 +207 210 220 +11 12 221 +224 215 208 +211 215 224 +226 48 49 +226 225 212 +49 50 227 +209 225 227 +227 50 218 +209 227 218 +225 209 204 +226 49 227 +226 227 225 +211 53 54 +225 217 212 +224 52 53 +53 211 224 +219 224 208 +52 224 219 +223 10 11 +223 11 221 +220 60 59 +51 52 219 +218 51 219 +208 216 219 +216 204 209 +218 216 209 +216 218 219 +215 205 208 +205 215 222 +217 57 56 +212 56 55 +212 217 56 +207 206 221 +221 210 207 +223 221 206 +58 57 230 +230 57 217 +230 228 58 +231 225 204 +231 229 217 +217 225 231 +213 205 232 +232 205 222 +233 4 48 +55 4 233 +48 226 233 +12 0 234 +234 0 61 +59 58 228 +212 55 233 +212 233 226 +230 217 229 +228 230 229 +234 221 12 +210 221 234 +234 61 210 +59 228 220 +204 214 235 +214 213 236 +236 235 214 +237 207 220 +206 207 237 +231 204 235 +231 235 229 +237 228 229 +237 220 228 +237 229 235 +238 9 10 +232 9 238 +238 10 223 +213 206 236 +206 237 236 +236 237 235 +238 206 213 +213 232 238 +223 206 238 +8 9 232 +8 232 222 +54 2 239 +239 211 54 +239 2 6 +240 6 7 +239 6 240 +239 240 211 +215 211 240 +240 222 215 +7 8 222 +7 222 240 +13 14 245 +62 63 244 +241 246 247 +247 242 241 +251 64 65 +245 248 253 +245 253 255 +258 248 15 +259 69 70 +261 244 63 +243 244 261 +255 67 68 +251 250 243 +262 66 67 +262 67 255 +262 255 253 +261 63 64 +64 251 261 +261 251 243 +258 15 16 +260 242 247 +252 241 254 +241 242 254 +72 73 249 +15 248 14 +14 248 245 +256 244 243 +242 260 259 +256 243 263 +258 16 264 +256 263 265 +251 65 266 +266 250 251 +267 71 72 +254 71 267 +271 0 13 +68 0 271 +13 245 271 +70 71 272 +272 71 254 +266 65 66 +262 266 66 +255 68 271 +255 271 245 +269 249 265 +263 269 265 +247 246 264 +258 264 268 +268 264 246 +268 248 258 +73 74 265 +265 249 73 +265 74 256 +254 242 272 +272 242 259 +259 70 272 +264 16 17 +267 72 249 +267 249 269 +267 252 254 +267 269 252 +257 250 266 +262 253 257 +257 266 262 +273 253 248 +257 253 273 +248 268 273 +274 18 260 +260 247 274 +17 18 274 +264 17 274 +264 274 247 +18 19 260 +270 252 269 +269 263 270 +275 250 257 +243 250 276 +270 263 276 +276 263 243 +277 268 246 +277 275 257 +19 1 278 +69 259 278 +278 1 69 +241 252 279 +279 252 270 +276 250 275 +270 276 275 +277 257 273 +268 277 273 +260 19 278 +260 278 259 +246 241 279 +277 246 279 +270 275 279 +275 277 279 +280 5 62 +75 5 280 +74 75 280 +244 256 280 +280 62 244 +74 280 256 +75 74 286 +287 32 33 +282 283 290 +285 290 291 +291 290 283 +293 290 285 +285 288 293 +294 288 285 +282 290 295 +32 287 296 +296 287 284 +81 82 298 +286 289 298 +299 76 77 +77 78 300 +70 69 301 +293 281 295 +293 295 290 +299 77 300 +284 287 299 +72 71 297 +285 291 297 +285 297 294 +31 32 296 +296 284 302 +79 80 292 +283 282 289 +299 300 284 +303 297 291 +72 297 303 +305 30 31 +31 296 305 +301 294 306 +306 70 301 +306 294 297 +308 295 281 +281 302 308 +29 30 309 +311 1 27 +69 1 311 +33 3 312 +312 3 76 +313 5 75 +313 298 82 +82 5 313 +74 73 315 +315 286 74 +309 30 305 +313 75 286 +298 313 286 +73 72 303 +71 70 306 +71 306 297 +284 308 302 +307 302 281 +281 293 307 +310 307 293 +76 299 312 +312 299 287 +287 33 312 +301 69 311 +307 305 296 +296 302 307 +282 295 314 +314 292 282 +295 308 314 +310 293 288 +304 288 294 +301 304 294 +311 304 301 +79 292 316 +314 300 316 +316 292 314 +309 310 317 +317 29 309 +28 29 317 +28 317 304 +288 304 317 +288 317 310 +305 307 310 +309 305 310 +79 316 78 +78 316 300 +283 289 315 +315 289 286 +300 308 284 +314 308 300 +289 282 318 +318 282 292 +315 73 303 +303 291 283 +315 303 283 +81 298 318 +80 81 318 +318 298 289 +318 292 80 +27 28 304 +27 304 311 +41 42 325 +82 81 323 +324 46 47 +319 320 328 +322 328 329 +329 328 320 +331 328 322 +322 326 331 +332 326 322 +325 326 332 +319 328 333 +46 324 334 +334 324 321 +88 89 336 +323 327 336 +337 83 84 +84 85 338 +331 333 328 +337 84 338 +321 324 337 +79 78 335 +322 329 335 +322 335 332 +45 46 334 +334 321 339 +86 87 330 +320 319 327 +337 338 321 +340 335 329 +79 335 340 +341 325 42 +326 325 341 +43 44 343 +47 4 345 +345 4 83 +346 5 82 +346 336 89 +89 5 346 +81 80 347 +347 323 81 +346 82 323 +336 346 323 +80 79 340 +321 342 339 +341 42 43 +83 337 345 +345 337 324 +324 47 345 +343 341 43 +319 333 348 +348 330 319 +333 342 348 +86 330 349 +348 338 349 +349 330 348 +344 331 326 +326 341 344 +341 343 344 +86 349 85 +85 349 338 +320 327 347 +347 327 323 +338 342 321 +348 342 338 +334 339 350 +350 339 344 +327 319 351 +351 319 330 +347 80 340 +340 329 320 +347 340 320 +331 339 333 +339 331 344 +342 333 339 +350 44 45 +45 334 350 +343 44 350 +344 343 350 +88 336 351 +87 88 351 +351 336 327 +351 330 87 +325 332 352 +352 77 76 +353 335 78 +353 352 332 +332 335 353 +354 3 41 +76 3 354 +353 78 77 +352 353 77 +354 352 76 +325 352 354 +354 41 325 +55 56 363 +361 60 61 +365 364 356 +356 359 365 +355 365 367 +367 365 359 +86 85 369 +60 361 371 +371 361 358 +373 68 67 +376 372 363 +359 366 377 +377 366 362 +378 85 84 +84 372 378 +372 84 83 +369 85 378 +369 378 360 +376 360 378 +376 378 372 +89 88 362 +363 368 376 +88 87 377 +377 362 88 +359 377 370 +370 377 87 +56 57 368 +56 368 363 +67 66 375 +373 67 375 +59 60 371 +370 87 86 +370 86 369 +370 367 359 +360 355 367 +360 367 369 +370 369 367 +359 356 366 +374 366 356 +373 357 358 +358 361 373 +357 373 375 +381 57 58 +368 57 381 +58 379 381 +368 380 382 +382 376 368 +383 356 364 +374 356 383 +385 4 55 +83 4 385 +55 363 385 +61 0 386 +386 0 68 +379 58 59 +382 355 360 +376 382 360 +372 83 385 +372 385 363 +380 368 381 +380 381 379 +384 355 382 +380 384 382 +68 373 386 +386 373 361 +361 61 386 +387 357 364 +371 379 59 +371 358 388 +389 364 365 +387 364 389 +388 358 357 +387 388 357 +355 384 389 +389 365 355 +389 384 387 +380 379 388 +379 371 388 +384 380 388 +384 388 387 +66 65 390 +390 65 383 +375 66 390 +364 357 390 +390 383 364 +390 357 375 +391 5 89 +89 362 391 +62 5 391 +63 62 392 +392 62 391 +362 392 391 +392 362 366 +366 374 392 +383 65 64 +374 383 64 +374 64 63 +392 374 63 diff --git a/doc/tutorials/03-object_in_fluid/scripts/simulation.tcl b/doc/tutorials/03-object_in_fluid/scripts/simulation.tcl new file mode 100644 index 00000000000..e5629511f5b --- /dev/null +++ b/doc/tutorials/03-object_in_fluid/scripts/simulation.tcl @@ -0,0 +1,75 @@ +# Copyright (C) 2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +file delete -force "output" +file mkdir output + +# what input files to read +set fileNodes "input/cell_nodes.dat" +set fileTriangles "input/cell_triangles.dat" + +# integrator settings for the simulation +setmd time_step 0.1 +setmd skin 0.4 +thermostat off + +# rectangular channel box geometry +set boxX 50 +set boxY 22 +set boxZ 20 +setmd box_l $boxX $boxY $boxZ + +source boundaries.tcl + +# initialization of the object-in-fluid mechanisms +oif_init + +# creating templates +oif_create_template template-id 0 nodes-file $fileNodes triangles-file $fileTriangles stretch 3.0 3.0 3.0 ks 0.07 kb 0.01 kal 0.01 kag 0.01 kv 10.0 + +set pi 3.14159265359 + +# adding cells +oif_add_object object-id 0 template-id 0 origin 5 15 5 rotate 0 0 [expr $pi/2] part-type 0 mass 1 +oif_add_object object-id 1 template-id 0 origin 5 5 15 rotate 0 0 0 part-type 1 mass 1 + +# cell-cell interactions +inter 0 1 soft-sphere 0.005 2.0 0.3 0.0 + +# cell-wall interactions +inter 0 10 soft-sphere 0.0001 1.2 0.1 0.0 + +# set up fluid +lbfluid grid 1 dens 1.0 visc 1.5 tau 0.1 friction 0.5 + +# setting the constant velocity +# of the fluid on the left side of the md_box +lbboundary rhomboid velocity 0.005 0 0 corner 0 1 1 a 1 1 1 b 0 [expr $boxY-1] 1 c 0 1 [expr $boxZ-1] direction 1 + +# main iteration loop +set steps 200 +set counter 0 +while { $counter<200} { + + set cycle [expr $counter*$steps] + puts "cycle $cycle" + lbfluid print vtk velocity "output/fluid$cycle.vtk" + oif_object_output object-id 0 vtk-pos "output/cell0_$cycle.vtk" + oif_object_output object-id 1 vtk-pos "output/cell1_$cycle.vtk" + integrate $steps + incr counter +} diff --git a/doc/tutorials/Makefile.am b/doc/tutorials/Makefile.am index c89bb02e2b5..64dffb735d3 100644 --- a/doc/tutorials/Makefile.am +++ b/doc/tutorials/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -SUBDIRS=01-lennard_jones 02-charged_system +SUBDIRS=01-lennard_jones 02-charged_system 03-object_in_fluid if DEVEL_SRC diff --git a/doc/tutorials/common/common.tex b/doc/tutorials/common/common.tex index f0b00435fd6..160bfd304b6 100644 --- a/doc/tutorials/common/common.tex +++ b/doc/tutorials/common/common.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/Makefile.am b/doc/ug/Makefile.am index 110b21a81ce..c17d489f382 100644 --- a/doc/ug/Makefile.am +++ b/doc/ug/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold # # This file is part of ESPResSo. diff --git a/doc/ug/analysis-core.tex b/doc/ug/analysis-core.tex index b1c771014dd..532e0d20e49 100644 --- a/doc/ug/analysis-core.tex +++ b/doc/ug/analysis-core.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2012,2013 The ESPResSo project +% Copyright (C) 2012,2013,2014 The ESPResSo project % % This file is part of ESPResSo. % @@ -54,8 +54,11 @@ \section{Observables} \subsection{Introduction} The first step of the core analysis is to tell \es to create an observable. An observable in the sense of the core analysis can be considered as -a rule how to compute a certain set of numbers from a given state of the system. -It does not refer to the numbers itself. +a rule how to compute a certain set of numbers from a given state of the system +or a role how to collect data from other observables. Any observable +is represented as a single array of double values. Any more complex +shape (tensor, complex number, \ldots) must be compatible to this +prerequisite. Every observable however documents the storage order. Creating an observable means just allocating the corresponding memory, assigning a function to compute the observable value and reserving an \var{id} which will be used to refer @@ -66,7 +69,10 @@ \subsection{Introduction} The observable value is computed from the current state of the system at the moment when it is needed, \ie when requested explicitly by the user calling the \verb!observable print! function or when requested -automatically by some other analysis function. +automatically by some other analysis function. Updating is an orthogonal +concept: Observables that collect data over time (e.g. the average observable) +need to be updated regularly, even though their current value is not +of interest. Not all observables are implemented in parallel. When performing a parallel computation, too frequent updates to observables which are not implemented @@ -90,6 +96,8 @@ \subsubsection{Available observables} They are generic to all observables and are described after the list of observables. \todo{Missing descriptions of parameters of several observables} +Here are the observables, that only depend on the current state of the simulation +system: \begin{itemize} \item \lit{particle_positions} \var{particle\_specifications}\\ Positions of the particles, in the format @@ -100,6 +108,13 @@ \subsubsection{Available observables} $v^x_1,\ v^y_1,\ v^z_1,\ v^x_2,\ v^y_2,\ v^z_2,\ \dots\ v^x_n,\ v^y_n,\ v^z_n$. The particles are ordered ascending according to their ids. + \item \lit{particle_body_velocities} \var{particle\_specifications}\\ + Velocities of the particles in the body frame, in the format\\ + $v^x_1,\ v^y_1,\ v^z_1,\ v^x_2,\ v^y_2,\ v^z_2,\ + \dots\ v^x_n,\ v^y_n,\ v^z_n$. + The particles are ordered ascending according to their ids. This + command only produces a meaningful result when \texttt{ROTATIONS} + is compiled in. \item \lit{particle_forces} \var{particle\_specifications}\\ Forces on the particles, in the format\\ $f^x_1,\ f^y_1,\ f^z_1,\ f^x_2,\ f^y_2,\ f^z_2,\ @@ -111,6 +126,12 @@ \subsubsection{Available observables} \dots\ \omega^x_n,\ \omega^y_n,\ \omega^z_n$. The particles are ordered ascending according to their ids and the angular velocity/momentum is specified in the laboratory frame. + \item \lit{particle_body_angular_momentum} \var{particle\_specifications}\\ + Angular momenta (omega) of the particles, in the format\\ + $\omega^x_1,\ \omega^y_1,\ \omega^z_1,\ \omega^x_2,\ \omega^y_2,\ \omega^z_2,\ + \dots\ \omega^x_n,\ \omega^y_n,\ \omega^z_n$. + The particles are ordered ascending according to their ids and the + angular velocity/momentum is specified in the body (co-rotating) frame. \item \lit{com_position} \var{particle\_specifications} \opt{blocked \var{size}}\\ Position of the centre of mass. If \lit{blocked \var{size}} is specified, @@ -190,13 +211,25 @@ \subsubsection{Available observables} \item \lit{lb_radial_velocity_profile} \\ Compute the Lattice-Boltzmann velocity profile in cylindrical coordinates. For profile specifications, see section~\ref{sec:DensProfSpec}. + \end{itemize} +The tclcommand observable is a helpful tool, that allows to make the +analysis framework much more versatile, by allowing +the evaluation of arbitrary tcl commands. + \begin{itemize} \item \lit{tclcommand \var{dimQ} \var{command}} \\ An arbitrary Tcl function that returns a list of floating point numbers of fixed size \var{dimQ} can be specified. Although its execution might be slow, it allows to prototype new observables without a lot of trouble. Many existing analysis commands can be made to cooperate with the core analysis that way. \end{itemize} +The following commands allow to collect data automatically over time +once their autoupdate feature is enabled. + \begin{itemize} + \item \lit{average \var{ref}} \\ + The running average of the reference observable with id \var{ref}. + It can be resetted by \lit{observable \var{no} reset} + \end{itemize} \subsection{Printing an observable} \begin{essyntax} observable \var{id} print \opt{formatted} @@ -373,7 +406,10 @@ \subsection{Creating a correlation} corresponding components of the observables, \ie $C_i = (A_i-B_i)^2$. Example: when $A$ is \lit{particle_positions}, it produces the mean square displacement (for each component separately). + \item \lit{tensor_product} \\ + Tensor product of $A$ and $B$, \ie $C_{i \cdot l_B + j} = A_i B_j$, with $l_B$ the length of $B$. \item \lit{complex_conjugate_product} + \todo{Complex conjugate product must be defined.} \item \lit{fcs_acf} \var{w_x}\var{w_y} \var{w_z} \\ Fluorescence Correlation Spectroscopy (FCS) autocorrelation function, \ie \begin{equation} diff --git a/doc/ug/analysis.tex b/doc/ug/analysis.tex index 13ecc3d14a4..b4b8da05867 100644 --- a/doc/ug/analysis.tex +++ b/doc/ug/analysis.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -209,7 +209,13 @@ \subsection{Vkappa} analyze Vkappa \opt{\alt{ reset \asep read \asep set \var{V_{\kappa, 1}} \var{V_{\kappa, 2}} \var{avk} } } \end{essyntax} -\todo{Document the usage and what it is!} +Calculates the compressibility $V \times \kappa_T$ through the Volume fluctuations +$V \times \kappa_T = \beta \left(\langle V^2\rangle - \langle V \rangle^2\right)$ \cite{kolb99a}. +Given no arguments this function calculates and returns the current value of the +running average for the volume fluctuations. +The argument \keyword{reset} clears the currently stored values. With \keyword{read} +the cumulative mean volume, cumulative mean squared volume and how many samples were +used can be retrieved. Likewise the option \keyword{set} enables you to set those. \subsection{Radial distribution function} \label{analyze:rdf} @@ -389,7 +395,10 @@ \subsection{Finding holes} \analyzeindex{finding holes} \begin{essyntax} - analyze holes \var{typeid_\mathrm{probe}} \var{mesh\_size} + analyze holes \var{typeid_\mathrm{probe}} \var{mesh\_size} + \begin{features} + \required{LENNARD_JONES} + \end{features} \end{essyntax} Function for the calculation of the unoccupied volume (often also called free volume) in a system. Details can be found in @@ -427,8 +436,27 @@ \subsection{Finding holes} numbers give the position of a mesh point in the linear representation of the 3D grid (coordinates are in the order x, y, z). Attention: the algorithm assumes a cubic box. Surface results have not been tested. -Requires the feature LENNARD_JONES. \todo{I think there is still a - bug in there (Hanjo)}. +\todo{I think there is still a bug in there (Hanjo)}. + + +\subsection{Temperature of the LB fluid} +\label{analyze:lbtemp} +\analyzeindex{fluid temperature} + +\begin{essyntax} + \require{1 or 2 or 3}{analyze fluid temp} + \begin{features} + \required[1]{LB} + \required[2]{LB_GPU} + \required[3]{ELECTROKINETICS} + \end{features} +\end{essyntax} + +This command returns the temperature of the lattice-Boltzmann (LB) +fluid, see Chapter~\ref{sec:lb}, by averaging over the fluid nodes. In +case \feature{LB_BOUNDARIES} or \feature{LB_BOUNDARIES_GPU} are +compiled in and boundaries are defined, only the available fluid +volume is taken into account. \subsection{Energies} \label{analyze:energy} @@ -453,7 +481,6 @@ \subsection{Energies} \{ energy \var{value} \} \{ kinetic \var{value} \} \{ interaction \var{value} \} \dots \end{code} - \subsection{Pressure} \label{analyze:pressure} \analyzeindex{pressure} @@ -462,7 +489,7 @@ \subsection{Pressure} \variant{1} analyze pressure \variant{2} analyze pressure total \variant{3} analyze pressure \alt{totals \asep ideal \asep coulomb - \asep \\tot_nonbonded_inter \asep tot_nonbonded_intra} + \asep \\tot_nonbonded_inter \asep tot_nonbonded_intra \asep vs_relative} \variant{4} analyze pressure bonded \var{bondid} \variant{5} analyze pressure nonbonded \var{typeid1} \var{typeid2} \variant{6} analyze pressure nonbonded_intra \opt{\var{typeid}} @@ -505,7 +532,8 @@ \subsection{Pressure} Anything outside that is currently not implemented. Four-body dihedral potentials are not included. In case of rigid body rotation, virial contribution from torques is not included. -Constraints of any kind are not currently accounted for in the pressure calculations. +The pressure contribution for rigid bodies constructed by means of the VIRTUAL\_SITES\_RELATIVE mechanism is included. On the other hand, the pressure contribution for rigid bonds is not included. +All other constraints of any kind are not currently accounted for in the pressure calculations. The pressure is no longer correct, e.g., when particles are confined to a plane. The command is implemented in parallel. @@ -626,18 +654,6 @@ \section{Analyzing groups of particles (molecules)} \analyzeindex{topologies} \label{analyze:set} -The following set of functions is designed to facilitate analysis of molecules. Molecules are expected to be a group of particles -comprising a contiguous range of particle IDs. Each molecule -is a set of consecutively numbered particles and all molecules -are supposed to consist of the same number of particles. -Some functions in this group require that the particles constituting -a molecule are connected into linear chains (particle $n$ is connected -to $n+1$ and so on) while others are applicable to molecules -of whatever topology. - -The \lit{analyze set} command defines the structure of the current -system to be used with some of the analysis functions. - \begin{essyntax} \variant{1} analyze set chains \opt{\var{chain\_start} \var{n\_chains} \var{chain\_length}} @@ -646,13 +662,26 @@ \section{Analyzing groups of particles (molecules)} %\variant{4} analyze set trapmol \var{mol\_id} \var{xpos} \var{ypos} \var{zpos} \var{isrelative} \var{spring\_constant} \var{drag\_constant} coords \var{trapped\_coord\_x} \var{trapped\_coord\_y} \var{trapped\_coord\_z} noforce\_coords \var{noforce\_coord\_x} \var{noforce\_coord\_y} \var{noforce\_coord\_z} \end{essyntax} +The above set of functions is designed to facilitate analysis of +molecules. Molecules are expected to be a group of particles +comprising a contiguous range of particle IDs. Each molecule is a set +of consecutively numbered particles and all molecules are supposed to +consist of the same number of particles. Some functions in this group +require that the particles constituting a molecule are connected into +linear chains (particle $n$ is connected to $n+1$ and so on) while +others are applicable to molecules of whatever topology. + +The \lit{analyze set} command defines the structure of the current +system to be used with some of the analysis functions. + Variant \variant{1} defines a set of \var{n\_chains} chains of equal length \var{chain\_length} which start with the particle with particle number \var{chain\_start} and are consecutively numbered (\ie the last particle in that topology has number $\var{chain\_start} + \var{n\_chains}*\var{chain\_length} - 1$). -Variant \variant{2} synchronizes topology and particle data, assigning \var{mol\_id} values to particles. +Variant \variant{2} synchronizes topology and particle data, assigning +\var{mol\_id} values to particles. Variant \variant{3} will return the chains currently stored. diff --git a/doc/ug/aux.tex b/doc/ug/aux.tex index be54b447813..031a2a4193c 100644 --- a/doc/ug/aux.tex +++ b/doc/ug/aux.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2012,2013 The ESPResSo project +% Copyright (C) 2010,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -445,15 +445,9 @@ \subsection{\texttt{t\_random}} \end{code} with \var{status-list} being the tcl-list mentioned above without any braces. Be careful! A complete recovery of the current state of the -simulation is only possible if you make sure to include a call to The -invalidate\_system command after you saved the checkpoint -(tcl\_checkpoint\_set will do this automatically for you), because the -integration algorithm re-uses the old forces calculated in the -previous time-step; if something has changed in the system (or if it -has just been read from a file) the forces are re-derived (including -application of the thermostat and its random numbers) leading to -slightly different results compared to the uninterrupted run (see The -invalidate\_system command for details)! +simulation is only possible if you make sure to include a call to the +\texttt{sort_particles} command after you saved the blockfile to make +sure random numbers are applied in the same order. \end{itemize} The C implementation is t\_random @@ -498,16 +492,9 @@ \subsection{\texttt{The bit\_random command}} bit\_random stat \end{code} with being the tcl-list mentioned above without any -braces. Be careful! A complete recovery of the current state of the -simulation is only possible if you make sure to include a call to The -invalidate\_system command after you saved the checkpoint -(tcl\_checkpoint\_set will do this automatically for you), because the -integration algorithm re-uses the old forces calculated in the -previous time-step; if something has changed in the system (or if it -has just been read from a file) the forces are re-derived (including -application of the thermostat and its random numbers) leading to -slightly different results compared to the uninterrupted run (see The -invalidate\_system command for details)! +braces. Be careful! See \ref{ssec:trandom} for more information +on how to recover of the current state, include the sequence the random +numbers are applied. \item Note further that the bit-wise display of integers, as it is used by this random number generator, is platform dependent. As long as you stay on the same architecture this doesn't matter at all; diff --git a/doc/ug/check_consistency.sh b/doc/ug/check_consistency.sh index 6f1366fd4ae..954c991d4df 100644 --- a/doc/ug/check_consistency.sh +++ b/doc/ug/check_consistency.sh @@ -1,7 +1,7 @@ #!/bin/bash # check documentation of configuration switches # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010 Axel Arnold # # This file is part of ESPResSo. diff --git a/doc/ug/citations.bib b/doc/ug/citations.bib index 6ca5e18ee10..3b52a5a81ee 100644 --- a/doc/ug/citations.bib +++ b/doc/ug/citations.bib @@ -27,16 +27,6 @@ @INCOLLECTION{espresso2 } -@ARTICLE{adress, - author = {C.~Junghans and S.~Poblete}, - title = {A reference implementation of the adaptive resolution scheme in {ESPResSo}}, - journal = {Comp. Phys. Comm.}, - year = {2010}, - volume = {181}, - pages = {1449--1454}, - number = {8} -} - @ARTICLE{elc, author = {Axel Arnold and Jason {de Joannis} and Christian Holm}, title = {{Electrostatics in Periodic Slab Geometries I+II}}, @@ -109,3 +99,19 @@ @ARTICLE{cimrak volume = {64}, pages = {278--288} } + +@ARTICLE{sega13c, + title = {Mesoscale structures at complex fluid–fluid interfaces: a novel lattice Boltzmann/molecular dynamics coupling}, + author = {M. Sega and M. Sbragaglia and S. S. Kantorovich and A. O. Ivanov}, + journal = {Soft Matter}, + year = {2013, in press}, + doi = {10.1039/C3SM51556G} +} +@article{shan93a, + author={ X. Shan and H. Chen }, + title = {Lattice Boltzmann model for simulating flows with multiple phases and components}, + journal={ Phys. Rev. E}, + volume={47}, + pages={1815}, + year={1993} +} diff --git a/doc/ug/contributing.tex b/doc/ug/contributing.tex index 18bc663c674..9b68b4ba6a3 100644 --- a/doc/ug/contributing.tex +++ b/doc/ug/contributing.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2012,2013 The ESPResSo project +% Copyright (C) 2010,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/electrokinetics.tex b/doc/ug/electrokinetics.tex new file mode 100644 index 00000000000..e05b80c1715 --- /dev/null +++ b/doc/ug/electrokinetics.tex @@ -0,0 +1,504 @@ +% Copyright (C) 2013,2014 The ESPResSo project +% +% This file is part of ESPResSo. +% +% ESPResSo is free software: you can redistribute it and/or modify it +% under the terms of the GNU General Public License as published by the +% Free Software Foundation, either version 3 of the License, or (at your +% option) any later version. +% +% ESPResSo is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +% General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . +% +\newcommand{\lb}{l_\mathrm{B}} +\newcommand{\kT}{k_\mathrm{B}T} + +\chapter{\label{sec:electrokinetics}Electrokinetics} +\newescommand{electrokinetics} + +The electrokinetics setup in \es{} allows for the description of +electro-hydrodynamic systems on the level of ion density distributions +coupled to a Lattice-Boltzmann (LB) fluid. The ion density +distributions may also interact with explicit charged particles, which +are interpolated on the LB grid. In the following paragraph we +briefly explain the electrokinetic model implemented in \es, before +we come to the description of the interface. + +If you are interested in using the electrokinetic implementation in +\es for scientific purposes, please contact G.~Rempfer before you +start your project. + +\section{Electrokinetic Equations} + +In the electrokinetics code we solve the following system of coupled continuity, +diffusion-advection, Poisson, and Navier-Stokes equations: +\begin{eqnarray} +\label{eq:ek-model-continuity} \frac{\partial n_k}{\partial t} & = & -\, \nabla \cdot \vec{j}_k \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-model-fluxes} \vec{j}_{k} & = & -D_k \nabla n_k - \nu_k \, q_k n_k\, \nabla \Phi + n_k \vec{v}_{\mathrm{fl}} \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-model-poisson} \Delta \Phi & = & -4 \pi \, \lb \, \kT \sum_k q_k n_k \vphantom{\left(\frac{\partial}{\partial}\right)}; \\ +\nonumber \left(\frac{\partial \vec{v}_{\mathrm{fl}}}{\partial t} + \vec{v}_{\mathrm{fl}} \cdot \vec{\nabla} \vec{v}_{\mathrm{fl}} \right) \rho_\mathrm{fl} & = & -\kT \, \nabla \rho_\mathrm{fl} - q_k n_k \nabla \Phi \\ +\label{eq:ek-model-velocity} & & +\, \eta \vec{\Delta} \vec{v}_{\mathrm{fl}} + (\eta / 3 + \eta_{\text{\,b}}) \nabla (\nabla \cdot \vec{v}_{\mathrm{fl}}) \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-model-continuity-fl} \frac{\partial \rho_\mathrm{fl}}{\partial t} & = & -\,\nabla\cdot\left( \rho_\mathrm{fl} \vec{v}_{\mathrm{fl}} \right) \vphantom{\left(\frac{\partial}{\partial}\right)} , +\end{eqnarray} +which define relations between the following observables +\begin{description}[itemsep=0cm,labelindent=1.5em,leftmargin=4.5em,style=nextline] + \item[$n_k$] the number density of the particles of species $k$, + \item[$\vec{j}_k$] the number density flux of the particles of species $k$, + \item[$\Phi$] the electrostatic potential, + \item[$\rho_{\mathrm{fl}}$] the mass density of the fluid, + \item[$\vec{v}_{\mathrm{fl}}$] the advective velocity of the fluid, +\end{description} +and input parameters +\begin{description}[itemsep=0cm,labelindent=1.5em,leftmargin=4.5em,style=nextline] + \item[$D_k$] the diffusion constant of species $k$, + \item[$\nu_k$] the mobility of species $k$, + \item[$q_k$] the charge of a single particle of species $k$, + \item[$\lb$] the Bjerrum length, + \item[$\kT$] the thermal energy given by the product of Boltzmann's constant + $k_\text{B}$\\and the temperature $T$, + \item[$\eta$] the dynamic viscosity of the fluid, + \item[$\eta_{\text{\,b}}$] the bulk viscosity of the fluid. +\end{description} +The temperature $T$, and diffusion constants $D_k$ and mobilities $\nu_k$ of +individual species are linked through the Einstein-Smoluchowski relation $D_k / +\nu_k = \kT$. The system of equations described in +Eqs.~\eqref{eq:ek-model-continuity}-\eqref{eq:ek-model-continuity-fl}, combining +diffusion-advection, electrostatics, and hydrodynamics is conventionally +referred to as the \textit{Electrokinetic Equations}. + +\todo{Complete in broad strokes the applicability of the + electrokinetics model. Also mention the difference in temperatures + between EK and LB species.} + +The electrokinetic equations have the following properties: +\begin{itemize} +\item On the coarse time and length scale of the model, the dynamics + of the particle species can be described in terms of smooth density + distributions and potentials as opposed to the microscale where + highly localized densities cause singularities in the potential. + + In most situations, this restricts the application of the model to + species of monovalent ions, since ions of higher valency typically + show strong condensation and correlation effects -- the localization + of individual ions in local potential minima and the subsequent + correlated motion with the charges causing this minima. + +\item Only the entropy of an ideal gas and electrostatic interactions + are accounted for. In particular, there is no excluded volume. + + This restricts the application of the model to monovalent ions and + moderate charge densities. At higher valencies or densities, + overcharging and layering effects can occur, which lead to + non-monotonic charge densities and potentials, that can not be + covered by a mean-field model such as Poisson-Boltzmann or this one. + + Even in salt free systems containing only counter ions, the + counter-ion densities close to highly charged objects can be + overestimated when neglecting excluded volume effects. Decades of + the application of Poisson-Boltzmann theory to systems of + electrolytic solutions, however, show that those conditions are + fulfilled for monovalent salt ions (such as sodium chloride or + potassium chloride) at experimentally realizable concentrations. + +\item Electrodynamic and magnetic effects play no role. Electrolytic + solutions fulfill those conditions as long as they don't contain + magnetic particles. + +\item The diffusion coefficient is a scalar, which means there can not + be any cross-diffusion. Additionally, the diffusive behavior has + been deduced using a formalism relying on the notion of a local + equilibrium. The resulting diffusion equation, however, is known to + be valid also far from equilibrium. + +\item The temperature is constant throughout the system. + +\item The density fluxes instantaneously relax to their local + equilibrium values. Obviously one can not extract information about + processes on length and time scales not covered by the model, such + as dielectric spectra at frequencies, high enough that they + correspond to times faster than the diffusive time scales of the + charged species. +\end{itemize} + +\section{Setup} + +\subsection{\label{ssec:ek-init}Initialization} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \opt{agrid \var{agrid}} + \opt{lb_density \var{lb\_density}} + \opt{visc \var{viscosity}} + \opt{bulk_visc \var{bulk\_viscosity}} + \opt{friction \var{gamma} } + \opt{gamma_odd \var{gamma\_odd}} + \opt{gamma_even \var{gamma\_even}} + \opt{T \var{T}} + \opt{bjerrum_length \var{bjerrum\_length}} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{electrokinetics} command initializes the LB fluid with a given +set of parameters, and it is very similar to the \es{} Lattice-Boltzmann +\lit{lbfluid} command in set-up. We therefore refer the reader to +Chapter~\ref{sec:lb} for details on the implementation of LB in \es{} and +describe only the major differences here. + +The first major difference with the LB implementation is that the +electrokinetics set-up is a Graphics Processing Unit (GPU) only implementation. +There is no Central Processing Unit (CPU) version, and at this time there are no +plans to make a CPU version available in the future. To use the electrokinetics +features it is therefore imperative that your computer contains a CUDA capable +GPU which is sufficiently modern. + +To set up a proper LB fluid using the \lit{electrokinetics} command one has to +specify at least the following options: \var{agrid}, \var{lb\_density}, \var{visc}, +\var{friction}, \var{T}, and \var{bjerrum\_length}. The other options can be used to +modify the behavior of the LB fluid. Note that the \lit{electrokinetics} command +does not allow the user to set the time step parameter \lit{tau} as is the case for +the \lit{lbfluid} command, this parameter is instead taken directly from the input +of the \lit{setmd} \texttt{t\_step} command. The LB \emph{mass density} is set +independently from the electrokinetic \emph{number densities}, since the LB fluid +serves only as a medium through which hydrodynamic interactions are propagated, +as will be explained further in the next paragraph. If no \var{lb\_density} is +specified, then our algorithm assumes \var{lb\_density} = 1.0. The two `new' +parameters are \var{T} the temperature at which the diffusive species are simulated +and \var{bjerrum\_length} the Bjerrum length associated with the electrostatic +properties of the medium. See the above description of the electrokinetic +equations for an explanation of the introduction of a temperature, which does +not come in directly via a thermostat that produces thermal fluctuations. + +\subsection{\label{ssec:ek-diff-species}Diffusive Species} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \var{species\_number} + \opt{density \var{density}} + \opt{D \var{D}} + \opt{valency \var{valency}} + \opt{ext_force \var{f_x} \var{f_y} \var{f_z}} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{electrokinetics} command followed by an integer \var{species\_number} +(in the range 0 to 10) and several options can be used to initialize the +diffusive species. Here the options specify: the number density +\var{density}, the diffusion coefficient \var{D}, the valency of the particles +of that species \var{valency}, and an optional external (electric) force which +is applied to the diffusive species. As mentioned before, the LB density is +completely decoupled from the electrokinetic densities. This has the advantage +that greater freedom can be achieved in matching the internal parameters to an +experimental system. Moreover, it is possible to choose parameters for which +the LB is more stable. The LB fluid must already be (partially) set up using the +\lit{electrokinetics} \var{agrid} ... command, before the diffusive species can +be initialized. The variables \var{density}, \var{D}, and \var{valency} must be +set to properly initialize the diffusive species; the \var{ext\_force} is +optional. + +\subsection{\label{ssec:ek-boundaries}Boundaries} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \require{2}{boundary} + \opt{charge_density \var{charge\_density}} + \opt{shape \var{shape\_args}} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{boundary} command allows one to set up (internal or external) boundaries +for the electrokinetics algorithm in much the same way as the \lit{lbboundary} +command is used for the LB fluid. The major difference with the LB command is +given by the option \var{charge\_density}, with which a boundary can be endowed +with a volume charge density. To create a surface charge density, a combination +of two oppositely charged boundaries, one inside the other, can be used. +However, care should be taken to maintain the surface charge density when the +value of \var{agrid} is changed. Currently, the following \var{shape}s are +available: wall, sphere, cylinder, rhomboid, pore, and stomatocyte. We refer to +the documentation of the \lit{lbboundary} command (Chapter~\ref{sec:lb}) for +information on the options \var{shape\_args} associated to these shapes. In +order to properly set up the boundaries, the \var{charge\_density} and relevant +\var{shape\_args} must be specified. + +\section{\label{ssec:ek-output}Output} + +\subsection{\label{ssec:ek-output-fields}Fields} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + print + \require{1 or 2}{\var{property}} + \opt{vtk} + filename [\var{filename}] + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The print parameter of the \lit{electrokinetics} command enables simple +visualization of simulation data. A property of the fluid field can be exported +into a file with name \var{filename} in one go. Currently, supported values of +the parameter \var{property} are: \var{density}, \var{velocity}, +\var{potential}, and \var{boundary}, which give the LB fluid density, the LB +fluid velocity, the electrostatic potential, and the location and type of the +boundaries, respectively. The boundaries can only be printed when the +\texttt{EK_BOUNDARIES} is compiled in. The additional option \lit{vtk} can be +used to directly export in the vtk format. The vtk format is readable +by visualization software such as paraview\footnote{http://www.paraview.org/} +and mayavi2\footnote{http://code.enthought.com/projects/mayavi/}. If the +\opt{vtk} option is not specified, a gnuplot readable data will be exported. + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \var{species\_number} + print + \var{property} + \opt{vtk} + filename [\var{filename}] + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +This print statement is similar to the above command. It enables the export of +diffusive species properties, namely: \var{density} and \var{flux}, which +specify the number density and flux of species \var{species\_number}, +respectively. + +\subsection{\label{ssec:ek-local-quantities}Local Quantities} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + node \var{x} \var{y} \var{z} + velocity + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{node} option of the \lit{electrokinetics} command allows one to output +the value of a quantity on a single LB node. The node is addressed using three +integer values which run from 0 to \var{dim\_x}/\var{agrid}, +\var{dim\_y}/\var{agrid}, and \var{dim\_z}/\var{agrid}, respectively. Thus far, +only the velocity of the LB fluid can be printed in the standard electrokinetics +implementation. For other quantities the \lit{lbnode} command may be used. + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \var{species\_number} + node \var{x} \var{y} \var{z} + density + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +This command can be used to output the number density of the +\var{species\_number}-th diffusive species on a single LB node. + +\section{Catalytic Reaction} + +\subsection{Concept} + +The electrokinetics solver implemented in \es{} can be used to +simulate a system, for which in addition to the electrokinetic +equations, there is a (local) catalytic reaction which converts one +species into another. + +If you are interested in using this implementation in \es{} for +scientific purposes, please contact J.~de~Graaf before you start your +project. + +Currently, a linear reaction is implemented which converts one species into two others, in +order to model the catalytic decomposition of hydrogen peroxide in the presence +of a platinum catalyst: $2 \mathrm{H}_{2}\mathrm{O}_{2} \rightarrow +2 \mathrm{H}_{2}\mathrm{O} + \mathrm{O}_{2}$. The decomposition of +$\mathrm{H}_{2}\mathrm{O}_{2}$ is in reality more complicated than the linear +reaction introduced here, since it is assumed to proceed via several intermediate complexed-states, +but our model can be thought of as modeling the rate-limiting step. +If we assume that there are three non-ionic species with number densities +$n_{k}$, where $n_{0} = [ \mathrm{H}_{2}\mathrm{O}_{2} ]$, +$n_{1} = [ \mathrm{H}_{2}\mathrm{O} ]$, and $n_{2} = [ \mathrm{O}_{2} ]$, +then we can write the (electro)kinetic equations for this system as + +\begin{eqnarray} +\label{eq:ek-reaction-continuity} \frac{\partial n_k}{\partial t} & = & -\, \nabla \cdot \vec{j}_k +\, f_{k} c n_{k} \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-reaction-fluxes} \vec{j}_{k} & = & -D_k \nabla n_k + n_k \vec{v}_{\mathrm{fl}} \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\nonumber \left(\frac{\partial \vec{v}_{\mathrm{fl}}}{\partial t} + \vec{v}_{\mathrm{fl}} \cdot \vec{\nabla} \vec{v}_{\mathrm{fl}} \right) \rho_\mathrm{fl} & = & -\kT \, \sum_{k} \nabla n_k \\ +\label{eq:ek-reaction-velocity} & & +\, \eta \vec{\Delta} \vec{v}_{\mathrm{fl}} + (\eta / 3 + \eta_{\text{\,b}}) \nabla (\nabla \cdot \vec{v}_{\mathrm{fl}}) \vphantom{\left(\frac{\partial}{\partial}\right)} ; \\ +\label{eq:ek-reaction-continuity-fl} \frac{\partial \rho_\mathrm{fl}}{\partial t} & = & -\,\nabla\cdot\left( \rho_\mathrm{fl} \vec{v}_{\mathrm{fl}} \right) \vphantom{\left(\frac{\partial}{\partial}\right)} , +\end{eqnarray} +which define relations between the following observables +\begin{description}[itemsep=0cm,labelindent=1.5em,leftmargin=4.5em,style=nextline] + \item[$n_k$] the number density of the particles of species $k$, + \item[$\vec{j}_k$] the number density flux of the particles of species $k$, + \item[$\rho_{\mathrm{fl}}$] the mass density of the fluid, + \item[$\vec{v}_{\mathrm{fl}}$] the advective velocity of the fluid, +\end{description} +and input parameters +\begin{description}[itemsep=0cm,labelindent=1.5em,leftmargin=4.5em,style=nextline] + \item[$D_k$] the diffusion constant of species $k$, + \item[$\kT$] the thermal energy given by the product of Boltzmann's constant + $k_\text{B}$\\and the temperature $T$, + \item[$\eta$] the dynamic viscosity of the fluid, + \item[$\eta_{\text{\,b}}$] the bulk viscosity of the fluid, + \item[$f_{k}$] the reaction constant $f_{0} \equiv -1$, $f_{1} = 1$ and $f_{2} = 0.5$ for the above reaction, + \item[$c$] the reaction rate. +\end{description} +In this set of equations we have fully decoupled the number densities and the +fluid mass density. N.B. We have set the initial fluid mass density is not necessarily +equal to the sum of the initial species number densities. This means that +some care needs to be taken in the interpretation of the results obtained using +this feature. In particular, the solution of the Navier-Stokes equation exclusively +models the momentum transport through the (multicomponent) fluid, while the diffusive +properties of the individual chemical species are handled by Eqs.~\eqref{eq:ek-reaction-continuity} +and~\eqref{eq:ek-reaction-fluxes}. + +It is important to note that to ensure mass conservation the reaction must satisfy: +\begin{equation} +\label{eq:ek-mass-balance} \sum_{k} f_{k} m_{k} = 0 , +\end{equation} +where $m_{k}$ is the molecular mass of a reactive species. Unfortunately, the current +electrokinetic implementation does not conserve mass flux locally. That is to say, the +LB fluid is compressible and the sum of the fluxes of the three species is not equal to +zero in the frame co-moving with the advective fluid velocity. It is therefore debatable +whether it is necessary to impose Eq.~\eqref{eq:ek-mass-balance}, since the EK algorithm +itself does not conserve mass density. However, we strived to be as accurate as +possible and in future versions of the EK algorithm the lack of incompressiblity will +be addressed. + +The reaction is specified by the second term on the right-hand side of +Eq.~\eqref{eq:ek-reaction-continuity}. It is important to note that this term +can be set locally, as opposed to the other terms in the equation system +Eqs.~\eqref{eq:ek-reaction-continuity}-\eqref{eq:ek-reaction-continuity-fl}, in +our implementation, as will become clear in the following. This has the +advantage that catalytic surfaces may be modeled. + +\subsection{\label{ssec:ek-reac-init}Initialization and Geometry Definition} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \require{3}{reaction} + \opt{reactant_index \var{reactant\_index}} + \opt{product0_index \var{product0\_index}} + \opt{product1_index \var{product1\_index}} + \opt{reactant_resrv_density \var{reactant\_resrv\_density}} + \opt{product0_resrv_density \var{product0\_resrv\_density}} + \opt{product1_resrv_density \var{product1\_resrv\_density}} + \opt{reaction_rate \var{reaction\_rate}} + \opt{mass_reactant \var{mass\_reactant}} + \opt{mass_product0 \var{mass\_product0}} + \opt{mass_product1 \var{mass\_product1}} + \opt{reaction_fraction_pr_0 \var{reaction\_fraction\_pr\_0}} + \opt{reaction_fraction_pr_1 \var{reaction\_fraction\_pr\_1}} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{electrokinetics reaction} command is used to set up the catalytic +reaction between three previously defined the diffusive species, of which the i +identifiers are given by \var{reactant\_index}, \var{product0\_index}, and +\var{product1\_index}, respectively. In the 1:2 reaction, these fulfill the role +of the reactant and the two products, as indicated by the naming convention. For +each species a reservoir (number) density must be set, given by the variables +\var{reactant\_resrv\_density}, \var{product0\_resrv\_density}, and +\var{product1\_resrv\_density}, respectively. These reservoir densities +correspond to the initial number densities associated with the reactive species. +The reservoir densities, in tandem with reservoir nodes, see below, can be used +to keep the reaction from depleting all the reactant in the simulation box. The +\var{reaction\_rate} variable specifies the speed at which the reaction proceeds. +The three masses (typically given in the atomic weight equivalent) are used to +determine the total mass flux provided by the reaction, as described above, and +are also used to check whether the reaction ratios that are given satisfy the +chemical requirement of mass conservation. Finally, the parameters +\var{reaction\_fraction\_pr\_0} and \var{reaction\_fraction\_pr\_1} specify +what fractions of the product are generated when a given quantity of reactant is +catalytically converted. To use a chemical reaction, all options for the +\lit{electrokinetics reaction} command must be specified. + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \require{3}{reaction} + \require{3}{region} + \opt{reaction_type \var{reaction\_type}} + \opt{shape \var{shape\_args}} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{region} option of the \lit{electrokinetics reaction} command allows one +to set up regions in which the reaction takes place with the help of the +constraints that are available to set up boundaries. The integer value +\var{reaction\_type} can be used to select the reaction: 0 no reaction takes +place for this region, 1 the catalytic reaction takes place in this region, and +2 the region functions as a reservoir, wherein the species densities are reset +to their initial (or reservoir) concentrations. The rest of the command follows +the same format of the \lit{electrokinetics boundary} command. Currently, the +following \var{shape}s are available: box, wall, sphere, cylinder, rhomboid, +pore, and stomatocyte. The box shape is a \lit{region} specific command, which +can be used to set the entire simulation box to a specific reaction value. To +use the \lit{electrokinetics reaction region} command, one must first set up +a reaction, as described above. To successfully specify a region all the +relevant arguments that go with the shape constraints must be provided. + +\subsubsection{\label{sssec:ek-pdb-parse}Parsing PDB Files} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + \require{2}{pdb-parse} + \var{pdb\_filename} + \var{itp\_filename} + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The \lit{electrokinetics pdb-parse} feature allows the user to parse simple PDB files, a file format introduced by the protein database to encode molecular structures. Together with a topology file (here \var{itp\_filename}) the structure gets interpolated to the \lit{electrokinetics} grid. For the input you will need to prepare a PDB file with a \lit{gromacs} force field to generate the topology file. Normally the PDB file extension is \lit{.pdb}, the topology file extension is \lit{.itp}. Obviously the PDB file is placed instead of \var{pdb\_filename} and the topology file instead of \var{itp\_filename}. \todo{At the moment this fails badly, if you try to parse incorrectly formatted files. This will be fixed in the future.} + +\subsection{\label{ssec:ek-reac-output}Reaction-Specific Output} + +\begin{essyntax} + \require{1 or 2 or 3}{electrokinetics} + print + \require{3}{\var{property}} + \opt{vtk} + \var{filename} [\var{filename}] + \begin{features} + \required[1]{ELECTROKINETICS} + \required[2]{EK_BOUNDARIES} + \required[3]{EK_REACTIONS} + \end{features} +\end{essyntax} +The print parameter of the \lit{electrokinetics} command can be used in +combination with the \texttt{EK\_REACTION} feature to give advanced output +options. Currently, supported values of the parameter \var{property} are: +\var{pressure} and \var{reaction\_tags}, which give the +location and type of the reactive regions and the ideal-gas pressure coming from +the diffusive species, respectively. To use this command a reaction must be set up. + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "ug" +%%% End: diff --git a/doc/ug/examples.tex b/doc/ug/examples.tex index a199e0e23db..50fab1b3573 100644 --- a/doc/ug/examples.tex +++ b/doc/ug/examples.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2012,2013 The ESPResSo project +% Copyright (C) 2010,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/features.tex b/doc/ug/features.tex index bcff31f201c..591298ad929 100644 --- a/doc/ug/features.tex +++ b/doc/ug/features.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2012,2013 The ESPResSo project +% Copyright (C) 2010,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/figures/slitpore.pdf b/doc/ug/figures/slitpore.pdf new file mode 100644 index 00000000000..874d751fa71 Binary files /dev/null and b/doc/ug/figures/slitpore.pdf differ diff --git a/doc/ug/firststeps.tex b/doc/ug/firststeps.tex index ad4bdefa8ec..bfc6c259b42 100644 --- a/doc/ug/firststeps.tex +++ b/doc/ug/firststeps.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/fsi.tex b/doc/ug/fsi.tex index 8701da02dbd..8dd34e0b74d 100644 --- a/doc/ug/fsi.tex +++ b/doc/ug/fsi.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % % This file is part of ESPResSo. % diff --git a/doc/ug/installation.tex b/doc/ug/installation.tex index ff4b382042b..78b2c437ba7 100644 --- a/doc/ug/installation.tex +++ b/doc/ug/installation.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -32,8 +32,7 @@ \chapter{Getting, compiling and running \es} contributing to the software can instead obtain the current development code via the version control system software \textsf{git}\footnote{\url{http://git.org}} from \es's project page at -the Savannah GNU server -\footnote{\url{https://savannah.nongnu.org/projects/espressomd/}}. +Github \footnote{\url{https://github.com/espressomd/espresso}}. This code might be not as well tested and documented as the release code; it is recommended to use this code only if you have already gained some experience in using \es. @@ -56,9 +55,6 @@ \section{Running \texttt{configure}} \label{sec:configure} \index{configure} -\todo[inline]{Description of basic options: \keyword{CPPFLAGS}, - \keyword{CFLAGS}, \keyword{LDFLAGS}} - The first step of building \es is to run the shell script \codebox{configure} which is to be found in the top level source directory. The script collects all the information required by the @@ -76,7 +72,7 @@ \section{Running \texttt{configure}} If you are using the development source code from the \textsf{git} repository, before you can call \codebox{configure}, it is necessary to have the GNU autotools (\textsf{autoconf} and \textsf{automake}) -installed. Then you can call the script \codebox{bootstrap.sh} from +installed. Then you can call the script \codebox{bootstrap.sh} from the top level source directory, which will generate the \codebox{configure} script. @@ -87,13 +83,15 @@ \subsection{Source and build directories} Usually, when a program is compiled, the resulting binary files are put into the same directory as the sources of the program. In \es's build system, the \emph{source directory} that contains all the source -files is completely separated from the \emph{build directory}, where -the files created by the build process are put. The location of the -build directory is the current working directory at the time when +files can be completely separated from the \emph{build directory}, +where the files created by the build process are put. The location of +the build directory is the current working directory at the time when \codebox{configure} is called. In this way, you can build several variants of \es, each variant having different activated features, and for as many platforms as you want. All further commands concerning compiling and running \es have to be called from the build directory. +None of the files in the source directory is ever modified when by the +build process. \paragraph{Example} When the source directory is \codebox{\$srcdir} (\ie the files where @@ -107,22 +105,19 @@ \subsection{Source and build directories} Espresso \end{code} -\subsection{Options} +\subsection{Options and Variables} \label{ssec:configureoptions} \index{configure options} The behaviour of \codebox{configure} can be -controlled by the means of command line options. In the following -only those command line options that are specific to \es will be -explained. For a complete list of options and explanations thereof, -call +controlled by the means of command line options and variables. In the +following, only important command line options and variables \es will +be explained. For a complete list of options, variables and +explanations thereof, call \begin{code} configure --help \end{code} \begin{description} -\item[\texttt{--with-myconfig=MYCONFIG\_HEADER}] This option sets the - name of the local configuration header (see \vref{sec:myconfig}). It - defaults to ``\texttt{myconfig.h}''. \item[\texttt{--with-mpi=\alt{\lit{yes} \asep \lit{no} \asep \lit{guess}}}/ \texttt{--without-mpi}] By default, \codebox{configure} will automatically determine whether an MPI @@ -155,11 +150,26 @@ \subsection{Options} be used to define compiler flags for the NVIDIA CUDA-compiler \texttt{nvcc}. For example, \texttt{NVCCFLAGS = "{}-gencode arch=compute_20,code=sm_20"{}} will compile code only for Fermi - cards. Default is to compile for compute models 1.1 and 2.0, - i.e. everything with a G90 chip or newer. Note that we require at - least compute model 1.1. + cards. Default is to compile for compute model 2.0, + i.e. everything with a Fermi chip or newer. Note that we require at + least compute model 1.1, that is G90. However, to use G90 (e.\,g.~Tesla + C1060), you need to manually specificy compute model 1.1. +\item[\texttt{LDFLAGS=\textit{linker-flags}}] This variable can be + used to change the flags that the linker will get when linking the + \es binaries. This variable can be used to modify the path where + the compiler finds library files when they are installed in + non-standard places, \eg \codebox{LDFLAGS="-L/home/juser/lib"}. +\item[\texttt{CPPFLAGS=\textit{preprocessor-flags}}] This variable can + be used to change the flags that the preprocessor will see. This + variable can be used to modify the path wherer the compiler finds + include files when they are installed in non-standard places, \eg + \codebox{CPPFLAGS="-I/home/juser/include"}. +\item[\texttt{CXXFLAGS=\textit{C++-compiler flags}}] This variable can + be used to modify the compilation flags, \eg to change the + optimization level for debugging (\codebox{CXXFLAGS="-g -O0"}). \end{description} + \section{\texttt{make}: Compiling, testing and installing \es} \label{sec:make} @@ -198,9 +208,9 @@ \section{\texttt{make}: Compiling, testing and installing \es} The variable \texttt{extra} can be used to specify additional files and directories that are to be included in the archive file. \\ - \textbf{Example:} \verb!make dist extra="myconfig.h internal"!\\ + \textbf{Example:} \verb!make dist extra="myconfig.hpp internal"!\\ will create the archive file and include the file - \texttt{myconfig.h} and the directory \texttt{internal} with all + \texttt{myconfig.hpp} and the directory \texttt{internal} with all files and subdirectories. \item[\texttt{install}] Install \es. The variables \texttt{prefix} and \texttt{exec-prefix} can be used to specify the installation @@ -261,10 +271,10 @@ \section{Running \es} instead of ``-n'' or ``mpirun'' instead of ``mpiexec''. -\section{\texttt{myconfig.h}: Activating and deactivating features} +\section{\texttt{myconfig.hpp}: Activating and deactivating features} \label{sec:myconfig} -\index{features} \index{myconfig.h} \index{configuration header} \es +\index{features} \index{myconfig.hpp} \index{configuration header} \es has a large number of features that can be compiled into the binary. However, it is not recommended to actually compile in all possible features, as this will slow down \es significantly. Instead, compile @@ -273,24 +283,25 @@ \section{\texttt{myconfig.h}: Activating and deactivating features} for a single one, e.g. \feature{LENNARD_JONES}. For the developers, it is also possible to turn on or off a number of debugging messages. The features and debug messages can be controlled via a configuration -header file that contains C-preprocessor declarations. Appendix -\vref{chap:features} lists and describes all available features. When -no configuration header is provided by the user, a default header, -found in src/myconfig-default.h, will be used that turns on the -default features. The file \texttt{myconfig-sample.h} in the source -directory contains a list of all possible features that can be copied -into your own configuration file. +header file that contains C-preprocessor declarations. Appendix +\vref{chap:features} lists and describes all available features. The +file \texttt{myconfig-sample.hpp} that configure will generate in the +build directory contains a list of all possible features that can be +copied into your own configuration file. When no configuration header +is provided by the user, a default header, found in +\texttt{src/core/myconfig-default.hpp}, will be used that turns on the +default features. When you distinguish between the build and the source directory, the configuration header can be put in either of these. Note, however, that when a configuration header is found in both directories, the one in the build directory will be used. -By default, the configuration header is called \texttt{myconfig.h}. +By default, the configuration header is called \texttt{myconfig.hpp}. The name of the configuration header can be changed either when the -\texttt{configure}-script is called with the option -\mbox{\texttt{--with-myconfig}} (see section \vref{sec:configure}), or -when \texttt{make} is called with the setting +\texttt{configure}-script is called via the variable +\mbox{\texttt{MYCONFIG}} (see section \vref{sec:configure}), or when +\texttt{make} is called with the setting \mbox{\texttt{myconfig=}\textit{myconfig\_header}} (see section \vref{sec:make}). @@ -301,13 +312,13 @@ \section{\texttt{myconfig.h}: Activating and deactivating features} \texttt{\$builddir2} that contain different configuration headers: \begin{itemize} -\item \texttt{\$builddir1/myconfig.h}: +\item \texttt{\$builddir1/myconfig.hpp}: \begin{code} #define ELECTROSTATICS #define LENNARD-JONES \end{code} -\item \texttt{\$builddir2/myconfig.h}: +\item \texttt{\$builddir2/myconfig.hpp}: \begin{code} #define LJCOS \end{code} diff --git a/doc/ug/inter.tex b/doc/ug/inter.tex index 273d9420aea..3dcaf607320 100644 --- a/doc/ug/inter.tex +++ b/doc/ug/inter.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -188,6 +188,38 @@ \subsection{Lennard-Jones interaction} $\var{r_\mathrm{cut}}=2^\frac{1}{6}\var{\sigma}$. The WCA potential is purely repulsive, and is often used to mimick hard sphere repulsion. + +When coupling particles to a Shan-Chen fluid, if the \lit{affinity} interaction is set, the Lennard-Jones potential is multiplied by the function + +\begin{equation} + \label{eq:lj-affinity} + A(r) = \Biggl\{ + \begin{array}{ll} + \frac{(1-\alpha_1)}{2} [1+\tanh(2\phi)] + \frac{(1-\alpha_2)}{2} [1+\tanh(-2\phi)] + & \mathrm{, if~} \var{r} > \var{r_\mathrm{cut}}+2^{\frac{1}{6}}\sigma\\ + 1 + & \mathrm{, otherwise~} \\ + \end{array}, +\end{equation} +where $\alpha_i$ is the affinity to the $i$-th fluid component (see +\ref{sec:affinity}), and the order parameter $\phi$ is calculated +from the fluid component local density as $\phi=\frac{\rho_1 - +\rho_2}{\rho_1+\rho_2}$. For example, if the affinities are chosen +so that the first component is a good solvent ($\alpha_1=1$) and +the second one is a bad solvent ($\alpha_2=0$), then, if the two +particles are both in a region rich in the first component, then +$\phi\simeq1$, and $A(r)\simeq0$ for +$r>\var{r_\mathrm{cut}}+2^{\frac{1}{6}}\sigma$. Therefore, the +interaction potential will be very close to the WCA one. Conversely, +if both particles are in a region rich in the second component, +then $\phi\simeq-1$, and $A(r)\simeq 1$, so that the potential +will be very close to the full LJ one. If the cutoff has been set +large enough, the particle will experience the attractive part of +the potential, mimiking the effective attraction induced by the bad +solvent. + + + \subsection{Generic Lennard-Jones interaction} \index{Generic Lennard-Jones interaction|mainindex} \index{interactions!Generic Lennard-Jones|mainindex} @@ -667,6 +699,35 @@ \subsection{Gay-Berne interaction} being $\var{k_1} = 3$, $\var{k_2} = 5$, $\var{\mu} = 2$ and $\var{\nu} = 1$. +\subsection{Affinity interaction} +\label{sec:affinity} + +\index{Affinity interaction|mainindex} +\index{interactions!Affinity|mainindex} +\begin{essyntax} + inter \var{type1} + \var{type2} + affinity + \var{\alpha_1} \var{\alpha_2} + \begin{features} + \required{SHANCHEN} + \end{features} +\end{essyntax} + +Instead of defining a new interaction, this command acts as a +modifier for existing interactions, so that the conditions of +good/bad solvent associated to the two components of a Shan-Chen +fluid. The two types must match those of the interaction that one +wants to modify, and the two affinity values \var{\alpha_1} and +\var{\alpha_2} are values between 0 and 1. A value of 1 (of 0) +indicates that the component acts as a good (bad) solvent. The +specific functional form depends on the interaction type and is +listed in the interaction section. So far, only the standard +Lennard-Jones interaction is modified by the \lit{affinity} +interaction. + + + \section{Bonded interactions} \label{sec:inter-bonded} \index{bonded interactions|mainindex} @@ -746,6 +807,43 @@ \subsection{Harmonic bond} \var{r_\mathrm{cut}}, the bond will be reported as broken, and a background error will be raised. +\subsection{Quartic bond} +\index{quartic bond|mainindex} +\index{interactions!quartic|mainindex} + +\begin{essyntax} + inter \var{bondid} + quartic \var{K_0} \var{K_1} \var{R} \opt{\var{r_\mathrm{cut}}} +\end{essyntax} +This creates a bond type with identificator \var{bondid} with a +quartic potential. The potential is minimal at particle distance $r=R$. +It is given by +\begin{equation} + V(r) = \frac{1}{2} K_0 \left( r - R \right)^2 + \frac{1}{4} K_1 \left( r - R \right)^4 +\end{equation} +The fourth, optional, parameter \var{r_\mathrm{cut}} defines a cutoff +radius. Whenever a quartic bond gets longer than +\var{r_\mathrm{cut}}, the bond will be reported as broken, and a +background error will be raised. + +\subsection{Bonded coulomb} +\index{bonded coulomb bond|mainindex} +\index{interactions!bonded_coulomb|mainindex} + +\begin{essyntax} + inter \var{bondid} + bonded_coulomb \var{\alpha} +\end{essyntax} +This creates a bond type with identificator \var{bondid} with a +coulomb pair potential. +It is given by +\begin{equation} + V(r) = \frac{\alpha q_1 q_2}{r}, +\end{equation} +where \var{q_1} and \var{q_2} are the charges of the bound particles. +There is no cutoff, the bejerrum length of other coulomb interactions +is not taken into account. + \subsection{Subtracted Lennard-Jones bond} \index{subtracted Lennard-Jones bond|mainindex} \index{interactions!subtracted Lennard-Jones|mainindex} @@ -1368,6 +1466,61 @@ \subsubsection{Additional P3M parameters} \end{description} +\subsection{Coulomb Ewald GPU} +\label{sec:coulombewald} +\index{EwaldGPU method|mainindex} +\index{interactions!EwaldGPU|mainindex} + +\begin{essyntax} + inter coulomb \var{l_B} ewaldgpu + \var{r_\mathrm{cut}} \alt{\var{K_\mathrm{cut}} \asep \{\var{K_\mathrm{cut,x}} \var{K_\mathrm{cut,y}} \var{K_\mathrm{cut,x}}\}} \var{alpha} + \begin{features} + \required{ELECTROSTATICS} + \end{features} +\end{essyntax} + +This command activates the Ewald method to compute the electrostatic +interactions between charged particles. The far field is computed by the GPU with single precision and the near field by the CPU with double precision. It only works for the case of cubic boxes. +\begin{description} +\item[\var{l_B}] Bjerrum length as positive floating point number +\item[\var{r_\mathrm{cut}}] Real space cutoff as positive floating point number +\item[\var{K_\mathrm{cut}}] Reciprocal space cutoff as single positive integer +\item[\var{K_\mathrm{cut,xyz}}] Reciprocal space cutoff in x, y and z direction (relevant for noncubic boxes) +\item[\var{alpha}] Ewald parameter as positive floating point number +\end{description} + +\subsubsection{Tuning Ewald GPU} +\label{ssec:tuneewaldgpu} +\begin{essyntax} + inter coulomb \var{l_B} ewaldgpu tune + accuracy \var{accuracy} precision \var{precision} + K_max \var{K_\mathrm{max}} + \begin{features} + \required{ELECTROSTATICS} + \end{features} +\end{essyntax} + +The tuning algorithm first computes the optimal \var{r_\mathrm{cut}} and \var{alpha} for every \var{K_\mathrm{cut}} between one and \var{K_\mathrm{max}} as described in \cite{kolafa92}. Then the performance for all those (\var{K_\mathrm{cut}}, \var{r_\mathrm{cut}}, \var{alpha})-triplets will be measured via a short test simulation and the fastest will be chosen. + +\begin{description} +\item[\var{accuracy}] Maximal allowed root mean square error regarding the forces +\item[\var{precision}] Determines how precise alpha will be computed +\item[\var{K_\mathrm{max}}] Maximal reciprocal space cutoff \var{K_\mathrm{cut}} to be tested in the tuning algorithm +\end{description} + +\subsubsection{Tuning Alpha Ewald GPU} +\label{ssec:tunealphaewaldgpu} +\begin{essyntax} + inter coulomb \var{l_B} ewaldgpu tunealpha + \var{r_\mathrm{cut}} \alt{\var{K_\mathrm{cut}} \asep \{\var{K_\mathrm{cut,x}} \var{K_\mathrm{cut,y}} \var{K_\mathrm{cut,x}}\}} \var{precision} + \begin{features} + \required{ELECTROSTATICS} + \end{features} +\end{essyntax} + +If \var{K_\mathrm{cut}} and \var{r_\mathrm{cut}} are given by the user, then \keyword{tunealpha} computes the optimal \var{alpha} with the chosen \var{precision} as described in \cite{kolafa92}. But in general \keyword{tune} should be chosen for tuning. + + \subsection{Debye-H\"uckel potential} \index{Debye-H\"uckel potential|mainindex} \index{interactions!Debye-H\"uckel|mainindex} @@ -1392,7 +1545,6 @@ \subsection{Debye-H\"uckel potential} For $\kappa = 0$, this corresponds to the plain coulomb potential. - \subsection{MMM2D} \index{MMM2D method|mainindex} \index{interactions!MMM2D|mainindex} @@ -1408,6 +1560,7 @@ \subsection{MMM2D} \opt{\var{fixed\_far\_cutoff}} \opt{dielectric \var{\epsilon_t} \var{\epsilon_m} \var{\epsilon_b}} \opt{dielectric-contrasts \var{\Delta_t} \var{\Delta_b}} + \opt{capacitor \var{U}} \begin{features} \required{ELECTROSTATICS} \end{features} @@ -1435,6 +1588,28 @@ \subsection{MMM2D} this form allows to choose $\Delta_{t/b}=-1$, corresponding to metallic boundary conditions. +Using \keyword{capacitor} \var{U} allows to maintain a constant +electric potential difference \var{U} between the xy-plane at $z=0$ +and $z=L$, where $L$ denotes the box length in $z$-direction. +This is done by countering the total dipol moment of +the system with the electric field $E_{induced}$ and superposing +a homogeneous electric field $E_{applied} = \frac{U}{L}$ +to retain \var{U}. This mimics the induction of surface charges +$\pm\sigma = E_{induced} \cdot \epsilon_0$ for planar electrodes at $z=0$ +and $z=L$ in a capacitor connected to a battery with voltage \var{U}. +Using \var{capacitor} 0 is equivalent to $\Delta_{t/b}=-1$. + +\begin{essyntax} + efield_caps \alt{total \asep induced \asep applied} + \begin{features} + \required{ELECTROSTATICS} + \end{features} +\end{essyntax} + +The electric fields added by \var{capacitor} \var{U} can be obtained +by calling the above command, where \var{induced} returns $E_{induced}$, +\var{applied} returns $E_{applied}$ and \var{total} their sum. + \subsection{MMM1D} \index{MMM1D method|mainindex} \index{interactions!MMM1D|mainindex} @@ -1446,7 +1621,7 @@ \subsection{MMM1D} \begin{essyntax} \variant{1} inter coulomb \var{l_B} mmm1d \var{switch\_radius} - \opt{\var{bessel\_cutoff}} \var{maximal\_pairwise\_error} + \var{maximal\_pairwise\_error} \variant{2} inter coulomb \var{l_B} mmm1d tune \var{maximal\_pairwise\_error} @@ -1458,14 +1633,39 @@ \subsection{MMM1D} nsquared cell system (see section \vref{sec:cell-systems}). The first form sets parameters manually. The switch radius determines at which xy-distance the force calculation switches from the near to the far -formula. If the Bessel cutoff is not explicitly given, it is -determined from the maximal pairwise error, otherwise this error only -counts for the near formula. The second, tuning form just takes the +formula. The Bessel cutoff does not need to be specified as it is +automatically determined from the particle distances and maximal +pairwise error. The second tuning form just takes the maximal pairwise error and tries out a lot of switching radii to find out the fastest one. If this takes too long, you can change the value of the setmd variable \keyword{timings}, which controls the number of -test force calculations. For details on the MMM family of algorithms, -refer to appendix \vref{chap:mmm}. +test force calculations. + +\begin{essyntax} + \variant{1} + inter coulomb \var{l_B} mmm1dgpu \var{switch\_radius} + \opt{\var{bessel\_cutoff}} \var{maximal\_pairwise\_error} + + \variant{2} + inter coulomb \var{l_B} mmm1dgpu tune \var{maximal\_pairwise\_error} + \begin{features} + \required{CUDA} + \required{ELECTROSTATICS} + \required{MMM1D_GPU} + \end{features} +\end{essyntax} +MMM1D is also available in a GPU implementation. Unlike its CPU +counterpart, it does not need the nsquared cell system. The first +form sets parameters manually. The switch radius determines at which +xy-distance the force calculation switches from the near to the far +formula. If the Bessel cutoff is not explicitly given, it is +determined from the maximal pairwise error, otherwise this error only +counts for the near formula. The second tuning form just takes the +maximal pairwise error and tries out a lot of switching radii to find +out the fastest one. + +For details on the MMM family of algorithms, refer to appendix +\vref{chap:mmm}. \subsection{Maxwell Equation Molecular Dynamics (MEMD)} \index{Maggs method|mainindex} @@ -1621,6 +1821,7 @@ \subsection{Electrostatic Layer Correction (ELC)} \opt{noneutralization} \opt{dielectric \var{\epsilon_t} \var{\epsilon_m} \var{\epsilon_b}} \opt{dielectric-contrasts \var{\Delta_t} \var{\Delta_b}} + \opt{capacitor \var{U}} \begin{features} \required{ELECTROSTATICS} \end{features} @@ -1662,7 +1863,11 @@ \subsection{Electrostatic Layer Correction (ELC)} disable the neutralization. The dielectric contrast features work exactly the same as for MMM2D, -see the documentation above. +see the documentation above. Same accounts for \keyword{capacitor} +\var{U}, but the constant potential is maintained between the xy-plane +at $z=0$ and $z=L-gap\_size$. The command \var{efield\_caps} to read +out the electric fields added by \var{capacitor} \var{U} also applies +for the capacitor-feature of ELC. Make sure that you read the papers on ELC (\cite{elc,icelc}) before using it. @@ -1727,12 +1932,21 @@ \subsubsection{Quick setup of dielectric interfaces} \variant{2} dielectric wall normal \var{nx} \var{ny} \var{nz} dist \var{d} res \var{res} \variant{3} dielectric cylinder center \var{cx} \var{cy} \var{cz} axis \var{ax} \var{ay} \var{az} radius \var{r} direction \var{d} \variant{4} dielectric pore center \var{cx} \var{cy} \var{cz} axis \var{ax} \var{ay} \var{az} radius \var{r} length \var {l} smoothing\_radius \var{rs} res \var{res} + \variant{5} dielectric slitpore pore_mouth \var{z} \ + channel_width \var{c} \ + pore_width \var{w} \ + pore_length \var{l} \ + upper_smoothing_radius \var{us} \ + lower_smoothing_radius \var{ls} + \end{essyntax} The command \keyword{dielectric} allows to conveniently create dielectric interfaces similar to the constraint and the lbboundary command. Currently the creation of spherical, cylindrical and planar -geometries as well as a pore geometry is supported. It is implemented +geometries as well as a pore and slitpore geometry is supported. +Please check the documentation of the corresponding constraint for the detailed geometry. +It is implemented in Tcl and places particles in the right positions and adds the correct values to the global Tcl variables \var{icc\_areas} \var{icc\_normals} \var{icc\_sigmas} \var{icc\_epsilons} and increases @@ -1943,18 +2157,18 @@ \subsection{Tunable-slip boundary interaction}\label{sec:tunableSlip} In recent years, experiments have indicated that the no-slip boundary condition is indeed usually not valid on the micrometer -scale. Instead, it has to be replaced by the {\em {partial-slip - boundary condition}} +scale. Instead, it has to be replaced by the \emph{partial-slip + boundary condition} \begin{displaymath} -\delta_B \: \: \partial_{{\bf n}} v_{\parallel}|_{{\bf r}_B} = -v_{\parallel}|_{{\bf r}_B}, +\delta_B \; \; \partial_\mathbf{n} v_{\parallel} \rVert_{\mathbf{r}_B} = +v_{\parallel} \rVert_{\mathbf{r}_B}, \end{displaymath} where $v_{\parallel}$ denotes the tangential component of the velocity -and $\partial_{{\bf n}} v_{\parallel}$ its spatial derivative normal -to the surface, both evaluated at the position ${\bf r}_B$ of the -so-called {\em hydrodynamic boundary}. This boundary condition is +and $\partial_\mathbf{n} v_{\parallel}$ its spatial derivative normal +to the surface, both evaluated at the position $\mathbf{r}_B$ of the +so-called \emph{hydrodynamic boundary}. This boundary condition is characterized by two effective parameters, namely (i) the slip length -$\delta_B$ and (ii) the hydrodynamic boundary ${\bf r}_B$. +$\delta_B$ and (ii) the hydrodynamic boundary $\mathbf{r}_B$. Within the approach of the tunable-slip boundary interactions it is possible to tune the slip length systematically from full-slip to @@ -1994,9 +2208,9 @@ \subsection{DPD interaction}\label{sec:DPDinter} This is a special interaction that is to be used in conjunction with the Dissipative Particle Dynamics algorithm \ref{sec:DPD} when the -\texttt{INTER_DPD} implementation is used. The parameters correspond -to the parameters of the DPD thermostat \vref{sec:DPDinter}, but -can be set individually for the different interactions. +\feature{INTER_DPD} implementation is used. The parameters correspond +to the parameters of the DPD thermostat \vref{sec:DPDinter}, but can +be set individually for the different interactions. \subsection{Fixing the center of mass} \begin{essyntax} @@ -2011,14 +2225,22 @@ \subsection{Fixing the center of mass} all the forces acting on particles of type \var{typeid1} are calculated. These include all the forces due to other interaction types and also the thermostat. Next a force equal in magnitude, but in -the oppositte direction is applied on the particles. This force is -divided equally on all the particles of type \var{typeid1}, since -currently there is no mass concept in \es. Note that the syntax of the +the opposite direction is applied to all the particles. This force is +divided on the particles of type \var{typeid1} relative to +their respective mass. Under periodic boundary conditions, this fixes +the itinerant center of mass, that is, the one obtained from the +unfolded coordinates. + +Note that the syntax of the declaration of comfixed interaction requires the same particle type to be input twice. If different particle types are given in the input, the program exits with an error message. \var{flag} can be set to 1 (which turns on the interaction) or 0 (to turn off the interaction). + +Since the necessary communication is lacking at present, this interaction +only works on a single node. + \subsection{Pulling particles apart} \begin{essyntax} inter \var{typeid1} \var{typeid2} @@ -2048,7 +2270,7 @@ \subsection{Capping the force during warmup} \label{sec:forcecap} \begin{essyntax} - \variant{1} inter forcecap \alt{\var{F_\mathrm{max}} \asep individual} + inter forcecap \alt{\var{F_\mathrm{max}} \asep individual} \end{essyntax} Non-bonded interactions are often used to model the hard core diff --git a/doc/ug/internal.tex b/doc/ug/internal.tex index 572d05ee33d..b836c215540 100644 --- a/doc/ug/internal.tex +++ b/doc/ug/internal.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2012,2013 The ESPResSo project +% Copyright (C) 2010,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % diff --git a/doc/ug/introduction.tex b/doc/ug/introduction.tex index 1d818f24293..6537793c7b0 100644 --- a/doc/ug/introduction.tex +++ b/doc/ug/introduction.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -111,31 +111,81 @@ \section{Guiding principles} \section{Available simulation methods} -\begin{itemize} -\item Ensembles: - \begin{itemize} - \item NVE - \item NVT - \item NpT - \end{itemize} -\item Algorithms for charged systems: - \begin{itemize} - \item P3M for fully periodic systems - \item ELC and MMM-family of algorithms for charged systems with - non-periodic boundary conditions - \item MEMD (Maggs algorithm) - \end{itemize} -\item Hydrodynamics: - \begin{itemize} - \item DPD (as a thermostat) - \item Lattice-Boltzmann - \end{itemize} -\item Non-equilibrium MD to simulate shear flow -\item Parallel tempering -\item Metadynamics -\item Rigid bodies via virtual sites -\item AdResS -\end{itemize} +\es provides a number of useful methods. The following table shows the +various methods as well as their status. The table distinguishes +between the state of the development of a certain feature and the +state of its use. We distinguish between five levels: +\begin{description} +\item[Core] means that the method is part of the core of \es, and that + it is extensively developed and used by many people. +\item[Good] means that the method is developed and used by independent + people from different groups. +\item[Group] means that the method is developed and used in one group. +\item[Single] means that the method is developed and used by one + person only. +\item[None] means that the method is developed and used by nobody. +\end{description} +If you believe that the status of a certain method is wrong, please +report so to the developers. + +\newpage +\definecolor{supportgrey}{rgb}{0.9,0.9,0.9} +\rowcolors{1}{supportgrey}{} +\begin{longtable}{|l|l|l|} + \hline + \textbf{Feature} & \textbf{Development Status} & \textbf{Usage Status}\\\hline% + \multicolumn{3}{|c|}{\textbf{Integrators, Thermostats, Barostats}} \\ + Velocity-Verlet Integrator & Core & Core \\ + Langevin Thermostat & Core & Core \\ + GHMC Thermostat & Single & Single \\ + DPD Thermostat & None & Good \\ + Isotropic NPT & None & Single \\ + NEMD & None & Group \\ + Quarternion Integrator & None & Good \\ + \multicolumn{3}{|c|}{\textbf{Interactions}} \\ + Short-range Interactions & Core & Core \\ + Directional Lennard-Jones & Single & Single \\ + Gay-Berne Interaction & None & Single \\ + Constraints & Core & Core \\ + Relative Virtual Sites & Good & Good \\ + Center-of-mass Virtual Sites & None & Good \\ + RATTLE Rigid Bonds & None & Group \\ + \multicolumn{3}{|c|}{\textbf{Coulomb Interaction}} \\ + P3M & Core & Core \\ + P3M on GPU & Single & Single \\ + Dipolar P3M & Group & Good \\ + Ewald on GPU & Single & Single \\ + MMM1D & Single & Good \\ + MMM2D & Single & Good \\ + MMM1D on GPU & Single & Single \\ + ELC & Good & Good \\ + MEMD & Single & Group \\ + ICC* & Group & Group \\ + \multicolumn{3}{|c|}{\textbf{Hydrodynamic Interaction}} \\ + Lattice-Boltzmann & Core & Core \\ + Lattice-Boltzmann on GPU & Group & Core \\ + DPD & None & Good \\ + Shan-Chen Multicomponent Fluid & Group & Group \\ + Tunable Slip Boundary & Single & Single \\ + \multicolumn{3}{|c|}{\textbf{Analysis}} \\ + uwerr & None & Good \\ + \multicolumn{3}{|c|}{\textbf{Input/Output}} \\ + Blockfiles & Core & Core \\ + VTF output & Core & Core \\ + VTK output & Group & Group \\ + PDB output & Good & Good \\ + Online visulation with VMD & Good & Good \\ + \multicolumn{3}{|c|}{\textbf{Miscellaneous}} \\ + Grand canonical feature & Single & Single \\ + Metadynamics & Single & Single \\ + Parallel Tempering & Single & Single \\ + Electrokinetics & Group & Group \\ + Object-in-fluid & Group & Group \\ + Collision Detection & Group & Group \\ + Catalytic Reactions & Single & Single \\ + mbtools package & Group & Group \\ + \hline +\end{longtable} \section{Basic program structure} \label{sec:structure} @@ -297,8 +347,8 @@ \section{Syntax description} type. \item \texttt{\alt{\var{alt1} \asep \var{alt2}}} specifies, that one of the alternatives \var{alt1} or \var{alt2} can be used. -\item \texttt{\opt{\var{argument}}} specifies, that the augment - \var{argument} is optional, \ie{} it can be omitted. +\item \texttt{\opt{\var{argument}}} specifies, that the argument + \var{argument} is optional, \ie it can be omitted. \item When an optional argument or a whole command is marked by a superscript label (\fmark{1}), this denotes that the argument can only be used, when the corresponding feature (see appendix diff --git a/doc/ug/io.tex b/doc/ug/io.tex index eff89f85272..64442671eb5 100644 --- a/doc/ug/io.tex +++ b/doc/ug/io.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -29,27 +29,28 @@ \section{No generic checkpointing!} this state to or read it from a file. This would be most useful to be able to restart a simulation from a specific point in time. -Unfortunately, a simple command \texttt{checkpoint} could not work, -out of two reasons. The main reason is that \es has no way to -determine what information constitutes the actual state of the -simulation. On the one hand, \es scripts sometimes use Tcl-variables -that contain essential information about a simulation, \eg the stored -values of an observable that was computed in previous time steps, -counters, etc. These would have to be contained in a checkpoint. -However, not all Tcl-variables are of interest. For example, Tcl has a -number of automatically set variables that contain information about -the hostname, the machine type, etc. These variables should most -probably \emph{not} be included the simulation state. \es has no way -to distinguish between these variables. On the other hand, the \es -core has a number of internal variables, \eg the particle coordinates. -While most of these are probably good candidates for being included -into a checkpoint, this is not necessarily so. For example, when you -have particles in your system that have fixed coordinates, should -these be stored in a checkpoint, or not? If the system contains -mostly fixed particles and only very few moving particles, this would -increase the memory size of a checkpoint needlessly. And what about -the interactions in the system, or the bonds? Should these be stored -in a checkpoint, or are they generated by the script? +Unfortunately, it is impossible to provide a simple command (\eg +\texttt{checkpoint}), out of two reasons. The main reason is that \es +has no way to determine what information constitutes the actual state +of the simulation. On the one hand, \es scripts sometimes use +Tcl-variables that contain essential information about a simulation, +\eg the stored values of an observable that was computed in previous +time steps, counters, etc. These would have to be contained in a +checkpoint. However, not all Tcl-variables are of interest. For +example, Tcl has a number of automatically set variables that contain +information about the hostname, the machine type, etc. These variables +should most probably \emph{not} be included the simulation state. \es +has no way to distinguish between these variables. On the other hand, +the \es core has a number of internal variables, \eg the particle +coordinates. While most of these are probably good candidates for +being included into a checkpoint, this is not necessarily so. For +example, when you have particles in your system that have fixed +coordinates, should these be stored in a checkpoint, or not? If the +system contains mostly fixed particles and only very few moving +particles, this would increase the memory size of a checkpoint +needlessly. And what about the interactions in the system, or the +bonds? Should these be stored in a checkpoint, or are they generated +by the script? Another problem with a generic checkpoint would be the control flow of the script. In principle, the checkpoint would have to store where in @@ -59,7 +60,29 @@ \section{No generic checkpointing!} Instead, in \es, the user has to specify what information needs to be saved to a file to be able to restore the simulation state. The -\texttt{blockfile} command helps you to do that. +\texttt{blockfile} and \texttt{writemd} commands help you to do that. +\texttt{blockfile} writes text files. When floating point numbers are +stored in such files (\eg the particle positions), there is only a +limited precision. Therefore, it is not possible to bitwise reproduce +a simulation state using this function. When you need bitwise +reproducibility, you will have to use the command \lit{writemd}, which +stores positions, forces and velocities in binary format. Note that +there is no command to write other MD parameters like time step or +interactions in binary format. You should restore these using exactly +the same Tcl command that you used to create them. + +Finally, there is one more complication: random forces are computed +in the order the particles are stored in memory. This order usually +differs after reading a blockfile back, since the particles are +stored in consecutive identity order. In memory, they are usually +not in a specific order. Therefore, you need to use \texttt{sort_particles} +after writing a blockfile that you want to use for checkpointing, so +that the particles are resorted to the same consecutive order. Note +that this does not change physics, just the order the random numbers +are applied. + +When using an LB fluid, you need to also write out the fluid nodes, +see the \texttt{lbfluid} command for further details. \section{\texttt{blockfile}: Using the structured file format} \label{sec:structured-file-format} @@ -142,13 +165,18 @@ \subsection{Writing particles, bonds and interactions} \variant{3} blockfile \var{channel} write interactions \end{essyntax} -\todo{How is a Tcl-range specified?} Variant \variant{1} writes +Variant \variant{1} writes particle information in a standardized format to \var{channel}. \var{what} can be any list of parameters that can be specified in \codebox{part \var{part_id} print}, except for \lit{bonds}. Note that \lit{id} and \lit{pos} will automatically be added if missing. -\var{range} is a Tcl list of ranges which particles to write. The -keyword \keyword{all} denotes all known particles. +\var{range} is a Tcl list of ranges which particles to write. A range +is defined as \textit{start}-\textit{stop}, where \textit{start} and +\textit{stop} are particle identities. \textit{stop} can also be the +string ``end'', denoting the highest used particle identity. Thus +\texttt{"{} 0-5 10-end"{}} are all particles with the exception of +particles 6-9. The keyword \keyword{all} denotes all known particles, +\ie{} is eqivalent to \texttt{"0-end"{}}). Variant \variant{2} writes the bond information in a standardized format to \var{channel}. The involved particles and bond types must @@ -225,10 +253,10 @@ \subsection{Reading blocks} \begin{essyntax} \variant{1} blockfile \var{channel} read start \variant{2} blockfile \var{channel} read toend - \variant{3} blockfile \var{channel} read \alt{particles \asep + \variant{3} blockfile \var{channel} read auto + \variant{4} blockfile \var{channel} read \alt{particles \asep interactions \asep bonds \asep variable \asep seed \asep random \asep bitrandom \asep configs} - \variant{4} blockfile \var{channel} read auto \end{essyntax} Variants \variant{1} and \variant{2} are the low-level block-reading @@ -236,11 +264,8 @@ \subsection{Reading blocks} returns the block title, while variant \variant{2} reads the block data and returns it. -\todo{Needs to be rewritten!} -Variants \variant{3} and \variant{4} read whole blocks. Variant -\variant{3} reads the beginning of one block, checks wether it -contains data of the given type and reads it. Variant \variant{4} -reads in one block and does the following: +Variants \variant{3} and \variant{4} read whole blocks. +Variant \variant{3} reads in one block and does the following: \begin{enumerate} \item if a procedure \keyword{blockfile_read_auto_\var{tag}} exists, this procedure takes over (\var{tag} is the first expression in the @@ -257,7 +282,7 @@ \subsection{Reading blocks} \item if the file is at the end, it returns \lit{eof} \end{enumerate} -Variant \variant{3} checks for a block with tag \var{block} and then +Variant \variant{4} checks for a block with tag \var{block} and then again executes the corresponding \lit{blockfile_read_auto_\var{tag}}, if it exists. @@ -310,6 +335,31 @@ \subsection{Reading blocks} This is basically all you need to restore the information in the blockfile, overwriting the current settings in \es. +\section{Writing and reading binary files} +\index{binary I/O} + +Binary files are written using the command +\begin{essyntax} + writemd \var{channel} \opt{posx|posy|posz|vx|vy|vz|fx|fy|fz}\dots +\end{essyntax} +This will write out particle data to the Tcl channel \var{channel} for +all particles in binary format. Apart from the mandatory particle id, +only limited information can be stored. The coordinates (\keyword{posx}, +\keyword{posy} and \keyword{posz}), velocities (\keyword{vx}, \keyword{vy} and +\keyword{vz}) and forces (\keyword{fx}, \keyword{fy} and \keyword{fz}). Other +information should be stored in a blockfile or reconstructed +differently. Note that since both \texttt{blockfile} and +\texttt{writemd} are using a Tcl channel, it is actually possible to +mix them, so that you can write a single checkpoint file. However, the +\texttt{blockfile read auto} mechanism cannot handle the binary +section, thus you need to read this section manually. Reading of +binary particle data happens through +\begin{essyntax} + readmd \var{channel} +\end{essyntax} +For the exact format of the written binary sequence, see +\texttt{src/tcl/binary_file_tcl.cpp}. + \section{Writing VTF files} \label{sec:vtf} %\quickrefheading{Handling of VTF files} @@ -372,7 +422,6 @@ \subsection{\texttt{writevsf}: Writing the topology} \opt{\alt{short \asep verbose}} \opt{radius \alt{\var{radii} \asep auto}} \opt{typedesc \var{typedesc}} - \opt{ignore_charges} \end{essyntax} Writes a structure block describing the system's structure to the channel given by \var{channelId}. \var{channelId} must be an @@ -405,12 +454,6 @@ \subsection{\texttt{writevsf}: Writing the topology} is an atom name and \textit{type} is the type id. \minisec{Example} \verb!writevsf $file typedesc {0 "name colloid" 1 "name pe"}! -\item[\opt{ignore_charges}] - this is a temporary workaround for a bug in the VTF reader of VMD, - which cannot handle multiple atom sections for the same - atom. However, charges are written out per-atom, so that VMD forgets - about atom types and radii. If you don't need the charges, you can - switch them off by this flat, making the other settings work again. \end{arguments} \subsection{\texttt{writevcf}: Writing the coordinates} @@ -681,7 +724,7 @@ \subsection{Automatically setting up a VMD connection} parameters and boolean values for \opt{start} and \opt{constraints}, as described above. -\section{Errorhandling} +\section{Error handling} Errors in the parameters are detected as early as possible, and hopefully self-explanatory error messages returned without any changes to the data in the internal data of \es. This include errors such as diff --git a/doc/ug/latexmk b/doc/ug/latexmk index fabbe331156..97b765e8582 100755 --- a/doc/ug/latexmk +++ b/doc/ug/latexmk @@ -5,7 +5,7 @@ if 0; #!/opt/local/bin/perl -w #!/usr/local/bin/perl -w # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright John Collins 1998-2004 # (username collins at node phys.psu.edu) # (and thanks to David Coppit (username david at node coppit.org) diff --git a/doc/ug/lb.tex b/doc/ug/lb.tex index bed01ba055b..4136580b040 100644 --- a/doc/ug/lb.tex +++ b/doc/ug/lb.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % % This file is part of ESPResSo. % @@ -53,6 +53,7 @@ \section{Setting up a LB fluid} \require{1 or 2 or 3}{\opt{bulk_visc \var{bulk\_viscosity}}} \require{1 or 2 or 3}{\opt{ext_force \var{f_x} \var{f_y} \var{f_z}}} \require{1 or 2 or 3}{\opt{friction \var{gamma} } } + \require{2}{\opt{couple \var{2pt/3pt} } } \require{1 or 2 or 3}{\opt{gamma_odd \var{gamma\_odd}}} \require{1 or 2 or 3}{\opt{gamma_even \var{gamma\_even}}} \require{3}{\opt{mobility} \var{mobilities} } @@ -111,7 +112,7 @@ \section{Setting up a LB fluid} If the feature \lit{SHANCHEN} is activated, the Lattice Boltzmann code (so far GPU version only) is extended to a two-component -Shan-Chen method. The \lit{lbfluid} command requires in this case +Shan-Chen (SC) method. The \lit{lbfluid} command requires in this case to supply two values, for the respective fluid components, to each of the options \lit{dens}, \lit{visc}, \lit{bulk_visc}, \lit{friction}, \lit{gamma_odd} and \lit{gamma_even}, when they are used, otherwise @@ -137,7 +138,12 @@ \section{Setting up a LB fluid} The first two save commands save all of the LB fluid nodes' populations to \var{filename} in ascii or binary format respectively. The two load commands load the populations from \var{filename}. This is useful for restarting a simulation either on the same machine or a different machine. Some care should be taken when using the binary format as the format of doubles can depend -on both the computer being used as well as the compiler. This is currently only implemented for the cpu version of LB. +on both the computer being used as well as the compiler. One thing that one needs to be aware of is that loading the checkpoint also requires the used to reuse the old forces. This is necessary +since the coupling force between the paricles and the fluid has already been applied to the fluid. Failing to reuse the old forces breaks momentum conservation, which is in general a problem. It is +particularly problematic for bulk simulations as the system as a whole acquires a drift of the center of mass, causing errors in the calculation of velocities and diffusion coefficients. +The correct way to restart +an LB simulation is to first load in the particles with the correct forces, and use ``integrate {\it steps} reuse_forces'' upon the first +call to integrate. This causes the old forces to be reused and thus conserves momentum. \section{LB as a thermostat} \begin{essyntax} @@ -155,6 +161,8 @@ \section{LB as a thermostat} \vec{F} = -\gamma \left(\vec{v}-\vec{u}\right) + \vec{F}_R. \end{equation*} The momentum acquired by the particles is then transferred back to the fluid using a linear interpolation scheme, to preserve total momentum. +In the GPU implementation the force can alternatively be interpolated using a three point scheme which couples the particles to the nearest 27 LB nodes. +This can be called using ``lbfluid \lit{couple} 3pt'' and is described in D\"{u}nweg and Ladd by equation 301\cite{duenweg08a}. Note that the three point coupling scheme is incompatible with the Shan Chen Lattice Boltmann. The frictional force tends to decrease the relative velocity between the fluid and the particle whereas the random forces are chosen so large that the average kinetic energy per particle corresponds to @@ -171,15 +179,23 @@ \section{LB as a thermostat} Section~\ref{sec:units}. \section{The Shan Chen bicomponent fluid\label{sec:shanchen}} -The Lattice Boltzmann variant of Shan and Chan\cite{...} is widely +\begin{citebox} + Please cite~\citewbibkey{sega13c} if you use the Shan Chen implementation described below. +\end{citebox} + + +The Lattice Boltzmann variant of Shan and Chan\cite{shan93a} is widely used as it is simple and yet very effective in reproducing the most important traits of multicomponent or multiphase fluids. The version -of the Shan-Chen method implemented in \es is an extension of the -single-component, multi-relaxation times Lattice Boltzmann with -fluctuations applied to all modes, that is already present in \es. +of the Shan-Chen method implemented in \es is an extension to +bi-component fluids of the multi-relaxation-times Lattice Boltzmann +with fluctuations applied to all modes, that is already present in +\es. It features, in addition, coupling with particles\cite{sega13c} +and component-dependent particle interactions (see sections +\ref{sec:scmd-coupling} and\ref{sec:scmd-affinity}). + The Shan-Chen fluid is set up using the \lit{lbfluid} command, -supplying two Besides the usual transport coefficients (shear and -bulk viscosity, and relaxation constants for the ghost modes) it +supplying two values (one per component) to the \lit{dens} option. Optionally, two values can be set for each of the usual transport coefficients (shear and bulk viscosity), and for the ghost modes. It is possible to set a relaxation time also for the momentum modes, since they are not conserved quantities in the Shan-Chen method, by using the option \lit{mobility}. The mobility transport coefficient @@ -189,7 +205,30 @@ \section{The Shan Chen bicomponent fluid\label{sec:shanchen}} fluctuations are switched on, a random noise is added, in addition, also to the momentum modes. Differently from the other modes, a correlated noise is added to the momentum ones, in order to preserve -the \emph{total} momentum. The coupling between the fluid components +the \emph{total} momentum. + + +The fluctuating hydrodynamic equations that are simulated using the +Shan-Chen approach are +\begin{equation}\label{eq:shanchen-NS} +\rho \left(\frac{\partial }{\partial t} {\vec {u}} + ({\vec {u}}\cdot {\vec {\nabla}}) {\vec {u}} \right)=-{\vec {\nabla}} p+{\vec {\nabla}} \cdot ({\vec {\Pi}}+\hat{{\vec {\sigma}}})+\sum_{\zeta} {\vec {g}}_{\zeta}, +\end{equation} +\begin{equation}\label{eq:shanchen-cont} +\frac{\partial }{\partial t} \rho_{\zeta}+{\vec {\nabla}} \cdot (\rho_{\zeta} {\vec {u}}) = {\vec {\nabla}} \cdot ({\vec {D}}_{\zeta}+\hat{{\vec {\xi}}}_{\zeta}), +\end{equation} +\begin{equation}\label{eq:shanchen-globalcont} +\partial_t \rho+{\vec {\nabla}} \cdot (\rho {\vec {u}}) = 0, +\end{equation} +where the index $\zeta=1,2$ specifies the component, $\vec{u}$ is +the fluid (baricentric) velocity, $\rho=\sum_\zeta\rho_\zeta$ is +the total density, and $p=\sum_{\zeta} p_{\zeta}=\sum_{\zeta} c_s^2 +\rho_{\zeta}$ is the internal pressure of the mixture ($c_s$ being +the sound speed). Two fluctuating terms $\hat{{\vec{\sigma}}}$ and +$\hat{{\vec{\xi}}}_{\zeta}$ are associated, respectivelu, to the +diffusive current ${\vec{D}}_{\zeta}$ and to the viscous stress +tensor ${\vec{\Pi}}$. + +The coupling between the fluid components is realized by the force \begin{equation} \vec{g}_{\zeta}(\vec{r}) = - \rho_{\zeta}(\vec{r}) @@ -209,38 +248,59 @@ \section{The Shan Chen bicomponent fluid\label{sec:shanchen}} \lit{lb_components}. -\section{Coupling particle dynamics to the Shan-Chen fluid\label{sec:scmd-coupling}} -The coupling of particle dynamics to the Shan-Chen fluid has been conceived as an extension -of the Ahlrichs and D\"unweg's point coupling, with the force acting on a particle given by +\section{SC as a thermostat\label{sec:scmd-coupling}} +The coupling of particle dynamics to the Shan-Chen fluid has been +conceived as an extension of the Ahlrichs and D\"unweg's point +coupling, with the force acting on a particle given by \begin{equation} \vec{F} = -\frac{\sum_\zeta \gamma_\zeta \rho_\zeta(\vec{r})}{\sum_\zeta \rho_\zeta(\vec{r}_\zeta)} \left(\vec{v}-\vec{u}\right) + \vec{F}_R + \vec{F}^{ps}, \end{equation} -where $\zeta$ identifies the component, $\rho_\zeta(\vec{r})$ is a linear interpolation of the component density on the nodes surrounding the particle, $\gamma_\zeta$ is the component-dependent friction coefficient, $\vec{F}_R$ is the usual random force, and +where $\zeta$ identifies the component, $\rho_\zeta(\vec{r})$ is a +linear interpolation of the component density on the nodes surrounding +the particle, $\gamma_\zeta$ is the component-dependent friction +coefficient, $\vec{F}_R$ is the usual random force, and \begin{equation} \vec{F}^{\mathrm{ps}}= - \sum_{\zeta} \kappa_{\zeta} \nabla \rho_{\zeta}(\vec{r}). \end{equation} This is an effective solvation force, that can drive the particle -towards density maxima or minima of each component, depending on -the sign of the constant $\kappa_\zeta$. Note that by setting the -coupling constant to the same negative value for both components -will, in absence of other forces, push the particle to the interfacial region. - -In addition to the solvation force acting on particles, another one that acts on the fluid components is present, -representing the solvation force of particles on the -fluid. +towards density maxima or minima of each component, depending on the +sign of the constant $\kappa_\zeta$. Note that by setting the coupling +constant to the same negative value for both components will, in +absence of other forces, push the particle to the interfacial region. + +In addition to the solvation force acting on particles, another one +that acts on the fluid components is present, representing the +solvation force of particles on the fluid. \begin{equation} - \vec{F}_{\zeta}^{\mathrm{fs}}(\vec{r}) = -\lambda_{\zeta} \rho_{\zeta}(\vec{r}) \sum_i \sum_{\vec{r}'} \Theta \left[\frac{(\vec{r}_i-\vec{r})}{|\vec{r}_i-\vec{r}|} \cdot \frac{(\vec{r}'-\vec{r})}{|\vec{r}'-\vec{r}|} \right] (\vec{r}'-\vec{r}), + \vec{F}_{\zeta}^{\mathrm{fs}}(\vec{r}) = -\lambda_{\zeta} \rho_{\zeta}(\vec{r}) \sum_i \sum_{\vec{r}'} \Theta \left[\frac{(\vec{r}_i-\vec{r})}{|\vec{r}_i-\vec{r}|} \cdot \frac{(\vec{r}'-\vec{r})}{|\vec{r}'-\vec{r}|} \right] \frac{\vec{r}'-\vec{r}}{|\vec{r}'-\vec{r}|^2}, \end{equation} -where $\Theta(x)=1$ if $0 %% %% This program is free software: you can redistribute it and/or modify diff --git a/doc/ug/ug.tex b/doc/ug/ug.tex index 280815e8cbb..4cf06cc56b7 100644 --- a/doc/ug/ug.tex +++ b/doc/ug/ug.tex @@ -1,4 +1,4 @@ -% Copyright (C) 2010,2011,2012,2013 The ESPResSo project +% Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project % Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 % Max-Planck-Institute for Polymer Research, Theory Group % @@ -49,6 +49,9 @@ \usepackage{xspace} \usepackage{units} \usepackage[numbers]{natbib} +\usepackage{enumitem} +\usepackage[table,x11names]{xcolor} +\usepackage{longtable} %\usepackage{showframe} % Turn this on when debugging the % margin etc. @@ -183,7 +186,7 @@ \raggedright% }{} -%% Layout thesyntax description box +%% Layout the syntax description box \newsavebox{\theessyntaxbox} \newlength{\essyntaxboxheight} \newlength{\essyntaxboxdepth} @@ -209,7 +212,7 @@ \setcounter{essyntaxcounter}{0} \newenvironment{essyntax}{% \stepcounter{essyntaxcounter}% - \label{essyntax:\arabic{essyntaxcounter}} + \label{essyntax:\arabic{essyntaxcounter}}% % Create headings \minisec{Syntax}\nopagebreak% \smallskip\nopagebreak% @@ -317,6 +320,7 @@ \include{io} \include{aux} \include{lb} +\include{electrokinetics} \include{fsi} \include{mbtools} diff --git a/maintainer/Espresso.spec b/maintainer/Espresso.spec index 5f02f6a853e..5c0c40f6129 100644 --- a/maintainer/Espresso.spec +++ b/maintainer/Espresso.spec @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright 2009,2010 Christoph Junghans # # This file is part of ESPResSo. diff --git a/maintainer/check_features.py b/maintainer/check_features.py index 1c243f2bfb5..70381837aff 100644 --- a/maintainer/check_features.py +++ b/maintainer/check_features.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -18,13 +18,14 @@ # # Check whether all features used in the code are defined # +from __future__ import print_function import sys, os sys.path.append(os.path.join(sys.path[0], '..', 'config')) import featuredefs if len(sys.argv) != 2: - print "Usage: %s FILE" % sys.argv[0] + print("Usage: %s FILE" % sys.argv[0]) exit(2) fdefs = featuredefs.defs(sys.argv[1]) diff --git a/maintainer/espresso-2.1.2j.ebuild b/maintainer/espresso-2.1.2j.ebuild index 9dde82eebf7..09410f1f907 100644 --- a/maintainer/espresso-2.1.2j.ebuild +++ b/maintainer/espresso-2.1.2j.ebuild @@ -1,4 +1,4 @@ -# Copyright 2010,2011,2012,2013 The ESPResSo project +# Copyright 2010,2011,2012,2013,2014 The ESPResSo project # Copyright 1999-2009 Gentoo Foundation # # This file is part of ESPResSo. diff --git a/maintainer/files_with_header.sh b/maintainer/files_with_header.sh index d10774f8c6b..e666b4b46f2 100644 --- a/maintainer/files_with_header.sh +++ b/maintainer/files_with_header.sh @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -17,12 +17,14 @@ # along with this program. If not, see . # git ls-files --exclude-standard | -egrep -v '\.(gz|data|dat|tab|chk|jpg|png|pdf|fig|gif|xcf|bib|vtf|svg|ico|eps)$' | +egrep -v '\.(blk|gz|data|dat|tab|chk|jpg|png|pdf|fig|gif|xcf|bib|vtf|vtk|svg|ico|eps)$' | egrep -v '^testsuite/configs/|^old/' | egrep -v '(ChangeLog|AUTHORS|COPYING|bootstrap\.sh)' | egrep -v '(\.gitignore|pkgIndex\.tcl)' | -egrep -v '(config/config\.guess|config/config\.sub|config/install-sh|config/myconfig-sample-header\.h\.in)' | +egrep -v '(config/config\.guess|config/config\.sub|config/install-sh|config/myconfig-sample-header\.hpp\.in)' | egrep -v '(Doxyfile|latexmk\.1|latexmkrc|assemble_quickref\.awk|doc/misc/homepage/palette\.html)' | egrep -v '(src/features\.def)' | egrep -v '(doc/ug/ug-dist\.tex)' | -egrep -v '(featurelist)' +egrep -v '(featurelist)' | +egrep -v '(\.cproject|\.project|\.settings)' | +egrep -v '(maintainer/jenkins|samples/games/highscore.txt)' diff --git a/maintainer/find_missing_header.sh b/maintainer/find_missing_header.sh index f77123612f2..2a82bc47c73 100644 --- a/maintainer/find_missing_header.sh +++ b/maintainer/find_missing_header.sh @@ -1,5 +1,5 @@ #! /bin/bash -x -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -57,5 +57,7 @@ else fi echo - +if [ -n "$nolicense" ] || [ -n "$missing_current_copyright" ]; then + exit 1 +fi diff --git a/maintainer/git2changelog.py b/maintainer/git2changelog.py index 58b26ff59b0..ab5e5a48b32 100644 --- a/maintainer/git2changelog.py +++ b/maintainer/git2changelog.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2011 Olaf Lenz # Copyright 2008 Marcus D. Hanwell # @@ -16,6 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +from __future__ import print_function import string, re, os # Execute git log with the desired command line options. @@ -106,7 +107,7 @@ elif authorLine == prevAuthorLine: pass else: - print("\n" + authorLine) + print(("\n" + authorLine)) # Assemble the actual commit message line(s) and limit the line length # to 80 characters. diff --git a/maintainer/headers.txt b/maintainer/headers.txt index cfc7625b88b..264384db03b 100644 --- a/maintainer/headers.txt +++ b/maintainer/headers.txt @@ -1,6 +1,6 @@ For long files, use: -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2013 Olaf Lenz # # This file is part of ESPResSo. diff --git a/maintainer/jenkins/ESPResSo-nightly-3core.sh b/maintainer/jenkins/ESPResSo-nightly-3core.sh deleted file mode 100644 index 5ebd1868efa..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-3core.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh - -bootstrap - -configure --with-mpi CPU_COUNT="3" - -# copy config file -if [ "$myconfig" != default ]; then - use_myconfig $myconfig -fi - -# create mympiexec.sh -echo 'exec mpiexec --bind-to-core $@' > mympiexec.sh -chmod +x mympiexec.sh - -start "BUILD" -make -j 3 -end "BUILD" - -check diff --git a/maintainer/jenkins/ESPResSo-nightly-4core.sh b/maintainer/jenkins/ESPResSo-nightly-4core.sh deleted file mode 100644 index f81672dc43f..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-4core.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh - -cd $SOURCEDIR; bootstrap - -cd $BUILDDIR -start "CONFIGURE" -./configure --with-mpi CPU_COUNT="4" -end "CONFIGURE" - -# copy config file -if [ "$myconfig" != default ]; then - use_myconfig $myconfig -fi - -# create mympiexec.sh -echo 'exec mpiexec --bind-to-core $@' > mympiexec.sh -chmod +x mympiexec.sh - -start "BUILD" -make -j 4 -end "BUILD" - -check - diff --git a/maintainer/jenkins/ESPResSo-nightly-CUDA.sh b/maintainer/jenkins/ESPResSo-nightly-CUDA.sh deleted file mode 100644 index acddab9162e..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-CUDA.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh - -cd $SOURCEDIR; bootstrap - -cd $BUILDDIR -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64 - -start "CONFIGURE" -./configure --with-mpi --with-cuda CPU_COUNT="4" -end "CONFIGURE" - -use_myconfig LBGPU - -start "BUILD" -make -j 4 -end "BUILD" - -check - diff --git a/maintainer/jenkins/ESPResSo-nightly-mpich.sh b/maintainer/jenkins/ESPResSo-nightly-mpich.sh deleted file mode 100644 index 6ac113b01e9..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-mpich.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh -bootstrap - -start "CONFIGURE" -./configure \ - CC=/home/jenkins/mpich/bin/mpicc \ - CXX=/home/jenkins/mpich/bin/mpic++ \ - MPIEXEC=/home/jenkins/mpich/bin/mpiexec \ - CPU_COUNT=4 -end "CONFIGURE" - -use_myconfig maxset - -start "BUILD" -make -j 4 -end "BUILD" - -check diff --git a/maintainer/jenkins/ESPResSo-nightly-nofftw.sh b/maintainer/jenkins/ESPResSo-nightly-nofftw.sh deleted file mode 100644 index fbd2220e945..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-nofftw.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh - -echo "#error ERROR: fftw not really present but used somewhere." > src/fftw3.h - -bootstrap - -start "CONFIGURE" -./configure --without-fftw CPU_COUNT=2 -end "CONFIGURE" - -use_myconfig nofftw - -start "BUILD" -make -j 2 -end "BUILD" - -check diff --git a/maintainer/jenkins/ESPResSo-nightly-nompi.sh b/maintainer/jenkins/ESPResSo-nightly-nompi.sh deleted file mode 100644 index aef86ddb611..00000000000 --- a/maintainer/jenkins/ESPResSo-nightly-nompi.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash --login -e -# Copyright (C) 2013 Olaf Lenz -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. This file is offered as-is, -# without any warranty. -source maintainer/jenkins/common.sh - -bootstrap - -start "CONFIGURE" -./configure --without-mpi -end "CONFIGURE" - -# copy config file -if [ "$myconfig" != default ]; then - use_myconfig $myconfig -fi - -# create mympiexec.sh -echo 'exec mpiexec --bind-to-core $@' > mympiexec.sh -chmod +x mympiexec.sh - -start "BUILD" -make -end "BUILD" - -check diff --git a/maintainer/jenkins/ESPResSo-nightly.sh b/maintainer/jenkins/bootstrap.sh old mode 100644 new mode 100755 similarity index 65% rename from maintainer/jenkins/ESPResSo-nightly.sh rename to maintainer/jenkins/bootstrap.sh index 81d24a32c02..3b5a093cb24 --- a/maintainer/jenkins/ESPResSo-nightly.sh +++ b/maintainer/jenkins/bootstrap.sh @@ -1,10 +1,16 @@ -#!/bin/bash --login -e +#!/bin/bash --login # Copyright (C) 2013 Olaf Lenz # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. -source maintainer/jenkins/common.sh +DIR=`dirname $0` +source $DIR/common.sh + +start "BOOTSTRAP" +pushd $srcdir +./bootstrap.sh || exit $? +popd +end "BOOTSTRAP" -bootstrap diff --git a/maintainer/jenkins/build.sh b/maintainer/jenkins/build.sh new file mode 100755 index 00000000000..aadf8cdfc49 --- /dev/null +++ b/maintainer/jenkins/build.sh @@ -0,0 +1,43 @@ +#!/bin/bash --login +# Copyright (C) 2013 Olaf Lenz +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +DIR=`dirname $0` +source $DIR/common.sh + +start "BUILD" +# DEFAULTS +[ -z "$myconfig" ] && myconfig="default" +[ -z "$build_procs" ] && build_procs=4 +outp myconfig build_procs + +# change into build dir +pushd $builddir + +# BUILD + +if [ "$myconfig" = "default" ]; then + echo "Using default myconfig." + if [ -e $builddir/myconfig.hpp ]; then + echo "Deleting $builddir/myconfig.hpp..." + rm $builddir/myconfig.hpp + fi +else + myconfig_file=$srcdir/maintainer/jenkins/configs/$myconfig.hpp + if [ ! -e "$myconfig_file" ]; then + echo "$myconfig_file does not exist!" + exit 1 + fi + echo "Copying $myconfig.hpp to $builddir/myconfig.hpp..." + cp $myconfig_file $builddir/myconfig.hpp +fi + +make_params="-j $build_procs" +cmd "make $make_params" || exit $? + +popd +end "BUILD" + diff --git a/maintainer/jenkins/check.sh b/maintainer/jenkins/check.sh new file mode 100755 index 00000000000..f408d104f70 --- /dev/null +++ b/maintainer/jenkins/check.sh @@ -0,0 +1,30 @@ +#!/bin/bash --login +# Copyright (C) 2013 Olaf Lenz +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +DIR=`dirname $0` +source $DIR/common.sh + +start "TEST" +[ -z "$with_mpi" ] && with_mpi="true" +! $with_mpi && check_procs=1 +[ -z "$with_cuda" ] && with_cuda="true" +[ -z "$check_procs" ] && check_procs=4 + +outp with_mpi with_cuda check_procs + +$with_cuda && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64 + +# change into build dir +pushd $builddir + +[ "$check_procs" != "1" ] && make_params="processors=\"$check_procs\"" +# something should be done after ||, otherwise Jenkins will mark +# job as failed +cmd "make check $make_params" || CHECK_UNSTABLE=1 + +popd +end "TEST" diff --git a/maintainer/jenkins/check_maintainer.py b/maintainer/jenkins/check_maintainer.py new file mode 100644 index 00000000000..b6490f263b7 --- /dev/null +++ b/maintainer/jenkins/check_maintainer.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from __future__ import print_function +import sys, os, subprocess + +# Test for precious files in commit +current_commit = os.environ["GIT_COMMIT"] + +if "GIT_PREVIOUS_COMMIT" in os.environ: + prev_commit = os.environ["GIT_PREVIOUS_COMMIT"] + refspec = "{}..{}".format(current_commit, prev_commit) +else: + refspec = current_commit + +gitout = subprocess.check_output(["git", "diff", "--name-only", refspec]) +files = gitout.split() + +warnings = [] +for fname in files: + if fname.startswith('maintainer/') or \ + fname == "src/myconfig-default.hpp": + print("check_maintainer.py: Precious file was modified: {}".format(fname)) diff --git a/maintainer/jenkins/common.sh b/maintainer/jenkins/common.sh index 7189a439a56..6a0cb60100d 100644 --- a/maintainer/jenkins/common.sh +++ b/maintainer/jenkins/common.sh @@ -16,48 +16,60 @@ function end() { echo "END $1" } -function bootstrap() { - cd $SRCDIR - start "BOOTSTRAP" - ./bootstrap.sh - end "BOOTSTRAP" - cd $BUILDDIR +function cmd() { + echo ">$1" + eval $1 } -function configure() { - start "CONFIGURE" - $SRCDIR/configure $@ - end "CONFIGURE" +function outp() { + for p in $*; do + echo " $p=${!p}" + done } -function use_myconfig() { - myconfig=$SRCDIR/testsuite/configs/myconfig-$1.hpp - if [ ! -e "$myconfig" ]; then - echo "$myconfig does not exist!" - exit 1 - fi - echo "Using $myconfig." - cp $myconfig myconfig.hpp -} +# DIR SETTINGS +[ -z "$insource" ] && insource="true" +[ -z "$srcdir" ] && srcdir=`pwd` +if $insource; then + builddir=$srcdir +elif [ -z "$builddir" ]; then + builddir=$srcdir/build +fi -function check() { - start "TEST" - # something should be done after ||, otherwise Jenkins will mark - # job as failed - make check || CHECK_UNSTABLE=1 - end "TEST" -} +outp srcdir builddir insource -function doc() { - start "DOC" - make doc - end "DOC" -} +if [ ! -e $srcdir/configure.ac ]; then + echo "Could not find configure.ac in $srcdir!" + exit 1 +fi -function dist() { - start "DIST" - make dist - make dist-xz - end "DIST" -} +if ! $insource; then + if [ ! -d $builddir ]; then + echo "Creating $builddir..." + mkdir -p $builddir + fi +fi + +# PARALLELISM SETTINGS +if [ -n "$parallelism" ]; then + outp parallelism + + case $parallelism in + ("34core") + with_mpi=true + check_procs="3 4" + ;; + ("3core") + with_mpi=true + check_procs=3 + ;; + ("4core") + with_mpi=true + check_procs=4 + ;; + ("nompi") + with_mpi=false + ;; + esac +fi diff --git a/testsuite/configs/myconfig-empty.hpp b/maintainer/jenkins/configs/empty.hpp similarity index 100% rename from testsuite/configs/myconfig-empty.hpp rename to maintainer/jenkins/configs/empty.hpp diff --git a/testsuite/configs/myconfig-maxset.hpp b/maintainer/jenkins/configs/maxset.hpp similarity index 83% rename from testsuite/configs/myconfig-maxset.hpp rename to maintainer/jenkins/configs/maxset.hpp index 6d66d124238..af233122b5c 100644 --- a/testsuite/configs/myconfig-maxset.hpp +++ b/maintainer/jenkins/configs/maxset.hpp @@ -11,13 +11,16 @@ #define COMFORCE #define COMFIXED #define MOLFORCES + +#ifdef FFTW #define MODES +#endif + #define BOND_VIRTUAL #define COLLISION_DETECTION #define LANGEVIN_PER_PARTICLE #define ROTATION_PER_PARTICLE #define CATALYTIC_REACTIONS -#define GRANDCANONCIAL #define NEMD #define NPT @@ -27,12 +30,23 @@ #define LB_BOUNDARIES #define LB_ELECTROHYDRODYNAMICS +#ifdef CUDA +#define LB_GPU +#define LB_BOUNDARIES_GPU +#define ELECTROKINETICS +#define EK_BOUNDARIES +#define EK_REACTION +#define MMM1D_GPU +#define EWALD_GPU +#endif + #define AREA_FORCE_GLOBAL #define VOLUME_FORCE #define TABULATED #define LENNARD_JONES #define LENNARD_JONES_GENERIC +#define LJGEN_SOFTCORE #define LJCOS #define LJCOS2 #define GAUSSIAN diff --git a/testsuite/configs/myconfig-molcut.hpp b/maintainer/jenkins/configs/molcut.hpp similarity index 100% rename from testsuite/configs/myconfig-molcut.hpp rename to maintainer/jenkins/configs/molcut.hpp diff --git a/testsuite/configs/myconfig-compileonly.hpp b/maintainer/jenkins/configs/nocheck-maxset.hpp similarity index 70% rename from testsuite/configs/myconfig-compileonly.hpp rename to maintainer/jenkins/configs/nocheck-maxset.hpp index 15c8deae1ee..1bac7c312cd 100644 --- a/testsuite/configs/myconfig-compileonly.hpp +++ b/maintainer/jenkins/configs/nocheck-maxset.hpp @@ -1,11 +1,10 @@ -/* maximal set of features usable at the same time */ -/* plus all debug switches */ +/* maximal set of features usable at the same time plus all debug switches */ +/* Do not run the testsuite with this set, only compile it. */ #define PARTIAL_PERIODIC #define ELECTROSTATICS #define DIPOLES #define ROTATION #define ROTATIONAL_INERTIA -#define MDLC #define EXTERNAL_FORCES #define CONSTRAINTS #define MASS @@ -13,23 +12,45 @@ #define COMFORCE #define COMFIXED #define MOLFORCES + +#ifdef FFTW #define MODES +#endif + #define BOND_VIRTUAL #define COLLISION_DETECTION -#define GRANDCANONICAL +#define LANGEVIN_PER_PARTICLE +#define ROTATION_PER_PARTICLE +#define CATALYTIC_REACTIONS #define NEMD #define NPT +#define GHMC #define LB #define LB_BOUNDARIES #define LB_ELECTROHYDRODYNAMICS +#ifdef CUDA +#define LB_GPU +#define LB_BOUNDARIES_GPU +#define ELECTROKINETICS +#define EK_BOUNDARIES +#define EK_REACTION +#define MMM1D_GPU +#endif + +#define AREA_FORCE_GLOBAL +#define VOLUME_FORCE + #define TABULATED #define LENNARD_JONES #define LENNARD_JONES_GENERIC +#define LJGEN_SOFTCORE #define LJCOS #define LJCOS2 +#define GAUSSIAN +#define HAT #define LJ_ANGLE #define GAY_BERNE #define SMOOTH_STEP @@ -39,9 +60,13 @@ #define BUCKINGHAM #define SOFT_SPHERE #define INTER_RF +#define OVERLAPPED #define BOND_ANGLE #define BOND_ANGLEDIST +#define BOND_ANGLEDIST_HARMONIC +#define BOND_ENDANGLEDIST +#define BOND_ENDANGLEDIST_HARMONIC #define VIRTUAL_SITES_RELATIVE diff --git a/testsuite/configs/myconfig-restcompile1.hpp b/maintainer/jenkins/configs/rest1.hpp similarity index 100% rename from testsuite/configs/myconfig-restcompile1.hpp rename to maintainer/jenkins/configs/rest1.hpp diff --git a/testsuite/configs/myconfig-restcompile2.hpp b/maintainer/jenkins/configs/rest2.hpp similarity index 100% rename from testsuite/configs/myconfig-restcompile2.hpp rename to maintainer/jenkins/configs/rest2.hpp diff --git a/maintainer/jenkins/configs/shanchen.hpp b/maintainer/jenkins/configs/shanchen.hpp new file mode 100644 index 00000000000..b4374d9dc27 --- /dev/null +++ b/maintainer/jenkins/configs/shanchen.hpp @@ -0,0 +1,6 @@ +/* minimal config to run SHANCHEN testcase */ +#define LB_GPU +#define SHANCHEN +#define EXTERNAL_FORCES +#define PARTIAL_PERIODIC + diff --git a/testsuite/configs/myconfig-tunableslip.hpp b/maintainer/jenkins/configs/tunableslip.hpp similarity index 100% rename from testsuite/configs/myconfig-tunableslip.hpp rename to maintainer/jenkins/configs/tunableslip.hpp diff --git a/maintainer/jenkins/configure.sh b/maintainer/jenkins/configure.sh new file mode 100755 index 00000000000..56a263d133d --- /dev/null +++ b/maintainer/jenkins/configure.sh @@ -0,0 +1,81 @@ +#!/bin/bash --login +# Copyright (C) 2013 Olaf Lenz +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +DIR=`dirname $0` +source $DIR/common.sh + +start "CONFIGURE" + +# DEFAULTS +[ -z "$configure_params" ] && configure_params="" +[ -z "$configure_vars" ] && configure_vars="" +[ -z "$with_cuda" ] && with_cuda="true" +[ -z "$with_mpi" ] && with_mpi="true" +[ -z "$with_fftw" ] && with_fftw="true" +[ -z "$with_tcl" ] && with_tcl="true" +[ -z "$with_python_interface" ] && with_python_interface="false" +outp configure_params configure_vars with_cuda with_mpi with_fftw \ + with_tcl with_python_interface + +# change into build dir +pushd $builddir + +# set up configure params +configure_params="--enable-silent-rules $configure_params" + +if $with_mpi; then + configure_params="--with-mpi $configure_params" +else + configure_params="--without-mpi $configure_params" +fi + +CUDA_HEADER=$srcdir/src/cuda.h +if $with_cuda; then + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64 + configure_params="--with-cuda $configure_params" + if [ -e $CUDA_HEADER ]; then + echo "Using CUDA => deleting mock $CUDA_HEADER..." + rm $CUDA_HEADER + fi +else + configure_params="--without-cuda $configure_params" + configure_vars="$configure_vars NVCC=/bin/false" + echo "Not using CUDA => generating mock $CUDA_HEADER..." + echo "#error ERROR: cuda is not really present but used somewhere." \ + > $CUDA_HEADER +fi + +FFTW_HEADER=$srcdir/src/fftw3.h +if $with_fftw; then + configure_params="--with-fftw $configure_params" + if [ -e $FFTW_HEADER ]; then + echo "Using FFTW => deleting mock $FFTW_HEADER..." + rm $FFTW_HEADER + fi +else + configure_params="--without-fftw $configure_params" + echo "Not using FFTW => generating mock $FFTW_HEADER..." + echo "#error ERROR: fftw is not really present but used somewhere." \ + > $FFTW_HEADER +fi + +if $with_tcl; then + configure_params="--with-tcl $configure_params" +else + configure_params="--without-tcl $configure_params" +fi + +if $with_python_interface; then + configure_params="--with-python-interface $configure_params" +else + configure_params="--without-python-interface $configure_params" +fi + +cmd "$srcdir/configure $configure_params $configure_vars" || exit $? +end "CONFIGURE" + +popd diff --git a/maintainer/jenkins/ESPResSo-nightly-debug.sh b/maintainer/jenkins/dist.sh old mode 100644 new mode 100755 similarity index 62% rename from maintainer/jenkins/ESPResSo-nightly-debug.sh rename to maintainer/jenkins/dist.sh index 5e1c29d890f..50fa981d776 --- a/maintainer/jenkins/ESPResSo-nightly-debug.sh +++ b/maintainer/jenkins/dist.sh @@ -1,19 +1,19 @@ -#!/bin/bash --login -e +#!/bin/bash --login # Copyright (C) 2013 Olaf Lenz # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. -source maintainer/jenkins/common.sh +DIR=`dirname $0` +source $DIR/common.sh -cd $SOURCEDIR; bootstrap +start "DIST" -cd $BUILDDIR +pushd $builddir +# DIST +cmd "make dist dist-xz" || exit $? -use_myconfig compileonly - -start "BUILD" -make -j 4 -end "BUILD" +popd +end "DIST" diff --git a/maintainer/jenkins/ESPResSo-nightly-distcheck.sh b/maintainer/jenkins/distcheck.sh old mode 100644 new mode 100755 similarity index 50% rename from maintainer/jenkins/ESPResSo-nightly-distcheck.sh rename to maintainer/jenkins/distcheck.sh index 120478684f9..5bf9fb6ff7b --- a/maintainer/jenkins/ESPResSo-nightly-distcheck.sh +++ b/maintainer/jenkins/distcheck.sh @@ -1,23 +1,22 @@ -#!/bin/bash --login -ex +#!/bin/bash --login # Copyright (C) 2013 Olaf Lenz # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. -source maintainer/jenkins/common.sh +DIR=`dirname $0` +source $DIR/common.sh -# clean up dir before build -chmod -R u+w espresso-* || /bin/true -git clean -fd +# DEFAULTS +[ ! -v distcheck_flags ] && distcheck_flags="" +outp distcheck_flags -bootstrap -export LD_LIBRARY_PATH=/usr/local/cuda/lib64 - -start "CONFIGURE" -./configure -end "CONFIGURE" +# change into build dir +pushd $builddir start "DISTCHECK" -make distcheck DISTCHECK_CONFIGURE_FLAGS="CPU_COUNT=2" +cmd "make distcheck DISTCHECK_CONFIGURE_FLAGS=\"$distcheck_flags\"" || exit $? end "DISTCHECK" + +popd diff --git a/maintainer/jenkins/ESPResSo.sh b/maintainer/jenkins/doc.sh old mode 100644 new mode 100755 similarity index 51% rename from maintainer/jenkins/ESPResSo.sh rename to maintainer/jenkins/doc.sh index 21286230af6..b5a7e97485a --- a/maintainer/jenkins/ESPResSo.sh +++ b/maintainer/jenkins/doc.sh @@ -1,25 +1,18 @@ -#!/bin/bash --login -e +#!/bin/bash --login # Copyright (C) 2013 Olaf Lenz # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. -BUILDDIR="$(pwd)" -SOURCEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/../.." +DIR=`dirname $0` +source $DIR/common.sh -source maintainer/jenkins/common.sh +# change into build dir +pushd $builddir -bootstrap +start "DOC" +cmd "make doc" || exit $? +end "DOC" -configure CPU_COUNT=4 - -use_myconfig maxset - -start "BUILD" -make -j 4 -end "BUILD" - -check -doc -dist +popd diff --git a/maintainer/run_multiconfig.sh b/maintainer/run_multiconfig.sh new file mode 100644 index 00000000000..d990e447c9b --- /dev/null +++ b/maintainer/run_multiconfig.sh @@ -0,0 +1,142 @@ +#!/bin/bash +# Copyright (C) 2013,2014 Axel Arnold +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# parallelism levels to check +parallelisms="34core nompi" +# default build dir +builddir=build_multiconfig +# continue after encountering an error +contaftererror=n +# number of processors to build on +build_procs=8 + +# parse options +######################################################## +configure_params="" +while test -n "$1"; do + case "$1" in + --myconfigs) myconfigs="$2"; shift ;; + --continue) contaftererror=y ;; + --build-dir) builddir="$2"; shift ;; + --build-procs) build_procs="$2"; shift ;; + --help) echo "usage: $0 [--myconfigs \"config1 config2...\"] [--continue] [--build-dir ] [--build-procs ] " 1>&2 ; exit 1 ;; + *) configure_params="$configure_params $1" ;; + esac + shift +done + +# get the topdir +######################################################## +topdir="`dirname $0`/.." + +sourcefile="$topdir/src/features.def" +if ! test -f $sourcefile; then + echo "Cannot determine the source directory." 1>&2 + echo "I am >$0< and think the source directory is >$topdir<." 1>&2 + echo "However, >$sourcefile< is missing." 1>&2 + exit 1 +fi + +# check the build directory +######################################################## + +if test -d "$builddir"; then + if ! test -f "$builddir/.multiconfig_stamp"; then + echo "Refusing to build in existing directory $builddir, which was not created by $0." 1>&2 + echo "Remove the directory first." 1>&2 + exit 1 + fi +else + mkdir -p "$builddir" +fi +touch "$builddir/.multiconfig_stamp" + +# make builddir absolute path +builddir="`cd "$builddir"; pwd -P`" + +# get the configs we have +######################################################## + +if test -z "$myconfigs"; then + myconfigs="" + pushd "$topdir/maintainer/jenkins/configs" + for file in *.hpp; do + myconfigs="$myconfigs ${file%.hpp}" + done + popd +fi + +# run the tests +######################################################## + +logdir="$builddir/log" +mkdir -p "$logdir" + +export builddir +export insource=false +export build_procs +export configure_params + +log="$logdir/configure" +set -o pipefail +bash "$topdir"/maintainer/jenkins/configure.sh 2>&1 | tee "$log" +# don't put that into if, pipefail doesn't work then, and we don't really want to continue +if test "$?" != 0 ; then + echo "Could not configure Espresso, see $log and $builddir/config.log for details" 1>&2 + echo "Exiting..." 1>&2 + exit 1 +fi + +for myconfig in $myconfigs; do + for parallelism in $parallelisms; do + log="$logdir/$myconfig-$parallelism" + export myconfig + export parallelism + # cleanup first to force rebuild + ( cd "$builddir" && make clean ) + + bash "$topdir"/maintainer/jenkins/build.sh 2>&1 | tee "$log" + if test "$?" != 0 ; then + buildfails="$buildfails $myconfig-$parallelism" + else + bash "$topdir"/maintainer/jenkins/check.sh 2>&1 | tee -a "$log" + if test "$?" != 0 ; then + checkfails="$checkfails $myconfig-$parallelism" + else + # failed tests are reported differently, figure out from the log + if grep -q "Not all test cases were successful!" "$log"; then + checkfails="$checkfails $myconfig-$parallelism" + fi + fi + fi + # save runtest.log + mv "$builddir/testsuite/runtest.log" "$log-runtest" + done +done + +if test -n "$buildfails"; then + echo "" + echo "The following test configurations could not be compiled, see $logdir/ for details:" + for conf in $buildfails; do echo $conf; done +fi +if test -n "$checkfails"; then + echo "" + echo "The following test configurations could be compiled, but tests failed, see $logdir/ and $logdir/-runtest for details:" + for conf in $checkfails; do echo $conf; done +fi diff --git a/maintainer/travis/build.sh b/maintainer/travis/build.sh new file mode 100755 index 00000000000..357731106f8 --- /dev/null +++ b/maintainer/travis/build.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env bash +# Copyright (C) 2014 Olaf Lenz +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. + + +# HELPER FUNCTIONS + +# output value of env variables +function outp { + for p in $*; do + echo " $p=${!p}" + done +} + +# start a block +function start { + echo "==================================================" + echo "START $1" + echo "==================================================" +} + +# end a block +function end { + echo "==================================================" + echo "END $1" + echo "==================================================" +} + +# execute and output a command +function cmd { + echo ">$1" + eval $1 +} + + +# handle environment variables +[ -z "$insource" ] && insource="true" +[ -z "$srcdir" ] && srcdir=`pwd` +[ -z "$configure_params" ] && configure_params="" +[ -z "$configure_vars" ] && configure_vars="" +[ -z "$with_mpi" ] && with_mpi="true" +[ -z "$with_fftw" ] && with_fftw="true" +[ -z "$with_tcl" ] && with_tcl="true" +[ -z "$with_python_interface" ] && with_python_interface="false" +[ -z "$myconfig" ] && myconfig="default" +! $with_mpi && check_procs=1 +[ -z "$check_procs" ] && check_procs=4 +[ -z "$make_check" ] && make_check="true" + +if $insource; then + builddir=$srcdir +elif [ -z "$builddir" ]; then + builddir=$srcdir/build +fi + +outp insource srcdir builddir \ + configure_params configure_vars with_mpi with_fftw \ + with_tcl with_python_interface myconfig check_procs + +if ! $insource; then + if [ ! -d $builddir ]; then + echo "Creating $builddir..." + mkdir -p $builddir + fi +fi + +# BOOTSTRAP +start "BOOTSTRAP" +$srcdir/bootstrap.sh || exit $? +end "BOOTSTRAP" + +if ! $insource ; then + cd $builddir +fi + +# CONFIGURE +start "CONFIGURE" + +if $with_mpi; then + configure_params="--with-mpi $configure_params" + configure_vars="CXX=mpic++" +else + configure_params="--without-mpi $configure_params" +fi + +FFTW_HEADER=$srcdir/src/core/fftw3.h +if $with_fftw; then + configure_params="--with-fftw $configure_params" +else + configure_params="--without-fftw $configure_params" + echo "Not using FFTW => generating mock $FFTW_HEADER..." + echo "#error ERROR: fftw is not really present but used somewhere." \ + > $FFTW_HEADER +fi + +if $with_tcl; then + configure_params="--with-tcl $configure_params" +else + configure_params="--without-tcl $configure_params" +fi + +if $with_python_interface; then + configure_params="--with-python-interface $configure_params" +else + configure_params="--without-python-interface $configure_params" +fi + +cmd "$srcdir/configure $configure_params $configure_vars" || exit $? +end "CONFIGURE" + +# BUILD +start "BUILD" + +MYCONFIG_DIR=$srcdir/maintainer/jenkins/configs +if [ "$myconfig" = "default" ]; then + echo "Using default myconfig." +else + myconfig_file=$MYCONFIG_DIR/$myconfig.hpp + if [ ! -e "$myconfig_file" ]; then + echo "$myconfig_file does not exist!" + exit 1 + fi + echo "Copying $myconfig.hpp to $builddir/myconfig.hpp..." + cp $myconfig_file $builddir/myconfig.hpp +fi + +cmd "make" || exit $? + +end "BUILD" + +# CHECK +if $make_check; then + start "TEST" + + cmd "make check $make_params" + ec=$? + if [ $ec != 0 ]; then + cat $srcdir/testsuite/runtest.log + exit $ec + fi + + end "TEST" +fi diff --git a/maintainer/update_header.sh b/maintainer/update_header.sh index c20ae6b6d01..9127b99bbf9 100644 --- a/maintainer/update_header.sh +++ b/maintainer/update_header.sh @@ -1,4 +1,4 @@ -# Copyright (C) 2012,2013 Olaf Lenz +# Copyright (C) 2012,2013,2014 Olaf Lenz # # This file is part of ESPResSo. # diff --git a/packages/mbtools/README b/packages/mbtools/README index 668167ec738..020970a2035 100644 --- a/packages/mbtools/README +++ b/packages/mbtools/README @@ -70,7 +70,7 @@ set message_allowlist { } #################################### # License and Copyright ### #################################### -Copyright (C) 2010,2011,2012,2013 The ESPResSo project +Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/packages/mbtools/analysis/analysis.tcl b/packages/mbtools/analysis/analysis.tcl index ae6d567773f..2937a7a0ebe 100644 --- a/packages/mbtools/analysis/analysis.tcl +++ b/packages/mbtools/analysis/analysis.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/boxl.tcl b/packages/mbtools/analysis/boxl.tcl index 56ee40a1fe2..d652280ffcf 100644 --- a/packages/mbtools/analysis/boxl.tcl +++ b/packages/mbtools/analysis/boxl.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/clusters.tcl b/packages/mbtools/analysis/clusters.tcl index 7f9c2e47537..3abea9d86a6 100644 --- a/packages/mbtools/analysis/clusters.tcl +++ b/packages/mbtools/analysis/clusters.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/cylinder_radius.tcl b/packages/mbtools/analysis/cylinder_radius.tcl index fb5fc013373..ff6524aa163 100644 --- a/packages/mbtools/analysis/cylinder_radius.tcl +++ b/packages/mbtools/analysis/cylinder_radius.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/density_profile.tcl b/packages/mbtools/analysis/density_profile.tcl index cc10208816f..d69b99bb6ef 100644 --- a/packages/mbtools/analysis/density_profile.tcl +++ b/packages/mbtools/analysis/density_profile.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/distance.tcl b/packages/mbtools/analysis/distance.tcl index 4e5e395e040..65de01bb876 100644 --- a/packages/mbtools/analysis/distance.tcl +++ b/packages/mbtools/analysis/distance.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/energy.tcl b/packages/mbtools/analysis/energy.tcl index 843990bb74b..137e6d71fda 100644 --- a/packages/mbtools/analysis/energy.tcl +++ b/packages/mbtools/analysis/energy.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/flipflop.tcl b/packages/mbtools/analysis/flipflop.tcl index d515c51a80d..d4bac9b44c8 100644 --- a/packages/mbtools/analysis/flipflop.tcl +++ b/packages/mbtools/analysis/flipflop.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/fluctuations.tcl b/packages/mbtools/analysis/fluctuations.tcl index fb37722eb82..2bc97b10161 100644 --- a/packages/mbtools/analysis/fluctuations.tcl +++ b/packages/mbtools/analysis/fluctuations.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/localheights.tcl b/packages/mbtools/analysis/localheights.tcl index 09622e337a7..91e9bc44ca4 100644 --- a/packages/mbtools/analysis/localheights.tcl +++ b/packages/mbtools/analysis/localheights.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/localorients.tcl b/packages/mbtools/analysis/localorients.tcl index 47ab1e4fcce..a25796453fb 100644 --- a/packages/mbtools/analysis/localorients.tcl +++ b/packages/mbtools/analysis/localorients.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/molcom.tcl b/packages/mbtools/analysis/molcom.tcl index e4d0c3698c1..241833fbc91 100644 --- a/packages/mbtools/analysis/molcom.tcl +++ b/packages/mbtools/analysis/molcom.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/molforce.tcl b/packages/mbtools/analysis/molforce.tcl index c15ca936cb4..9c99a32434b 100644 --- a/packages/mbtools/analysis/molforce.tcl +++ b/packages/mbtools/analysis/molforce.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/oop.tcl b/packages/mbtools/analysis/oop.tcl index 6f5489e2ba1..4a765345aa0 100644 --- a/packages/mbtools/analysis/oop.tcl +++ b/packages/mbtools/analysis/oop.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/pressure.tcl b/packages/mbtools/analysis/pressure.tcl index 8cb1b59cb22..4c3f4e513ef 100644 --- a/packages/mbtools/analysis/pressure.tcl +++ b/packages/mbtools/analysis/pressure.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/radial_density_profile.tcl b/packages/mbtools/analysis/radial_density_profile.tcl index 330b8ebf6cb..67ad213b3b3 100644 --- a/packages/mbtools/analysis/radial_density_profile.tcl +++ b/packages/mbtools/analysis/radial_density_profile.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/stray.tcl b/packages/mbtools/analysis/stray.tcl index 1a4177b856e..c2f032b2215 100644 --- a/packages/mbtools/analysis/stray.tcl +++ b/packages/mbtools/analysis/stray.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/stress_profile.tcl b/packages/mbtools/analysis/stress_profile.tcl index b40e8d9b0b6..0e18c0a45ac 100644 --- a/packages/mbtools/analysis/stress_profile.tcl +++ b/packages/mbtools/analysis/stress_profile.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/stress_tensor.tcl b/packages/mbtools/analysis/stress_tensor.tcl index ba1a1b46396..340183e57dc 100644 --- a/packages/mbtools/analysis/stress_tensor.tcl +++ b/packages/mbtools/analysis/stress_tensor.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/analysis/tiltangle.tcl b/packages/mbtools/analysis/tiltangle.tcl index 028453a3fe9..7226a832826 100644 --- a/packages/mbtools/analysis/tiltangle.tcl +++ b/packages/mbtools/analysis/tiltangle.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/packages/mbtools/doc/analysis.html b/packages/mbtools/doc/analysis.html index ea0957147bb..891bfbe2d1a 100644 --- a/packages/mbtools/doc/analysis.html +++ b/packages/mbtools/doc/analysis.html @@ -1,6 +1,6 @@ Warning! <--" - puts "----------------" - puts "--> Could not find 'countBonds.tcl' which is required for execution!" - puts "Aborting..." - exit - } - } - puts "Done." - } elseif { [lsearch [info procs] "polyBlockWrite"] == -1 } { - puts -nonewline "\n Function 'polyBlockWrite' is missing - trying to reload... " - flush stdout - if { [catch [source auxiliary.tcl]]!=0 } { - if { [catch [source ./scripts/auxiliary.tcl]]!=0 && [catch [source $ESPRESSO_SCRIPTS/auxiliary.tcl]]!=0 } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> Could not find 'auxiliary.tcl' which is required for execution!" - puts "Aborting..." - exit - } - } - puts "Done." - } else { - puts "Done (all required functions accounted for)." - } - - # The internal names of the Deserno-variables from 'polygelSetup' will be stored in 'conf', - # the corresponding counterparts for 'Espresso' in 'corr' at the same relative position within the lists; - # 'spec' specifies any special properties one has to take into account when using the parameters - puts -nonewline " Correlate parameter names... " - flush stdout - global conf corr spec iptq - set conf [concat { prefix postfix seed startTime endTime deltaT - integrationSteps saveResults saveConfig N_P N_CPP chargeDist - val_CI N_Salt val_pS val_nS N_T boxLen subbox_1D - skin rcut_P3M k_FENE r_FENE eps_LJ rcut_LJ alpha mesh ip - Bjerrum Temp Gamma N_CR } ] - # ...and correlate it with the ones from 'Espresso' - # ('NA' = there's no implementation in 'Espresso') - set corr [concat { NA NA NA NA NA time_step - NA NA NA NA NA NA - NA NA NA NA max_part box_l NA - skin p3m_r_cut NA NA NA NA p3m_alpha p3m_mesh NA - bjerrum temp gamma NA } ] - # Note the special properties some 'Espresso' variables have: - # 'ro' = read only; '3d' = 3D input required; 'OK' = nothing special - set spec [concat { OK OK OK OK OK OK - OK OK OK OK OK OK - OK OK OK OK ro 3d OK - OK OK OK OK OK OK OK 3d OK - OK OK OK OK } ] - set iptq "id pos type q" - # sets which informations (out of pos|type|q|v|f) on the particles should be saved to disk ('Deserno2MD' only) - puts "Done." - - puts -nonewline " Preparing global variables... " - flush stdout - # Determine which type-number should be assigned to monomers, counter-ions, salt-ions, ... - global type_P type_CI type_S - set type_P 0 - set type_CI 1 - set type_S 2 - # Determine which type-number should be assigned to the interactions - global type_FENE type_bend - set type_FENE 0 - set type_bend 1 - # Specify additional parameters for the potentials - global pot_bend pot_LJ_sigma pot_LJ_shift pot_LJ_offset pot_ramp_cut pot_ramp_fmax - set pot_bend 1 - set pot_LJ_sigma 1.0 - set pot_LJ_shift 0 - set pot_LJ_offset 0 - set pot_ramp_cut 1.3 - set pot_ramp_fmax 100 - # Define additional parameters which are not supplied by Deserno but have to be calculated later on - global MPC N_CI N_pS N_nS N_S - # MPC = [expr ($N_CPP-1)*$chargeDist+1] is the number of monomers per polymer chain - # N_CI = [expr $N_P*$N_CPP/$val_CI] is the number of counterions - # N_pS = [expr $N_Salt*$val_pS] is the number of positively charged salt ions - # N_nS = [expr $N_Salt*$val_nS] is the number of negatively charged salt ions - # N_S = [expr $N_pS+$N_nS] is the total number of salt ions - # (not to be confused with N_Salt, which is the number of salt _molecules_) - # Define auxiliary parameters - global step foldCoord - # step = amount of integration steps taken so far - # (only used for MD2Deserno; has to be supplied by user) - set foldCoord 0 - # foldCoord = decides whether to periodically fold the particle's coordinates before working with them; - # this is important, since 'polygelSetup' by default creates an unfolded system of polymers, - # centered in a box with boxlenght L, but extending outside, too. - puts "Done." - - # Mark this initialization procedure as being completed - global convertInitDone - set convertInitDone 1 - puts " Initialization completed." -} - - - -############################################################# -# convertDeserno2MD # -############################################################# - -proc convertDeserno2MD {origin destination} { - # Initialize necessary parameters - initConversion - - # Continue - convertDeserno2MDmain "$origin" "$destination" -} - - -############################################################# -# convertDeserno2MDmain # -############################################################# - -proc convertDeserno2MDmain {origin destination} { - # Check if initialization was done - global convertInitDone - if { $convertInitDone!=1 } { - puts " !!! Warning !!! You're bypassing the initialization sequence! Continuing at your own risk..." - } - - # Note that tcl requires to have the name of used global variables repeated here - # => cross-check with 'initConversion' to make sure everything there matches an entry here - global conf corr spec iptq - global type_P type_CI type_S - global type_FENE type_bend - global pot_bend pot_LJ_sigma pot_LJ_shift pot_LJ_offset pot_ramp_cut pot_ramp_fmax - global MPC N_CI N_pS N_nS N_S - global foldCoord - - - # Check the supplied file-names for existence and correctness - if { ![ file exists $origin ] } { - puts "Failed.\n " - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The file containing the Deserno-configuration could not be found!" - puts "--> (You supplied: $origin)" - puts "Aborting...\n" - exit - } - if { $destination == "-1" } { - puts " No output-file was given, everything will be submitted without saving to 'Espresso' only..." - } - - - # Open the input-file which must have the Deserno-format, e.g. created by 'polygelSetup' - # looking like this: - # Line defining a parameter --> '# Description............: ' - # Line defining coordinates --> ' ' - # Line defining crosslinking parameters --> '# Description......: var = ' - # Line defining the crosslinks --> ' ' - puts -nonewline " Preparing Deserno-configuration to be read from '[lindex [split $origin \"/\"] end]'... " - flush stdout - set in [open $origin "r"] - puts "Done." - - -# Import entries in Deserno-file -############################################################# - - # Now get the file's entries and assign them to the corresponding variable - puts " Conversion in progress..." - flush stdout - set i 0 - set j 0 - while { ![eof $in] } { - # Consecutively load in each line of the input-file - # and assign it to the names in 'conf' - # (call it 'dummy' if you've run out of names) - if {$i<[llength $conf]} { - set tmp_var [lindex $conf $i] - } else { - set tmp_var "dummy" - } - eval global $tmp_var T$tmp_var - eval gets $in $tmp_var - # This trick allows to access the current variable's name by '$tmp_var' - # while using the variable itself by 'eval ... $$tmp_var' - -# Submit Parameters -############################################################# - - # If the current line starts with '#' it contains a parameter - if { [eval string compare -length 1 \"$$tmp_var\" \"\#\"]==0 } then { - if {$j==0} { set sep ":" } else { set sep "=" } - - # Check for consistency - if { ![expr $i<[llength $conf]] } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> There are more parameters found in the file than specified in 'conf'!" - puts "--> Supply more tags in 'conf', 'corr' and 'spec'!" - puts "Aborting...\n" - exit - } - - # Split the line into its components: - # Left part is the parameter's description -> e.g. 'Tprefix' (with 'T'='Text') - eval set T$tmp_var \"[lindex [eval split \"$$tmp_var\" $sep] 0]: \" - # Right part is the value of the parameter -> e.g. 'prefix' (as stored in 'conf') - eval set $tmp_var \"[string trim [lindex [eval split \"$$tmp_var\" $sep] 1] ]\" - - # If possible, sent the value to 'Espresso': - if { [string compare "[lindex $corr $i]" "NA"]!=0 } { - # Intercept 'read-only' parameters until they are available in 'Espresso' - if { [string compare "[lindex $spec $i]" "ro"]!=0 } { - puts -nonewline " ---> Espresso <--- Submitting " - eval puts -nonewline \"'$[concat "T$tmp_var"] [lindex $conf $i]' \" - puts -nonewline "\t to " - eval puts \"'[lindex $corr $i]' (= $$tmp_var).\" - - # some parameters require 3D, although Deserno specified only one - if { [string compare "[lindex $spec $i]" "3d"]==0 } { - setmd [lindex $corr $i] [eval concat \"$$tmp_var\"] \ - [eval concat \"$$tmp_var\"] [eval concat \"$$tmp_var\"] - } else { - # regular parameters don't make trouble ;-/ - setmd [lindex $corr $i] [eval concat \"$$tmp_var\"] - } - } else { - # If read-only, the parameter is not submitted, but stored in a global variable - # for further use in this or any other script - puts -nonewline " Setting read-only variable " - eval puts \"'$[concat "T$tmp_var"] [lindex $conf $i]' (= $$tmp_var).\" - } - } else { - # Even if they're not sent to 'Espresso' the parameters are set up globally - # for further use in this or any other script - puts -nonewline " Assigning global variable " - eval puts \"'$[concat "T$tmp_var"] [lindex $conf $i]' (= $$tmp_var).\" - } - - # Goto next parameter in 'conf' - incr i - - # Otherwise (i.e. if the current line read from $origin does not start with '#') - # it's probably either the particles' coordinates or the crosslinks' configurations - } else { - # Switch from indirect variables (needed for the parameters) to direct access - eval set tmp_var $$tmp_var - - # Distinguish between particles (second block) and crosslinks (fourth block) - if {$j==0} { - # Derive some additional parameters - set MPC [expr ($N_CPP-1)*$chargeDist+1] - set N_CI [expr $N_P*$N_CPP/$val_CI] - set N_pS [expr $N_Salt*$val_pS] - set N_nS [expr $N_Salt*$val_nS] - set N_S [expr $N_pS+$N_nS] - -# Submit Interactions -############################################################# - - # Create the bonded interactions - puts " Preparing bonded interactions: " - puts -nonewline " Lennard-Jones (eps=[format %4.2f $eps_LJ], " - puts -nonewline "sigma=[format %4.2f $pot_LJ_sigma], rcut=[format %4.2f $rcut_LJ], " - puts "shift=[format %4.2f $pot_LJ_shift], offset=[format %4.2f $pot_LJ_offset]) between: " - puts -nonewline " Polymer-Polymer... " - flush stdout - inter $type_P $type_P lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts -nonewline "Polymer-Counterion... " - flush stdout - inter $type_P $type_CI lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts -nonewline "Polymer-Salt... " - flush stdout - inter $type_P $type_S lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts " " - puts -nonewline " Counterion-Counterion... " - flush stdout - inter $type_CI $type_CI lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts -nonewline "Counterion-Salt... " - flush stdout - inter $type_CI $type_S lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts -nonewline "Salt-Salt... " - flush stdout - inter $type_S $type_S lennard-jones $eps_LJ $pot_LJ_sigma $rcut_LJ $pot_LJ_shift $pot_LJ_offset - puts " " - - # Create the non-bonded interactions - puts " Preparing non-bonded interactions: " - puts " Type $type_FENE: FENE (k=[format %4.2f $k_FENE], r=[format %4.2f $r_FENE])... " - inter $type_FENE fene $k_FENE $r_FENE - puts " Type $type_bend: Cosine (pot_bend=$pot_bend)... " - inter $type_bend angle $pot_bend - - puts " Interactions completed." - -# Submit Polymers -############################################################# - - # Setting up the polymers - puts -nonewline " Submitting $N_P polymers with $MPC monomers (of type $type_P) each... " - flush stdout - set old [expr 10*($N_P*$MPC)] - set k 0 - for {set j 0} {$j<[expr $N_P*$MPC]} {incr j} { - # Draw a status bar for every 10% of progress - if { [expr $j*100]>=$old} { - set old [expr $old + 10*($N_P*$MPC)] - puts -nonewline ".,." - flush stdout - } - # upon entering this part of the program we already have an unprocessed line stored in 'tmp_var' - # (which we used to detect that it does not contain a parameter), hence we only load additional - # lines once we've processed this one, i.e. for $j>0 - if { $j>0 } { gets $in tmp_var } - - # Submit the data to 'Espresso' - if { $foldCoord == 1 } { - part $j pos [expr [lindex $tmp_var 0] - floor([lindex $tmp_var 0] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 1] - floor([lindex $tmp_var 1] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 2] - floor([lindex $tmp_var 2] / $boxLen)*$boxLen] - } else { - part $j pos [lindex $tmp_var 0] [lindex $tmp_var 1] [lindex $tmp_var 2] - } - part $j v [lindex $tmp_var 3] [lindex $tmp_var 4] [lindex $tmp_var 5] - part $j q [lindex $tmp_var 6] - part $j type $type_P - - # Setting a bond between all $MPC monomers of the same polymer - # => omit monomer 0, 1*$MPC, 2*$MPC,..., ($N_P-1)*$MPC - if { [expr $j%$MPC]!=0 } { - part $j bond $type_FENE [expr $j-1] - # Note that Espresso stores bonds only with the particle of lower particle-number; - # hence, a bond between 'a' and 'b' for 'a use the function 'countBonds' to get a tcl-list 'bonds' - # which has '{0 a}' at particle 'b' as well! - incr k - } - } - puts ".,. $j particles total, $k of which bounded (by type $type_FENE)." - -# Submit remaining Particles -############################################################# - - # Setting up some counterions - puts -nonewline " Submitting $N_CI counterions (of type $type_CI)... " - flush stdout - set old [expr 10*$N_CI+100*($N_P*$MPC)] - for {set j $j} {$j<[expr $N_CI+($N_P*$MPC)] } {incr j} { - # Draw a status bar for every 10% of progress - if { [expr $j*100]>=$old } { - set old [expr $old + 10*$N_CI] - puts -nonewline ".,." - flush stdout - } - gets $in tmp_var - # Submit the data to 'Espresso' - if { $foldCoord == 1 } { - part $j pos [expr [lindex $tmp_var 0] - floor([lindex $tmp_var 0] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 1] - floor([lindex $tmp_var 1] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 2] - floor([lindex $tmp_var 2] / $boxLen)*$boxLen] - } else { - part $j pos [lindex $tmp_var 0] [lindex $tmp_var 1] [lindex $tmp_var 2] - } - part $j v [lindex $tmp_var 3] [lindex $tmp_var 4] [lindex $tmp_var 5] - part $j q [lindex $tmp_var 6] - part $j type $type_CI - } - puts ".,. [expr $j-($N_P*$MPC)] particles with valency $val_CI total." - - # Setting up the salt-molecules - puts -nonewline " Submitting $N_nS " - for {set k 0} {$k<$val_nS} {incr k} {puts -nonewline "-"} - puts -nonewline " and $N_pS " - for {set k 0} {$k<$val_pS} {incr k} {puts -nonewline "+"} - puts -nonewline " salt ions (of type $type_S)... " - flush stdout - set old [expr 10*$N_S+100*($N_CI+$N_P*$MPC)] - for {set j $j} {$j<[expr $N_S+($N_CI+$N_P*$MPC)] } {incr j} { - # Draw a status bar for every 10% of progress - if { [expr $j*100]>=$old } { - set old [expr $old + 10*$N_S] - puts -nonewline ".,." - flush stdout - } - gets $in tmp_var - # Submit the data to 'Espresso' - if { $foldCoord == 1 } { - part $j pos [expr [lindex $tmp_var 0] - floor([lindex $tmp_var 0] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 1] - floor([lindex $tmp_var 1] / $boxLen)*$boxLen] \ - [expr [lindex $tmp_var 2] - floor([lindex $tmp_var 2] / $boxLen)*$boxLen] - } else { - part $j pos [lindex $tmp_var 0] [lindex $tmp_var 1] [lindex $tmp_var 2] - } - part $j v [lindex $tmp_var 3] [lindex $tmp_var 4] [lindex $tmp_var 5] - part $j q [lindex $tmp_var 6] - part $j type $type_S - } - puts ".,. [expr $j-($N_CI+$N_P*$MPC)] particles in $N_Salt molecules total." - -# Submit Crosslinks -############################################################# - - # Deal with crosslinks between the polymer chains - } elseif {$j==[expr ($N_CI+$N_P*$MPC)+$N_S] && [string length $tmp_var]>0} { - # Connecting cross-linked monomers - puts -nonewline " Crosslinking [expr 2*$N_CR] monomers... " - flush stdout - set old [expr 10*$N_CR+100*($N_S+$N_CI+$N_P*$MPC)] - for {set j $j} {$j<[expr $N_CR+($N_S+$N_CI+$N_P*$MPC)]} {incr j} { - # Draw a status bar for every 10% of progress - if { [expr $j*100]>=$old } { - set old [expr $old + 10*$N_CR] - puts -nonewline ".,." - flush stdout - } - # upon entering this part of the program we already have an unprocessed line stored in 'tmp_var' - # (which we used to detect that it does not contain a parameter), hence we only load additional - # lines once we've processed this one, i.e. for $j>($N_S+$N_CI+$N_P*$MPC) - if { $j>[expr $N_S+$N_CI+$N_P*$MPC] } { gets $in tmp_var } - - # Crosslink particles - part [lindex $tmp_var 0] bond $type_FENE [lindex $tmp_var 1] - # Note that Espresso stores bonds only with the particle of lower particle-number; - # hence, a bond between 'a' and 'b' for 'a use the function 'countBonds' to get a tcl-list 'bonds' - # which has '{0 a}' at particle 'b' as well! - } - puts ".,. [expr $j-($N_S+$N_CI+$N_P*$MPC)] additional bonds (of type $type_FENE) created." - } elseif {[string length $N_CR]==0 } { - set N_CR 0 - } - } - } - # Finish up the conversion part by closing the input-file - close $in - puts " Conversion completed." - - -# Write output file -############################################################# - - # Save all converted configurations, parameters, and interactions to $destination - # using AxA's blockfile-format for 'Espresso'; skip if user specified "-1" as file-name - if { $destination != "-1" } { - # The converted configurations should be compressed on-the-fly using - # 'set f [open "|gzip -c - >$destination" w]' for output, allowing later usage with - # 'set f [open "|gzip -cd $destination" r]' to read it in - # This is done in 'polyBlockWrite' which writes all we've done so far to a 'Espresso'-compatible file - puts -nonewline " Saving all configurations in 'Espresso'-format to '[lindex [split $destination \"/\"] end]'... " - flush stdout - foreach j $corr { - if { $j != "NA" } { lappend tmp_corr $j } - } - polyBlockWrite $destination $tmp_corr $iptq - puts "Done " - - } else { - puts " Skipping to save converted configurations: Nothing will be written to disk, only 'Espresso' will have them!" - } - - - # End this script - puts " Function successfully completed. Returning control to calling script..." -} - - - - -############################################################# -# convertMD2Deserno # -############################################################# - -proc convertMD2Deserno {origin destination} { - # Initialize necessary parameters - initConversion - - # Set parameters which cannot be determined from 'Espresso' or from $origin - global conf - foreach i $conf { global $i } - global step - set prefix AA0000 - set postfix 0 - set seed -1 - set startTime -1 - set endTime -1 - set integrationSteps -1 - set saveResults -1 - set saveConfig -1 - set subbox_1D -1 - set ip -1 - set step -1 - - # Continue - convertMD2DesernoMain "$origin" "$destination" -} - - -############################################################# -# convertMD2DesernoMain # -############################################################# - -proc convertMD2DesernoMain {origin destination} { - # Check if initialization was done - global convertInitDone - if { $convertInitDone!=1 } { - puts " !!! Warning !!! You're bypassing the initialization sequence! Continuing at your own risk..." - } - - # Note that tcl requires to have the name of used global variables repeated here - # => cross-check with 'initConversion' to make sure everything there matches an entry here - global conf corr spec iptq - foreach i $conf { global $i } - global type_P type_CI type_S - global type_FENE type_bend - global pot_bend pot_LJ_sigma pot_LJ_shift pot_LJ_offset pot_ramp_cut pot_ramp_fmax - global MPC N_CI N_pS N_nS N_S - global step - - -# Import entries from file -############################################################# - - # If the user specified '-1' for $origin, then there is no input-file and everything is directly taken from Espresso - if { [string compare "$origin" "-1"]==0 } { - puts " No input-file was specified, let's hope that all required informations are accessible from 'Espresso'!" - } else { - # Open the (compressed) input-file which is expected to contain a configuration in 'Espresso'-blockfile-format - puts -nonewline " Preparing 'Espresso'-configuration to be read from '[lindex [split $origin \"/\"] end]'... " - flush stdout - if { [string compare [lindex [split $origin "."] end] "gz"]==0 } { - set in [open "|gzip -cd $origin" "r"] - } else { - set in [open "$origin" "r"] - } - puts "Done." - - # Now get the file's entries - puts " Reading content of '[lindex [split $origin \"/\"] end]' (this may take a while)... " - while {[blockfile $in read auto] != "eof" } {} - puts " Got coordinates for [expr [setmd max_part] + 1] particles total..." - puts " Got all the bonds between particles..." - puts " Got all the interactions..." - close $in - puts " ... and closed the file." - } - - -# Get the rest from 'tcl-md' -############################################################# - - # Now everything should either have been loaded from the blockfile $origin into 'Espresso' - # or (in case $origin==-1) it was already there - puts " Gathering informations from 'Espresso'... " - flush stdout - - # Load everything useful out of 'Espresso' - puts -nonewline " Getting" - foreach i $corr j $conf { - if { [string compare "$i" "NA"]!=0 } { - puts -nonewline " $i/" - flush stdout - set $j [lindex [setmd $i] 0] - puts -nonewline "$j ." - } - } - - # Load interactions parameters: - puts "..\n Load interactions parameters..." - flush stdout - set tmp_FENE 0 - set tmp_LJ 0 - set tmp_int [inter] - for {set i 0} {$i<[llength $tmp_int]} {incr i} { - set tmp_var [lindex $tmp_int $i] - # FENE,... - if { [string compare [lindex $tmp_var 1] "FENE"]==0 } { - if { $tmp_FENE==0 } { - puts -nonewline " Setting FENE-parameters " - set k_FENE [lindex $tmp_var 2] - puts -nonewline " (k_FENE = $k_FENE, " - flush stdout - set r_FENE [lindex $tmp_var 3] - puts -nonewline "r_FENE = $r_FENE)... " - set tmp_FENE 1 - puts "Done." - } elseif { $k_FENE!=[lindex $tmp_var 2] || $r_FENE!=[lindex $tmp_var 3] } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> FENE-interaction parameters must be constant for all bonds!" - puts "--> (Found $k_FENE=k_FENE=[lindex $tmp_var 2] and $r_FENE=r_FENE=[lindex $tmp_var 3])" - puts "Aborting...\n" - exit - } - # ...and Lennard-Jones - } elseif {[string compare [lindex $tmp_var 2] "lennard-jones"]==0} { - if { $tmp_LJ==0 } { - puts -nonewline " Setting Lennard-Jones-parameters " - set eps_LJ [lindex $tmp_var 3] - puts -nonewline " (eps_LJ = $eps_LJ, " - set rcut_LJ [lindex $tmp_var 5] - puts -nonewline "rcut_LJ = $rcut_LJ)... " - set tmp_LJ 1 - puts "Done." - } elseif { $eps_LJ!=[lindex $tmp_var 3] || $rcut_LJ!=[lindex $tmp_var 5] } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> Lennard-Jones parameters must be constant for all particles!" - puts "--> (Found $eps_LJ=eps_LJ=[lindex $tmp_var 3] and $rcut_LJ=rcut_LJ=[lindex $tmp_var 5])" - puts "Aborting...\n" - exit - } - } - } - puts " Done with interactions." - - # Load all particle data - puts -nonewline " Getting informations on any particle... " - flush stdout - set part_all [part] - set N_T [llength $part_all] - puts "Done (got $N_T particles)." - - # Everything should be back in this function now - puts " Gathering completed." - - -# Re-build network structure -############################################################# - - # Now create a tcl-list with all bonds in it - set bonds [countBonds $part_all] - - - # Get an idea of the network structure - puts " Analyzing network structure... " - - # In a polymer melt the monomers on a chain have usually two bonds while their ends have just one; - # in a end-to-end-linked network the ends are cross-linked, too, so that their new partners have three bonds - puts -nonewline " Checking number of bonds on $N_T particles... " - flush stdout - set part_end {} - set part_lin {} - set part_crs {} - set old [expr 10*$N_T] - for {set i 0} {$i<$N_T} {incr i} { - # Draw a status bar for every 10% of progress - if { [expr $i*100]>=$old } { - set old [expr $old + 10*$N_T] - puts -nonewline ".,." - flush stdout - } - # Check if the current particle has any cross-links (e.g. counter-ions have not). - # Note, that $bonds contains an entry for every particle (i.e. the particle_number), - # hence the number of bonds is -1 smaller than the length of that entry. - if { [llength [lindex $bonds $i]]>1 } { - # Check the number of cross-links: - switch [llength [lindex $bonds $i]] { - 2 { # 1 bond: particle is the end of a polymer chain - lappend part_end $i } - 3 { # 2 bonds: particle is monomer in a chain - lappend part_lin $i } - 4 { # 3 bonds: particle also has a cross-link to another chain - lappend part_crs $i } - default { - # 4+ bonds??? => hmm... too much?! - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> Current particle [lindex [lindex $bonds $i] 0] (found at index $i) has too many bonds!" - puts "--> (Got: [expr [llength [lindex $bonds $i]]-1]; expected: 1-3)" - puts "Aborting...\n" - exit - } - } - } else { - # no bonds, no cross-links => must be something else (counter-ion, etc.), but must _not_ be a monomer - if { [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] type]]!=$type_P } { - lappend part_else $i - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts -nonewline "--> Current particle [lindex [lindex $bonds $i] 0] (found at index $i) " - puts "is a loose monomer (type $type_P) without any bonds!" - puts "--> (Stats: [lindex $part_all $i])" - puts "Aborting...\n" - exit - } - } - } - puts ".,. found [llength $part_end] ends, [llength $part_lin] linear bonds, [llength $part_crs] cross-links." - - -# Identify Polymer Melt -############################################################# - - # If 'part_crs' is empty, there's no network but only a melt; hence, the polymer chains are easy to identify - if { [llength $part_crs]==0 } { - puts " => polymer melt/solution detected." - set N_CR 0 - puts -nonewline " Identifying polymer chains... " - flush stdout - set tmp_CPP 0 - set tmp_cD 0 - set tmp_NP 0 - set tmp_MPC 0 - set old_i 0 - set old_e [llength $part_end] - set old [expr 10*$old_e] - - # loop all particles found having only one bond, because these are the chains' ends - foreach i $part_end { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - # make sure that current end is not the end of a previously reconstructed chain - set tmp_var 0 - if { $tmp_NP>0} { - for {set j 0} {$j<[llength $polymer_chains]} {incr j} { - if { [expr [lindex [lindex $polymer_chains $j] 0]==$i] || \ - [expr [lindex [lindex $polymer_chains $j] end]==$i] } { - set tmp_var 1 - } - } - } - if { $tmp_var==1 } continue - - # build the chain following the bond information stored with each particle - set chains [lindex [lindex $bonds $i] 0] - set tmp_CPP_k 0 - set tmp_cD_k -1 - set tmp_MPC_k 0 - while { $tmp_MPC_k<$N_T } { - set j [lindex $chains end] - set j_bond [lrange [lindex $bonds $j] 1 end] - set j_bond_nr 0 - # is current particle charged? => keep track of the amount of charges and the distances between them - if { [lindex [lindex $part_all $j] [findPropPos [lindex $part_all $j] q]]!=0 } { - if { [expr $tmp_cD_k+1]==$tmp_cD || $tmp_cD_k==-1 } { - incr tmp_CPP_k - set tmp_cD_k 0 - } elseif { $tmp_cD==0 } { - incr tmp_CPP_k - set tmp_cD [expr $tmp_cD_k+1] - set tmp_cD_k 0 - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The distance between charges on a chain must be constant!" - puts "--> (Found a chain with distances $tmp_cD and $tmp_cD_k)" - puts "Aborting...\n" - exit - } - } elseif { $tmp_cD_k>-1 } { incr tmp_cD_k } - # agglomerate the monomers - if { [llength $j_bond]==1 } { - if { $tmp_MPC_k>0 } { - # last particle -> wrap up evaluation - incr tmp_MPC_k - break - } - } else { - # check which of the bonds lead "forward" on the chain - if { [lindex [lindex $j_bond 0] 1]==[lindex $chains end-1] } { - set j_bond_nr 1 - } - } - lappend chains [lindex [lindex $j_bond $j_bond_nr] 1] - incr tmp_MPC_k - } - - # check for consistency - if { $tmp_CPP_k!=$tmp_CPP } { - if { $tmp_CPP==0 } { - set tmp_CPP $tmp_CPP_k - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The amount of charges on a chain must be constant!" - puts "--> (Found chains with $tmp_CPP and $tmp_CPP_k)" - puts "Aborting...\n" - exit - } - } - if { $tmp_MPC_k==$tmp_MPC } { - lappend polymer_chains $chains - incr tmp_NP - } elseif { [lindex $part_end 0]==$i} { - set tmp_MPC $tmp_MPC_k - lappend polymer_chains $chains - incr tmp_NP - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The number of monomers on all chains must be constant!" - puts "--> (Found chains with $tmp_MPC and $tmp_MPC_k)" - puts "Aborting...\n" - exit - } - } - set N_CPP $tmp_CPP - set chargeDist $tmp_cD - set N_P $tmp_NP - set MPC $tmp_MPC - puts -nonewline ".,. reconstructed $N_P chains with $MPC monomers each " - puts -nonewline "($N_CPP charged with distance $chargeDist" - if { $chargeDist>0 } { - puts -nonewline ", like " - for {set j 0} {$j<3} {incr j} { - puts -nonewline "c" - for {set i 0} {$i<[expr $chargeDist-1]} {incr i} { puts -nonewline "." } - } - puts -nonewline "c etc." - } - puts ")." - - -# Identify cross-linked Network -############################################################# - - # If 'part_end' is empty, this is an end-to-end cross-linked network, - # where any of the three partners in 'part_end' may be one of the chain's end; - # therefore, one has to have a closer look - } elseif { [llength $part_end]==0 } { - puts " => end-to-end crosslinked network detected." - puts " (Note that the reconstruction will only be successful if the chains are aligned consecutively!)" - puts -nonewline " Attempting to identify polymer chains... " - flush stdout - set tmp_CPP 0 - set tmp_cD 0 - set tmp_NP 0 - set tmp_MPC 0 - set tmp_NCR 0 - set old_i 0 - set old_e [expr [llength $part_crs]+[llength $part_lin]] - set old [expr 10*$old_e] - - # loop all particles with at least two bonds - for {set i 0} {$i<$old_e} {incr i} { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - # get the bonding informations on the current particle & check if they comply with the rules - set tmp_bond [lindex $bonds $i] - set tmp_current [lindex $tmp_bond 0] - if {[llength $tmp_bond]<2} { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> An end-to-end crosslinked network may only be reconstructed" - puts "--> if the chains are aligned consecutively!" - puts -nonewline "--> (Expected $old_e particles with bonds, but found particle $tmp_current " - puts "(at index $i) having none)" - puts "Aborting...\n" - exit - } - set tmp_bond [lrange $tmp_bond 1 end] - - # build the chain following the bond information stored with each particle - # and making use of the requirement that all chains have to be aligned - set tmp_end -1 - for {set j 0} {$j<[llength $tmp_bond]} {incr j} { - set tmp_partner [lindex [lindex $tmp_bond $j] 1] - if { $tmp_partner==[expr $tmp_current-1] } { - # bonding partner is left neighbour => append $i to the chain - lappend chains $tmp_current - incr tmp_MPC_k - # is current particle charged? => keep track of the amount of charges and the distances between them - if { [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] q]]!=0 } { - if { [expr $tmp_cD_k+1]==$tmp_cD || $tmp_cD_k==-1 } { - incr tmp_CPP_k - set tmp_cD_k 0 - } elseif { $tmp_cD==0 } { - incr tmp_CPP_k - set tmp_cD [expr $tmp_cD_k+1] - set tmp_cD_k 0 - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The distance between charges on a chain must be constant!" - puts "--> (Found a chain with distances $tmp_cD and $tmp_cD_k)" - puts "Aborting...\n" - exit - } - } elseif { $tmp_cD_k>-1 } { incr tmp_cD_k } - } elseif { $tmp_partner!=[expr $tmp_current+1] } { - # bonding partner is not on this chain => append to crosslinks - # if the current particle is at the end of a chain - if { [llength $tmp_bond]==2 } { - set tmp_end $j - if {$tmp_partner < $tmp_current} { - lappend cross "{$tmp_partner $tmp_current}" - } else { - lappend cross "{$tmp_current $tmp_partner}" - } - incr tmp_NCR - } - } - } - # if current particle is at the end of a chain, - # check if it's the left one => in that case open a new chain - if {$tmp_end > -1} { - set tmp_partner [lindex [lindex $tmp_bond [expr $tmp_end*(-1)+1]] 1] - if { $tmp_partner==[expr $tmp_current+1] } { - # left end => new chain - set chains $tmp_current - set tmp_MPC_k 1 - # is current particle charged? => keep track of the amount of charges and the distances between them - if { [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] q]]!=0 } { - set tmp_CPP_k 1 - set tmp_cD_k 0 - } else { - set tmp_CPP_k 0 - set tmp_cD_k -1 - } - } else { - # right end => wrap up evaluation of this chain by checking for consistency - if { $tmp_CPP_k!=$tmp_CPP } { - if { $tmp_CPP==0 } { - set tmp_CPP $tmp_CPP_k - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The amount of charges on a chain must be constant!" - puts "--> (Found chains with $tmp_CPP and $tmp_CPP_k)" - puts "Aborting...\n" - exit - } - } - if { $tmp_MPC_k==$tmp_MPC } { - lappend polymer_chains $chains - incr tmp_NP - } elseif { $tmp_MPC==0 && $tmp_NP==0 } { - set tmp_MPC $tmp_MPC_k - lappend polymer_chains $chains - incr tmp_NP - } else { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The number of monomers on all chains must be constant!" - puts "--> (Found chains with $tmp_MPC and $tmp_MPC_k)" - puts "Aborting...\n" - exit - } - } - } - } - set N_CPP $tmp_CPP - set chargeDist $tmp_cD - set N_P $tmp_NP - set MPC $tmp_MPC - set N_CR $tmp_NCR - puts -nonewline ".,. reconstructed $N_P chains with $MPC monomers each ($N_CPP charged with distance $chargeDist" - if { $chargeDist>0 } { - puts -nonewline ", like " - for {set j 0} {$j<3} {incr j} { - puts -nonewline "c" - for {set i 0} {$i<[expr $chargeDist-1]} {incr i} { puts -nonewline "." } - } - puts -nonewline "c etc." - } - puts "), found $N_CR crosslinks." - } - puts " Analysis completed." - - -# Derive remaining particle informations -############################################################# - - # Determine N_CPP, chargeDist, val_CI, N_Salt, val_pS, val_nS - puts " Analyzing particle data..." - - # Determine val_CI, N_Salt, val_pS, val_nS - puts -nonewline " Determining valency of counter-ions and salt-molecules... " - flush stdout - set tmp_CI 0 - set tmp_valCI 0 - set tmp_Salt 0 - set tmp_pS 0 - set tmp_nS 0 - set old_i 0 - set old_e [llength $part_else] - set old [expr 10*$old_e] - - # loop all remaining particles with no bonds - foreach i $part_else { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - set tmp_if [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] type]] - if { $tmp_if==$type_CI } { - # it's a counter-ion - set tmp_var [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] q]] - if { $tmp_CI==0} { - set tmp_valCI $tmp_var - } elseif { $tmp_valCI!=$tmp_var } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The valency of the counter-ions must be constant!" - puts "--> (Found some with $tmp_valCI and others with $tmp_var)" - puts "Aborting...\n" - exit - } - incr tmp_CI - } elseif { $tmp_if==$type_S } { - # it's a salt-molecule - set tmp_var [lindex [lindex $part_all $i] [findPropPos [lindex $part_all $i] q]] - if { $tmp_var>0 } { set tmp_S tmp_pS } else { set tmp_S tmp_nS } - if { [eval expr $$tmp_S==0] } { - eval set $tmp_S $tmp_var - } elseif { [eval expr $$tmp_S!=$tmp_var] } { - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts "--> The valency of the salt ions must be constant!" - eval puts "--> (Found some with $$tmp_S and others with $tmp_var)" - puts "Aborting...\n" - exit - } - incr tmp_Salt - } else { - # neither salt nor counter-ion but having no bonds at all??? => hmm... something's wrong?! - puts "Failed.\n" - puts "----------------" - puts "--> Warning! <--" - puts "----------------" - puts -nonewline "--> Found unbound particle $i which is neither counter-ion ($type_CI) " - puts "nor salt ($type_S), but of type $tmp_if!" - puts "--> Confused: What shall I do with it?" - puts "--> (Stats: [lindex $part_all $i])" - puts "Aborting...\n" - exit - } - } - set N_CI $tmp_CI - set val_CI $tmp_valCI - set N_Salt $tmp_Salt - set val_pS $tmp_pS - set val_nS [expr (-1)*$tmp_nS] - puts -nonewline ".,. found $N_CI counter-ions with valency $val_CI and $N_Salt salt-molecules" - if { $val_nS>0 || $val_pS>0} { - puts -nonewline " with valency " - for {set k 0} {$k<$val_nS} {incr k} {puts -nonewline "-"} - puts -nonewline " or " - for {set k 0} {$k<$val_pS} {incr k} {puts -nonewline "+"} - } - puts "." - - - # So much for the particle data - puts " Analysis completed." - - -# Write output file -############################################################# - - # Open output-file - puts -nonewline " Preparing converted configurations to be written to '[lindex [split $destination \"/\"] end]'... " - flush stdout - set out [open $destination "w"] - puts "Done." - - # Now write all we've done so far to a Deserno-compatible file - puts " Saving all configurations in Deserno-format to disk... " - puts -nonewline " Writing file header... " - flush stdout - puts $out "# Praefix-String......................: $prefix" - puts $out "# Postfix-Nummer......................: $postfix" - puts $out "# Zufallszahlen-Seed..................: $seed" - puts $out "# Physikalische Zeit..................: [expr $startTime+$step*$deltaT]" - puts $out "# Physikalische Endzeit...............: $endTime" - puts $out "# Diskretisierungs-Schritt............: $deltaT" - puts $out "# Anzahl der Integrationsschritte.....: $integrationSteps" - puts $out "# Messergebnisse herausschreiben......: $saveResults" - puts $out "# Konfigurationen herausschreiben.....: $saveConfig" - puts $out "# Anzahl der Polymere.................: $N_P" - puts $out "# Ladungen pro Polymer................: $N_CPP" - puts $out "# Ladungsabstand......................: $chargeDist" - puts $out "# Valenz der Polymer-Gegenionen.......: $val_CI" - puts $out "# Anzahl der Salzmolekuele............: $N_Salt" - puts $out "# Valenz der positiven Salzionen......: $val_pS" - puts $out "# Valenz der negativen Salzionen......: $val_nS" - puts $out "# Teilchenzahl........................: $N_T" - puts $out "# Boxlaenge...........................: $boxLen" - puts $out "# Subboxen pro Boxlaenge..............: $subbox_1D" - puts $out "# Skin................................: $skin" - puts $out "# Ortsraum-Cutoff.....................: $rcut_P3M" - puts $out "# k-FENE..............................: $k_FENE" - puts $out "# r-FENE..............................: $r_FENE" - puts $out "# epsilon-LJ..........................: $eps_LJ" - puts $out "# LJ-Cutoff...........................: $rcut_LJ" - puts $out "# alpha...............................: $alpha" - puts $out "# FFT-Mesh............................: $mesh" - puts $out "# Gitter-ip...........................: $ip" - puts $out "# Bjerrum-Laenge......................: $Bjerrum" - puts $out "# Temperatur..........................: $Temp" - puts $out "# Gamma...............................: $Gamma" - puts "Done." - - # Note the format requirements: - # 1. Monomers MMMM MMMM MMMM MMMM | ++++ ++++ ++++ | ++++ ++++ ++++ | ---- ---- ---- - # 2. Counter-ions First, N_P polymer | Second, | Third, | Last, - # 3. Positive Salt chains with MPC | N_CI | val_pS*N_Salt | val_nS*N_Salt - # 4. Negative Salt monomers each | counter-ions | positive salt | negative salt - - # Write out the polymer chains - set old_i 0 - set old_e [expr $N_P*$MPC] - set old [expr 10*$old_e] - puts -nonewline " Writing $N_P polymer chains with $MPC monomers and $N_CPP charges each... " - flush stdout - foreach i $polymer_chains { - # The Deserno-file-format requires that first the monomer's data has to be written in the order of the chains - foreach j $i { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - # write monomer - set tmp_part [lindex $part_all $j] - set tmp_var [findPropPos $tmp_part pos] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+1]]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+2]]\t" - set tmp_var [findPropPos $tmp_part v] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+1]]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+2]]\t" - set tmp_var [findPropPos $tmp_part q] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\n" - } - } - puts ".,. completed." - - # Write out any remaining counter-ions or salt molecules - puts -nonewline " Writing [expr $N_CPP*$N_P/$val_CI] counter-ions and $N_Salt salt molecules... " - flush stdout - set old_i 0 - set old_e [expr 3*[llength $part_else]] - set old [expr 10*$old_e] - for {set j 0} {$j<3} {incr j} { - # The Deserno-file-format requires that after the monomer's datas - # first the counter-ions, then the positive salt ions, and last the negative salt ions - # have to be written; hence we'll pass this loop three times... *sigh* - foreach i $part_else { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - # write particles - set tmp_part [lindex $part_all $i] - set tmp_if [lindex $tmp_part [findPropPos $tmp_part type]] - set tmp_fi [lindex $tmp_part [findPropPos $tmp_part q]] - set tmp_d 0 - if { $j==0 && $tmp_if==$type_CI } { set tmp_d 1 } - if { $j==1 && $tmp_if==$type_S && $tmp_fi>0 } { set tmp_d 1 } - if { $j==2 && $tmp_if==$type_S && $tmp_fi<0 } { set tmp_d 1 } - if { $tmp_d==1 } { - set tmp_var [findPropPos $tmp_part pos] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+1]]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+2]]\t" - set tmp_var [findPropPos $tmp_part v] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+1]]\t" - puts -nonewline $out "[lindex $tmp_part [expr $tmp_var+2]]\t" - set tmp_var [findPropPos $tmp_part q] - puts -nonewline $out "[lindex $tmp_part $tmp_var]\n" - } - } - } - puts ".,. completed." - - # Write out cross-links (if any) - if { $N_CR>0 } { - puts -nonewline " Writing $N_CR cross-links... " - flush stdout - puts $out "# Number of Crosslinks.........: N_CR = $N_CR" - set old_i 0 - set old_e $N_CR - set old [expr 10*$old_e] - foreach i $cross { - # draw a status bar for every 10% of progress - if { [expr $old_i*100]>=$old } { - set old [expr $old + 10*$old_e] - puts -nonewline ".,." - flush stdout - } - incr old_i - - # write cross-links - puts $out "[lindex $i 0]\t[lindex $i 1]" - } - puts ".,. completed." - } - - # Done - puts " Saving completed." - - - # Now finish up by closing the file - puts -nonewline " Closing output file... " - flush stdout - close $out - puts "Done." - puts " Function successfully completed. Returning control to calling script..." -} diff --git a/scripts/obsolete/pov.tcl b/scripts/obsolete/pov.tcl deleted file mode 100644 index 15bd533d376..00000000000 --- a/scripts/obsolete/pov.tcl +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project -# Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 -# Max-Planck-Institute for Polymer Research, Theory Group -# -# This file is part of ESPResSo. -# -# ESPResSo is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# ESPResSo is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -proc writepov {file {folded "no"} {boxopt "no"} {render "no"} {rotate "-10 22.5 0"} {nofold_list 0} } { -#writes the current configuration in pov-ray format -#file is the name of the output -#use -folded if you want folded coordinates -#use -box if you want to output the box -#use -render if you want to render the pov-ray file -#render contains a vector by which the entire configuration is rotated -#nofold_list contains a list of types that should not be folded if 'folded' is set to -folded - if {$folded == "-folded"} { - set de "folded" - } else {set de "pos"} - if {[file exists "$file"] } { - error "ERROR: $file already exists; please use a different file name!\nAborting..." - } else { - set f [open $file "w"] - } - set box [setmd box_l] - - #write background, camera, lighting - puts $f "background {color rgb <0.98,0.98,0.98>}" - puts $f "light_source \{\n<1000,1000,-100>\ncolor rgb 1\n\}" - puts $f "light_source \{\n<-1000,1000,-100>\ncolor rgb 1\n\}" - puts $f "camera \{\northographic\nlocation <[expr [lindex $box 0]*0.5],\ - [expr [lindex $box 1]*0.5],-[expr [lindex $box 2]*1.5]>\n\ - look_at <[expr [lindex $box 0]*0.5],[expr [lindex $box 1]*0.5],[expr [lindex $box 2]*0.5]>\n\}" - - #write atoms and bonds - set radius [expr [lindex $box 0]*0.004] - set b_radius [expr $radius*0.25] - lappend color <0.36,0.57,0.31> <0.66,0.0,0.12> <0.20,0.32,0.53> - set mp [setmd max_part] - set texture "texture { finish { ambient 0.000 diffuse 0.650 phong 0.1 phong_size 40.000 specular 0.500 } }" - puts $f "union \{" - for {set p 0} { $p <= $mp} {incr p} { - set type [part $p print type] - # if {$type==0 || $type==1} {set de "pos"} else {set de "folded"} - if {$nofold_list != 0} { if {[lsearch $nofold_list $type] != -1 } {set de "pos"} else {set de "folded"} } - set pos [part $p print $de] - puts $f "\/\/ $p POS\nsphere \{\n<[lindex $pos 0],[lindex $pos 1],[lindex $pos 2]>,\n$radius\n$texture\n\ - pigment \{color rgb [lindex $color $type] \}\nno_shadow\n\}" - if {[llength [lindex [part $p print bond] 0]] > 0} { - set n_bond [llength [lindex [part $p print bond] 0]] - for {set q 0} {$q < $n_bond} {incr q} { - set end [part [lindex [part $p print bond] 0 $q 1] print $de] - if {[veclen [vecsub $pos $end]] < [expr [lindex $box 0]*0.8]} { - puts $f "\/\/ $p [lindex [part $p print bond] 0 $q 1] BOND\n\ - cylinder \{\n<[lindex $pos 0],[lindex $pos 1],[lindex $pos 2]>,\n\ - <[lindex $end 0],[lindex $end 1],[lindex $end 2]>,\n$b_radius\n\ - $texture\npigment \{ color rgb [lindex $color $type]\}\nno_shadow\n\}" - } - } - } - } - #write box - if {$boxopt == "-box"} { - set c_radius [expr $radius*1.5] - puts $f "\/\/ box" - puts $f "cylinder \{\n<0,0,0>,\n<[lindex $box 0],0,0>,\n$c_radius\n$texture\npigment \{ color rgb [lindex $color 0]\}\ - no_shadow \n \}" - puts $f "cylinder \{\n<0,0,0>,\n<0,[lindex $box 1],0>,\n$c_radius\n$texture\npigment \{ color rgb [lindex $color 0]\}\ - no_shadow \n \}" - puts $f "cylinder \{\n<0,0,0>,\n<0,0,[lindex $box 2]>,\n$c_radius\n$texture\npigment \{ color rgb [lindex $color 0]\}\ - no_shadow \n \}" - - puts $f "cylinder \{\n<[lindex $box 0],0,[lindex $box 2]>,\n<[lindex $box 0],0,0>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<[lindex $box 0],0,[lindex $box 2]>,\n<[lindex $box 0],[lindex $box 1],[lindex $box 2]>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<[lindex $box 0],0,[lindex $box 2]>,\n<0,0,[lindex $box 2]>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - - puts $f "cylinder \{\n<[lindex $box 0],[lindex $box 1],0>,\n<[lindex $box 0],0,0>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<[lindex $box 0],[lindex $box 1],0>,\n<0,[lindex $box 1],0>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<[lindex $box 0],[lindex $box 1],0>,\n<[lindex $box 0],[lindex $box 1],[lindex $box 2]>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - - puts $f "cylinder \{\n<0,[lindex $box 1],[lindex $box 2]>,\n<0,[lindex $box 1],0>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<0,[lindex $box 1],[lindex $box 2]>,\n<0,0,[lindex $box 2]>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - puts $f "cylinder \{\n<0,[lindex $box 1],[lindex $box 2]>,\n<[lindex $box 0],[lindex $box 1],[lindex $box 2]>,\n$c_radius\n$texture\npigment\ - \{ color rgb [lindex $color 0]\} \nno_shadow \n \}" - } - #write rotation - puts $f "rotate <[lindex $rotate 0],[lindex $rotate 1],[lindex $rotate 2]>" - puts $f "\}" - close $f - - #Render pov-file - if {$render=="-render"} { - catch { exec povray +FT +W800 +H600 +A0.2 -I$file -O$file.tga } - } -} - -proc morph {f1 f2 f3 {arg 100} {render ""}} { -# morphs 2 povray-files in arg steps -#f1 is the start of the morph -#f2 is the end of the morph -#f3 is the name of the output - - set inp2 [open $f2 r] - set list "" - while {[eof $inp2]==0} { - set l2 [gets $inp2] - set wl2 [string map { "\{" " "} $l2] - if {[lindex $wl2 2]=="POS"} { - gets $inp2 - set l2 [gets $inp2] - lappend list $l2 - } - } - close $inp2 - - for {set j 0} {$j < [expr $arg+1]} {incr j} { - set outp [open $f3-[format %05d $j].pov w] - set inp1 [open $f1 r] - - while {[eof $inp1]==0} { - - set l1 [gets $inp1] - set wl1 [string map { "\{" " "} $l1] - set wl1 [string map { "\}" " "} $wl1] - - if {[lindex $wl1 2]=="POS"} { - puts $outp $l1 - set part [lindex $l1 1] - set l1 [gets $inp1] - puts $outp $l1 - set l1 [gets $inp1] - set l2 [lindex $list $part] - set pos1 [string map { "<" " "} $l1] - set pos2 [string map { "<" " "} $l2] - set pos1 [string map { ">" " "} $pos1] - set pos2 [string map { ">" " "} $pos2] - set pos1 [string map { "," " "} $pos1] - set pos2 [string map { "," " "} $pos2] - set morph_pos [vecadd $pos1 [vecscale [expr $j.0/$arg.0] [vecsub $pos2 $pos1]]] - puts $outp "<[lindex $morph_pos 0],[lindex $morph_pos 1],[lindex $morph_pos 2]>" - set l1 [gets $inp1] - puts $outp $l1 - set l1 [gets $inp1] - puts $outp $l1 - set l1 [gets $inp1] - set rgb [string map { "<" " "} $l1] - set rgb [string map { ">" " "} $rgb] - set rgb [string map { "," " "} $rgb] - set color "[lindex $rgb 1 2] [lindex $rgb 1 3] [lindex $rgb 1 4]" - puts $outp "pigment \{ color rgbt <[lindex $color 0],[lindex $color 1],[lindex $color 2],0.6> \}" - set l1 [gets $inp1] - puts $outp $l1 - set l1 [gets $inp1] - puts $outp $l1 - } elseif {[lindex $wl1 3]=="BOND"} { - - for {set cnt 0} {$cnt < 8} {incr cnt} { - gets $inp1 - } - } else { - puts $outp $l1 - } - } - close $outp - close $inp1 - - if {$render=="-render"} { - puts "rendering" - catch {exec povray +FT +W800 +H600 +A0.2 -I$f3-[format %05d $j].pov -O$f3-[format %05d $j].tga} - puts "rendering done" - } - } -} diff --git a/scripts/parallel_tempering.tcl b/scripts/parallel_tempering.tcl index 9c99d3e270d..34b86207eda 100644 --- a/scripts/parallel_tempering.tcl +++ b/scripts/parallel_tempering.tcl @@ -4,7 +4,7 @@ # ############################################################# # -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2007,2008,2009,2010 Axel Arnold # # This file is part of ESPResSo. diff --git a/scripts/pdb.tcl b/scripts/pdb.tcl index 0762944f913..925065ad213 100644 --- a/scripts/pdb.tcl +++ b/scripts/pdb.tcl @@ -1,4 +1,4 @@ -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/scripts/polymer.tcl b/scripts/polymer.tcl index 1ccf4fb9a3a..9984f6c62e4 100644 --- a/scripts/polymer.tcl +++ b/scripts/polymer.tcl @@ -6,7 +6,7 @@ # Script to setup polymer chains & networks. # # # ############################################################# -# Copyright (C) 2010,2012,2013 The ESPResSo project +# Copyright (C) 2010,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # Max-Planck-Institute for Polymer Research, Theory Group # diff --git a/scripts/statistics.tcl b/scripts/statistics.tcl index fdb054ce48a..778c78faeac 100644 --- a/scripts/statistics.tcl +++ b/scripts/statistics.tcl @@ -7,7 +7,7 @@ # # ############################################################# # -# Copyright (C) 2010,2011,2012,2013 The ESPResSo project +# Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project # Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 # # Max-Planck-Institute for Polymer Research, Theory Group diff --git a/scripts/vtf.tcl b/scripts/vtf.tcl index a729d516d09..14118789e28 100644 --- a/scripts/vtf.tcl +++ b/scripts/vtf.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2006,2007,2008,2009,2010,2011 Olaf Lenz # # This file is part of ESPResSo. @@ -98,7 +98,6 @@ proc writevsf { file args } { set typedesc {} set radius {} set short 0 - set no_charges 0 # Parse options for { set argnum 0 } { $argnum < [llength $args] } { incr argnum } { @@ -113,9 +112,6 @@ proc writevsf { file args } { set radius $val incr argnum } - "ignore_charges" { - set no_charges 1 - } "verbose" { set short 0 } "short" { set short 1 } default { @@ -129,6 +125,13 @@ proc writevsf { file args } { global vtf_pid array unset vtf_pid + # Print unitcell data + if { $short } then { + puts $file "p [setmd box_l]" + } else { + puts $file "pbc [setmd box_l]" + } + set max_pid [setmd max_part] # compute the maximal type @@ -143,51 +146,70 @@ proc writevsf { file args } { set typedesclist [get_typedesc_list $max_type $typedesc] set radiuslist [get_radius_list $max_type $radius] - ################################################## - # OUTPUT - ################################################## - # Print unitcell data - if { $short } then { - puts $file "p [setmd box_l]" - } else { - puts $file "pbc [setmd box_l]" - } - - # Print atom data - set from 0 - set to 0 - set prev_type "na" - - # Output the type + # collect combinations of charge and type + set uses_electrostatics [has_feature "ELECTROSTATICS"] + set qs "" for { set pid 0 } { $pid <= $max_pid } { incr pid } { - if { [part $pid] != "na" } then { - # look for the type - set type [part $pid print type] - if { $prev_type == "na" } then { - set prev_type $type - } elseif { $prev_type == $type } then { - set to $pid - } else { - # output from $from to $pid - puts $file [get_atom_record $from $to $prev_type] - - set to $pid - set from $pid - set prev_type $type - } - } + set type [part $pid print type] + if { $uses_electrostatics } then { + set q [part $pid print q] + set qs "q$q" + } + set this "t$type$qs" + if { ! [info exists combination($this)] } then { + set combination($this) $pid + set desc "radius [lindex $radiuslist $type]" + set desc "$desc [lindex $typedesclist $type]" + if { $uses_electrostatics } then { set desc "$desc q $q" } + set combination("desc-$this") $desc + } else { + lappend combination($this) $pid + } } - puts $file [get_atom_record $from $to $prev_type] - if { [has_feature "ELECTROSTATICS"] && !$no_charges} { - # Output the charge - for { set pid 0 } { $pid <= $max_pid } { incr pid } { - if { [part $pid] != "na" } then { - puts $file "atom [vtfpid $pid] q [part $pid print q]" - } - } + # loop over the combinations and create atom record + foreach c [array names combination "t*"] { + set pids $combination($c) + set desc $combination("desc-$c") + set to [vtfpid [lindex $pids 0]] + set aids "" + foreach pid $pids { + set vpid [vtfpid $pid] + if { [expr $vpid-1] != $to } then { + if { [info exists from] } then { + # print out records from $from to $to + if { $from == $to } then { + lappend aids "$to" + } else { + lappend aids "$from:$to" + } + } + set from $vpid + } + set to $vpid + } + if { $from == $to } then { + lappend aids "$to" + } else { + lappend aids "$from:$to" + } + unset from + # let's group atom ranges, so that there are no more than 8 per line + # This fixes a problem with the vmd plugin, and makes the vtf more + # readable anyway. + set start 0 + set maxlen 8 + set ll [llength [lrange $aids $start end ]] + while { $ll >= $maxlen } { + puts $file "atom [join [lrange $aids $start [expr $start + $maxlen -1]] ,] $desc" + incr start $maxlen + set ll [llength [lrange $aids $start end ]] + } + if { $start < [llength $aids ] } { + puts $file "atom [join [lrange $aids $start end] ,] $desc" + } } - + # Print bond data for { set from 0 } { $from <= $max_pid } { incr from } { if { [part $from] != "na" } then { diff --git a/scripts/vtk.tcl b/scripts/vtk.tcl index 13cd645f9ad..134246c16c2 100644 --- a/scripts/vtk.tcl +++ b/scripts/vtk.tcl @@ -1,5 +1,5 @@ # -# Copyright (C) 2012,2013 The ESPResSo project +# Copyright (C) 2012,2013,2014 The ESPResSo project # Copyright (C) 2006,2007,2008,2009,2010,2011 Olaf Lenz # # This file is part of ESPResSo. diff --git a/src/Makefile.am b/src/Makefile.am index d317a5bb063..93d5dac0219 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,4 @@ -# Copyright (C) 2012,2013 The ESPResSo project -# Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold +# Copyright (C) 2014 The ESPResSo project # # This file is part of ESPResSo. # @@ -17,409 +16,18 @@ # along with this program. If not, see . # -# List headers that are not used by the program here -noinst_HEADERS = \ - myconfig-default.hpp - -noinst_LIBRARIES = libEspresso.a - -# List the sources of the Espresso binary here -# config-features.cpp must be at the beginning so that it is compiled first -nodist_libEspresso_a_SOURCES = -libEspresso_a_SOURCES = \ - config-features.cpp \ - adresso.cpp adresso.hpp \ - cells.cpp cells.hpp \ - collision.cpp collision.hpp \ - communication.cpp communication.hpp \ - comfixed.cpp comfixed.hpp \ - comforce.hpp comforce.cpp \ - config.hpp \ - constraint.cpp constraint.hpp \ - cuda_interface.cpp cuda_interface.hpp\ - cuda_init.hpp \ - debug.cpp debug.hpp \ - domain_decomposition.cpp domain_decomposition.hpp \ - energy.cpp energy.hpp \ - errorhandling.cpp errorhandling.hpp \ - fft.cpp fft.hpp \ - fft-common.cpp fft-common.hpp \ - fft-dipolar.cpp fft-dipolar.hpp \ - forcecap.cpp forcecap.hpp \ - forces.cpp forces.hpp \ - galilei.cpp galilei.hpp \ - ghosts.cpp ghosts.hpp \ - global.cpp global.hpp \ - grid.cpp grid.hpp \ - halo.cpp halo.hpp \ - iccp3m.cpp iccp3m.hpp \ - imd.cpp imd.hpp \ - initialize.cpp initialize.hpp \ - integrate.cpp integrate.hpp \ - interaction_data.cpp interaction_data.hpp \ - lattice.cpp lattice.hpp \ - layered.cpp layered.hpp \ - lb.cpp lb.hpp \ - lb-boundaries.cpp lb-boundaries.hpp \ - lb-d3q18.hpp lb-d3q19.hpp \ - lbgpu.cpp lbgpu.hpp\ - metadynamics.cpp metadynamics.hpp \ - modes.cpp modes.hpp \ - molforces.cpp molforces.hpp \ - mol_cut.cpp mol_cut.hpp \ - nemd.cpp nemd.hpp \ - npt.hpp \ - nsquare.cpp nsquare.hpp \ - particle_data.cpp particle_data.hpp \ - polymer.cpp polymer.hpp \ - polynom.hpp \ - pressure.cpp pressure.hpp \ - random.cpp random.hpp \ - rattle.cpp rattle.hpp \ - reaction.cpp reaction.hpp \ - rotation.cpp rotation.hpp \ - specfunc.cpp specfunc.hpp \ - statistics.cpp statistics.hpp \ - statistics_chain.cpp statistics_chain.hpp \ - statistics_cluster.cpp statistics_cluster.hpp \ - statistics_correlation.cpp statistics_correlation.hpp \ - statistics_fluid.cpp statistics_fluid.hpp \ - statistics_molecule.cpp statistics_molecule.hpp \ - statistics_observable.cpp statistics_observable.hpp \ - statistics_wallstuff.cpp statistics_wallstuff.hpp \ - thermostat.cpp thermostat.hpp \ - topology.cpp topology.hpp \ - tuning.cpp tuning.hpp \ - utils.hpp \ - uwerr.cpp uwerr.hpp \ - verlet.cpp verlet.hpp \ - virtual_sites.cpp virtual_sites.hpp \ - virtual_sites_com.cpp virtual_sites_com.hpp \ - virtual_sites_relative.cpp virtual_sites_relative.hpp \ - vmdsock.cpp vmdsock.hpp \ - ghmc.cpp ghmc.hpp - -# nonbonded potentials and forces -libEspresso_a_SOURCES += \ - bmhtf-nacl.cpp bmhtf-nacl.hpp \ - buckingham.cpp buckingham.hpp \ - dpd.cpp dpd.hpp \ - gaussian.cpp gaussian.hpp \ - gb.cpp gb.hpp \ - hat.cpp hat.hpp \ - hertzian.cpp hertzian.hpp \ - lj.cpp lj.hpp \ - ljangle.cpp ljangle.hpp \ - ljcos.cpp ljcos.hpp \ - ljcos2.cpp ljcos2.hpp \ - ljgen.cpp ljgen.hpp \ - morse.cpp morse.hpp \ - soft_sphere.cpp soft_sphere.hpp \ - steppot.cpp steppot.hpp \ - tab.cpp tab.hpp \ - tunable_slip.cpp tunable_slip.hpp - -# bonded potentials and forces -libEspresso_a_SOURCES += \ - angle.cpp angle.hpp \ - angle_harmonic.cpp angle_harmonic.hpp \ - angle_cosine.cpp angle_cosine.hpp \ - angle_cossquare.cpp angle_cossquare.hpp \ - angledist.cpp angledist.hpp \ - dihedral.cpp dihedral.hpp \ - endangledist.cpp endangledist.hpp \ - fene.cpp fene.hpp \ - harmonic.cpp harmonic.hpp \ - overlap.cpp overlap.hpp \ - subt_lj.cpp subt_lj.hpp \ - object-in-fluid/area_force_local.cpp object-in-fluid/area_force_local.hpp \ - object-in-fluid/area_force_global.cpp object-in-fluid/area_force_global.hpp \ - object-in-fluid/bending_force.cpp object-in-fluid/bending_force.hpp \ - object-in-fluid/stretching_force.cpp object-in-fluid/stretching_force.hpp \ - object-in-fluid/stretchlin_force.cpp object-in-fluid/stretchlin_force.hpp \ - object-in-fluid/volume_force.cpp object-in-fluid/volume_force.hpp - -# Coulomb methods -libEspresso_a_SOURCES += \ - debye_hueckel.cpp debye_hueckel.hpp \ - elc.cpp elc.hpp \ - magnetic_non_p3m_methods.cpp magnetic_non_p3m_methods.hpp \ - mdlc_correction.cpp mdlc_correction.hpp \ - maggs.cpp maggs.hpp \ - mmm1d.cpp mmm1d.hpp \ - mmm2d.cpp mmm2d.hpp \ - mmm-common.cpp mmm-common.hpp \ - p3m.cpp p3m.hpp \ - p3m_gpu.hpp \ - p3m-common.cpp p3m-common.hpp \ - p3m-dipolar.cpp p3m-dipolar.hpp \ - reaction_field.cpp reaction_field.hpp - +EXTRA_DIST = +CLEANFILES = +DIST_SUBDIRS = core tcl python/espressomd +SUBDIRS = core if TCL - -libEspresso_a_SOURCES += \ - tcl/adresso_tcl.cpp tcl/adresso_tcl.hpp \ - tcl/bin_tcl.cpp \ - tcl/binary_file_tcl.cpp tcl/binary_file_tcl.hpp \ - tcl/blockfile_tcl.cpp \ - tcl/cells_tcl.cpp \ - tcl/channels_tcl.cpp \ - tcl/collision_tcl.cpp \ - tcl/comfixed_tcl.cpp tcl/comfixed_tcl.hpp \ - tcl/comforce_tcl.cpp tcl/comforce_tcl.hpp \ - tcl/config_tcl.cpp \ - tcl/constraint_tcl.cpp tcl/constraint_tcl.hpp \ - tcl/domain_decomposition_tcl.cpp tcl/domain_decomposition_tcl.hpp \ - tcl/energy_tcl.cpp \ - tcl/galilei_tcl.cpp tcl/galilei_tcl.hpp \ - tcl/global_tcl.cpp tcl/global_tcl.hpp \ - tcl/grid_tcl.cpp tcl/grid_tcl.hpp \ - tcl/iccp3m_tcl.cpp tcl/iccp3m_tcl.hpp \ - tcl/imd_tcl.cpp \ - tcl/initialize_interpreter.cpp \ - tcl/integrate_tcl.cpp tcl/integrate_tcl.hpp \ - tcl/interaction_data_tcl.cpp tcl/interaction_data_tcl.hpp \ - tcl/lb-boundaries_tcl.cpp \ - tcl/lb_tcl.cpp tcl/lb_tcl.hpp \ - tcl/metadynamics_tcl.cpp tcl/metadynamics_tcl.hpp \ - tcl/nemd_tcl.cpp \ - tcl/mol_cut_tcl.cpp tcl/mol_cut_tcl.hpp \ - tcl/parser.cpp tcl/parser.hpp \ - tcl/particle_data_tcl.cpp \ - tcl/polymer_tcl.cpp tcl/polymer_tcl.hpp \ - tcl/pressure_tcl.cpp tcl/pressure_tcl.hpp \ - tcl/random_tcl.cpp tcl/random_tcl.hpp \ - tcl/reaction_tcl.cpp tcl/reaction_tcl.hpp \ - tcl/rattle_tcl.cpp tcl/rattle_tcl.hpp \ - tcl/statistics_chain_tcl.cpp tcl/statistics_chain_tcl.hpp \ - tcl/statistics_cluster_tcl.cpp tcl/statistics_cluster_tcl.hpp \ - tcl/statistics_correlation_tcl.cpp tcl/statistics_correlation_tcl.hpp \ - tcl/statistics_fluid_tcl.cpp tcl/statistics_fluid_tcl.hpp \ - tcl/statistics_observable_tcl.cpp tcl/statistics_observable_tcl.hpp \ - tcl/statistics_wallstuff_tcl.cpp tcl/statistics_wallstuff_tcl.hpp \ - tcl/statistics_tcl.cpp tcl/statistics_tcl.hpp \ - tcl/thermostat_tcl.cpp tcl/thermostat_tcl.hpp \ - tcl/topology_tcl.cpp \ - tcl/tuning_tcl.cpp \ - tcl/uwerr_tcl.cpp \ - tcl/virtual_sites_com_tcl.cpp tcl/virtual_sites_com_tcl.hpp \ - tcl/ghmc_tcl.cpp tcl/ghmc_tcl.hpp - -# nonbonded potentials and forces -libEspresso_a_SOURCES += \ - tcl/bmhtf-nacl_tcl.cpp tcl/bmhtf-nacl_tcl.hpp \ - tcl/buckingham_tcl.cpp tcl/buckingham_tcl.hpp \ - tcl/dpd_tcl.cpp tcl/dpd_tcl.hpp \ - tcl/forcecap_tcl.cpp tcl/forcecap_tcl.hpp \ - tcl/gaussian_tcl.cpp tcl/gaussian_tcl.hpp \ - tcl/gb_tcl.cpp tcl/gb_tcl.hpp \ - tcl/hat_tcl.cpp tcl/hat_tcl.hpp \ - tcl/hertzian_tcl.cpp tcl/hertzian_tcl.hpp \ - tcl/lj_tcl.cpp tcl/lj_tcl.hpp \ - tcl/ljangle_tcl.cpp tcl/ljangle_tcl.hpp \ - tcl/ljcos2_tcl.cpp tcl/ljcos2_tcl.hpp \ - tcl/ljcos_tcl.cpp tcl/ljcos_tcl.hpp \ - tcl/ljgen_tcl.cpp tcl/ljgen_tcl.hpp \ - tcl/morse_tcl.cpp tcl/morse_tcl.hpp \ - tcl/soft_sphere_tcl.cpp tcl/soft_sphere_tcl.hpp \ - tcl/steppot_tcl.cpp tcl/steppot_tcl.hpp \ - tcl/tab_tcl.cpp tcl/tab_tcl.hpp \ - tcl/tunable_slip_tcl.cpp tcl/tunable_slip_tcl.hpp - -# bonded potentials and forces -libEspresso_a_SOURCES += \ - tcl/angle_tcl.cpp tcl/angle_tcl.hpp \ - tcl/angle_harmonic_tcl.cpp tcl/angle_harmonic_tcl.hpp \ - tcl/angle_cosine_tcl.cpp tcl/angle_cosine_tcl.hpp \ - tcl/angle_cossquare_tcl.cpp tcl/angle_cossquare_tcl.hpp \ - tcl/angledist_tcl.cpp tcl/angledist_tcl.hpp \ - tcl/dihedral_tcl.cpp tcl/dihedral_tcl.hpp \ - tcl/endangledist_tcl.cpp tcl/endangledist_tcl.hpp \ - tcl/fene_tcl.cpp tcl/fene_tcl.hpp \ - tcl/harmonic_tcl.cpp tcl/harmonic_tcl.hpp \ - tcl/overlap_tcl.cpp tcl/overlap_tcl.hpp \ - tcl/subt_lj_tcl.cpp tcl/subt_lj_tcl.hpp \ - tcl/object-in-fluid/area_force_local_tcl.cpp \ - tcl/object-in-fluid/area_force_local_tcl.hpp \ - tcl/object-in-fluid/area_force_global_tcl.cpp \ - tcl/object-in-fluid/area_force_global_tcl.hpp \ - tcl/object-in-fluid/bending_force_tcl.cpp \ - tcl/object-in-fluid/bending_force_tcl.hpp \ - tcl/object-in-fluid/stretching_force_tcl.cpp \ - tcl/object-in-fluid/stretching_force_tcl.hpp \ - tcl/object-in-fluid/stretchlin_force_tcl.cpp \ - tcl/object-in-fluid/stretchlin_force_tcl.hpp \ - tcl/object-in-fluid/volume_force_tcl.cpp \ - tcl/object-in-fluid/volume_force_tcl.hpp - -# Coulomb methods -libEspresso_a_SOURCES += \ - tcl/debye_hueckel_tcl.cpp tcl/debye_hueckel_tcl.hpp \ - tcl/elc_tcl.cpp tcl/elc_tcl.hpp \ - tcl/magnetic_non_p3m_methods_tcl.cpp tcl/magnetic_non_p3m_methods_tcl.hpp \ - tcl/maggs_tcl.cpp tcl/maggs_tcl.hpp \ - tcl/mmm1d_tcl.cpp tcl/mmm1d_tcl.hpp \ - tcl/mmm2d_tcl.cpp tcl/mmm2d_tcl.hpp \ - tcl/p3m-dipolar_tcl.cpp tcl/p3m-dipolar_tcl.hpp \ - tcl/p3m_tcl.cpp tcl/p3m_tcl.hpp \ - tcl/reaction_field_tcl.cpp tcl/reaction_field_tcl.hpp \ - tcl/mdlc_correction_tcl.cpp tcl/mdlc_correction_tcl.hpp - +SUBDIRS += tcl endif - -if TCL - -################################################################# -# Compile the (TCL) main program -################################################################# - -# Two binaries are generated: Espresso for the build dir, -# Espresso.install for the installation dir. -# The ".install" suffix is removed upon installation. -noinst_PROGRAMS = Espresso -Espresso_CPPFLAGS = -D ESPRESSO_SCRIPTS_DEFAULT=\"$(buildscriptsdir)\" -Espresso_SOURCES = tcl/scriptsdir.cpp tcl/main.cpp -Espresso_LDADD = libEspresso.a - -bin_PROGRAMS = Espresso.install -Espresso_install_CPPFLAGS = -D ESPRESSO_SCRIPTS_DEFAULT=\"$(scriptsdir)\" -Espresso_install_SOURCES = tcl/scriptsdir.cpp tcl/main.cpp -Espresso_install_LDADD = libEspresso.a - -ESPRESSO = `echo Espresso | sed '$(transform)'`$(EXEEXT) -ESPRESSO_INSTALL = `echo Espresso.install | sed '$(transform)'`$(EXEEXT) -# rename Espresso after installation -install-exec-hook: - $(am__mv) \ - $(DESTDIR)$(bindir)/$(ESPRESSO_INSTALL) \ - $(DESTDIR)$(bindir)/$(ESPRESSO) - -uninstall-local: - -rm -f $(DESTDIR)$(bindir)/$(ESPRESSO) - +if PYTHON_INTERFACE +SUBDIRS += python/espressomd endif -################################################################# -# Handling of myconfig.hpp -################################################################# -nodist_libEspresso_a_SOURCES += myconfig-final.hpp -BUILT_SOURCES = myconfig-final.hpp -CLEANFILES = myconfig-final.hpp - -myconfig-final.hpp: FORCE - @echo -n "Determining myconfig file..." - @config_files="\ - $(top_builddir)/$(myconfig) \ - $(top_srcdir)/$(myconfig)"; \ - if test $(myconfig) = myconfig.hpp; then \ - config_files="$$config_files $(top_srcdir)/src/myconfig-default.hpp"; \ - fi; \ - for file in $$config_files; do \ - if test -e $$file; then \ - echo " $$file"; \ - myconfig_found=1; \ - if test -e $@; then \ - cmp -s $$file $@ || cp $$file $@; \ - else \ - cp $$file $@; \ - fi; \ - break; \ - fi; \ - done; \ - if test ! $$myconfig_found; then \ - echo "ERROR: Couldn't find $(myconfig) anywhere"; \ - exit 1; \ - fi - ################################################################# # Handling of the features ################################################################# -# config-features.cpp must occur at the beginning of the SOURCES so that it is compiled first -#libEspresso_a_SOURCES += config-features.cpp -EXTRA_DIST = \ - features.def \ - config-features.hpp config-features.cpp \ - config-doxygen.hpp - -if HAVE_PYTHON - -BUILT_SOURCES += config-features.hpp config-features.cpp -CLEANFILES += config-features.hpp config-features.cpp config-doxygen.hpp -config-features.hpp config-features.cpp: features.def $(top_srcdir)/config/gen_featureconfig.py - $(PYTHON) $(top_srcdir)/config/gen_featureconfig.py $(srcdir)/features.def config-features.hpp config-features.cpp - -config-doxygen.hpp: features.def $(top_srcdir)/config/gen_doxyconfig.py - $(PYTHON) $(top_srcdir)/config/gen_doxyconfig.py $(srcdir)/features.def config-doxygen.hpp - -else - -config-doxygen.hpp config-features.hpp config-features.cpp: features.def - @echo "Python was not found in your PATH." - @echo "If you change the set of features, you need Python!" - @echo "Install it and rerun configure." - -endif - -doc doxygen: config-doxygen.hpp - -################################################################# -# Handling of the version -################################################################# -libEspresso_a_SOURCES += config-version.cpp -BUILT_SOURCES += config-version.cpp -CLEANFILES += config-version.cpp -config-version.cpp: FORCE - VERSION=`cd $(top_srcdir); sh config/genversion.sh -c`; \ - if ! test -e "config-version.cpp" || \ - test "$$VERSION" != "`cat config-version.cpp`"; then \ - echo "$$VERSION" > config-version.cpp; \ - fi - -################################################################# -# Handling of the MPI fake implementation -################################################################# -if MPI_FAKE -libEspresso_a_SOURCES += mpifake/mpi.h mpifake/mpi.cpp -# mpifake should come before any system includes -AM_CPPFLAGS = -I$(srcdir)/mpifake -if TCL -Espresso_CPPFLAGS += $(AM_CPPFLAGS) -Espresso_install_CPPFLAGS += $(AM_CPPFLAGS) -endif -endif - -################################################## -# CUDA rules -################################################## -if CUDA -SUFFIXES=.cu -.cu.o: - $(NVCC) -c $(NVCCFLAGS) $(DEFAULT_INCLUDES) $(CPPFLAGS) $(INCLUDES) $(DEFS) -o $@ $< - -CUDA_SOURCES = \ - cuda_init_cuda.cu \ - cuda_common_cuda.cu \ - lbgpu_cuda.cu \ - p3m_gpu_cuda.cu - -cuda_interface.o: cuda_interface.hpp myconfig-final.hpp -cuda_init.o: cuda_init.hpp myconfig-final.hpp -lbgpu.o: lbgpu.hpp myconfig-final.hpp -p3m_gpu.o: p3m_gpu.hpp myconfig-final.hpp - -if TCL - -Espresso_SOURCES += cuda_is_cpp.cpp -Espresso_install_SOURCES += cuda_is_cpp.cpp -CUDA_SOURCES += \ - tcl/cuda_init_tcl.cpp - -endif - -libEspresso_a_SOURCES += $(CUDA_SOURCES) - -EXTRA_DIST += $(CUDA_SOURCES) -endif - -.PHONY: FORCE -FORCE: +EXTRA_DIST += features.def featuredefs.py diff --git a/src/adresso.cpp b/src/adresso.cpp deleted file mode 100644 index cb3f8c63182..00000000000 --- a/src/adresso.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file adresso.c - This is the place for adaptive resolution scheme - Implementation of adresso.h -*/ - -#include "adresso.hpp" -#include "interaction_data.hpp" -#include "communication.hpp" -#include "cells.hpp" -#include "grid.hpp" - -/** \name Privat Functions */ -/************************************************************/ -/*@{*/ -#ifdef ADRESS -/** calc weighting function of a distance - @param dist distance - @return weight of the distance -*/ -double adress_wf(double dist); - -#endif - -/*@}*/ - -double adress_vars[7] = {0, 0, 0, 0, 0, 0, 0}; - -#ifdef ADRESS - -double adress_wf_vector(double x[3]){ - int topo=(int)adress_vars[0]; - double dist; - int dim; - - - - switch (topo) { - case 0: - return 0.0; - break; - case 1: - return adress_vars[1]; - break; - case 2: - dim=(int)adress_vars[3]; - //dist=fabs(x[dim]-adress_vars[4]); - dist = x[dim]-adress_vars[4]; - if(dist>0) - while(dist>box_l[dim]/2.0) - dist = dist - box_l[dim]; - else if(dist < 0) - while(dist< -box_l[dim]/2.0) - dist = dist + box_l[dim]; - dist = fabs(dist); - return adress_wf(dist); - break; - case 3: - //int img_box[3]; - //double temp_pos[3]; - //for(dim=0;dim<3;dim++){ - // img_box[dim]=0; - // temp_pos[dim]=x[dim]; - //} - //fold_position(temp_pos,img_box); - dist=distance(x,&(adress_vars[3])); - return adress_wf(dist); - break; - default: - return 0.0; - break; - } -} - -double adress_wf(double dist){ - int wf; - double tmp; - - //explicit region - if (dist < adress_vars[1]) return 1; - //cg regime - else if (dist> adress_vars[1]+adress_vars[2]) return 0; - else { - wf=(int)adress_vars[6]; - if (wf == 0){ //cos - tmp=PI/2/adress_vars[2]*(dist-adress_vars[1]); - return cos(tmp)*cos(tmp); - } - else{ //wf == 1 - tmp=(dist-adress_vars[1]); - return 1+2*tmp*tmp-3*tmp*tmp*tmp; - } - } -} - -void adress_update_weights(){ - Particle *p; - int i, np, c; - Cell *cell; - for (c = 0; c < local_cells.n; c++) { - cell = local_cells.cell[c]; - p = cell->part; - np = cell->n; - for(i = 0; i < np; i++) { - if (ifParticleIsVirtual(&p[i])) { - p[i].p.adress_weight=adress_wf_vector((&p[i])->r.p); - //printf("LOCAL %f %f\n", p[i].r.p[0], p[i].p.adress_weight); - } - } - } - for (c = 0; c < local_cells.n; c++) { - cell = ghost_cells.cell[c]; - p = cell->part; - np = cell->n; - for(i = 0; i < np; i++) { - if (ifParticleIsVirtual(&p[i])) { - p[i].p.adress_weight=adress_wf_vector((&p[i])->r.p); - //printf("GHOST %f %f\n", p[i].r.p[0], p[i].p.adress_weight); - } - } - } -} - -#ifdef INTERFACE_CORRECTION -int adress_tab_set_params(int part_type_a, int part_type_b, char* filename) -{ - IA_parameters *data; - FILE* fp; - //int ic_points; - int npoints; - double minval,minval2, maxval, maxval2; - int i, j, newsize; - int token; - double dummr; - token = 0; - - data = get_ia_param_safe(part_type_a, part_type_b); - - if (!data) - return 1; - - if (strlen(filename) > MAXLENGTH_ADRESSTABFILE_NAME-1 ) - return 2; - - /*Open the file containing force and energy tables */ - fp = fopen( filename , "r"); - if ( !fp ) - return 3; - - /*Look for a line starting with # */ - while ( token != EOF) { - token = fgetc(fp); - if ( token == 35 ) { break; } // magic number for # symbol - } - if ( token == EOF ) { - fclose(fp); - return 4; - } - - /* First read two important parameters we read in the data later*/ - //fscanf( fp , "%d ", &ic_points); - fscanf( fp , "%d ", &npoints); - fscanf( fp, "%lf ", &minval); - fscanf( fp, "%lf ", &maxval); - - // Set the newsize to the same as old size : only changed if a new force table is being added. - newsize = adress_tab_forces.max; - - if ( data->ADRESS_TAB_npoints == 0){ - // A new potential will be added so set the number of points, the startindex and newsize - //considering that if ic_points = 0, we have two forces: ex and cg - //we keep the same for npoints - data->ADRESS_TAB_npoints = npoints; - data->ADRESS_TAB_startindex = adress_tab_forces.max; - newsize += 2*npoints; - } else { - // We have existing data for this pair of monomer types check array sizing - if ( data->ADRESS_TAB_npoints != npoints ) { - fclose(fp); - return 5; - } - } - - /* Update parameters */ - data->ADRESS_TAB_maxval = maxval; - data->ADRESS_TAB_minval = minval; - strcpy(data->ADRESS_TAB_filename,filename); - - /* Calculate dependent parameters */ - maxval2 = maxval*maxval; - minval2 = minval*minval; - data->ADRESS_TAB_stepsize = (maxval-minval)/(double)(data->ADRESS_TAB_npoints - 1); - - /* Allocate space for new data */ - realloc_doublelist(&adress_tab_forces,newsize); - realloc_doublelist(&adress_tab_energies,newsize); - - /* Read in the new force and energy table data */ - for (i =0 ; i < npoints ; i++) - { - fscanf(fp,"%lf",&dummr); - //for (j =0 ; j < ic_points + 2; j++) - for (j =0 ; j < 2; j++) - { - //j = 0 -> CG FORCE - //j = 1 -> CG_ic FORCE - - fscanf(fp,"%lf", &(adress_tab_forces.e[j*npoints+i+data->ADRESS_TAB_startindex])); - fscanf(fp,"%lf", &(adress_tab_energies.e[j*npoints+i+data->ADRESS_TAB_startindex])); - } - } - fclose(fp); - - /* broadcast interaction parameters including force and energy tables*/ - mpi_bcast_ia_params(part_type_a, part_type_b); - - //no force cap for the moment! - //if (force_cap != -1.0) { - // mpi_cap_forces(force_cap);} - return 0; -} - -#endif - -int tf_set_params(int part_type, double prefactor, char * filename) -{ - TF_parameters *data; - FILE *fp; - int npoints; - double minval, maxval; - int i, newsize; - int token = 0; - double dummr; - - make_particle_type_exist(part_type); - data = get_tf_param(part_type); - if (!data) - return 1; - - if (strlen(filename) > MAXLENGTH_TABFILE_NAME-1 ) - return 2; - - /*Open the file containing force and energy tables */ - fp = fopen( filename , "r"); - if ( !fp ) - return 3; - - /*Look for a line starting with # */ - while ( token != EOF) { - token = fgetc(fp); - if ( token == 35 ) { break; } // magic number for # symbol - } - if ( token == EOF ) { - fclose(fp); - return 4; - } - - /* First read two important parameters we read in the data later*/ - if (fscanf( fp , "%d ", &npoints) != 1 || - fscanf( fp, "%lf ", &minval) != 1 || - fscanf( fp, "%lf ", &maxval) != 1) - return 5; - // Set the newsize to the same as old size : only changed if a new force table is being added. - newsize = thermodynamic_forces.max; - if ( data->TF_TAB_npoints == 0){ - // A new potential will be added so set the number of points, the startindex and newsize - data->TF_TAB_npoints = npoints; - data->TF_TAB_startindex = thermodynamic_forces.max; - newsize += npoints; - } else { - // We have existing data for this pair of monomer type check array sizing - if ( data->TF_TAB_npoints != npoints ) { - fclose(fp); - return 5; - } - } - - /* Update parameters */ - data->TF_TAB_maxval = maxval; - data->TF_TAB_minval = minval; - strcpy(data->TF_TAB_filename, filename); - data->TF_prefactor = prefactor; - - data->TF_TAB_stepsize = (maxval-minval)/(double)(data->TF_TAB_npoints - 1); - - /* Allocate space for new data */ - realloc_doublelist(&thermodynamic_forces, newsize); - realloc_doublelist(&thermodynamic_f_energies, newsize); - - /* Read in the new force and energy table data */ - for (i = 0 ; i < npoints ; i++){ - if (fscanf(fp, "%lf", &dummr) != 1 || - fscanf(fp, "%lf", &(thermodynamic_forces.e[i+data->TF_TAB_startindex])) != 1 || - fscanf(fp, "%lf", &(thermodynamic_f_energies.e[i+data->TF_TAB_startindex])) != 1) - return 5; - if(i==0 && dummr !=0) { - fprintf(stderr, "First point of the thermodynamic force has to be zero.\n"); - errexit(); - } - else if (i== npoints-1 && dummr != 1){ - fprintf(stderr, "Last point of the thermodynamic force has to be one.\n"); - errexit(); - } - } - - fclose(fp); - - /* broadcast interaction parameters including force and energy tables */ - mpi_bcast_tf_params(part_type); - - return ES_OK; -} - -#endif diff --git a/src/adresso.hpp b/src/adresso.hpp deleted file mode 100644 index 3885b966593..00000000000 --- a/src/adresso.hpp +++ /dev/null @@ -1,444 +0,0 @@ -/* - Copyright (C) 2010,2012,2013 The ESPResSo project - Copyright (C) 2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef _ADRESSO_H -#define _ADRESSO_H -/** \file adresso.h - This is the place for adaptive resolution scheme (adress) - Implementation of adresso.h - - For more details about adress see: - - M. Praprotnik, L. Delle Site and K. Kremer, JCP 123, 224106, 2005. - - M. Praprotnik, L. Delle Site and K. Kremer, Annu. Rev. Phys. Chem. 59, 545-571, 2008. - - S. Poblete, M. Praprotnik, K. Kremer and L. Delle Site, J. Chem. Phys. 132, 114101, 2010. - - For more detail about the implementation here see: - - C. Junghans and S. Poblete, Comp. Phys. Comm. 181, 1449, 2010. -*/ - -#include "particle_data.hpp" -#include "interaction_data.hpp" -#include "virtual_sites.hpp" -#include "grid.hpp" - -/** \name Exported Variables */ -/************************************************************/ -/*@{*/ -extern double adress_vars[7]; -/*@}*/ - -/** \name Exported Functions */ -/************************************************************/ -/*@{*/ -/** Implements the Tcl command "adress". This allows for seetings for adress -*/ - -#ifdef ADRESS - -/** Calc adress weight function of a vector - @param x input vector - @return weight of the vector -*/ -double adress_wf_vector(double x[3]); - -/** Calc adress weight function of a particle - @param p input particle - @return weight of the particle -*/ -inline double adress_wf_particle(Particle *p){ - if (p==NULL) return 0.0; - if (ifParticleIsVirtual(p)){ - return p->p.adress_weight; - } - else{ - return adress_wf_particle(get_mol_com_particle(p)); - } -} - -/** Update adress weight of all particles -*/ -void adress_update_weights(); - -inline double adress_non_bonded_force_weight(Particle *p1,Particle *p2){ - double adress_weight_1,adress_weight_2,force_weight; - int virtual_1,virtual_2; - - //NOTE this is in order of probability to appear - adress_weight_1=adress_wf_particle(p1); - virtual_1=ifParticleIsVirtual(p1); - - //if particles 1 is ex, but in the cg regime - if ( (adress_weight_11-ROUND_ERROR_PREC) return 0.0; - force_weight=1-force_weight; - - } - //both are ex -> force_weight is already set - //if ((virtual_1+virtual_2)==0) force_weight=force_weight; - //(ifParticleIsVirtual(p1) ==0 || ifParticleIsVirtual(p2) ==0) - // printf(" particle %d %d virtual %d %d weights %f %f product %f\n", p1->p.identity, p2->p.identity, ifParticleIsVirtual(p1), ifParticleIsVirtual(p2), adress_weight_1, adress_weight_2, force_weight); - return force_weight; -} - -inline double adress_bonded_force_weight(Particle *p1,Particle *p2){ - double weight=1.0; - if((get_mol_com_particle(p1))->p.identity == (get_mol_com_particle(p2))->p.identity ) - weight=1.0; - else { - double weight_1, weight_2; - int virtual_1, virtual_2, n_part_int=2; - weight_1=adress_wf_particle(p1); - virtual_1=ifParticleIsVirtual(p1); - if( (weight_10 && sum_virtualp.identity == (get_mol_com_particle(p2))->p.identity &&(get_mol_com_particle(p1))->p.identity == (get_mol_com_particle(p3))->p.identity ) - weight=1.0; - else { - double weight_1, weight_2, weight_3; - int virtual_1, virtual_2, virtual_3, n_part_int=3; - weight_1=adress_wf_particle(p1); - virtual_1=ifParticleIsVirtual(p1); - if( (weight_10 && sum_virtualp.identity == (get_mol_com_particle(p2))->p.identity &&(get_mol_com_particle(p1))->p.identity == (get_mol_com_particle(p3))->p.identity && (get_mol_com_particle(p1))->p.identity == (get_mol_com_particle(p4))->p.identity) - weight=1.0; - else { - double weight_1, weight_2, weight_3, weight_4; - int virtual_1, virtual_2, virtual_3, virtual_4, n_part_int=4; - weight_1=adress_wf_particle(p1); - virtual_1=ifParticleIsVirtual(p1); - if( (weight_10 && sum_virtualADRESS_TAB_npoints; - double phi, dindex, fac; - double maxval = ia_params->ADRESS_TAB_maxval; - double minval = ia_params->ADRESS_TAB_minval; - //int ic_points = ia_params->ADRESS_IC_npoints; - //int max_index = 1; - - fac = 0.0; - - //if(index == max_index) - //return; - if ( maxval > 0 ) { - if ( dist < maxval){ - table_start = ia_params->ADRESS_TAB_startindex; - dindex = (dist-minval)/ia_params->ADRESS_TAB_stepsize; - tablepos = (int)(floor(dindex)); - - if ( dist > minval ) { - phi = dindex - tablepos; - fac = adress_tab_forces.e[inter_index + table_start + tablepos]*(1-phi) + adress_tab_forces.e[inter_index + table_start + tablepos+1]*phi; - } - else { - /* Use an extrapolation beyond the table */ - if ( dist > 0 ) { - tablepos = 0; - phi = dindex - tablepos; - fac = (adress_tab_forces.e[inter_index + table_start]*minval)*(1-phi) + - (adress_tab_forces.e[inter_index + table_start+1]*(minval+ia_params->ADRESS_TAB_stepsize))*phi; - fac = fac/dist; - } - else { /* Particles on top of each other .. leave fac as 0.0 */ - } - } - - } - for(j=0;j<3;j++) - force[j] += fac * d[j]; - } - - -} - -inline double correction_function(double x){ - /* correction function goes between zero and one */ - double ic_s; - ic_s = 4.0*(sqrt(x)-0.5)*(sqrt(x)-0.5); - return ic_s; -} - -/// -int adress_tab_set_params(int part_type_a, int part_type_b, char* filename); - -/** Adds force in an Adress way. Also useful for virial calculations */ -inline void add_adress_tab_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_params, - double d[3], double dist, double force[3]) -{ - int j; - //int ic_points = ia_params->ADRESS_IC_npoints; - //int max_index = 1; - - double left_force[3] = {0,0,0}; - double right_force[3] = {0,0,0}; - //double ex_force[3] = {0,0,0}; - double cg_force[3] = {0,0,0}; - //int left_index, right_index; - - //ASK FOR THE WEIGHTING FUNCTIONS!!! - double x = p1->p.adress_weight*p2->p.adress_weight; - //double x = local_particles[p1->p.identity]->p.adress_weight*local_particles[p2->p.identity]->p.adress_weight; - - //NO EXPLICIT CASE!!! - //EXPLICIT CASE - just for non-virtual particles - if(x == 1){ - //adress_interpolation(ia_params, d, dist, force,ic_points+1); - return; - } - //COARSE-GRAINED CASE - else if(x == 0){ - adress_interpolation(ia_params, d, dist, cg_force, 0); - for(j=0;j<3;j++){ - force[j] += cg_force[j]; - } - //if (sqrt(cg_force[0]*cg_force[0]+cg_force[1]*cg_force[1]+cg_force[2]*cg_force[2])!=0) - //printf("%f %f\n", dist, sqrt(cg_force[0]*cg_force[0]+cg_force[1]*cg_force[1]+cg_force[2]*cg_force[2])); - return; - } - //INTERFACE PRESSURE CORRECTION: we restrict ourselves to the switching region - else { - //THE EXPLICIT CONTRIBUTION - just if particles are not virtual - //adress_interpolation(ia_params, d, dist, ex_force, ic_points+1); - //for(j=0;j<3;j++) - // force[j] += x*ex_force[j]; - - //THE COARSE-GRAINED CONTRIBUTION - //classify the position of the particle: - //if(ic_points !=0) { - //double ic_step = 1.0/((double)ic_points + 1.0); - // double w = 0; - // while(x > w+ic_step){ - //left_index++; - //w = w+ic_step; - //} - //right_index = left_index+1; - - //if(right_index < max_index){ - adress_interpolation(ia_params,d,dist,left_force, 0); - adress_interpolation(ia_params,d,dist,right_force, 1); - - for(j=0;j<3;j++) - cg_force[j] = correction_function(x)*left_force[j] + (1.0 - correction_function(x))*right_force[j]; - //} else { - //adress_interpolation(ia_params,d,dist,cg_force,left_index); - //} - - for(j=0;j<3;j++){ - force[j] += cg_force[j]; - } - return; - } - -} -#endif - -/* #ifdef THERMODYNAMIC_FORCE */ - -inline double inverse_weight(double w){ - if(adress_vars[0] == 2) { - return 2/M_PI*asin(sqrt(w)); - } else { - fprintf(stderr, "Thermodynamic force not implemented for this topology.\n"); - errexit(); - } - return 0; -} - -inline double adress_dw_dir(double pos[3], double dir[3]){ - int topo=(int)adress_vars[0]; - double dist, mod=0; - int i, dim; - - for(i=0;i<3;i++) - dir[i]=0.0; - - switch (topo) { - case 0: - return 0.0; - break; - case 1: - return 0.0; - break; - case 2: - dim=(int)adress_vars[3]; - //dist=fabs(x[dim]-adress_vars[4]); - dist = pos[dim]-adress_vars[4]; - if(dist>0) - while(dist>box_l[dim]/2.0) - dist = dist - box_l[dim]; - else if(dist < 0) - while(dist< -box_l[dim]/2.0) - dist = dist + box_l[dim]; - dir[dim]=1; - if(dist>0) - return -1; - else return 1; - - break; - case 3: - /* NOT TESTED */ - dist=distance(pos,&(adress_vars[3])); - for(i=0;i<3;i++) - mod += (pos[i]-adress_vars[3+i])*(pos[i]-adress_vars[3+i]); - if(mod == 0){ - fprintf(stderr,"Particle located at the center of the box: Thermodynamic force not defined.\n"); - errexit(); - } - for(i=0;i<3;i++) - dir[i]=(pos[i]-adress_vars[3+i])/mod; - if(dist < adress_vars[1]+adress_vars[2]) - return -1; - else return 1; - break; - default: - return 0.0; - break; - } -} - -/// -int tf_set_params(int part_type, double prefactor, char * filename); - -inline double tf_profile(double x_com, int type, TF_parameters * tf_params){ - double phi, dindex, force, pol; - int tablepos, table_start; - //double maxval = tf_params->TF_TAB_maxval; - double minval = tf_params->TF_TAB_minval; - - //if(weight == 0 || weight == 1) - //force = 0.0; - //else { - table_start = tf_params->TF_TAB_startindex; - dindex = (x_com-minval)/tf_params->TF_TAB_stepsize; - tablepos = (int)(floor(dindex)); - phi = dindex - tablepos; - pol = thermodynamic_forces.e[table_start + tablepos]*(1-phi) + thermodynamic_forces.e[table_start + tablepos+1]*phi; - - /* THERE IS NO EXTRAPOLATION! - the table has to start and end ALWAYS at zero and one respectively - */ - force = pol; - //} - - return force; -} - -inline void add_thermodynamic_force(Particle * p){ - TF_parameters *tf_params = get_tf_param(p->p.type); - double pref = tf_params->TF_prefactor; - if (pref !=0){ - double weight, width, force, sign; - int i, type; - double dir[3] = {0,0,0}; - - weight = p->p.adress_weight; - if(weight>0 && weight < 1){ - type = p->p.type; - width = adress_vars[2]; - sign = adress_dw_dir(p->r.p, dir); - - - force = pref*sign*tf_profile(inverse_weight(weight), type, tf_params)/width; - - for(i=0;i<3;i++) - p->f.f[i] += force*dir[i]; - } - } -} - -/* #endif */ - -#endif -/*@}*/ -#endif diff --git a/src/core/EspressoSystemInterface.cpp b/src/core/EspressoSystemInterface.cpp new file mode 100644 index 00000000000..917bf48d09f --- /dev/null +++ b/src/core/EspressoSystemInterface.cpp @@ -0,0 +1,158 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "EspressoSystemInterface.hpp" +#include "cells.hpp" +#include "particle_data.hpp" +#include "grid.hpp" +#include "cuda_interface.hpp" + +#include + +/* Need explicite specialization, otherwise some compilers do not produce the objects. */ + +template class EspressoSystemInterface::const_iterator; +template class EspressoSystemInterface::const_iterator; +template class EspressoSystemInterface::const_iterator; + +/********************************************************************************************/ + +template +value_type EspressoSystemInterface::const_iterator::operator*() const { + return (*m_const_iterator); +} + +template +SystemInterface::const_iterator &EspressoSystemInterface::const_iterator::operator=(const SystemInterface::const_iterator &rhs) { + m_const_iterator = static_cast &>(rhs).m_const_iterator; + return *this; +} + +template +EspressoSystemInterface::const_iterator &EspressoSystemInterface::const_iterator::operator=(typename std::vector::const_iterator rhs) { + m_const_iterator = rhs; + return *this; +} + +template +bool EspressoSystemInterface::const_iterator::operator==(SystemInterface::const_iterator const &rhs) const { + return (m_const_iterator == static_cast &>(rhs).m_const_iterator); +} + +template +bool EspressoSystemInterface::const_iterator::operator!=(SystemInterface::const_iterator const &rhs) const { + return (m_const_iterator != static_cast &>(rhs).m_const_iterator); +} + +template +SystemInterface::const_iterator &EspressoSystemInterface::const_iterator::operator++() { + ++m_const_iterator; + return *this; +} + +/********************************************************************************************/ + +void EspressoSystemInterface::gatherParticles() { + Cell *cell; + Particle *p; + int i,c,np; + + // get particles from other nodes +#ifdef CUDA + if (m_gpu) + { + if(gpu_get_global_particle_vars_pointer_host()->communication_enabled) { + ESIF_TRACE(puts("Calling copy_part_data_to_gpu()")); + copy_part_data_to_gpu(); + reallocDeviceMemory(gpu_get_global_particle_vars_pointer_host()->number_of_particles); + if(m_splitParticleStructGpu && (this_node == 0)) + split_particle_struct(); + } + } +#endif + + if (needsQ() || needsR()) { + R.clear(); + #ifdef ELECTROSTATICS + Q.clear(); + #endif + + for (c = 0; c < local_cells.n; c++) { + cell = local_cells.cell[c]; + p = cell->part; + np = cell->n; + if(needsR()) + R.reserve(R.size()+np); +#ifdef ELECTROSTATICS + if(needsQ()) + Q.reserve(Q.size()+np); +#endif + for(i = 0; i < np; i++) { + if(needsR()) + R.push_back(Vector3(p[i].r.p)); +#ifdef ELECTROSTATICS + if(needsQ()) + Q.push_back(p[i].p.q); +#endif + } + } + } +} + +void EspressoSystemInterface::init() { + gatherParticles(); +} + +void EspressoSystemInterface::update() { + gatherParticles(); +} + +SystemInterface::const_vec_iterator &EspressoSystemInterface::rBegin() { + m_r_begin = R.begin(); + return m_r_begin; +} + +const SystemInterface::const_vec_iterator &EspressoSystemInterface::rEnd() { + m_r_end = R.end(); + return m_r_end; +} + +#ifdef ELECTROSTATICS +SystemInterface::const_real_iterator &EspressoSystemInterface::qBegin() { + m_q_begin = Q.begin(); + return m_q_begin; +} + +const SystemInterface::const_real_iterator &EspressoSystemInterface::qEnd() { + m_q_end = Q.end(); + return m_q_end; +} + +#endif + +unsigned int EspressoSystemInterface::npart() { + return m_npart; +} + +SystemInterface::Vector3 EspressoSystemInterface::box() { + return Vector3(box_l); +} + + + +EspressoSystemInterface espressoSystemInterface; diff --git a/src/core/EspressoSystemInterface.hpp b/src/core/EspressoSystemInterface.hpp new file mode 100644 index 00000000000..c62d59d3265 --- /dev/null +++ b/src/core/EspressoSystemInterface.hpp @@ -0,0 +1,183 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef ESPRESSOSYSTEMINTERFACE_H +#define ESPRESSOSYSTEMINTERFACE_H + +#define ESIF_TRACE(A) + +#include "SystemInterface.hpp" +#include "cuda_interface.hpp" + +class EspressoSystemInterface : public SystemInterface { +public: + EspressoSystemInterface() : m_gpu_npart(0), m_gpu(false), m_r_gpu_begin(0), m_r_gpu_end(0), m_v_gpu_begin(0), m_v_gpu_end(0), m_q_gpu_begin(0), m_q_gpu_end(0), m_needsParticleStructGpu(false), m_splitParticleStructGpu(false) {}; + virtual ~EspressoSystemInterface() {} + + void init(); + void update(); + + SystemInterface::Vector3 box(); + unsigned int npart(); + + typedef std::vector Vector3Container; + typedef std::vector RealContainer; + + template + class const_iterator : public SystemInterface::const_iterator { + public: + value_type operator*() const; + SystemInterface::const_iterator &operator=(const SystemInterface::const_iterator &rhs); + EspressoSystemInterface::const_iterator &operator=(typename std::vector::const_iterator rhs); + bool operator==(SystemInterface::const_iterator const &rhs) const; + bool operator!=(SystemInterface::const_iterator const &rhs) const; + SystemInterface::const_iterator &operator++(); + private: + typename std::vector::const_iterator m_const_iterator; + }; + + typedef const_iterator const_real_iterator; + typedef const_iterator const_vec_iterator; + typedef const_iterator const_int_iterator; + + + SystemInterface::const_vec_iterator &rBegin(); + const SystemInterface::const_vec_iterator &rEnd(); + bool hasR() { return true; }; + +#ifdef ELECTROSTATICS + SystemInterface::const_real_iterator &qBegin(); + const SystemInterface::const_real_iterator &qEnd(); + bool hasQ() { return true; }; +#endif + +#ifdef CUDA + float *rGpuBegin() { return m_r_gpu_begin; }; + float *rGpuEnd() { return m_r_gpu_end; }; + bool hasRGpu() { return true; }; + bool requestRGpu() { + m_needsRGpu = hasRGpu(); + m_splitParticleStructGpu |= m_needsRGpu; + m_gpu |= m_needsRGpu; + if(m_gpu) + enableParticleCommunication(); + return m_needsRGpu; + }; + + float *vGpuBegin() { return m_v_gpu_begin; }; + float *vGpuEnd() { return m_v_gpu_end; }; + bool hasVGpu() { return true; }; + bool requestVGpu() { + m_needsVGpu = hasVGpu(); + m_splitParticleStructGpu |= m_needsVGpu; + m_gpu |= m_needsVGpu; + if(m_gpu) + enableParticleCommunication(); + return m_needsVGpu; + }; + + float *qGpuBegin() { return m_q_gpu_begin; }; + float *qGpuEnd() { return m_q_gpu_end; }; + bool hasQGpu() { return true; }; + bool requestQGpu() { + m_needsQGpu = hasQGpu(); + m_splitParticleStructGpu |= m_needsQGpu; + m_gpu |= m_needsQGpu; + if(m_gpu) + enableParticleCommunication(); + return m_needsQGpu; + }; + + bool requestParticleStructGpu() { + m_needsParticleStructGpu = true; + m_gpu |= m_needsParticleStructGpu; + if(m_gpu) + enableParticleCommunication(); + return true; + } + + float *fGpuBegin() { return (float *)gpu_get_particle_force_pointer(); }; + float *fGpuEnd() { return (float *)(gpu_get_particle_force_pointer()) + 3*m_gpu_npart; }; + float *eGpu() { return (float *)gpu_get_energy_pointer(); }; + bool hasFGpu() { return true; }; + bool requestFGpu() { + m_needsFGpu = hasFGpu(); + m_gpu |= m_needsFGpu; + if(m_gpu) + enableParticleCommunication(); + return m_needsFGpu; + }; +#endif + + unsigned int npart_gpu() { +#ifdef CUDA + return m_gpu_npart; +#else + return 0; +#endif + }; + +protected: + void gatherParticles(); + void split_particle_struct(); +#ifdef CUDA + void enableParticleCommunication() { + if(!gpu_get_global_particle_vars_pointer_host()->communication_enabled) { + ESIF_TRACE(puts("gpu communication not enabled;")); + ESIF_TRACE(puts("enableParticleCommunication")); + gpu_init_particle_comm(); + cuda_bcast_global_part_params(); + reallocDeviceMemory(gpu_get_global_particle_vars_pointer_host()->number_of_particles); + } + }; + void reallocDeviceMemory(int n); +#endif + + Vector3Container R; + #ifdef ELECTROSTATICS + RealContainer Q; + #endif + + const_vec_iterator m_r_begin; + const_vec_iterator m_r_end; + + const_real_iterator m_q_begin; + const_real_iterator m_q_end; + + int m_gpu_npart; + bool m_gpu; + + float *m_r_gpu_begin; + float *m_r_gpu_end; + + float *m_v_gpu_begin; + float *m_v_gpu_end; + + float *m_q_gpu_begin; + float *m_q_gpu_end; + + unsigned int m_npart; + Vector3 m_box; + + bool m_needsParticleStructGpu; + bool m_splitParticleStructGpu; +}; + +extern EspressoSystemInterface espressoSystemInterface; + +#endif diff --git a/src/core/EspressoSystemInterface_cuda.cu b/src/core/EspressoSystemInterface_cuda.cu new file mode 100644 index 00000000000..b2a0cc87def --- /dev/null +++ b/src/core/EspressoSystemInterface_cuda.cu @@ -0,0 +1,123 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "EspressoSystemInterface.hpp" +#include "cuda_interface.hpp" +#include "cuda_utils.hpp" + +__global__ void split_kernel_rq(CUDA_particle_data *particles, float *r, float *q, int n) { + int idx = blockDim.x*blockIdx.x + threadIdx.x; + if(idx >= n) + return; + + CUDA_particle_data p = particles[idx]; + + r[3*idx + 0] = p.p[0]; + r[3*idx + 1] = p.p[1]; + r[3*idx + 2] = p.p[2]; + #ifdef ELECTROSTATICS + q[idx] = p.q; + #endif +} + +__global__ void split_kernel_q(CUDA_particle_data *particles,float *q, int n) { + int idx = blockDim.x*blockIdx.x + threadIdx.x; + if(idx >= n) + return; + +#ifdef ELECTROSTRATICS + CUDA_particle_data p = particles[idx]; + + q[idx] = p.q; +#endif +} + +__global__ void split_kernel_r(CUDA_particle_data *particles, float *r, int n) { + int idx = blockDim.x*blockIdx.x + threadIdx.x; + if(idx >= n) + return; + + CUDA_particle_data p = particles[idx]; + + idx *= 3; + + r[idx + 0] = p.p[0]; + r[idx + 1] = p.p[1]; + r[idx + 2] = p.p[2]; +} + +__global__ void split_kernel_v(CUDA_particle_data *particles, float *v, int n) { + int idx = blockDim.x*blockIdx.x + threadIdx.x; + if(idx >= n) + return; + + CUDA_particle_data p = particles[idx]; + + idx *= 3; + + v[idx + 0] = p.v[0]; + v[idx + 1] = p.v[1]; + v[idx + 2] = p.v[2]; +} + +void EspressoSystemInterface::reallocDeviceMemory(int n) { + + if(m_needsRGpu && ((n != m_gpu_npart) || (m_r_gpu_begin == 0))) { + if(m_r_gpu_begin != 0) + cuda_safe_mem(cudaFree(m_r_gpu_begin)); + cuda_safe_mem(cudaMalloc(&m_r_gpu_begin, 3*n*sizeof(float))); + m_r_gpu_end = m_r_gpu_begin + 3*n; + } + + if(m_needsVGpu && ((n != m_gpu_npart) || (m_v_gpu_begin == 0))) { + if(m_v_gpu_begin != 0) + cuda_safe_mem(cudaFree(m_v_gpu_begin)); + cuda_safe_mem(cudaMalloc(&m_v_gpu_begin, 3*n*sizeof(float))); + m_v_gpu_end = m_v_gpu_begin + 3*n; + } + + if(m_needsQGpu && ((n != m_gpu_npart) || (m_q_gpu_begin == 0))) { + if(m_q_gpu_begin != 0) + cuda_safe_mem(cudaFree(m_q_gpu_begin)); + cuda_safe_mem(cudaMalloc(&m_q_gpu_begin, 3*n*sizeof(float))); + m_q_gpu_end = m_q_gpu_begin + 3*n; + } + + m_gpu_npart = n; +} + +void EspressoSystemInterface::split_particle_struct() { + int n = gpu_get_global_particle_vars_pointer_host()->number_of_particles; + if(n == 0) + return; + + ESIF_TRACE(printf("n = %d, m_gpu_npart = %d\n", n, m_gpu_npart)); + + dim3 grid(n/512+1,1,1); + dim3 block(512,1,1); + + if(m_needsQGpu && m_needsRGpu) + split_kernel_rq<<>>(gpu_get_particle_pointer(), m_r_gpu_begin,m_q_gpu_begin,n); + if(m_needsQGpu && !m_needsRGpu) + split_kernel_q<<>>(gpu_get_particle_pointer(), m_q_gpu_begin,n); + if(!m_needsQGpu && m_needsRGpu) + split_kernel_r<<>>(gpu_get_particle_pointer(), m_r_gpu_begin,n); + if(m_needsVGpu) + split_kernel_v<<>>(gpu_get_particle_pointer(), m_v_gpu_begin,n); +} diff --git a/src/core/Makefile.am b/src/core/Makefile.am new file mode 100644 index 00000000000..20cb936e9ab --- /dev/null +++ b/src/core/Makefile.am @@ -0,0 +1,329 @@ +# Copyright (C) 2012,2013,2014 The ESPResSo project +# Copyright (C) 2007,2008,2009,2010,2011 Olaf Lenz, Axel Arnold +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +EXTRA_DIST = +CLEANFILES = + +AM_DEFAULT_SOURCE_EXT = .cpp + +noinst_LTLIBRARIES = libEspresso.la +# List the sources of the Espresso binary here +# config-features.cpp must be at the beginning so that it is compiled first +libEspresso_la_SOURCES = \ + config-features.cpp \ + cells.cpp cells.hpp \ + collision.cpp collision.hpp \ + communication.cpp communication.hpp \ + comfixed.cpp comfixed.hpp \ + comforce.hpp comforce.cpp \ + config.hpp \ + constraint.cpp constraint.hpp \ + cuda_interface.cpp cuda_interface.hpp\ + cuda_init.hpp \ + debug.cpp debug.hpp \ + domain_decomposition.cpp domain_decomposition.hpp \ + electrokinetics_pdb_parse.cpp electrokinetics_pdb_parse.hpp \ + energy.cpp energy_inline.hpp energy.hpp \ + external_potential.hpp external_potential.cpp \ + errorhandling.cpp errorhandling.hpp \ + fft.cpp fft.hpp \ + fft-common.cpp fft-common.hpp \ + fft-dipolar.cpp fft-dipolar.hpp \ + forcecap.cpp forcecap.hpp \ + forces.cpp forces_inline.hpp forces.hpp \ + galilei.cpp galilei.hpp \ + ghosts.cpp ghosts.hpp \ + global.cpp global.hpp \ + grid.cpp grid.hpp \ + halo.cpp halo.hpp \ + iccp3m.cpp iccp3m.hpp \ + imd.cpp imd.hpp \ + initialize.cpp initialize.hpp \ + integrate.cpp integrate.hpp \ + interaction_data.cpp interaction_data.hpp \ + lattice.cpp lattice_inline.hpp lattice.hpp \ + layered.cpp layered.hpp \ + lb.cpp lb.hpp \ + lb-boundaries.cpp lb-boundaries.hpp \ + lb-d3q18.hpp lb-d3q19.hpp \ + lbgpu.cpp lbgpu.hpp\ + lees_edwards.cpp lees_edwards.hpp \ + lees_edwards_domain_decomposition.cpp lees_edwards_domain_decomposition.hpp \ + lees_edwards_comms_manager.cpp lees_edwards_comms_manager.hpp \ + metadynamics.cpp metadynamics.hpp \ + modes.cpp modes.hpp \ + molforces.cpp molforces.hpp \ + mol_cut.cpp mol_cut.hpp \ + nemd.cpp nemd.hpp \ + npt.hpp \ + nsquare.cpp nsquare.hpp \ + particle_data.cpp particle_data.hpp \ + polymer.cpp polymer.hpp \ + polynom.hpp \ + pressure.cpp pressure.hpp \ + random.cpp random.hpp \ + rattle.cpp rattle.hpp \ + reaction.cpp reaction.hpp \ + Ringbuffer.hpp \ + rotation.cpp rotation.hpp \ + RuntimeErrorCollector.cpp RuntimeErrorCollector.hpp \ + specfunc.cpp specfunc.hpp \ + statistics.cpp statistics.hpp \ + statistics_chain.cpp statistics_chain.hpp \ + statistics_cluster.cpp statistics_cluster.hpp \ + statistics_correlation.cpp statistics_correlation.hpp \ + statistics_fluid.cpp statistics_fluid.hpp \ + statistics_molecule.cpp statistics_molecule.hpp \ + statistics_observable.cpp statistics_observable.hpp \ + statistics_wallstuff.cpp statistics_wallstuff.hpp \ + thermostat.cpp thermostat.hpp \ + topology.cpp topology.hpp \ + tuning.cpp tuning.hpp \ + utils.hpp \ + uwerr.cpp uwerr.hpp \ + verlet.cpp verlet.hpp \ + virtual_sites.cpp virtual_sites.hpp \ + virtual_sites_com.cpp virtual_sites_com.hpp \ + virtual_sites_relative.cpp virtual_sites_relative.hpp \ + vmdsock.cpp vmdsock.hpp \ + ghmc.cpp ghmc.hpp \ + Vector.hpp \ + SystemInterface.hpp \ + EspressoSystemInterface.hpp EspressoSystemInterface.cpp + +# nonbonded potentials and forces +libEspresso_la_SOURCES += \ + bmhtf-nacl.cpp bmhtf-nacl.hpp \ + buckingham.cpp buckingham.hpp \ + dpd.cpp dpd.hpp \ + gaussian.cpp gaussian.hpp \ + gb.cpp gb.hpp \ + hat.cpp hat.hpp \ + hertzian.cpp hertzian.hpp \ + lj.cpp lj.hpp \ + ljangle.cpp ljangle.hpp \ + ljcos.cpp ljcos.hpp \ + ljcos2.cpp ljcos2.hpp \ + ljgen.cpp ljgen.hpp \ + morse.cpp morse.hpp \ + soft_sphere.cpp soft_sphere.hpp \ + steppot.cpp steppot.hpp \ + tab.cpp tab.hpp \ + tunable_slip.cpp tunable_slip.hpp + +# bonded potentials and forces +libEspresso_la_SOURCES += \ + angle.cpp angle.hpp \ + angle_harmonic.cpp angle_harmonic.hpp \ + angle_cosine.cpp angle_cosine.hpp \ + angle_cossquare.cpp angle_cossquare.hpp \ + angledist.cpp angledist.hpp \ + dihedral.cpp dihedral.hpp \ + endangledist.cpp endangledist.hpp \ + fene.cpp fene.hpp \ + harmonic.cpp harmonic.hpp \ + quartic.cpp quartic.hpp \ + overlap.cpp overlap.hpp \ + bonded_coulomb.cpp bonded_coulomb.hpp \ + subt_lj.cpp subt_lj.hpp \ + object-in-fluid/area_force_local.cpp object-in-fluid/area_force_local.hpp \ + object-in-fluid/area_force_global.cpp object-in-fluid/area_force_global.hpp \ + object-in-fluid/bending_force.cpp object-in-fluid/bending_force.hpp \ + object-in-fluid/stretching_force.cpp object-in-fluid/stretching_force.hpp \ + object-in-fluid/stretchlin_force.cpp object-in-fluid/stretchlin_force.hpp \ + object-in-fluid/volume_force.cpp object-in-fluid/volume_force.hpp + +# Coulomb methods +libEspresso_la_SOURCES += \ + debye_hueckel.cpp debye_hueckel.hpp \ + elc.cpp elc.hpp \ + magnetic_non_p3m_methods.cpp magnetic_non_p3m_methods.hpp \ + mdlc_correction.cpp mdlc_correction.hpp \ + maggs.cpp maggs.hpp \ + mmm1d.cpp mmm1d.hpp \ + mmm2d.cpp mmm2d.hpp \ + mmm-common.cpp mmm-common.hpp \ + p3m.cpp p3m.hpp \ + p3m-common.cpp p3m-common.hpp \ + p3m-dipolar.cpp p3m-dipolar.hpp \ + reaction_field.cpp reaction_field.hpp + +# Generic actors +libEspresso_la_SOURCES += \ + actor/Actor.hpp \ + actor/ActorList.cpp actor/ActorList.hpp \ + actor/HarmonicWell.cpp actor/HarmonicWell.hpp \ + actor/Mmm1dgpuForce.cpp actor/Mmm1dgpuForce.hpp \ + actor/EwaldgpuForce.cpp actor/EwaldgpuForce.hpp actor/EwaldgpuForce_ShortRange.hpp \ + actor/mmm-common_cuda.hpp actor/specfunc_cuda.hpp + +################################################## +# CUDA rules +################################################## +if CUDA + +SUFFIXES=.cu + +CUDA_HEADER_FILES = \ + cuda_utils.hpp \ + cuda_interface.hpp \ + p3m_gpu.hpp \ + cuda_init.hpp \ + actor/mmm-common_cuda.hpp actor/specfunc_cuda.hpp \ + electrokinetics.hpp + +CUDA_SOURCE_FILES = \ + cuda_init_cuda.cu \ + cuda_common_cuda.cu \ + electrokinetics_cuda.cu \ + lbgpu_cuda.cu \ + p3m_gpu_cuda.cu \ + EspressoSystemInterface_cuda.cu \ + actor/Mmm1dgpuForce_cuda.cu \ + actor/EwaldgpuForce_cuda.cu \ + actor/HarmonicWell_cuda.cu + +# include the dependency tracking files +include ./$(DEPDIR)/cuda_init_cuda.Plo +include ./$(DEPDIR)/cuda_common_cuda.Plo +include ./$(DEPDIR)/electrokinetics_cuda.Plo +include ./$(DEPDIR)/libgpu_cuda.Plo +include ./$(DEPDIR)/p3m_gpu_cuda.Plo +include ./$(DEPDIR)/EspressoSystemInterface_cuda.Plo +include ./actor/$(DEPDIR)/HarmonicWell_cuda.Plo +include ./actor/$(DEPDIR)/Mmm1dgpuForce.Plo +include ./actor/$(DEPDIR)/Mmm1dgpuForce_cuda.Plo +include ./actor/$(DEPDIR)/EwaldgpuForce.Plo +include ./actor/$(DEPDIR)/EwaldgpuForce_cuda.Plo + +LOFILES = $(CUDA_SOURCE_FILES:.cu=.lo) + +cuda_verbose = $(cuda_verbose_@AM_V@) +cuda_verbose_ = $(cuda_verbose_@AM_DEFAULT_V@) +cuda_verbose_0 = @echo " NVCC $@"; + +# nvcc does not allow for option MF for dependency generation, +# therefore make a separate run to generate dependencies +# putting them into DEPDIR ensures configure creates empties dummies +$(LOFILES): %.lo: %.cu + $(cuda_verbose)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ + $(NVCC) $(NVCCFLAGS) $(DEFAULT_INCLUDES) $(CPPFLAGS) $(INCLUDES) $(DEFS) \ + -M -MT $@ -o $$depbase.Plo $<; \ + $(LIBTOOL) $(AM_V_lt) --tag=CUDA $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(NVCC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_NVCCFLAGS) $(NVCCFLAGS) -c -o $@ $< + +libEspresso_la_LIBADD = $(LOFILES) +EXTRA_DIST += $(CUDA_SOURCE_FILES) $(CUDA_HEADER_FILES) +CLEANFILES += $(LOFILES) + +endif + + +################################################################# +# Handling of myconfig.hpp +################################################################# +noinst_HEADERS = myconfig-default.hpp +CLEANFILES += myconfig-final.hpp +BUILT_SOURCES = myconfig-final.hpp + +if MYCONFIG +myconfig-final.hpp: FORCE + @if test -e $(top_builddir)/@MYCONFIG@; then \ + echo " GEN $@ <= @MYCONFIG@"; \ + if test -e $@; then \ + cmp -s $(top_builddir)/@MYCONFIG@ $@ || cp $(top_builddir)/@MYCONFIG@ $@; \ + else \ + cp $(top_builddir)/@MYCONFIG@ $@; \ + fi; \ + else \ + echo "ERROR: Couldn't find @MYCONFIG@."; \ + exit 1; \ + fi +else +myconfig-final.hpp: FORCE + @config_files="\ + $(top_builddir)/myconfig.hpp \ + $(top_srcdir)/myconfig.hpp \ + $(srcdir)/myconfig-default.hpp"; \ + for file in $$config_files; do \ + if test -e $$file; then \ + echo " GEN $@ <= $$file"; \ + myconfig_found=1; \ + if test -e $@; then \ + cmp -s $$file $@ || cp $$file $@; \ + else \ + cp $$file $@; \ + fi; \ + break; \ + fi; \ + done; \ + if test ! $$myconfig_found; then \ + echo "ERROR: Couldn't find $(myconfig) anywhere"; \ + exit 1; \ + fi +endif + +################################################################# +# Handling of the features +################################################################# +EXTRA_DIST += gen_featureconfig.py config-features.hpp config-features.cpp + +if HAVE_PYTHON + +BUILT_SOURCES += config-features.hpp config-features.cpp +CLEANFILES += config-features.hpp config-features.cpp +config-features.hpp config-features.cpp: $(top_srcdir)/src/features.def $(srcdir)/gen_featureconfig.py + $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_featureconfig.py \ + $(top_srcdir)/src/features.def config-features.hpp config-features.cpp \ + > /dev/null + +else + +config-features.hpp config-features.cpp: features.def + @echo "Python was not found in your PATH." + @echo "If you change the set of features, you need Python!" + @echo "Install it and rerun configure." + +endif + +################################################################# +# Handling of the version +################################################################# +libEspresso_la_SOURCES += config-version.cpp +CLEANFILES += config-version.cpp +config-version.cpp: FORCE + $(AM_V_GEN)VERSION=`cd $(top_srcdir); sh config/genversion.sh -c`; \ + if ! test -e "config-version.cpp" || \ + test "$$VERSION" != "`cat config-version.cpp`"; then \ + echo "$$VERSION" > config-version.cpp; \ + fi + +################################################################# +# Handling of the MPI fake implementation +################################################################# +if MPI_FAKE +libEspresso_la_SOURCES += mpifake/mpi.h mpifake/mpi.cpp +# mpifake should come before any system includes +AM_CPPFLAGS = -I$(srcdir)/mpifake +endif + +.PHONY: FORCE +FORCE: diff --git a/src/core/Ringbuffer.hpp b/src/core/Ringbuffer.hpp new file mode 100644 index 00000000000..f4b7dbd7534 --- /dev/null +++ b/src/core/Ringbuffer.hpp @@ -0,0 +1,50 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __RINGBUFFER_HPP +#define __RINGBUFFER_HPP + +#include + +template +class Ringbuffer { +public: + Ringbuffer(int _n) { + if(_n =< 0) + n = 1; + else if (_n > d.max_size()) + n = d.max_size(); + else + n = _n; + }; + void Ringbuffer::push(T value) { + if(d.size() >= n) + d.pop_front(); + d.push_back(value); + }; + std::deque::iterator begin() { return d.begin(); }; + std::deque::iterator end() { return d.end(); }; +private: + int n; + std::deque d; +}; + +#endif diff --git a/src/core/RuntimeErrorCollector.cpp b/src/core/RuntimeErrorCollector.cpp new file mode 100644 index 00000000000..cee2f9c6794 --- /dev/null +++ b/src/core/RuntimeErrorCollector.cpp @@ -0,0 +1,137 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "RuntimeErrorCollector.hpp" +#include +#include "communication.hpp" + +using namespace std; + +RuntimeErrorCollector:: +RuntimeErrorCollector(MPI_Comm _comm) { + this->comm = _comm; +} + +void RuntimeErrorCollector:: +warning(const string &msg, + const char* function, const char* file, const int line) { + ostringstream ostr; + ostr << "{ WARNING: "; + ostr << msg; + ostr << " in function " << function << " (" << file << ":" << line + << ") on node " << this_node; + ostr << " } "; + errors.push_back(ostr.str()); +} + +void RuntimeErrorCollector:: +warning(const char *msg, + const char* function, const char* file, const int line) { + this->warning(string(msg), function, file, line); +} + +void RuntimeErrorCollector:: +warning(const ostringstream &mstr, + const char* function, const char* file, const int line) { + this->warning(mstr.str(), function, file, line); +} + +void RuntimeErrorCollector:: +error(const string &msg, + const char* function, const char* file, const int line) { + ostringstream ostr; + ostr << "{ ERROR: "; + ostr << msg; + ostr << " in function " << function << " (" << file << ":" << line + << ") on node " << this_node; + ostr << " } "; + errors.push_back(ostr.str()); +} + +void RuntimeErrorCollector:: +error(const char *msg, + const char* function, const char* file, const int line) { + this->error(string(msg), function, file, line); +} + +void RuntimeErrorCollector:: +error(const ostringstream &mstr, + const char* function, const char* file, const int line) { + this->error(mstr.str(), function, file, line); +} + + +int RuntimeErrorCollector:: +count() { + int numMessages = this->errors.size(); + MPI_Allreduce(MPI_IN_PLACE, &numMessages, 1, MPI_INT, MPI_SUM, this->comm); + return numMessages; +} + +void RuntimeErrorCollector::clear() { + errors.clear(); +} + +list RuntimeErrorCollector:: +gather() { + int numMessages = this->count(); + + // If no processor encountered an error, return + if (numMessages == 0) return list(); + + list allerrors = this->errors; + + // subtract the number of messages on the master, as they are not to be sent + numMessages -= this->errors.size(); + + MPI_Status status; + int count; + for (int i = 0; i < numMessages; ++i) { + // get the next message + MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, this->comm, &status); + MPI_Get_count(&status, MPI_CHAR, &count); + + char buffer[count]; + MPI_Recv(buffer, count, MPI_CHAR, + MPI_ANY_SOURCE, MPI_ANY_TAG, this->comm, MPI_STATUS_IGNORE); + + allerrors.push_back(string()); + string &s = allerrors.back(); + s.assign(buffer, count); + } + + this->clear(); + + return allerrors; +} + +void RuntimeErrorCollector:: +gatherSlave() { + // If no processor encountered an error, return + if (this->count() == 0) return; + + // send all messages + for (list::iterator it = this->errors.begin(); + it != errors.end(); ++it) { + MPI_Send(const_cast(it->data()), it->length(), MPI_CHAR, 0, 42, this->comm); + } + + // finally empty the list + this->clear(); +} + diff --git a/src/core/RuntimeErrorCollector.hpp b/src/core/RuntimeErrorCollector.hpp new file mode 100644 index 00000000000..59e0441f1bc --- /dev/null +++ b/src/core/RuntimeErrorCollector.hpp @@ -0,0 +1,61 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _RUNTIMEERRORCOLLECTOR_HPP +#define _RUNTIMEERRORCOLLECTOR_HPP + +#include "config.hpp" +#include +#include +#include "mpi.h" + +class RuntimeErrorCollector { + std::list errors; + MPI_Comm comm; +public: + RuntimeErrorCollector(MPI_Comm comm); + + void + warning(const std::string &msg, + const char* function, const char* file, const int line); + void + warning(const char *msg, + const char* function, const char* file, const int line); + void + warning(const std::ostringstream &mstr, + const char* function, const char* file, const int line); + + void + error(const std::string &msg, + const char* function, const char* file, const int line); + void + error(const char *msg, + const char* function, const char* file, const int line); + void + error(const std::ostringstream &mstr, + const char* function, const char* file, const int line); + + int count(); + void clear(); + + std::list gather(); + void gatherSlave(); +}; + +#endif diff --git a/src/core/SystemInterface.hpp b/src/core/SystemInterface.hpp new file mode 100644 index 00000000000..23d61a8451c --- /dev/null +++ b/src/core/SystemInterface.hpp @@ -0,0 +1,161 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef SYSTEMINTERFACE_H +#define SYSTEMINTERFACE_H + +#include "Vector.hpp" +#include + +/** @todo: Turn needsXY in getter/setter **/ + +class SystemInterface { +public: + SystemInterface() : m_needsR(false), m_needsV(false), m_needsQ(false), m_needsRGpu(false), m_needsVGpu(false), m_needsQGpu(false) {}; + typedef Vector3d Vector3; + typedef double Real; + + virtual void init() = 0; + virtual void update() = 0; + + template + class const_iterator { + public: + virtual value_type operator*() const = 0; + virtual const_iterator &operator=(const const_iterator &rhs) = 0; + virtual bool operator==(const_iterator const &rhs) const = 0; + virtual bool operator!=(const_iterator const &rhs) const = 0; + virtual const_iterator &operator++() = 0; + }; + + class null_vec_iterator : public SystemInterface::const_iterator { + public: + Vector3 operator*() const { return Vector3(); }; + const_iterator &operator=(const const_iterator &rhs) { return *this; }; + bool operator==(const_iterator const &rhs) const { return true; }; + bool operator!=(const_iterator const &rhs) const { return false; }; + const_iterator &operator++() {return *this;}; + }; + + null_vec_iterator null_vector; + + class null_real_iterator : public SystemInterface::const_iterator { + public: + Real operator*() const { return Real(); }; + const_iterator &operator=(const const_iterator &rhs) { return *this; }; + bool operator==(const_iterator const &rhs) const { return true; }; + bool operator!=(const_iterator const &rhs) const { return false; }; + const_iterator &operator++() {return *this;}; + }; + + null_real_iterator null_scalar; + + template + class const_iterator_stl : public SystemInterface::const_iterator { + public: + const_iterator_stl(typename stl_container::const_iterator it) { + m_const_iterator = it; + }; + const_iterator_stl() {}; + const typename stl_container::value_type operator*() const { + return (*m_const_iterator); + }; + SystemInterface::const_iterator &operator=(const SystemInterface::const_iterator &rhs) { + m_const_iterator = static_cast &>(rhs).m_const_iterator; + return static_cast &>(*this); + }; + const_iterator_stl &operator=(const typename stl_container::const_iterator &rhs) { + m_const_iterator = rhs; + return *this; + }; + + const_iterator_stl &operator=(const const_iterator_stl &rhs) { + m_const_iterator = rhs.m_const_iterator; + return *this; + }; + + bool operator==(SystemInterface::const_iterator const &rhs) const { + return (m_const_iterator == static_cast &>(rhs).m_const_iterator); + }; + bool operator!=(SystemInterface::const_iterator const &rhs) const { + return (m_const_iterator != static_cast &>(rhs).m_const_iterator); + }; + const_iterator &operator++() { + ++m_const_iterator; + return *this; + }; + private: + typename stl_container::const_iterator m_const_iterator; + }; + + typedef const_iterator const_vec_iterator; + typedef const_iterator const_real_iterator; + typedef const_iterator const_int_iterator; + + virtual const_vec_iterator &rBegin() { return SystemInterface::null_vector; }; + virtual const const_vec_iterator &rEnd() { return SystemInterface::null_vector; }; + virtual bool hasR() { return false; }; + virtual bool requestR() { m_needsR = hasR(); return m_needsR; } + + virtual float *rGpuBegin() { return 0; }; + virtual float *rGpuEnd() { return 0; }; + virtual bool hasRGpu() { return false; }; + virtual bool requestRGpu() { m_needsRGpu = hasRGpu(); return m_needsRGpu; } + + virtual float *vGpuBegin() { return 0; }; + virtual float *vGpuEnd() { return 0; }; + virtual bool hasVGpu() { return false; }; + virtual bool requestVGpu() { m_needsVGpu = hasVGpu(); return m_needsVGpu; } + + virtual float *qGpuBegin() { return 0; }; + virtual float *qGpuEnd() { return 0; }; + virtual bool hasQGpu() { return false; }; + virtual bool requestQGpu() { m_needsQGpu = hasQGpu(); return m_needsQGpu; } + + virtual float *fGpuBegin() { return 0; }; + virtual float *fGpuEnd() { return 0; }; + virtual float *eGpu() { return 0; }; + virtual bool hasFGpu() { return false; }; + virtual bool requestFGpu() { m_needsFGpu = hasFGpu(); return m_needsFGpu; } + + virtual const_real_iterator &qBegin() { return null_scalar; }; + virtual const const_real_iterator &qEnd() { return null_scalar; }; + virtual bool hasQ() { return false; }; + virtual bool requestQ() { m_needsQ = hasQ(); return m_needsQ; } + + virtual unsigned int npart() = 0; + virtual unsigned int npart_gpu() { return 0; }; + virtual Vector3 box() = 0; + + virtual bool needsR() { return m_needsR; }; + virtual bool needsRGpu() { return m_needsRGpu;}; + virtual bool needsQGpu() { return m_needsQGpu;}; + virtual bool needsQ() { return m_needsQ;}; + virtual bool needsFGpu() { return m_needsFGpu; }; + +protected: + bool m_needsR; + bool m_needsV; + bool m_needsQ; + bool m_needsRGpu; + bool m_needsVGpu; + bool m_needsQGpu; + bool m_needsFGpu; +}; + +#endif diff --git a/src/core/Vector.hpp b/src/core/Vector.hpp new file mode 100644 index 00000000000..222b17a813d --- /dev/null +++ b/src/core/Vector.hpp @@ -0,0 +1,62 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include + +template +class Vector { +private: + Scalar *d; +public: + Vector() : d(new Scalar[n]) {}; + + Vector(Scalar *a) : d(new Scalar[n]) { + for (int i = 0; i < n; i++) + d[i] = a[i]; + }; + + ~Vector() { + delete[] d; + } + + Vector(const Vector& rhs) : d(new Scalar[n]) { + std::copy(rhs.d,rhs.d+n,d); + } + + void swap(Vector& rhs) { + std::swap(d,rhs.d); + } + + Vector& operator=(Vector& rhs) { + Vector tmp(rhs); swap(rhs); return *this; + }; + + Scalar &operator[](int i) { + return d[i]; + }; + + Scalar dot(Vector b) { + Scalar sum = 0.0; + for(int i = 0; i < n; i++) + sum += d[i]*b[i]; + return sum; + }; +}; + +typedef Vector<3, double> Vector3d; + diff --git a/src/core/actor/Actor.hpp b/src/core/actor/Actor.hpp new file mode 100644 index 00000000000..30194091f19 --- /dev/null +++ b/src/core/actor/Actor.hpp @@ -0,0 +1,35 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _ACTOR_ACTOR_HPP +#define _ACTOR_ACTOR_HPP + +#include "SystemInterface.hpp" + +/** + * Generic abstract potential class. + * All potentials should be derived from this one. + */ +class Actor { +public: + virtual void computeForces(SystemInterface &s) = 0; + virtual void computeEnergy(SystemInterface &s) = 0; + virtual ~Actor() {} +}; + +#endif /* _ACTOR_ACTOR_HPP */ diff --git a/src/core/actor/ActorList.cpp b/src/core/actor/ActorList.cpp new file mode 100644 index 00000000000..ee0b074e9cb --- /dev/null +++ b/src/core/actor/ActorList.cpp @@ -0,0 +1,32 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "ActorList.hpp" +#include +#include + +void ActorList::add(Actor *actor) { + this->push_back(actor); +} + +void ActorList::remove(Actor *actor) { + iterator needle = std::find(this->begin(), this->end(), actor); + assert(needle != this->end()); + this->erase(needle); +} diff --git a/src/core/actor/ActorList.hpp b/src/core/actor/ActorList.hpp new file mode 100644 index 00000000000..6895a52df6b --- /dev/null +++ b/src/core/actor/ActorList.hpp @@ -0,0 +1,31 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _ACTOR_ACTORLIST_HPP +#define _ACTOR_ACTORLIST_HPP + +#include +#include "Actor.hpp" + +class ActorList : public std::vector { +public: + void add(Actor *actor); + void remove(Actor *actor); +}; + +#endif /* ACTORLIST_HPP_ */ diff --git a/src/core/actor/EwaldgpuForce.cpp b/src/core/actor/EwaldgpuForce.cpp new file mode 100644 index 00000000000..78cfb660d9e --- /dev/null +++ b/src/core/actor/EwaldgpuForce.cpp @@ -0,0 +1,340 @@ +#include "actor/EwaldgpuForce.hpp" + +#ifdef EWALD_GPU + +#include +#include +#include "tuning.hpp" +#include "integrate.hpp" +#include "grid.hpp" +#include "interaction_data.hpp" +#include "cells.hpp" + +typedef ewaldgpu_real real; +extern Ewaldgpu_params ewaldgpu_params; + +//Compute reciprocal space vectors k +void EwaldgpuForce::compute_num_k() +{ + int Index=0;//Arrayindex + + for (long long ix=0; ix<=m_num_kx; ix++) + { + for (long long iy=-m_num_ky; iy<=m_num_ky; iy++) + { + for (long long iz=-m_num_kz; iz<=m_num_kz; iz++) + { + if(ix*(2*m_num_ky+1)*(2*m_num_kz+1)+iy*(2*m_num_kz+1)+iz >= 0//Half m_k-space + and SQR(ix)*SQR(m_num_ky)*SQR(m_num_kz) + + SQR(iy)*SQR(m_num_kx)*SQR(m_num_kz) + + SQR(iz)*SQR(m_num_kx)*SQR(m_num_ky) + <=SQR(m_num_kx)*SQR(m_num_ky)*SQR(m_num_kz))//m_k-space ellipsoid + { + Index+=1; + } + } + } + } + m_num_k=Index; +} +void EwaldgpuForce::compute_k_AND_influence_factor() +{ + real k_sqr;//Absolute square of m_k-vector + int Index=0;//Arrayindex + + for (long long ix=0; ix<=m_num_kx; ix++)//Half m_k-space + { + for (long long iy=-m_num_ky; iy<=m_num_ky; iy++) + { + for (long long iz=-m_num_kz; iz<=m_num_kz; iz++) + { + if(ix*(2*m_num_ky+1)*(2*m_num_kz+1)+iy*(2*m_num_kz+1)+iz >= 0//Half m_k-space + and SQR(ix)*SQR(m_num_ky)*SQR(m_num_kz) + + SQR(iy)*SQR(m_num_kx)*SQR(m_num_kz) + + SQR(iz)*SQR(m_num_kx)*SQR(m_num_ky) + <=SQR(m_num_kx)*SQR(m_num_ky)*SQR(m_num_kz))//m_k-space ellipsoid + { + //m_k vectors + m_k[Index] = 2*M_PI/m_box_l[0]*ix; + m_k[Index+m_num_k] = 2*M_PI/m_box_l[1]*iy; + m_k[Index+2*m_num_k] = 2*M_PI/m_box_l[2]*iz; + //Influence factor + k_sqr= SQR(m_k[Index]) + SQR(m_k[Index+m_num_k]) + SQR(m_k[Index+2*m_num_k]); + m_infl_factor[Index] = 8*M_PI/m_V*expf(-k_sqr/(4*SQR(m_alpha)))/k_sqr; + //Index + Index+=1; + } + } + } + } m_infl_factor[0] = 0;//Influence factor at m_k=(0,0,0) +} + +//Real space +void EwaldgpuForce::EwaldCPU_EnergySelf() +{ + m_energy_self=coulomb.prefactor * (-m_alpha/sqrt(M_PI) * m_q_sqr[0]); +} + +//Parameters +int EwaldgpuForce::set_params(double rcut, int num_kx, int num_ky, int num_kz, double alpha) +{ + IA_parameters *data = get_ia_param_safe(0, 0); + data->max_cut = rcut; + ewaldgpu_params.rcut = rcut; + ewaldgpu_params.num_kx = num_kx; + ewaldgpu_params.num_ky = num_ky; + ewaldgpu_params.num_kz = num_kz; + ewaldgpu_params.alpha = alpha; + + return 0; +} +int EwaldgpuForce::set_params_tune(double accuracy, double precision, int K_max, int time_calc_steps) +{ + ewaldgpu_params.accuracy = accuracy; + ewaldgpu_params.precision = precision; + ewaldgpu_params.K_max = K_max; + ewaldgpu_params.time_calc_steps = time_calc_steps; + + return 0; +} + +//Tuning +int EwaldgpuForce::adaptive_tune(char **log,SystemInterface &s) +{ + ewaldgpu_params.isTuned = false; + int Kmax = ewaldgpu_params.K_max; + double alpha_array[Kmax]; //All computed alpha in dependence of K + double rcut_array[Kmax]; //All computed r_cut in dependence of all computed alpha + + //Squared charge + Particle *particle; + particle = (Particle*)malloc(n_part*sizeof(Particle)); + mpi_get_particles(particle, NULL); + double q_sqr = compute_q_sqare(particle); + + char b[3*ES_INTEGER_SPACE + 3*ES_DOUBLE_SPACE + 128]; + + if (skin == -1) { + *log = strcat_alloc(*log, "ewaldgpu cannot be tuned, since the skin is not yet set"); + return ES_ERROR; + } + + //Compute alpha for all reciprocal k-sphere radius K + for(int K = 0; K < Kmax ;K++) + { + alpha_array[K] = tune_alpha(ewaldgpu_params.accuracy/sqrt(2), ewaldgpu_params.precision, K+1, box_l[0]*box_l[1]*box_l[2], q_sqr, n_part); + //printf("K:%i alpha:%f\n",K+1,alpha_array[K]); + } + //Compute r_cut for all computed alpha + for(int K = 0; K < Kmax ;K++) + { + rcut_array[K] = tune_rcut(ewaldgpu_params.accuracy/sqrt(2), ewaldgpu_params.precision, alpha_array[K], box_l[0]*box_l[1]*box_l[2], q_sqr, n_part); + //printf("K:%i rcut:%f \n",K+1,rcut_array[K]); + } + //Test if accuracy was reached + if(rcut_array[Kmax-1]<0) + { + return ES_ERROR; + } + + /*********************************************************************************** + PERFORMANCE TIME + ***********************************************************************************/ + + //Test performance time for the diverent (K, rcut, alpha) + double int_time_best = 1E30; + int K_best = Kmax; + for(int K = 0; K < Kmax ;K++) + { + if(alpha_array[K]>0 and rcut_array[K]>0 and rcut_array[K]<(std::min(box_l[0],std::min(box_l[1],box_l[2])))/2.0-skin) + { + set_params(rcut_array[K], K+1, K+1, K+1, alpha_array[K]); + mpi_bcast_coulomb_params(); + double int_time = time_force_calc(ewaldgpu_params.time_calc_steps); + if(int_time 0.0) + { + return -1; // Value unusable + } + + do + { + alpha_guess = 0.5 *(alpha_low + alpha_high); + fkt_guess = error_estimate_k(q_sqr, N, K, V, alpha_guess, accuracy); + if (fkt_low*fkt_guess < 0.0) alpha_high = alpha_guess; + else alpha_low = alpha_guess; + + } while (fabs(alpha_low-alpha_high) > precision); + + return 0.5 *(alpha_low + alpha_high); +} +double EwaldgpuForce::tune_rcut(double accuracy, double precision, double alpha, double V, double q_sqr, int N) +{ + double rcut_low=0.0; + double rcut_high=0.5 * std::max(box_l[0],std::max(box_l[1],box_l[2])); + double rcut_guess; + double fkt_low; + double fkt_high; + double fkt_guess; + + // Find rcut with given K in k-space error estimate via bisection + fkt_low = error_estimate_r(q_sqr, N, rcut_low, V, alpha, accuracy); + fkt_high = error_estimate_r(q_sqr, N, rcut_high, V, alpha, accuracy); + + if (fkt_low*fkt_high > 0.0) + { + return -1; // Value unusable + } + + do + { + rcut_guess = 0.5 *(rcut_low + rcut_high); + fkt_guess = error_estimate_r(q_sqr, N, rcut_guess, V, alpha, accuracy); + if (fkt_low*fkt_guess < 0.0) rcut_high = rcut_guess; + else rcut_low = rcut_guess; + + } while (fabs(rcut_low-rcut_high) > precision); + + return 0.5 *(rcut_low + rcut_high); +} +int EwaldgpuForce::determine_calc_time_steps() +{ + Cell *cell; + Particle *part; + int i,c,np; + int sum_qpart =0; + + for (c = 0; c < local_cells.n; c++) + { + cell = local_cells.cell[c]; + part = cell->part; + np = cell->n; + for(i=0;i 0.0) + { + fprintf(stderr, "Error: Could not init method to find optimal alpha!\n"); + exit(1); + } + + do + { + alpha_guess = 0.5 *(alpha_low + alpha_high); + f_guess = compute_E_error_estimate_r(alpha_guess, rcut, q_sqr, box_l) - compute_E_error_estimate_k(alpha_guess, num_kx, num_ky, num_kz, q_sqr, box_l); + if (f_low*f_guess < 0.0) alpha_high = alpha_guess; + else alpha_low = alpha_guess; + counter++; + if(counter>10000) + { + fprintf(stderr, "Find optimal alpha: Maximum number of loops exceeded: %i loops",counter); + exit(1); + } + } while (fabs(alpha_low-alpha_high) > precision); + + return 0.5 *(alpha_low + alpha_high); +} +double EwaldgpuForce::compute_q_sqare(Particle *particle) +{ + double q_sqr=0; + + for(int i = 0; i < n_part; i++) + { + q_sqr += SQR(particle[i].p.q); + } + return q_sqr; +} + +#endif diff --git a/src/core/actor/EwaldgpuForce.hpp b/src/core/actor/EwaldgpuForce.hpp new file mode 100644 index 00000000000..38a0b5cd0ee --- /dev/null +++ b/src/core/actor/EwaldgpuForce.hpp @@ -0,0 +1,109 @@ +#ifndef EWALDGPUFORCE_HPP +#define EWALDGPUFORCE_HPP +#include "config.hpp" + +#ifdef EWALD_GPU + +#include "SystemInterface.hpp" +#include "Actor.hpp" +#include "particle_data.hpp" +#include + +typedef float ewaldgpu_real; + +void addEwaldgpuForce(double r_cut, int num_kx, int num_ky, int num_kz, double alpha); + +typedef struct { + //Ewald parameters + double rcut; + int num_kx; + int num_ky; + int num_kz; + double alpha; + //Tuning + double accuracy; + double precision; + bool isTuned; // Tuning is over + bool isTunedFlag; // Flag tuning is over + int K_max; // Maximal reciprocal K-vector in tuning + int time_calc_steps; // Steps in time_force_calc function +} Ewaldgpu_params; + +extern Ewaldgpu_params ewaldgpu_params; + +class EwaldgpuForce : public Actor { +public: + EwaldgpuForce(SystemInterface &s, double r_cut, int num_kx, int num_ky, int num_kz, double alpha); + ~EwaldgpuForce(); + void setup(SystemInterface &s); + void computeForces(SystemInterface &s); + void computeEnergy(SystemInterface &s); + //Set parameters + int set_params(double rcut, int num_kx, int num_ky, int num_kz, double alpha); + int set_params_tune(double accuracy, double precision, int K_max, int time_calc_steps); + //Tuning + int adaptive_tune(char **log, SystemInterface &s); + double error_estimate_r(double q_sqr, int N, double r_cut, double V, double alpha, double accuracy); + double error_estimate_k(double q_sqr, int N, int K, double V, double alpha, double accuracy); + double tune_alpha(double accuracy, double precision, int K, double V, double q_sqr, int N); + double tune_rcut(double accuracy, double precision, double alpha, double V, double q_sqr, int N); + int determine_calc_time_steps(); + //Kolaffa compute optimal alpha + double compute_E_error_estimate_r(double alpha, double rcut, double q_sqr, double box_l[3]); + double compute_E_error_estimate_k(double alpha, int num_kx, int num_ky, int num_kz, double q_sqr, double box_l[3]); + double E_estimate_error(double rcut, int num_kx, int num_ky, int num_kz, double alpha, double q_sqr, double box_l[3]); + double compute_optimal_alpha(double rcut, int num_kx, int num_ky, int num_kz, double q_sqr, double box_l[3], double precision); + double compute_q_sqare(Particle *particle); + +protected: + //System + double m_box_l[3]; //Box length + double m_V; //Volume + double m_coulomb_prefactor; //Forces, energy is multiplied with this factor + int m_N; //Number of particles + ewaldgpu_real *m_k; //k-vectors + ewaldgpu_real *m_dev_k; //k-vectors + ewaldgpu_real *m_forces_reci; //Forces k-space + ewaldgpu_real *m_dev_forces_reci; //Forces k-space + ewaldgpu_real *m_infl_factor; //Influence factor + ewaldgpu_real *m_dev_infl_factor; //Influence factor + ewaldgpu_real *m_rho_hat; //Rho hat + ewaldgpu_real *m_dev_rho_hat; //Rho hat + ewaldgpu_real *m_energy_reci; //Energy k-space + ewaldgpu_real *m_dev_energy_reci; //Energy k-space + ewaldgpu_real *m_q_sqr; //Sum of the squares of the particle charges + ewaldgpu_real *m_dev_q_sqr; //Sum of the squares of the particle charges + ewaldgpu_real m_energy_self; //Energy self + ewaldgpu_real m_energy_tot; //Energy total + //Parameters + double m_alpha; //Separation parameter + double m_rcut; //Cutoff radius + int m_num_kx, m_num_ky, m_num_kz, m_num_k; //Number of k's in xyz-direction + +protected: + //Variables + bool m_isTuned; //Tuning is over + SystemInterface *System; + //Ccompute k's + void compute_num_k(); //Compute the number of k's in sphere respectively in ellipsoid + void compute_k_AND_influence_factor(); //Compute the k-vectors in sphere respectively in ellipsoid and influence factor + //GPU program + void GPU_Forces(SystemInterface &s); //Run GPU forces part + void GPU_Energy(SystemInterface &s); //Run GPU energy part + void GPU_q_sqr(SystemInterface &s); // Compute q squared + int nextPow2(int x); //Determine the next power of x + bool isPow2(int x); //Determine if x of power 2 + void getNumBlocksAndThreads(int Size, int maxBlocks, int maxThreads, int &blocks, int &threads); // Determine the number of blocks and threads in GPU part + //Output + void Output(); //Output in terminal + //Real space + void EwaldCPU_EnergySelf(); //Calculate the self energy +}; + +extern EwaldgpuForce *ewaldgpuForce; + +void addEwaldgpuForce(double rcut, int num_kx, int num_ky, int num_kz, double alpha); + +#endif +#endif + diff --git a/src/core/actor/EwaldgpuForce_ShortRange.hpp b/src/core/actor/EwaldgpuForce_ShortRange.hpp new file mode 100644 index 00000000000..4d80342c8de --- /dev/null +++ b/src/core/actor/EwaldgpuForce_ShortRange.hpp @@ -0,0 +1,37 @@ +#ifndef EWALDGPUFORCESHORTRANGE_HPP_ +#define EWALDGPUFORCESHORTRANGE_HPP_ + +#ifdef EWALD_GPU +#include "actor/EwaldgpuForce.hpp" + +//Add energy +inline double ewaldgpu_coulomb_pair_energy(double chgfac, double *d,double dist2,double dist) +{ + if (dist < ewaldgpu_params.rcut) + { + return coulomb.prefactor*chgfac*erfc(ewaldgpu_params.alpha*dist)/dist; + } + return 0.0; +} + +//Add forces +inline void add_ewald_gpu_coulomb_pair_force(Particle *p1, Particle *p2, double d[3], double dist, double force[3]) +{ + int j; + double fac; + double rcut=ewaldgpu_params.rcut; + if(dist < rcut) + { + fac=coulomb.prefactor * p1->p.q * p2->p.q * ( 2*ewaldgpu_params.alpha/sqrt(M_PI) * exp(-pow(ewaldgpu_params.alpha *dist,2)) + erfc(ewaldgpu_params.alpha*dist)/dist )/pow(dist,2); + + for(j=0;j<3;j++) + force[j] += fac * d[j]; + + ONEPART_TRACE(if(p1->p.identity==check_id) fprintf(stderr,"%d: OPT: EWALD_GPU f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2],p2->p.identity,dist,fac)); + ONEPART_TRACE(if(p2->p.identity==check_id) fprintf(stderr,"%d: OPT: EWALD_GPU f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2],p1->p.identity,dist,fac)); + } +} + +#endif + +#endif /* EWALDGPUFORCESHORTRANGE_HPP_ */ diff --git a/src/core/actor/EwaldgpuForce_cuda.cu b/src/core/actor/EwaldgpuForce_cuda.cu new file mode 100644 index 00000000000..1e950ff1928 --- /dev/null +++ b/src/core/actor/EwaldgpuForce_cuda.cu @@ -0,0 +1,1097 @@ +#include "actor/EwaldgpuForce.hpp" +#include "cuda_utils.hpp" + +#ifdef EWALD_GPU + +#include +#include + +#include "interaction_data.hpp" +#include "EspressoSystemInterface.hpp" + +#if defined(OMPI_MPI_H) || defined(_MPI_H) +#error CU-file includes mpi.h! This should not happen! +#endif + +typedef ewaldgpu_real real; +Ewaldgpu_params ewaldgpu_params; + +//Stream +cudaEvent_t *start, *stop; +cudaStream_t *stream0; + +void cuda_check_error(const dim3 &block, const dim3 &grid,const char *function, const char *file, unsigned int line); + +//Error handler +static void HandleError(cudaError_t err,const char *file,int line) +{ + if( cudaSuccess != err) { + fprintf(stderr, "Cuda Memory error at %s:%u.\n", file, line); + printf("CUDA error: %s\n", cudaGetErrorString(err)); + if ( err == cudaErrorInvalidValue ) + fprintf(stderr, "You may have tried to allocate zero memory at %s:%u.\n", file, line); + exit(EXIT_FAILURE); + } else { + err=cudaGetLastError(); + if (err != cudaSuccess) { + fprintf(stderr, "Error found during memory operation. Possibly however from an failed operation before. %s:%u.\n", file, line); + printf("CUDA error: %s\n", cudaGetErrorString(err)); + if ( err == cudaErrorInvalidValue ) + fprintf(stderr, "You may have tried to allocate zero memory before %s:%u.\n", file, line); + exit(EXIT_FAILURE); + } + } +} +#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) +#define HANDLE_NULL( a ) {if (a == NULL) {printf( "Host memory failed in %s at line %d\n", __FILE__, __LINE__ ); exit( EXIT_FAILURE );}} + +//Kernels +/*Here MaxThreads/LowThreads means that, if for example 10000 Particles/k-Vectors are given and the GPU uses 256 Threads the first 19*(2*256)=9728 will be +reduced by the MaxThread function and the remaining 272 Particles will be reduced by the LowThread function*/ +//Structure factor +template +__global__ void EwaldGPU_Rho_hat_MaxThreads(real *k,real *r_i, real *q_i, real *rho_hat, int N, int num_k, int maxThreadsPerBlock,int loops) +{ + //Reject unneeded blocks + if (blockIdx.x*gridDim.x+blockIdx.y >= num_k) return; + + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + real kr; + real factor; + real sin_kr; + real cos_kr; + real *sin_ptr=&sin_kr; + real *cos_ptr=&cos_kr; + int blockId = blockIdx.x*gridDim.x+blockIdx.y; + int l = loops; + + //Init + i = tid; + sdata[tid] = 0; + sdata[tid+2*blockSize] = 0; + + //Reduction + while (i < mTPB) + { + kr = k[blockId]*r_i[3*(i+2*l*mTPB)]+k[blockId+num_k]*r_i[3*(i+2*l*mTPB)+1]+k[blockId+2*num_k]*r_i[3*(i+2*l*mTPB)+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = q_i[i+2*l*mTPB]; + sdata[tid] += factor*cos_kr; + sdata[tid+2*blockSize] += -factor*sin_kr; + + //BECAUSE nIsPow2=True + kr = k[blockId]*r_i[3*(i+2*l*mTPB+blockSize)]+k[blockId+num_k]*r_i[3*(i+2*l*mTPB+blockSize)+1]+k[blockId+2*num_k]*r_i[3*(i+2*l*mTPB+blockSize)+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = q_i[i+2*l*mTPB+blockSize]; + sdata[tid] += factor*cos_kr; + sdata[tid+2*blockSize] += -factor*sin_kr; + + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + rho_hat[blockId] += sdata[0]; + rho_hat[blockId+num_k] += sdata[2*blockSize]; + } + __syncthreads(); +} +template +__global__ void EwaldGPU_Rho_hat_LowThreads(real *k,real *r_i, real *q_i, real *rho_hat, int N, int num_k,int maxThreadsPerBlock,int elapsedLoops) +{ + //Reject unneeded blocks + if (blockIdx.x*gridDim.x+blockIdx.y >= num_k) return; + + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + int l=elapsedLoops; + real kr; + real factor; + real sin_kr; + real cos_kr; + real *sin_ptr=&sin_kr; + real *cos_ptr=&cos_kr; + int blockId = blockIdx.x*gridDim.x+blockIdx.y; + + //Init + i = tid; + sdata[tid] = 0; + sdata[tid+2*blockSize] = 0; + + //Reduction + while (i < N-2*l*mTPB) + { + kr = k[blockId]*r_i[3*(i+2*l*mTPB)]+k[blockId+num_k]*r_i[3*(i+2*l*mTPB)+1]+k[blockId+2*num_k]*r_i[3*(i+2*l*mTPB)+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = q_i[i+2*l*mTPB]; + + sdata[tid] += factor*cos_kr; + sdata[tid+2*blockSize] += -factor*sin_kr; + if (nIsPow2 || i + blockSize < N-2*l*mTPB) + { + kr = k[blockId]*r_i[3*(i+blockSize+2*l*mTPB)]+k[blockId+num_k]*r_i[3*(i+blockSize+2*l*mTPB)+1]+k[blockId+2*num_k]*r_i[3*(i+blockSize+2*l*mTPB)+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = q_i[i+2*l*mTPB+blockSize]; + sdata[tid] += factor*cos_kr; + sdata[tid+2*blockSize] += -factor*sin_kr; + } + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + rho_hat[blockId] += sdata[0]; + rho_hat[blockId+num_k] += sdata[2*blockSize]; + } +} +//Forces in reciprocal space +template +__global__ void EwaldGPU_ForcesReci_MaxThreads(real *k,real *r_i, real *q_i, real *rho_hat, real *infl_factor, real *forces_reci, int N, int num_k, real V, real coulomb_prefactor, int maxThreadsPerBlock,int loops) +{ + //Reject unneeded blocks + if (blockIdx.x*gridDim.x+blockIdx.y >= N) return; + + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + real kr; + real factor; + real sin_kr; + real cos_kr; + real *sin_ptr=&sin_kr; + real *cos_ptr=&cos_kr; + int blockId = blockIdx.x*gridDim.x+blockIdx.y; + int l = loops; + + //Init + i = tid; + sdata[tid] = 0; + sdata[tid+2*blockSize] = 0; + sdata[tid+4*blockSize] = 0; + + //Reduction + while (i < mTPB) + { + kr = k[i+2*l*mTPB]*r_i[3*blockId] + k[i+2*l*mTPB+num_k]*r_i[3*blockId+1] + k[i+2*l*mTPB+2*num_k]*r_i[3*blockId+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = infl_factor[i+2*l*mTPB] * q_i[blockId]; + + sdata[tid] += factor * (k[i+2*l*mTPB]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + sdata[tid+2*blockSize] += factor * (k[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + sdata[tid+4*blockSize] += factor * (k[i+2*l*mTPB+2*num_k]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB+2*num_k]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + //BECAUSE nIsPow2=True + kr = k[i+2*l*mTPB+blockSize]*r_i[3*blockId] + k[i+2*l*mTPB+num_k+blockSize]*r_i[3*blockId+1] + k[i+2*l*mTPB+2*num_k+blockSize]*r_i[3*blockId+2]; + factor = infl_factor[i+2*l*mTPB+blockSize]* q_i[blockId]; + sincos(kr,sin_ptr,cos_ptr); + sdata[tid] += factor * (k[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + sdata[tid+2*blockSize] += factor * (k[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + sdata[tid+4*blockSize] += factor * (k[i+2*l*mTPB+2*num_k+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+2*num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 512];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 256];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 128];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 64]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 32];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 16];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 8]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 4]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 2]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 1]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + forces_reci[3*blockId] += sdata[0]*coulomb_prefactor; + forces_reci[3*blockId+1] += sdata[2*blockSize]*coulomb_prefactor; + forces_reci[3*blockId+2] += sdata[4*blockSize]*coulomb_prefactor; + } + __syncthreads(); +} +template +__global__ void EwaldGPU_ForcesReci_LowThreads(real *k,real *r_i, real *q_i, real *rho_hat, real *infl_factor, real *forces_reci, int N, int num_k, real V, real coulomb_prefactor, int maxThreadsPerBlock,int elapsedLoops) +{ + //Reject unneeded blocks + if (blockIdx.x*gridDim.x+blockIdx.y >= N) return; + + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + int l=elapsedLoops; + real kr; + real factor; + real sin_kr; + real cos_kr; + real *sin_ptr=&sin_kr; + real *cos_ptr=&cos_kr; + int blockId = blockIdx.x*gridDim.x+blockIdx.y; + + //Init + i = tid; + sdata[tid] = 0; + sdata[tid+2*blockSize] = 0; + sdata[tid+4*blockSize] = 0; + while (i < num_k-2*l*mTPB) + { + kr = k[i+2*l*mTPB]*r_i[3*blockId] + k[i+2*l*mTPB+num_k]*r_i[3*blockId+1] + k[i+2*l*mTPB+2*num_k]*r_i[3*blockId+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = infl_factor[i+2*l*mTPB] * q_i[blockId]; + + //Reduction + sdata[tid] += factor * (k[i+2*l*mTPB]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + sdata[tid+2*blockSize] += factor * (k[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + sdata[tid+4*blockSize] += factor * (k[i+2*l*mTPB+2*num_k]*rho_hat[i+2*l*mTPB] * sin_kr + k[i+2*l*mTPB+2*num_k]*rho_hat[i+2*l*mTPB+num_k] * cos_kr); + if (nIsPow2 || i + blockSize < num_k-2*l*mTPB) + { + kr = k[i+2*l*mTPB+blockSize]*r_i[3*blockId] + k[i+2*l*mTPB+num_k+blockSize]*r_i[3*blockId+1] + k[i+2*l*mTPB+2*num_k+blockSize]*r_i[3*blockId+2]; + sincos(kr,sin_ptr,cos_ptr); + factor = infl_factor[i+2*l*mTPB+blockSize] * q_i[blockId]; + sdata[tid] += factor * (k[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + sdata[tid+2*blockSize] += factor * (k[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + sdata[tid+4*blockSize] += factor * (k[i+2*l*mTPB+2*num_k+blockSize]*rho_hat[i+2*l*mTPB+blockSize] * sin_kr + k[i+2*l*mTPB+2*num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize] * cos_kr); + } + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 512];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 256];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 128];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 64]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 32];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16];sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 16];sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 8]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 4]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 2]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; sdata[tid+2*blockSize] += sdata[tid+2*blockSize + 1]; sdata[tid+4*blockSize] += sdata[tid+4*blockSize + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + forces_reci[3*blockId] += sdata[0]*coulomb_prefactor; + forces_reci[3*blockId+1] += sdata[2*blockSize]*coulomb_prefactor; + forces_reci[3*blockId+2] += sdata[4*blockSize]*coulomb_prefactor; + } +} +//Energy in reciprocal space +template +__global__ void EwaldGPU_EnergyReci_MaxThreads(real *rho_hat, real *infl_factor,real *energy_reci, int N, int num_k, real V,int maxThreadsPerBlock,int loops,real coulomb_prefactor) +{ + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + real factor; + int l = loops; + + //Init + i = tid; + sdata[tid] = 0; + + //Reduction + while (i < mTPB) + { + factor = infl_factor[i+2*l*mTPB] / 2; + + sdata[tid] += factor * (rho_hat[i+2*l*mTPB]*rho_hat[i+2*l*mTPB] + rho_hat[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB+num_k]); + //BECAUSE nIsPow2=True + factor = infl_factor[i+2*l*mTPB+blockSize] / 2; + sdata[tid] += factor * (rho_hat[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+blockSize] + rho_hat[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize]); + + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + energy_reci[0] += sdata[0]*coulomb_prefactor; + } + __syncthreads(); +} +template +__global__ void EwaldGPU_EnergyReci_LowThreads(real *rho_hat, real *infl_factor,real *energy_reci, int N, int num_k, real V,int maxThreadsPerBlock,int elapsedLoops,real coulomb_prefactor) +{ + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + int l=elapsedLoops; + real factor; + + //Init + i = tid; + sdata[tid] = 0; + + //Reduction + while (i < num_k-2*l*mTPB) + { + factor = infl_factor[i+2*l*mTPB] / 2; + + sdata[tid] += factor * (rho_hat[i+2*l*mTPB]*rho_hat[i+2*l*mTPB] + rho_hat[i+2*l*mTPB+num_k]*rho_hat[i+2*l*mTPB+num_k]); + if (nIsPow2 || i + blockSize < num_k-2*l*mTPB) + { + factor = infl_factor[i+2*l*mTPB+blockSize] / 2; + sdata[tid] += factor * (rho_hat[i+2*l*mTPB+blockSize]*rho_hat[i+2*l*mTPB+blockSize] + rho_hat[i+2*l*mTPB+num_k+blockSize]*rho_hat[i+2*l*mTPB+num_k+blockSize]); + } + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + energy_reci[0] += sdata[0]*coulomb_prefactor; + } +} +//q squared +template +__global__ void EwaldGPU_q_sqr_MaxThreads(real *q_i, real *q_sqr, int N, int maxThreadsPerBlock,int loops) +{ + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + int l = loops; + + //Init + i = tid; + sdata[tid] = 0; + + //Reduction + while (i < mTPB) + { + sdata[tid] += q_i[i+2*l*mTPB]*q_i[i+2*l*mTPB]; + //BECAUSE nIsPow2=True + sdata[tid] += q_i[i+2*l*mTPB+blockSize]*q_i[i+2*l*mTPB+blockSize]; + + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + q_sqr[0] += sdata[0]; + } + __syncthreads(); +} +template +__global__ void EwaldGPU_q_sqr_LowThreads(real *q_i, real *q_sqr, int N, int maxThreadsPerBlock,int elapsedLoops) +{ + //Variables + extern __shared__ real sdata[]; + int tid = threadIdx.x; + int i = tid; + int gridSize = blockSize*2*gridDim.x; + int mTPB=maxThreadsPerBlock; + int l=elapsedLoops; + + //Init + i = tid; + sdata[tid] = 0; + + //Reduction + while (i < N-2*l*mTPB) + { + sdata[tid] += q_i[i+2*l*mTPB]*q_i[i+2*l*mTPB]; + if (nIsPow2 || i + blockSize < N-2*l*mTPB) + { + sdata[tid] += q_i[i+2*l*mTPB+blockSize]*q_i[i+2*l*mTPB+blockSize]; + } + i += gridSize; + } + __syncthreads(); + + if (blockSize >= 1024){ if (tid < 512) { sdata[tid] += sdata[tid + 512]; } __syncthreads(); } + if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); } + if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); } + if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); } + if (tid < 32) { + if (blockSize >= 64) {sdata[tid] += sdata[tid + 32]; __syncthreads(); } + if (blockSize >= 32) {sdata[tid] += sdata[tid + 16]; __syncthreads(); } + if (blockSize >= 16) {sdata[tid] += sdata[tid + 8]; __syncthreads(); } + if (blockSize >= 8) {sdata[tid] += sdata[tid + 4]; __syncthreads(); } + if (blockSize >= 4) {sdata[tid] += sdata[tid + 2]; __syncthreads(); } + if (blockSize >= 2) {sdata[tid] += sdata[tid + 1]; __syncthreads(); } + } + //Write result for this block to global memory + if (tid == 0) + { + q_sqr[0] += sdata[0]; + } +} + +//Ewaldgpuforce +EwaldgpuForce::EwaldgpuForce(SystemInterface &s, double rcut, int num_kx, int num_ky, int num_kz, double alpha) +:m_dev_k(NULL), m_k(NULL), m_dev_rho_hat(NULL), m_rho_hat(NULL), m_dev_infl_factor(NULL), m_infl_factor(NULL), m_dev_energy_reci(NULL), m_energy_reci(NULL), m_dev_q_sqr(NULL), m_q_sqr(NULL) +{ + //Interface sanity checks + if(!s.requestFGpu()) + std::cerr << "EwaldgpuForce needs access to forces on GPU!" << std::endl; + + if(!s.requestRGpu()) + std::cerr << "EwaldgpuForce needs access to positions on GPU!" << std::endl; + + if(!s.requestQGpu()) + std::cerr << "EwaldgpuForce needs access to charges on GPU!" << std::endl; + + //Initialization values + m_rcut = rcut; + m_num_kx = num_kx; + m_num_ky = num_ky; + m_num_kz = num_kz; + m_alpha = alpha; + m_isTuned = false; + + //Compute the number of k's in k-sphere + compute_num_k(); + + set_params(m_rcut, m_num_kx, m_num_ky, m_num_kz, m_alpha); + if(ewaldgpu_params.time_calc_steps==-1) ewaldgpu_params.time_calc_steps = determine_calc_time_steps(); +} +EwaldgpuForce::~EwaldgpuForce() +{ + HANDLE_ERROR(cudaFree(m_k)); + HANDLE_ERROR(cudaFree(m_dev_k)); + HANDLE_ERROR(cudaFree(m_forces_reci)); + HANDLE_ERROR(cudaFree(m_dev_forces_reci)); + HANDLE_ERROR(cudaFree(m_infl_factor)); + HANDLE_ERROR(cudaFree(m_dev_infl_factor)); + HANDLE_ERROR(cudaFree(m_rho_hat)); + HANDLE_ERROR(cudaFree(m_dev_rho_hat)); + HANDLE_ERROR(cudaFree(m_energy_reci)); + HANDLE_ERROR(cudaFree(m_dev_energy_reci)); + HANDLE_ERROR(cudaFree(m_q_sqr)); + HANDLE_ERROR(cudaFree(m_dev_q_sqr)); +} +void EwaldgpuForce::setup(SystemInterface &s) +{ + if (s.npart_gpu() == m_N and ewaldgpu_params.isTunedFlag) // unchanged + { + return; + } + ewaldgpu_params.isTunedFlag = ewaldgpu_params.isTuned; + + //Initialization values + m_rcut = ewaldgpu_params.rcut; + m_num_kx = ewaldgpu_params.num_kx; + m_num_ky = ewaldgpu_params.num_ky; + m_num_kz = ewaldgpu_params.num_kz; + m_alpha = ewaldgpu_params.alpha; + m_coulomb_prefactor = coulomb.prefactor; + + //Compute the number of k's in k-sphere + compute_num_k(); + + if (m_dev_k) + HANDLE_ERROR(cudaFree(m_dev_k)); + HANDLE_ERROR(cudaMalloc((void**)&(m_dev_k),3*m_num_k*sizeof(real))); + if (m_k) + HANDLE_ERROR(cudaFreeHost(m_k)); + HANDLE_ERROR(cudaMallocHost((void**)&(m_k),3*m_num_k*sizeof(real))); + if (m_dev_rho_hat) + HANDLE_ERROR(cudaFree(m_dev_rho_hat)); + HANDLE_ERROR(cudaMalloc((void**)&(m_dev_rho_hat),2*m_num_k*sizeof(real))); + if (m_rho_hat) + HANDLE_ERROR(cudaFreeHost(m_rho_hat)); + HANDLE_ERROR(cudaMallocHost((void**)&(m_rho_hat),2*m_num_k*sizeof(real))); + if (m_dev_infl_factor) + HANDLE_ERROR(cudaFree(m_dev_infl_factor)); + HANDLE_ERROR(cudaMalloc((void**)&(m_dev_infl_factor),m_num_k*sizeof(real))); + if (m_infl_factor) + HANDLE_ERROR(cudaFreeHost(m_infl_factor)); + HANDLE_ERROR(cudaMallocHost((void**)&(m_infl_factor),m_num_k*sizeof(real))); + if (m_dev_energy_reci) + HANDLE_ERROR(cudaFree(m_dev_energy_reci)); + HANDLE_ERROR(cudaMalloc((void**)&(m_dev_energy_reci),sizeof(real))); + if (m_energy_reci) + HANDLE_ERROR(cudaFreeHost(m_energy_reci)); + HANDLE_ERROR(cudaMallocHost((void**)&(m_energy_reci),sizeof(real))); + if (m_dev_q_sqr) + HANDLE_ERROR(cudaFree(m_dev_q_sqr)); + HANDLE_ERROR(cudaMalloc((void**)&(m_dev_q_sqr),sizeof(real))); + if (m_q_sqr) + HANDLE_ERROR(cudaFreeHost(m_q_sqr)); + HANDLE_ERROR(cudaMallocHost((void**)&(m_q_sqr),sizeof(real))); + + //Resize box + m_box_l[0] = s.box()[0]; + m_box_l[1] = s.box()[1]; + m_box_l[2] = s.box()[2]; + + + //Particle number + m_N = s.npart_gpu(); + + //Compute reciprocal space vectors k + m_V=m_box_l[0]*m_box_l[1]*m_box_l[2]; + compute_k_AND_influence_factor(); + + //Init GPU stream + stream0 = (cudaStream_t *) malloc (1 * sizeof(cudaStream_t)); + start = (cudaEvent_t *) malloc (1 * sizeof(cudaEvent_t)); + stop = (cudaEvent_t *) malloc (1 * sizeof(cudaEvent_t)); + HANDLE_ERROR(cudaEventCreate(&(*start))); + HANDLE_ERROR(cudaEventCreate(&(*stop))); + HANDLE_ERROR(cudaStreamCreate(&(*stream0))); + HANDLE_ERROR(cudaDeviceSynchronize()); + HANDLE_ERROR(cudaEventRecord(*start, 0)); + + //Parameters + set_params(m_rcut, m_num_kx, m_num_ky, m_num_kz, m_alpha); + + //q squared + memset(m_q_sqr,0,sizeof(real)); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_q_sqr, m_q_sqr, sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + GPU_q_sqr(s); +} + +//Compute forces and energy +void EwaldgpuForce::computeForces(SystemInterface &s) +{ + if (coulomb.method != COULOMB_EWALD_GPU) // EWALDGPU was disabled. nobody cares about our calculations anymore + { + std::cerr << "EwaldGPU: coulomb.method has been changed, skipping calculation" << std::endl; + return; + } + + setup(s); + + //Resize box + m_box_l[0] = s.box()[0]; + m_box_l[1] = s.box()[1]; + m_box_l[2] = s.box()[2]; + + //Set to NULL + memset(m_rho_hat,0,2*m_num_k*sizeof(real)); + memset(m_energy_reci,0,sizeof(real)); + + //Copy arrays on the GPU + HANDLE_ERROR( cudaMemcpyAsync( m_dev_k, m_k, 3*m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 )); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_rho_hat, m_rho_hat, 2*m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_infl_factor, m_infl_factor, m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_energy_reci, m_energy_reci, sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + + //Start GPU calculation + GPU_Forces(s); +} +void EwaldgpuForce::computeEnergy(SystemInterface &s) +{ + if (coulomb.method != COULOMB_EWALD_GPU) // EWALDGPU was disabled. nobody cares about our calculations anymore + { + std::cerr << "EwaldGPU: coulomb.method has been changed, skipping calculation" << std::endl; + return; + } + setup(s); + + //Resize box + m_box_l[0] = s.box()[0]; + m_box_l[1] = s.box()[1]; + m_box_l[2] = s.box()[2]; + //Set to NULL + memset(m_energy_reci,0,sizeof(real)); + //Copy arrays on the GPU + HANDLE_ERROR( cudaMemcpyAsync( m_dev_k, m_k, 3*m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 )); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_rho_hat, m_rho_hat, 2*m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_infl_factor, m_infl_factor, m_num_k*sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + HANDLE_ERROR( cudaMemcpyAsync( m_dev_energy_reci, m_energy_reci, sizeof(real), cudaMemcpyHostToDevice, 0 ) ); + + //Start GPU calculation + GPU_Energy(s); + //Self energy + EwaldCPU_EnergySelf(); + //Total energy + m_energy_tot = m_energy_reci[0] + m_energy_self; + + HANDLE_ERROR( cudaMemcpy(&(((CUDA_energy*)s.eGpu())->coulomb), &m_energy_tot,sizeof(real),cudaMemcpyHostToDevice ) ); +} + +//Kernel calls +void EwaldgpuForce::GPU_Forces(SystemInterface &s) +{ + //Maximum Blocks/Threads + int maxThreadsPerBlockStructurFactor=256; + int maxThreadsPerBlockForce=128; + + /*Kernel*/ + //Blocks, threads + int threads; + int blocks; + cudaDeviceProp prop; + HANDLE_ERROR( cudaGetDeviceProperties( &prop, 0 ) ); + + /******************************************************************************************** + Structure factor / Rho_hat + ********************************************************************************************/ + + //Blocks, threads + getNumBlocksAndThreads(m_N, prop.sharedMemPerBlock, maxThreadsPerBlockStructurFactor, blocks, threads); + blocks=(int)ceil(sqrt(m_num_k)); + dim3 dimBlock1(threads, 1, 1); + dim3 dimGrid1(blocks, blocks, 1); + //Shared memory size + int smemSize = 2 * 2 * threads * sizeof(real); + + //Loops needed in EwaldGPU_Rho_hat_MaxThreads + int loops=m_N/(2*maxThreadsPerBlockStructurFactor); + + //Kernel call + for(int l=0;l<<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_Rho_hat_MaxThreads<512,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_Rho_hat_MaxThreads<256,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_Rho_hat_MaxThreads<128,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_Rho_hat_MaxThreads<64,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_Rho_hat_MaxThreads<32,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_Rho_hat_MaxThreads<16,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_Rho_hat_MaxThreads<8,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_Rho_hat_MaxThreads<4,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_Rho_hat_MaxThreads<2,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + } + } + + //Blocks, threads + getNumBlocksAndThreads(m_N-2*loops*maxThreadsPerBlockStructurFactor, prop.sharedMemPerBlock, maxThreadsPerBlockStructurFactor, blocks, threads); + blocks=(int)ceil(sqrt(m_num_k)); + dim3 dimBlock2(threads, 1, 1); + dim3 dimGrid2(blocks, blocks, 1); + + //Kernel call + if (isPow2(m_N-2*loops*maxThreadsPerBlockStructurFactor) && (m_N-2*loops*maxThreadsPerBlockStructurFactor != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_Rho_hat_LowThreads<1024,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_Rho_hat_LowThreads<512,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_Rho_hat_LowThreads<256,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_Rho_hat_LowThreads<128,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_Rho_hat_LowThreads<64,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_Rho_hat_LowThreads<32,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_Rho_hat_LowThreads<16,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_Rho_hat_LowThreads<8,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_Rho_hat_LowThreads<4,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_Rho_hat_LowThreads<2,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_Rho_hat_LowThreads<1,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + if (!isPow2(m_N-2*loops*maxThreadsPerBlockStructurFactor) && (m_N-2*loops*maxThreadsPerBlockStructurFactor != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_Rho_hat_LowThreads<1024,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_Rho_hat_LowThreads<512,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_Rho_hat_LowThreads<256,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_Rho_hat_LowThreads<128,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_Rho_hat_LowThreads<64,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_Rho_hat_LowThreads<32,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_Rho_hat_LowThreads<16,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_Rho_hat_LowThreads<8,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_Rho_hat_LowThreads<4,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_Rho_hat_LowThreads<2,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_Rho_hat_LowThreads<1,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_N,m_num_k,maxThreadsPerBlockStructurFactor,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + + //Copy the arrays back from the GPU to the CPU + HANDLE_ERROR(cudaMemcpy( m_rho_hat, m_dev_rho_hat,2*m_num_k*sizeof(real),cudaMemcpyDeviceToHost)); + + /******************************************************************************************** + Forces long range + ********************************************************************************************/ + + //Blocks, threads + getNumBlocksAndThreads(m_num_k, prop.sharedMemPerBlock, maxThreadsPerBlockForce, blocks, threads); + blocks=(int)ceil(sqrt(m_N)); + dim3 dimBlock3(threads, 1, 1); + dim3 dimGrid3(blocks, blocks, 1); + + //Shared memory size + smemSize = 3 * 2 * threads * sizeof(real); + + //Loops needed in EwaldGPU_ForcesReci_MaxThreads + loops=m_num_k/(2*maxThreadsPerBlockForce); + + //Kernel call + for(int l=0;l<<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_ForcesReci_MaxThreads<512,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_ForcesReci_MaxThreads<256,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_ForcesReci_MaxThreads<128,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_ForcesReci_MaxThreads<64,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_ForcesReci_MaxThreads<32,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_ForcesReci_MaxThreads<16,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_ForcesReci_MaxThreads<8,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_ForcesReci_MaxThreads<4,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_ForcesReci_MaxThreads<2,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,l);cuda_check_error(dimBlock3, dimGrid3, 0, __FILE__, __LINE__);break; + } + } + + //Blocks, threads + getNumBlocksAndThreads(m_num_k-2*loops*maxThreadsPerBlockForce, prop.sharedMemPerBlock, maxThreadsPerBlockForce, blocks, threads); + blocks=(int)ceil(sqrt(m_N)); + dim3 dimBlock4(threads, 1, 1); + dim3 dimGrid4(blocks, blocks, 1); + + //Shared memory size + smemSize = 3 * 2 * threads * sizeof(real); + + //Kernel call + if (isPow2(m_num_k-2*loops*maxThreadsPerBlockForce) && (m_num_k-2*loops*maxThreadsPerBlockForce != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_ForcesReci_LowThreads<1024,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_ForcesReci_LowThreads<512,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_ForcesReci_LowThreads<256,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_ForcesReci_LowThreads<128,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_ForcesReci_LowThreads<64,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_ForcesReci_LowThreads<32,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_ForcesReci_LowThreads<16,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_ForcesReci_LowThreads<8,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_ForcesReci_LowThreads<4,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_ForcesReci_LowThreads<2,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_ForcesReci_LowThreads<1,true><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + } + } + if (!isPow2(m_num_k-2*loops*maxThreadsPerBlockForce) && (m_num_k-2*loops*maxThreadsPerBlockForce != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_ForcesReci_LowThreads<1024,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_ForcesReci_LowThreads<512,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_ForcesReci_LowThreads<256,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_ForcesReci_LowThreads<128,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_ForcesReci_LowThreads<64,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_ForcesReci_LowThreads<32,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_ForcesReci_LowThreads<16,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_ForcesReci_LowThreads<8,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_ForcesReci_LowThreads<4,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_ForcesReci_LowThreads<2,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_ForcesReci_LowThreads<1,false><<>>(m_dev_k,s.rGpuBegin(),s.qGpuBegin(),m_dev_rho_hat,m_dev_infl_factor,s.fGpuBegin(),m_N,m_num_k,m_V,m_coulomb_prefactor,maxThreadsPerBlockForce,loops); cuda_check_error(dimBlock4, dimGrid4, 0, __FILE__, __LINE__);break; + } + } +} +void EwaldgpuForce::GPU_Energy(SystemInterface &s) +{ + //Maximum Blocks/Threads + int maxThreadsPerBlockEnergie=128; + + /*Kernel*/ + //Blocks, threads + int threads; + int blocks; + cudaDeviceProp prop; + HANDLE_ERROR( cudaGetDeviceProperties( &prop, 0 ) ); + + /******************************************************************************************** + Energy + ********************************************************************************************/ + + //Blocks, threads + getNumBlocksAndThreads(m_num_k, prop.sharedMemPerBlock, maxThreadsPerBlockEnergie, blocks, threads); + blocks=1; + dim3 dimBlock1(threads, 1, 1); + dim3 dimGrid1(blocks, 1, 1); + + //Shared memory size + int smemSize = 1 * 2 * threads * sizeof(real); + + //Loops needed in EwaldGPU_ForcesReci_MaxThreads + int loops=m_num_k/(2*maxThreadsPerBlockEnergie); + + //Kernel call + for(int l=0;l<<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_EnergyReci_MaxThreads<512,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_EnergyReci_MaxThreads<256,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_EnergyReci_MaxThreads<128,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_EnergyReci_MaxThreads<64,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_EnergyReci_MaxThreads<32,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_EnergyReci_MaxThreads<16,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_EnergyReci_MaxThreads<8,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_EnergyReci_MaxThreads<4,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_EnergyReci_MaxThreads<2,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,l,m_coulomb_prefactor);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + } + } + + //Blocks, threads + getNumBlocksAndThreads(m_num_k-2*loops*maxThreadsPerBlockEnergie, prop.sharedMemPerBlock, maxThreadsPerBlockEnergie, blocks, threads); + blocks=1; + dim3 dimBlock2(threads, 1, 1); + dim3 dimGrid2(blocks, 1, 1); + + //Shared memory size + smemSize = 1 * 2 * threads * sizeof(real); + + //Kernel call + if (isPow2(m_num_k-2*loops*maxThreadsPerBlockEnergie) && (m_num_k-2*loops*maxThreadsPerBlockEnergie != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_EnergyReci_LowThreads<1024,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_EnergyReci_LowThreads<512,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_EnergyReci_LowThreads<256,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_EnergyReci_LowThreads<128,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_EnergyReci_LowThreads<64,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_EnergyReci_LowThreads<32,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_EnergyReci_LowThreads<16,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_EnergyReci_LowThreads<8,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_EnergyReci_LowThreads<4,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_EnergyReci_LowThreads<2,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_EnergyReci_LowThreads<1,true><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + if (!isPow2(m_num_k-2*loops*maxThreadsPerBlockEnergie) && (m_num_k-2*loops*maxThreadsPerBlockEnergie != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_EnergyReci_LowThreads<1024,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_EnergyReci_LowThreads<512,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_EnergyReci_LowThreads<256,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_EnergyReci_LowThreads<128,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_EnergyReci_LowThreads<64,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_EnergyReci_LowThreads<32,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_EnergyReci_LowThreads<16,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_EnergyReci_LowThreads<8,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_EnergyReci_LowThreads<4,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_EnergyReci_LowThreads<2,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_EnergyReci_LowThreads<1,false><<>>(m_dev_rho_hat,m_dev_infl_factor,&(((CUDA_energy*)s.eGpu())->coulomb),m_N,m_num_k,m_V,maxThreadsPerBlockEnergie,loops,m_coulomb_prefactor); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + + //Copy the values back from the GPU to the CPU + HANDLE_ERROR( cudaMemcpy( m_energy_reci, &(((CUDA_energy*)s.eGpu())->coulomb),sizeof(real),cudaMemcpyDeviceToHost ) ); +} +void EwaldgpuForce::GPU_q_sqr(SystemInterface &s) +{ + //Maximum Blocks/Threads + int maxThreadsPerBlock_q_sqr=128; + + /*Kernel*/ + //Blocks, threads + int threads; + int blocks; + cudaDeviceProp prop; + HANDLE_ERROR( cudaGetDeviceProperties( &prop, 0 ) ); + + /******************************************************************************************** + q squared + ********************************************************************************************/ + + //Blocks, threads + getNumBlocksAndThreads(m_N, prop.sharedMemPerBlock, maxThreadsPerBlock_q_sqr, blocks, threads); + blocks=1; + dim3 dimBlock1(threads, 1, 1); + dim3 dimGrid1(blocks, 1, 1); + + //Shared memory size + int smemSize = 1 * 2 * threads * sizeof(real); + + //Loops needed in EwaldGPU_ForcesReci_MaxThreads + int loops=m_N/(2*maxThreadsPerBlock_q_sqr); + + //Kernel call + for(int l=0;l<<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_q_sqr_MaxThreads<512,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_q_sqr_MaxThreads<256,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_q_sqr_MaxThreads<128,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_q_sqr_MaxThreads<64,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_q_sqr_MaxThreads<32,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_q_sqr_MaxThreads<16,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_q_sqr_MaxThreads<8,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_q_sqr_MaxThreads<4,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_q_sqr_MaxThreads<2,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,l);cuda_check_error(dimBlock1, dimGrid1, 0, __FILE__, __LINE__);break; + } + } + + //Blocks, threads + getNumBlocksAndThreads(m_N-2*loops*maxThreadsPerBlock_q_sqr, prop.sharedMemPerBlock, maxThreadsPerBlock_q_sqr, blocks, threads); + blocks=1; + dim3 dimBlock2(threads, 1, 1); + dim3 dimGrid2(blocks, 1, 1); + + //Shared memory size + smemSize = 1 * 2 * threads * sizeof(real); + + //Kernel call + if (isPow2(m_N-2*loops*maxThreadsPerBlock_q_sqr) && (m_N-2*loops*maxThreadsPerBlock_q_sqr != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_q_sqr_LowThreads<1024,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_q_sqr_LowThreads<512,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_q_sqr_LowThreads<256,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_q_sqr_LowThreads<128,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_q_sqr_LowThreads<64,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_q_sqr_LowThreads<32,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_q_sqr_LowThreads<16,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_q_sqr_LowThreads<8,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_q_sqr_LowThreads<4,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_q_sqr_LowThreads<2,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_q_sqr_LowThreads<1,true><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + if (!isPow2(m_N-2*loops*maxThreadsPerBlock_q_sqr) && (m_N-2*loops*maxThreadsPerBlock_q_sqr != 0)) + { + switch (threads) + { + case 1024: EwaldGPU_q_sqr_LowThreads<1024,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 512: EwaldGPU_q_sqr_LowThreads<512,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 256: EwaldGPU_q_sqr_LowThreads<256,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 128: EwaldGPU_q_sqr_LowThreads<128,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 64: EwaldGPU_q_sqr_LowThreads<64,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 32: EwaldGPU_q_sqr_LowThreads<32,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 16: EwaldGPU_q_sqr_LowThreads<16,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 8: EwaldGPU_q_sqr_LowThreads<8,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 4: EwaldGPU_q_sqr_LowThreads<4,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 2: EwaldGPU_q_sqr_LowThreads<2,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + case 1: EwaldGPU_q_sqr_LowThreads<1,false><<>>(s.qGpuBegin(),m_dev_q_sqr,m_N,maxThreadsPerBlock_q_sqr,loops); cuda_check_error(dimBlock2, dimGrid2, 0, __FILE__, __LINE__);break; + } + } + + //Copy the values back from the GPU to the CPU + HANDLE_ERROR( cudaMemcpy( m_q_sqr, m_dev_q_sqr,sizeof(real),cudaMemcpyDeviceToHost) ); +} +void cuda_check_error(const dim3 &block, const dim3 &grid, const char *function, const char *file, unsigned int line) +{ + err=cudaGetLastError(); + if (err!=cudaSuccess) + { + fprintf(stderr, "%d: error \"%s\" calling %s with dim %d %d %d, grid %d %d %d in %s:%u\n", this_node, cudaGetErrorString(err), function, block.x, block.y, block.z, grid.x, grid.y, grid.z,file, line); + exit(EXIT_FAILURE); + } +} + +//Compute blocks and threads +int EwaldgpuForce::nextPow2(int x) +{ + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ++x; +} +bool EwaldgpuForce::isPow2(int x) +{ + if(x==1) return false; + else return ((x&(x-1))==0); +} +void EwaldgpuForce::getNumBlocksAndThreads(int Size, int maxBlocks, int maxThreads, int &blocks, int &threads) +{ + //Get device capability, to avoid block/grid size exceed the upbound + cudaDeviceProp prop; + int device; + + HANDLE_ERROR(cudaGetDevice(&device)); + HANDLE_ERROR(cudaGetDeviceProperties(&prop,device)); + + threads = (Size < maxThreads*2) ? nextPow2((Size + 1)/ 2) : maxThreads; +} + +#endif diff --git a/src/core/actor/HarmonicWell.cpp b/src/core/actor/HarmonicWell.cpp new file mode 100644 index 00000000000..ab2b9aac73d --- /dev/null +++ b/src/core/actor/HarmonicWell.cpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "HarmonicWell.hpp" +#include "EspressoSystemInterface.hpp" +#include "forces.hpp" + +#ifdef CUDA +HarmonicWell:: +HarmonicWell(float x1, float x2, float x3, float _k, SystemInterface &s) { + x = x1; + y = x2; + z = x3; + k = _k; + + if(!s.requestFGpu()) + std::cerr << "HarmonicWell needs access to forces on GPU!" << std::endl; + + if(!s.requestRGpu()) + std::cerr << "HarmonicWell needs access to positions on GPU!" << std::endl; +} + +#endif diff --git a/src/core/actor/HarmonicWell.hpp b/src/core/actor/HarmonicWell.hpp new file mode 100644 index 00000000000..e94067cfd3b --- /dev/null +++ b/src/core/actor/HarmonicWell.hpp @@ -0,0 +1,53 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _ACTOR_HARMONICWELL_HPP +#define _ACTOR_HARMONICWELL_HPP + +#include "config.hpp" + +#ifdef CUDA + +#include "Actor.hpp" +#include "SystemInterface.hpp" +#include + +void HarmonicWell_kernel_wrapper(float x, float y, float z, float k, + int n, float *pos, float *f); + +class HarmonicWell : public Actor { +public: + HarmonicWell(float x1, float x2, float x3, float _k, SystemInterface &s); + + virtual void computeForces(SystemInterface &s) { + HarmonicWell_kernel_wrapper(x,y,z,k,s.npart_gpu(), + s.rGpuBegin(), s.fGpuBegin()); + }; + + virtual void computeEnergy(SystemInterface &s) { + std::cout << "HarmonidWell does not currently support energies" << std::endl; + }; + + virtual ~HarmonicWell() {} +protected: + float x,y,z; + float k; +}; + +#endif +#endif diff --git a/src/core/actor/HarmonicWell_cuda.cu b/src/core/actor/HarmonicWell_cuda.cu new file mode 100644 index 00000000000..661d4ab3387 --- /dev/null +++ b/src/core/actor/HarmonicWell_cuda.cu @@ -0,0 +1,54 @@ +/* + Copyright (C) 2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "HarmonicWell.hpp" + +#include "cuda_utils.hpp" +#include + +__global__ void HarmonicWell_kernel(float x, float y, float z, float k, + int n, float *pos, float *f) { + + int id = blockIdx.x * blockDim.x + threadIdx.x; + + if(id >= n) + return; + + f[3*id + 0] += k*(x - pos[3*id + 0]); + f[3*id + 1] += k*(y - pos[3*id + 1]); + f[3*id + 2] += k*(z - pos[3*id + 2]); +} + + +void HarmonicWell_kernel_wrapper(float x, float y, float z, float k, int n, float *pos, float *f) { + dim3 grid(1,1,1); + dim3 block(1,1,1); + + if(n == 0) + return; + + if(n <= 512) { + grid.x = 1; + block.x = n; + } else { + grid.x = n/512 + 1; + block.x = 512; + } + + KERNELCALL(HarmonicWell_kernel,grid,block,(x, y, z, k, n, pos, f)) +} diff --git a/src/core/actor/Mmm1dgpuForce.cpp b/src/core/actor/Mmm1dgpuForce.cpp new file mode 100644 index 00000000000..df7ae81c82b --- /dev/null +++ b/src/core/actor/Mmm1dgpuForce.cpp @@ -0,0 +1,19 @@ +#include "actor/Mmm1dgpuForce.hpp" +#include "EspressoSystemInterface.hpp" +#include "communication.hpp" +#include "interaction_data.hpp" +#include "forces.hpp" +#include "grid.hpp" + +#ifdef MMM1D_GPU + +void Mmm1dgpuForce::check_periodicity() +{ + if (PERIODIC(0) || PERIODIC(1) || !PERIODIC(2)) + { + std::cerr << "MMM1D requires periodicity (0,0,1)" << std::endl; + exit(EXIT_FAILURE); + } +} + +#endif diff --git a/src/core/actor/Mmm1dgpuForce.hpp b/src/core/actor/Mmm1dgpuForce.hpp new file mode 100644 index 00000000000..681785e1553 --- /dev/null +++ b/src/core/actor/Mmm1dgpuForce.hpp @@ -0,0 +1,73 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "config.hpp" + +#ifdef MMM1D_GPU + +#include "SystemInterface.hpp" +#include "Actor.hpp" +#include + +typedef float mmm1dgpu_real; + +class Mmm1dgpuForce : public Actor +{ +public: + // constructor + Mmm1dgpuForce(SystemInterface &s, mmm1dgpu_real coulomb_prefactor, mmm1dgpu_real maxPWerror, mmm1dgpu_real far_switch_radius = -1, int bessel_cutoff = -1); + ~Mmm1dgpuForce(); + // interface methods + void computeForces(SystemInterface &s); + void computeEnergy(SystemInterface &s); + // configuration methods + void setup(SystemInterface &s); + void tune(SystemInterface &s, mmm1dgpu_real _maxPWerror, mmm1dgpu_real _far_switch_radius, int _bessel_cutoff); + void set_params(mmm1dgpu_real _boxz, mmm1dgpu_real _coulomb_prefactor, mmm1dgpu_real _maxPWerror, mmm1dgpu_real _far_switch_radius, int _bessel_cutoff, bool manual = false); + +private: + // CUDA parameters + unsigned int numThreads; + unsigned int numBlocks(SystemInterface &s); + + // the box length currently set on the GPU + // Needed to make sure it hasn't been modified using setmd after inter coulomb was used. + mmm1dgpu_real host_boxz; + // the number of particles we had during the last run. Needed to check if we have to realloc dev_forcePairs + int host_npart; + bool need_tune; + + // pairs==0: return forces using atomicAdd + // pairs==1: return force pairs + // pairs==2: return forces using a global memory reduction + int pairs; + // variables for forces and energies calculated pre-reduction + mmm1dgpu_real *dev_forcePairs, *dev_energyBlocks; + + // MMM1D parameters + mmm1dgpu_real coulomb_prefactor, maxPWerror, far_switch_radius; + int bessel_cutoff; + + // run a single force calculation and return the time it takes using high-precision CUDA timers + float force_benchmark(SystemInterface &s); + + // some functions to move MPI dependencies out of the .cu file + void check_periodicity(); +}; + +#endif diff --git a/src/core/actor/Mmm1dgpuForce_cuda.cu b/src/core/actor/Mmm1dgpuForce_cuda.cu new file mode 100644 index 00000000000..333b8456590 --- /dev/null +++ b/src/core/actor/Mmm1dgpuForce_cuda.cu @@ -0,0 +1,580 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "actor/Mmm1dgpuForce.hpp" +#include "cuda_utils.hpp" + +#ifdef MMM1D_GPU + +// the code is mostly multi-GPU capable, but Espresso is not yet +const int deviceCount = 1; +float multigpu_factors[] = {1.0}; +#define cudaSetDevice(d) + +#include "mmm-common_cuda.hpp" +#include "mmm1d.hpp" +#include "interaction_data.hpp" +#include "EspressoSystemInterface.hpp" + +#if defined(OMPI_MPI_H) || defined(_MPI_H) +#error CU-file includes mpi.h! This should not happen! +#endif + +__device__ inline void atomicadd(float* address, float value) +{ +#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 + atomicAdd(address, value); +#elif __CUDA_ARCH__ >= 110 + int oldval, newval, readback; + oldval = __float_as_int(*address); + newval = __float_as_int(__int_as_float(oldval) + value); + while ((readback=atomicCAS((int *)address, oldval, newval)) != oldval) + { + oldval = readback; + newval = __float_as_int(__int_as_float(oldval) + value); + } +#else +#error atomicAdd needs compute capability 1.1 or higher +#endif +} + +const mmm1dgpu_real C_GAMMAf = C_GAMMA; +const mmm1dgpu_real C_2PIf = C_2PI; + +__constant__ mmm1dgpu_real far_switch_radius_2 = 0.05*0.05; +__constant__ mmm1dgpu_real boxz; +__constant__ mmm1dgpu_real uz; +__constant__ mmm1dgpu_real coulomb_prefactor = 1.0; +__constant__ int bessel_cutoff = 5; +__constant__ mmm1dgpu_real maxPWerror = 1e-5; + +Mmm1dgpuForce::Mmm1dgpuForce(SystemInterface &s, mmm1dgpu_real _coulomb_prefactor, mmm1dgpu_real _maxPWerror, + mmm1dgpu_real _far_switch_radius, int _bessel_cutoff) +:coulomb_prefactor(_coulomb_prefactor), maxPWerror(_maxPWerror), far_switch_radius(_far_switch_radius), + bessel_cutoff(_bessel_cutoff), host_boxz(0), host_npart(0), pairs(-1), dev_forcePairs(NULL), dev_energyBlocks(NULL), + numThreads(64), need_tune(true) +{ + // interface sanity checks + if(!s.requestFGpu()) + std::cerr << "Mmm1dgpuForce needs access to forces on GPU!" << std::endl; + + if(!s.requestRGpu()) + std::cerr << "Mmm1dgpuForce needs access to positions on GPU!" << std::endl; + + if(!s.requestQGpu()) + std::cerr << "Mmm1dgpuForce needs access to charges on GPU!" << std::endl; + + // system sanity checks + check_periodicity(); + + modpsi_init(); +} + +void Mmm1dgpuForce::setup(SystemInterface &s) +{ + if (s.box()[2] <= 0) + { + std::cerr << "Error: Please set box length before initializing MMM1D!" << std::endl; + exit(EXIT_FAILURE); + } + if (need_tune == true && s.npart_gpu() > 0) + { + set_params(s.box()[2], coulomb.prefactor, maxPWerror, far_switch_radius, bessel_cutoff); + tune(s, maxPWerror, far_switch_radius, bessel_cutoff); + } + if (s.box()[2] != host_boxz) + { + set_params(s.box()[2], 0,-1,-1,-1); + } + if (s.npart_gpu() == host_npart) // unchanged + { + return; + } + + // For all but the largest systems, it is faster to store force pairs and then sum them up. + // Atomics are just so slow: so unless we're limited by memory, do the latter. + pairs = 2; + for (int d = 0; d < deviceCount; d++) + { + cudaSetDevice(d); + + size_t freeMem, totalMem; + cudaMemGetInfo(&freeMem, &totalMem); + if (freeMem/2 < 3*s.npart_gpu()*s.npart_gpu()*sizeof(mmm1dgpu_real)) // don't use more than half the device's memory + { + std::cerr << "Switching to atomicAdd due to memory constraints." << std::endl; + pairs = 0; + break; + } + } + if (dev_forcePairs) + cudaFree(dev_forcePairs); + if (pairs) // we need memory to store force pairs + { + cuda_safe_mem( cudaMalloc((void**)&dev_forcePairs, 3*s.npart_gpu()*s.npart_gpu()*sizeof(mmm1dgpu_real)) ); + } + if (dev_energyBlocks) + cudaFree(dev_energyBlocks); + cuda_safe_mem( cudaMalloc((void**)&dev_energyBlocks, numBlocks(s)*sizeof(mmm1dgpu_real)) ); + host_npart = s.npart_gpu(); +} + +unsigned int Mmm1dgpuForce::numBlocks(SystemInterface &s) +{ + int b = s.npart_gpu()*s.npart_gpu()/numThreads+1; + if (b > 65535) + b = 65535; + return b; +} + +Mmm1dgpuForce::~Mmm1dgpuForce() { + modpsi_destroy(); + cudaFree(dev_forcePairs); +} + +__forceinline__ __device__ mmm1dgpu_real sqpow(mmm1dgpu_real x) +{ + return pow(x,2); +} +__forceinline__ __device__ mmm1dgpu_real cbpow(mmm1dgpu_real x) +{ + return pow(x,3); +} + +__device__ void sumReduction(mmm1dgpu_real *input, mmm1dgpu_real *sum) +{ + int tid = threadIdx.x; + for (int i = blockDim.x/2; i > 0; i /= 2) + { + __syncthreads(); + if (tid < i) + input[tid] += input[i+tid]; + } + __syncthreads(); + if (tid == 0) + sum[0] = input[0]; +} + +__global__ void sumKernel(mmm1dgpu_real *data, int N) +{ + extern __shared__ mmm1dgpu_real partialsums[]; + if (blockIdx.x != 0) return; + int tid = threadIdx.x; + mmm1dgpu_real result = 0; + + for (int i = 0; i < N; i += blockDim.x) + { + if (i+tid >= N) + partialsums[tid] = 0; + else + partialsums[tid] = data[i+tid]; + + sumReduction(partialsums, &result); + if (tid == 0) + { + if (i == 0) data[0] = 0; + data[0] += result; + } + } +} + +__global__ void besselTuneKernel(int *result, mmm1dgpu_real far_switch_radius, int maxCut) +{ + mmm1dgpu_real arg = C_2PIf*uz*far_switch_radius; + mmm1dgpu_real pref = 4*uz*max(1.0f, C_2PIf*uz); + mmm1dgpu_real err; + int P = 1; + do + { + err = pref*dev_K1(arg*P)*exp(arg)/arg*(P-1 + 1/arg); + P++; + } while (err > maxPWerror && P <= maxCut); + P--; + + result[0] = P; +} + +void Mmm1dgpuForce::tune(SystemInterface &s, mmm1dgpu_real _maxPWerror, mmm1dgpu_real _far_switch_radius, int _bessel_cutoff) +{ + mmm1dgpu_real far_switch_radius = _far_switch_radius; + int bessel_cutoff = _bessel_cutoff; + mmm1dgpu_real maxrad = host_boxz; + + if (_far_switch_radius < 0 && _bessel_cutoff < 0) + // autodetermine switching radius and bessel cutoff + { + mmm1dgpu_real bestrad = 0, besttime = INFINITY; + + for (far_switch_radius = 0.05*maxrad; far_switch_radius < maxrad; far_switch_radius += 0.05*maxrad) + { + set_params(0, 0, _maxPWerror, far_switch_radius, bessel_cutoff); + tune(s, _maxPWerror, far_switch_radius, -2); // tune bessel cutoff + int runtime = force_benchmark(s); + if (runtime < besttime) + { + besttime = runtime; + bestrad = far_switch_radius; + } + } + far_switch_radius = bestrad; + + set_params(0, 0, _maxPWerror, far_switch_radius, bessel_cutoff); + tune(s, _maxPWerror, far_switch_radius, -2); // tune bessel cutoff + } + + else if (_bessel_cutoff < 0) + // autodetermine bessel cutoff + { + int *dev_cutoff; + int maxCut = 30; + cuda_safe_mem( cudaMalloc((void**)&dev_cutoff, sizeof(int)) ); + besselTuneKernel<<<1,1>>>(dev_cutoff, far_switch_radius, maxCut); + cuda_safe_mem( cudaMemcpy(&bessel_cutoff, dev_cutoff, sizeof(int), cudaMemcpyDeviceToHost) ); + cudaFree(dev_cutoff); + if (_bessel_cutoff != -2 && bessel_cutoff >= maxCut) // we already have our switching radius and only need to determine the cutoff, i.e. this is the final tuning round + { + std::cerr << "No reasonable Bessel cutoff could be determined." << std::endl; + exit(EXIT_FAILURE); + } + + set_params(0, 0, _maxPWerror, far_switch_radius, bessel_cutoff); + } +} + +void Mmm1dgpuForce::set_params(mmm1dgpu_real _boxz, mmm1dgpu_real _coulomb_prefactor, mmm1dgpu_real _maxPWerror, mmm1dgpu_real _far_switch_radius, int _bessel_cutoff, bool manual) +{ + if (_boxz > 0 && _far_switch_radius > _boxz) + { + std::cout << "switching radius must not be larger than box length" << std::endl; + exit(EXIT_FAILURE); + } + mmm1dgpu_real _far_switch_radius_2 = _far_switch_radius*_far_switch_radius; + mmm1dgpu_real _uz = 1.0/_boxz; + for (int d = 0; d < deviceCount; d++) + { + // double colons are needed to access the constant memory variables because they + // are file globals and we have identically named class variables + cudaSetDevice(d); + if (manual) // tuning needs to be performed again + { + far_switch_radius = _far_switch_radius; + bessel_cutoff = _bessel_cutoff; + } + if (_far_switch_radius >= 0) + { + mmm1d_params.far_switch_radius_2 = _far_switch_radius*_far_switch_radius; + cuda_safe_mem( cudaMemcpyToSymbol(::far_switch_radius_2, &_far_switch_radius_2, sizeof(mmm1dgpu_real)) ); + far_switch_radius = _far_switch_radius; + } + if (_boxz > 0) + { + host_boxz = _boxz; + cuda_safe_mem( cudaMemcpyToSymbol(::boxz, &_boxz, sizeof(mmm1dgpu_real)) ); + cuda_safe_mem( cudaMemcpyToSymbol(::uz, &_uz, sizeof(mmm1dgpu_real)) ); + } + if (_coulomb_prefactor != 0) + { + cuda_safe_mem( cudaMemcpyToSymbol(::coulomb_prefactor, &_coulomb_prefactor, sizeof(mmm1dgpu_real)) ); + coulomb_prefactor = _coulomb_prefactor; + } + if (_bessel_cutoff > 0) + { + mmm1d_params.bessel_cutoff = _bessel_cutoff; + cuda_safe_mem( cudaMemcpyToSymbol(::bessel_cutoff, &_bessel_cutoff, sizeof(int)) ); + bessel_cutoff = _bessel_cutoff; + } + if (_maxPWerror > 0) + { + mmm1d_params.maxPWerror = _maxPWerror; + cuda_safe_mem( cudaMemcpyToSymbol(::maxPWerror, &_maxPWerror, sizeof(mmm1dgpu_real)) ); + maxPWerror = _maxPWerror; + } + } + need_tune = true; + + // The changed parameters in mmm1d_params do not need to be broadcast: they are only accessed by the TCL print function (on node 0) when you call inter coulomb. The CUDA code only runs on node 0, so other nodes do not need the parameters. We couldn't broadcast from here anyway because set_params() might be called from inside computeForces() which is not a time at which the MPI loop on the slave nodes is waiting for broadcasts. +} + +__global__ void forcesKernel(const __restrict__ mmm1dgpu_real *r, const __restrict__ mmm1dgpu_real *q, __restrict__ mmm1dgpu_real *force, int N, int pairs, int tStart = 0, int tStop = -1) +{ + if (tStop < 0) + tStop = N*N; + + for (int tid = threadIdx.x + blockIdx.x * blockDim.x + tStart; tid < tStop; tid += blockDim.x * gridDim.x) + { + int p1 = tid%N, p2 = tid/N; + mmm1dgpu_real x = r[3*p2] - r[3*p1], y = r[3*p2+1] - r[3*p1+1], z = r[3*p2+2] - r[3*p1+2]; + mmm1dgpu_real rxy2 = sqpow(x) + sqpow(y); + mmm1dgpu_real rxy = sqrt(rxy2); + mmm1dgpu_real sum_r = 0, sum_z = 0; + +// if (boxz <= 0.0) return; // otherwise we'd get into an infinite loop if we're not initialized correctly + + while (fabs(z) > boxz/2) // make sure we take the shortest distance + z -= (z > 0? 1 : -1)*boxz; + + if (p1 == p2) // particle exerts no force on itself + { + rxy = 1; // so the division at the end doesn't fail with NaN (sum_r is 0 anyway) + } + else if (rxy2 <= far_switch_radius_2) // near formula + { + mmm1dgpu_real uzz = uz*z; + mmm1dgpu_real uzr = uz*rxy; + sum_z = dev_mod_psi_odd(0, uzz); + mmm1dgpu_real uzrpow = uzr; + for (int n = 1; n < device_n_modPsi; n++) + { + mmm1dgpu_real sum_r_old = sum_r; + mmm1dgpu_real mpe = dev_mod_psi_even(n, uzz); + mmm1dgpu_real mpo = dev_mod_psi_odd(n, uzz); + + sum_r += 2*n*mpe * uzrpow; + uzrpow *= uzr; + sum_z += mpo * uzrpow; + uzrpow *= uzr; + + if (fabs(sum_r_old - sum_r) < maxPWerror) + break; + } + + sum_r *= sqpow(uz); + sum_z *= sqpow(uz); + + sum_r += rxy*cbpow(rsqrt(rxy2+pow(z,2))); + sum_r += rxy*cbpow(rsqrt(rxy2+pow(z+boxz,2))); + sum_r += rxy*cbpow(rsqrt(rxy2+pow(z-boxz,2))); + + sum_z += z*cbpow(rsqrt(rxy2+pow(z,2))); + sum_z += (z+boxz)*cbpow(rsqrt(rxy2+pow(z+boxz,2))); + sum_z += (z-boxz)*cbpow(rsqrt(rxy2+pow(z-boxz,2))); + + if (rxy == 0) // particles at the same radial position only exert a force in z direction + { + rxy = 1; // so the division at the end doesn't fail with NaN (sum_r is 0 anyway) + } + } + else // far formula + { + for (int p = 1; p < bessel_cutoff; p++) + { + mmm1dgpu_real arg = C_2PIf*uz*p; + sum_r += p*dev_K1(arg*rxy)*cos(arg*z); + sum_z += p*dev_K0(arg*rxy)*sin(arg*z); + } + sum_r *= sqpow(uz)*4*C_2PIf; + sum_z *= sqpow(uz)*4*C_2PIf; + sum_r += 2*uz/rxy; + } + + mmm1dgpu_real pref = coulomb_prefactor*q[p1]*q[p2]; + if (pairs) + { + force[3*(p1+p2*N-tStart)] = pref*sum_r/rxy*x; + force[3*(p1+p2*N-tStart)+1] = pref*sum_r/rxy*y; + force[3*(p1+p2*N-tStart)+2] = pref*sum_z; + } + else + { +#ifdef ELECTROSTATICS_GPU_DOUBLE_PRECISION + atomicadd8(&force[3*p2], pref*sum_r/rxy*x); + atomicadd8(&force[3*p2+1], pref*sum_r/rxy*y); + atomicadd8(&force[3*p2+2], pref*sum_z); +#else + atomicadd(&force[3*p2], pref*sum_r/rxy*x); + atomicadd(&force[3*p2+1], pref*sum_r/rxy*y); + atomicadd(&force[3*p2+2], pref*sum_z); +#endif + } + } +} + +__global__ void energiesKernel(const __restrict__ mmm1dgpu_real *r, const __restrict__ mmm1dgpu_real *q, __restrict__ mmm1dgpu_real *energy, int N, int pairs, int tStart = 0, int tStop = -1) +{ + if (tStop < 0) + tStop = N*N; + + extern __shared__ mmm1dgpu_real partialsums[]; + if (!pairs) + { + partialsums[threadIdx.x] = 0; + __syncthreads(); + } + for (int tid = threadIdx.x + blockIdx.x * blockDim.x + tStart; tid < tStop; tid += blockDim.x * gridDim.x) + { + int p1 = tid%N, p2 = tid/N; + mmm1dgpu_real z = r[3*p2+2] - r[3*p1+2]; + mmm1dgpu_real rxy2 = sqpow(r[3*p2] - r[3*p1]) + sqpow(r[3*p2+1] - r[3*p1+1]); + mmm1dgpu_real rxy = sqrt(rxy2); + mmm1dgpu_real sum_e = 0; + +// if (boxz <= 0.0) return; // otherwise we'd get into an infinite loop if we're not initialized correctly + + while (fabs(z) > boxz/2) // make sure we take the shortest distance + z -= (z > 0? 1 : -1)*boxz; + + if (p1 == p2) // particle exerts no force on itself + { + } + else if (rxy2 <= far_switch_radius_2) // near formula + { + mmm1dgpu_real uzz = uz*z; + mmm1dgpu_real uzr2 = sqpow(uz*rxy); + mmm1dgpu_real uzrpow = uzr2; + sum_e = dev_mod_psi_even(0, uzz); + for (int n = 1; n < device_n_modPsi; n++) + { + mmm1dgpu_real sum_e_old = sum_e; + mmm1dgpu_real mpe = dev_mod_psi_even(n, uzz); + sum_e += mpe * uzrpow; + uzrpow *= uzr2; + + if (fabs(sum_e_old - sum_e) < maxPWerror) + break; + } + + sum_e *= -1*uz; + sum_e -= 2*uz*C_GAMMAf; + sum_e += rsqrt(rxy2+sqpow(z)); + sum_e += rsqrt(rxy2+sqpow(z+boxz)); + sum_e += rsqrt(rxy2+sqpow(z-boxz)); + } + else // far formula + { + sum_e = -(log(rxy*uz/2) + C_GAMMAf)/2; + for (int p = 1; p < bessel_cutoff; p++) + { + mmm1dgpu_real arg = C_2PIf*uz*p; + sum_e += dev_K0(arg*rxy)*cos(arg*z); + } + sum_e *= uz*4; + } + + if (pairs) + { + energy[p1+p2*N-tStart] = coulomb_prefactor*q[p1]*q[p2]*sum_e; + } + else + { + partialsums[threadIdx.x] += coulomb_prefactor*q[p1]*q[p2]*sum_e; + } + } + if (!pairs) + { + sumReduction(partialsums, &energy[blockIdx.x]); + } +} + +__global__ void vectorReductionKernel(mmm1dgpu_real *src, mmm1dgpu_real *dst, int N, int tStart = 0, int tStop = -1) +{ + if (tStop < 0) + tStop = N*N; + + for (int tid = threadIdx.x + blockIdx.x * blockDim.x; tid < N; tid += blockDim.x * gridDim.x) + { + int offset = ((tid + (tStart % N)) % N); + + for (int i = 0; tid+i*N < (tStop - tStart); i++) + { + #pragma unroll 3 + for (int d = 0; d<3; d++) + { + dst[3*offset+d] -= src[3*(tid+i*N)+d]; + } + } + } +} + +void Mmm1dgpuForce::computeForces(SystemInterface &s) +{ + if (coulomb.method != COULOMB_MMM1D_GPU) // MMM1DGPU was disabled. nobody cares about our calculations anymore + { + std::cerr << "MMM1D: coulomb.method has been changed, skipping calculation" << std::endl; + return; + } + setup(s); + + if (pairs < 0) + { + std::cerr << "MMM1D was not initialized correctly" << std::endl; + exit(EXIT_FAILURE); + } + + if (pairs) // if we calculate force pairs, we need to reduce them to forces + { + int blocksRed = s.npart_gpu()/numThreads+1; + KERNELCALL(forcesKernel,numBlocks(s),numThreads,(s.rGpuBegin(), s.qGpuBegin(), dev_forcePairs, s.npart_gpu(), pairs)) + KERNELCALL(vectorReductionKernel,blocksRed,numThreads,(dev_forcePairs, s.fGpuBegin(), s.npart_gpu())) + } + else + { + KERNELCALL(forcesKernel,numBlocks(s),numThreads,(s.rGpuBegin(), s.qGpuBegin(), s.fGpuBegin(), s.npart_gpu(), pairs)) + } +} + +__global__ void scaleAndAddKernel(mmm1dgpu_real *dst, mmm1dgpu_real *src, int N, mmm1dgpu_real factor) +{ + for (int tid = threadIdx.x + blockIdx.x * blockDim.x; tid < N; tid += blockDim.x * gridDim.x) + { + dst[tid] += src[tid]*factor; + } +} + +void Mmm1dgpuForce::computeEnergy(SystemInterface &s) +{ + if (coulomb.method != COULOMB_MMM1D_GPU) // MMM1DGPU was disabled. nobody cares about our calculations anymore + { + std::cerr << "MMM1D: coulomb.method has been changed, skipping calculation" << std::endl; + return; + } + setup(s); + + if (pairs < 0) + { + std::cerr << "MMM1D was not initialized correctly" << std::endl; + exit(EXIT_FAILURE); + } + int shared = numThreads*sizeof(mmm1dgpu_real); + + KERNELCALL_shared(energiesKernel,numBlocks(s),numThreads,shared,(s.rGpuBegin(), s.qGpuBegin(), dev_energyBlocks, s.npart_gpu(), 0)); + KERNELCALL_shared(sumKernel,1,numThreads,shared,(dev_energyBlocks, numBlocks(s))); + KERNELCALL(scaleAndAddKernel,1,1,(&(((CUDA_energy*)s.eGpu())->coulomb), &dev_energyBlocks[0], 1, 0.5)); // we have counted every interaction twice, so halve the total energy +} + +float Mmm1dgpuForce::force_benchmark(SystemInterface &s) +{ + cudaEvent_t eventStart, eventStop; + float elapsedTime; + mmm1dgpu_real *dev_f_benchmark; + + cuda_safe_mem( cudaMalloc((void**)&dev_f_benchmark, 3*s.npart_gpu()*sizeof(mmm1dgpu_real)) ); + cuda_safe_mem( cudaEventCreate(&eventStart) ); + cuda_safe_mem( cudaEventCreate(&eventStop) ); + cuda_safe_mem( cudaEventRecord(eventStart, stream[0]) ); + KERNELCALL(forcesKernel,numBlocks(s),numThreads,(s.rGpuBegin(), s.qGpuBegin(), dev_f_benchmark, s.npart_gpu(), 0)) + cuda_safe_mem( cudaEventRecord(eventStop, stream[0]) ); + cuda_safe_mem( cudaEventSynchronize(eventStop) ); + cuda_safe_mem( cudaEventElapsedTime(&elapsedTime, eventStart, eventStop) ); + cuda_safe_mem( cudaEventDestroy(eventStart) ); + cuda_safe_mem( cudaEventDestroy(eventStop) ); + cuda_safe_mem( cudaFree(dev_f_benchmark)); + + return elapsedTime; +} + +#endif /* MMM1D_GPU */ diff --git a/src/core/actor/mmm-common_cuda.hpp b/src/core/actor/mmm-common_cuda.hpp new file mode 100644 index 00000000000..e4c898e6351 --- /dev/null +++ b/src/core/actor/mmm-common_cuda.hpp @@ -0,0 +1,108 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "mmm-common.hpp" +#include "specfunc_cuda.hpp" +#include "cuda_utils.hpp" + +// order hardcoded. mmm1d_recalcTables() typically does order less than 30. +// As the coefficients are stored in __constant__ memory, the array needs to be sized in advance. +// We don't know exactly how many coefficients per order, so we size plentiful. +const int modpsi_order = 30; +const int modpsi_constant_size = modpsi_order*modpsi_order*2; + +// linearized array on host +int *linModPsi_offsets = NULL, *linModPsi_lengths = NULL; +mmm1dgpu_real *linModPsi = NULL; + +// linearized array on device +__constant__ int device_n_modPsi = 0; +__constant__ int device_linModPsi_offsets[2*modpsi_order], device_linModPsi_lengths[2*modpsi_order]; +__constant__ mmm1dgpu_real device_linModPsi[modpsi_constant_size]; + +int modpsi_init() +{ + if (n_modPsi < modpsi_order) + { + create_mod_psi_up_to(modpsi_order); + } + + // linearize the coefficients array + linModPsi_offsets = (int*) realloc(linModPsi_offsets, sizeof(int) * 2*n_modPsi); + linModPsi_lengths = (int*) realloc(linModPsi_lengths, sizeof(int) * 2*n_modPsi); + for (int i = 0; i < 2*n_modPsi; i++) + { + if (i == 0) + linModPsi_offsets[i] = 0; + else + linModPsi_offsets[i] = linModPsi_offsets[i-1] + linModPsi_lengths[i-1]; + linModPsi_lengths[i] = modPsi[i].n; + } + linModPsi = (mmm1dgpu_real*) realloc(linModPsi, sizeof(mmm1dgpu_real) * (linModPsi_offsets[2*n_modPsi-1] + linModPsi_lengths[2*n_modPsi-1])); + for (int i = 0; i < 2*n_modPsi; i++) + { + for (int j = 0; j < modPsi[i].n; j++) + { + linModPsi[linModPsi_offsets[i] + j] = (mmm1dgpu_real) modPsi[i].e[j]; // cast to single-precision if necessary + } + } + + for (int d = 0; d < deviceCount; d++) + { + cudaSetDevice(d); + + // copy to GPU + int linModPsiSize = linModPsi_offsets[2*n_modPsi-1] + linModPsi_lengths[2*n_modPsi-1]; + if (linModPsiSize > modpsi_constant_size) + { + printf("ERROR: __constant__ device_linModPsi[] is not large enough\n"); + exit(EXIT_FAILURE); + } + cuda_safe_mem( cudaMemcpyToSymbol(device_linModPsi_offsets, linModPsi_offsets, 2*n_modPsi*sizeof(int)) ); + cuda_safe_mem( cudaMemcpyToSymbol(device_linModPsi_lengths, linModPsi_lengths, 2*n_modPsi*sizeof(int)) ); + cuda_safe_mem( cudaMemcpyToSymbol(device_linModPsi, linModPsi, linModPsiSize*sizeof(mmm1dgpu_real)) ); + cuda_safe_mem( cudaMemcpyToSymbol(device_n_modPsi, &n_modPsi, sizeof(int)) ); + } + + return 0; +} + +int modpsi_destroy() +{ + // no need to delete the arrays off the device, they're in constant memory + // free arrays on host + free(linModPsi_offsets); + free(linModPsi_lengths); + free(linModPsi); + linModPsi_offsets = NULL; + linModPsi_lengths = NULL; + linModPsi = NULL; + return 0; +} + +__device__ mmm1dgpu_real dev_mod_psi_even(int n, mmm1dgpu_real x) +{ + return evaluateAsTaylorSeriesAt(&device_linModPsi[device_linModPsi_offsets[2*n]], + device_linModPsi_lengths[2*n], x*x); +} + +__device__ mmm1dgpu_real dev_mod_psi_odd(int n, mmm1dgpu_real x) +{ + return x*evaluateAsTaylorSeriesAt(&device_linModPsi[device_linModPsi_offsets[2*n+1]], + device_linModPsi_lengths[2*n+1], x*x); +} diff --git a/src/core/actor/specfunc_cuda.hpp b/src/core/actor/specfunc_cuda.hpp new file mode 100644 index 00000000000..ff752776d5d --- /dev/null +++ b/src/core/actor/specfunc_cuda.hpp @@ -0,0 +1,213 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "config.hpp" + +const mmm1dgpu_real M_LN2f = M_LN2; + +// Adapted from specfunc.c and polynom.h + +__constant__ static mmm1dgpu_real bk0_data[11] = { + -.5 -0.03532739323390276872, + 0.3442898999246284869, + 0.03597993651536150163, + 0.00126461541144692592, + 0.00002286212103119451, + 0.00000025347910790261, + 0.00000000190451637722, + 0.00000000001034969525, + 0.00000000000004259816, + 0.00000000000000013744, + 0.00000000000000000035 +}; +__constant__ static int bk0_size = 11; + +__constant__ static mmm1dgpu_real ak0_data[17] = { + 2.5 -0.07643947903327941, + -0.02235652605699819, + 0.00077341811546938, + -0.00004281006688886, + 0.00000308170017386, + -0.00000026393672220, + 0.00000002563713036, + -0.00000000274270554, + 0.00000000031694296, + -0.00000000003902353, + 0.00000000000506804, + -0.00000000000068895, + 0.00000000000009744, + -0.00000000000001427, + 0.00000000000000215, + -0.00000000000000033, + 0.00000000000000005 +}; +__constant__ static int ak0_size = 16; + +__constant__ static mmm1dgpu_real ak02_data[14] = { + 2.5 -0.01201869826307592, + -0.00917485269102569, + 0.00014445509317750, + -0.00000401361417543, + 0.00000015678318108, + -0.00000000777011043, + 0.00000000046111825, + -0.00000000003158592, + 0.00000000000243501, + -0.00000000000020743, + 0.00000000000001925, + -0.00000000000000192, + 0.00000000000000020, + -0.00000000000000002 +}; +__constant__ static int ak02_size = 13; + +__constant__ static mmm1dgpu_real bi0_data[12] = { + 5.5 -.07660547252839144951, + 1.92733795399380827000, + .22826445869203013390, + .01304891466707290428, + .00043442709008164874, + .00000942265768600193, + .00000014340062895106, + .00000000161384906966, + .00000000001396650044, + .00000000000009579451, + .00000000000000053339, + .00000000000000000245 +}; +__constant__ static int bi0_size = 12; + +__constant__ static mmm1dgpu_real bk1_data[11] = { + 1.5 +0.0253002273389477705, + -0.3531559607765448760, + -0.1226111808226571480, + -0.0069757238596398643, + -0.0001730288957513052, + -0.0000024334061415659, + -0.0000000221338763073, + -0.0000000001411488392, + -0.0000000000006666901, + -0.0000000000000024274, + -0.0000000000000000070 +}; +__constant__ static int bk1_size = 11; + +__constant__ static mmm1dgpu_real ak1_data[17] = { + 2.5 +0.27443134069738830, + 0.07571989953199368, + -0.00144105155647540, + 0.00006650116955125, + -0.00000436998470952, + 0.00000035402774997, + -0.00000003311163779, + 0.00000000344597758, + -0.00000000038989323, + 0.00000000004720819, + -0.00000000000604783, + 0.00000000000081284, + -0.00000000000011386, + 0.00000000000001654, + -0.00000000000000248, + 0.00000000000000038, + -0.00000000000000006 +}; +__constant__ static int ak1_size = 17; + +__constant__ static mmm1dgpu_real ak12_data[14] = { + 2.5 +0.06379308343739001, + 0.02832887813049721, + -0.00024753706739052, + 0.00000577197245160, + -0.00000020689392195, + 0.00000000973998344, + -0.00000000055853361, + 0.00000000003732996, + -0.00000000000282505, + 0.00000000000023720, + -0.00000000000002176, + 0.00000000000000215, + -0.00000000000000022, + 0.00000000000000002 +}; +__constant__ static int ak12_size = 14; + +__constant__ static mmm1dgpu_real bi1_data[11] = { + 1.75 -0.001971713261099859, + 0.407348876675464810, + 0.034838994299959456, + 0.001545394556300123, + 0.000041888521098377, + 0.000000764902676483, + 0.000000010042493924, + 0.000000000099322077, + 0.000000000000766380, + 0.000000000000004741, + 0.000000000000000024 +}; +__constant__ static int bi1_size = 11 ; + +__device__ mmm1dgpu_real evaluateAsChebychevSeriesAt(mmm1dgpu_real *c, int n, mmm1dgpu_real x) +{ + int j; + mmm1dgpu_real x2 = 2 * x; + mmm1dgpu_real dd = c[n - 1]; + mmm1dgpu_real d = x2*dd + c[n - 2]; + for(j = n - 3; j >= 1; j--) { + mmm1dgpu_real tmp = d; + d = x2*d - dd + c[j]; + dd = tmp; + } + return x*d - dd + c[0]/2; +} + +__device__ mmm1dgpu_real evaluateAsTaylorSeriesAt(mmm1dgpu_real *c, int n, mmm1dgpu_real x) +{ + int cnt = n - 1; + mmm1dgpu_real r = c[cnt]; + while (--cnt >= 0) + r = r*x + c[cnt]; + return r; +} + +__device__ mmm1dgpu_real dev_K0(mmm1dgpu_real x) +{ + mmm1dgpu_real c = evaluateAsChebychevSeriesAt( + x<=2? bk0_data :x<=8? ak0_data : ak02_data, + x<=2? bk0_size :x<=8? ak0_size : ak02_size, + x<=2? x*x/2-1.0f :x<=8? (16/x-5.0f)/3.0f : (16/x-1.0f) + ); + if (x <= 2) { + mmm1dgpu_real I0 = evaluateAsChebychevSeriesAt(bi0_data, bi0_size, x*x/4.5f-1.0f); + return (-log(x) + M_LN2f)*I0 + c; + } + return exp(-x)*c*rsqrt(x); +} + +__device__ mmm1dgpu_real dev_K1(mmm1dgpu_real x) +{ + mmm1dgpu_real c = evaluateAsChebychevSeriesAt( + x<=2? bk1_data :x<=8? ak1_data : ak12_data, + x<=2? bk1_size :x<=8? ak1_size : ak12_size, + x<=2? x*x/2-1.0f :x<=8? (16/x-5.0f)/3.0f : (16/x-1.0f) + ); + if(x <= 2) { + mmm1dgpu_real I1 = x * evaluateAsChebychevSeriesAt(bi1_data, bi1_size, x*x/4.5f-1.0f); + return (log(x) - M_LN2f)*I1 + c/x; + } + return exp(-x)*c*rsqrt(x); +} diff --git a/src/angle.cpp b/src/core/angle.cpp similarity index 90% rename from src/angle.cpp rename to src/core/angle.cpp index 4febda77af6..72321db7c40 100644 --- a/src/angle.cpp +++ b/src/core/angle.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle.c +/** \file angle.cpp * - * Implementation of \ref angle.h + * Implementation of \ref angle.hpp */ #include "angle.hpp" @@ -30,7 +30,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_set_params(int bond_type, double bend, double phi0) { diff --git a/src/angle.hpp b/src/core/angle.hpp similarity index 97% rename from src/angle.hpp rename to src/core/angle.hpp index d536be350c8..c16321cead0 100644 --- a/src/angle.hpp +++ b/src/core/angle.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef ANGLE_H #define ANGLE_H -/** \file angle.h +/** \file angle.hpp * Routines to calculate the angle energy or/and and force * for a particle triple. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -36,7 +36,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_set_params(int bond_type, double bend, double phi0); diff --git a/src/angle_cosine.cpp b/src/core/angle_cosine.cpp similarity index 88% rename from src/angle_cosine.cpp rename to src/core/angle_cosine.cpp index d9afd90414c..039bbb76de6 100644 --- a/src/angle_cosine.cpp +++ b/src/core/angle_cosine.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_cosine.c +/** \file angle_cosine.cpp * - * Implementation of \ref angle_cosine.h + * Implementation of \ref angle_cosine.hpp */ #include "angle_cosine.hpp" @@ -30,7 +30,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_cosine_set_params(int bond_type, double bend, double phi0) { diff --git a/src/angle_cosine.hpp b/src/core/angle_cosine.hpp similarity index 97% rename from src/angle_cosine.hpp rename to src/core/angle_cosine.hpp index f7eb614767f..07d0576e2bd 100644 --- a/src/angle_cosine.hpp +++ b/src/core/angle_cosine.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef ANGLE_COSINE_H #define ANGLE_COSINE_H -/** \file angle_cosine.h +/** \file angle_cosine.hpp * Routines to calculate the angle energy or/and and force * for a particle triple. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -36,7 +36,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_cosine_set_params(int bond_type, double bend, double phi0); diff --git a/src/angle_cossquare.cpp b/src/core/angle_cossquare.cpp similarity index 88% rename from src/angle_cossquare.cpp rename to src/core/angle_cossquare.cpp index e2661ab2792..23cadaa532a 100644 --- a/src/angle_cossquare.cpp +++ b/src/core/angle_cossquare.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_cossquare.c +/** \file angle_cossquare.cpp * - * Implementation of \ref angle.h + * Implementation of \ref angle.hpp */ #include "angle_cossquare.hpp" @@ -30,7 +30,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_cossquare_set_params(int bond_type, double bend, double phi0) { diff --git a/src/angle_cossquare.hpp b/src/core/angle_cossquare.hpp similarity index 97% rename from src/angle_cossquare.hpp rename to src/core/angle_cossquare.hpp index 013cfff72cb..b61dbafeb02 100644 --- a/src/angle_cossquare.hpp +++ b/src/core/angle_cossquare.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef ANGLE_COSSQUARE_H #define ANGLE_COSSQUARE_H -/** \file angle_cossquare.h +/** \file angle_cossquare.hpp * Routines to calculate the angle energy or/and and force * for a particle triple. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -36,7 +36,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_cossquare_set_params(int bond_type, double bend, double phi0); diff --git a/src/angle_harmonic.cpp b/src/core/angle_harmonic.cpp similarity index 88% rename from src/angle_harmonic.cpp rename to src/core/angle_harmonic.cpp index 1b55bef6f0e..9d41fca6a88 100644 --- a/src/angle_harmonic.cpp +++ b/src/core/angle_harmonic.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_harmonic.c +/** \file angle_harmonic.cpp * - * Implementation of \ref angle.h + * Implementation of \ref angle.hpp */ #include "angle_harmonic.hpp" @@ -30,7 +30,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_harmonic_set_params(int bond_type, double bend, double phi0) { diff --git a/src/angle_harmonic.hpp b/src/core/angle_harmonic.hpp similarity index 97% rename from src/angle_harmonic.hpp rename to src/core/angle_harmonic.hpp index 46e8d4772ec..ac6e9c2bf47 100644 --- a/src/angle_harmonic.hpp +++ b/src/core/angle_harmonic.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef ANGLE_HARMONIC_H #define ANGLE_HARMONIC_H -/** \file angle_harmonic.h +/** \file angle_harmonic.hpp * Routines to calculate the angle energy or/and and force * for a particle triple. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -36,7 +36,7 @@ /** set parameters for the angle potential. \todo The type of the angle potential - is chosen via config.h and cannot be changed at runtime. + is chosen via config.hpp and cannot be changed at runtime. */ int angle_harmonic_set_params(int bond_type, double bend, double phi0); diff --git a/src/angledist.cpp b/src/core/angledist.cpp similarity index 97% rename from src/angledist.cpp rename to src/core/angledist.cpp index ba31a42e99d..66378efbbb7 100644 --- a/src/angledist.cpp +++ b/src/core/angledist.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angledist.c +/** \file angledist.cpp * - * Implementation of \ref angledist.h + * Implementation of \ref angledist.hpp */ #include "angledist.hpp" @@ -101,8 +101,7 @@ static double calc_angledist_param(Particle *p_mid, Particle *p_left, pwdist[k]=0.0; } for(k=0;k. */ -/** \file bmhtf-nacl.c +/** \file bmhtf-nacl.cpp * - * Implementation of \ref bmhtf-nacl.h + * Implementation of \ref bmhtf-nacl.hpp */ #include "bmhtf-nacl.hpp" diff --git a/src/bmhtf-nacl.hpp b/src/core/bmhtf-nacl.hpp similarity index 95% rename from src/bmhtf-nacl.hpp rename to src/core/bmhtf-nacl.hpp index b9d05bb7d06..fb95ca50c50 100644 --- a/src/bmhtf-nacl.hpp +++ b/src/core/bmhtf-nacl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef BMHTF_NACL_H #define BMHTF_NACL_H -/** \file bmhtf-nacl.h +/** \file bmhtf-nacl.hpp * Routines to calculate the Born-Meyer-Huggins-Tosi-Fumi energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/core/bonded_coulomb.cpp b/src/core/bonded_coulomb.cpp new file mode 100644 index 00000000000..837a8277b1e --- /dev/null +++ b/src/core/bonded_coulomb.cpp @@ -0,0 +1,47 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file bonded_coulomb.cpp + * + * Implementation of \ref bonded_coulomb.hpp + */ +#include "bonded_coulomb.hpp" +#include "communication.hpp" + +#ifdef ELECTROSTATICS + +int bonded_coulomb_set_params(int bond_type, double prefactor) +{ + if(bond_type < 0) + return ES_ERROR; + + make_bond_type_exist(bond_type); + + bonded_ia_params[bond_type].p.bonded_coulomb.prefactor = prefactor; + bonded_ia_params[bond_type].type = BONDED_IA_BONDED_COULOMB; + bonded_ia_params[bond_type].num = 1; + + /* broadcast interaction parameters */ + mpi_bcast_ia_params(bond_type, -1); + + return ES_OK; +} + +#endif diff --git a/src/core/bonded_coulomb.hpp b/src/core/bonded_coulomb.hpp new file mode 100644 index 00000000000..cb89ee9feff --- /dev/null +++ b/src/core/bonded_coulomb.hpp @@ -0,0 +1,76 @@ +/* + Copyright (C) 2010,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _BONDED_COULOMB_HPP +#define _BONDED_COULOMB_HPP +/** \file bonded_coulomb.hpp + * Routines to calculate the HARMONIC Energy or/and HARMONIC force + * for a particle pair. + * \ref forces.cpp +*/ + +/************************************************************/ + +#include "utils.hpp" +#include "interaction_data.hpp" +#include "particle_data.hpp" + +#ifdef ELECTROSTATICS + +/// set the parameters for the bonded_coulomb potential +int bonded_coulomb_set_params(int bond_type, double prefactor); + +/** Computes the BONDED_COULOMB pair force and adds this + force to the particle forces (see \ref interaction_data.cpp). + @param p1 Pointer to first particle. + @param p2 Pointer to second/middle particle. + @param iaparams bond type number of the angle interaction (see \ref interaction_data.cpp). + @param dx particle distance vector + @param force returns force of particle 1 + @return 0. +*/ +inline int calc_bonded_coulomb_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force[3]) +{ + int i; + double fac; + double dist2 = sqrlen(dx); + double dist = sqrt(dist2); + + fac = iaparams->p.bonded_coulomb.prefactor * p1->p.q * p2->p.q / (dist*dist2); + + for(i=0;i<3;i++) + force[i] = fac*dx[i]; + ONEPART_TRACE(if(p1->p.identity==check_id) fprintf(stderr,"%d: OPT: BONDED_COULOMB f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2],p2->p.identity,dist2,fac)); + ONEPART_TRACE(if(p2->p.identity==check_id) fprintf(stderr,"%d: OPT: BONDED_COULOMB f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2],p1->p.identity,dist2,fac)); + + return 0; +} + +inline int bonded_coulomb_pair_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy) +{ + double dist = sqrt(sqrlen(dx)); + + *_energy = iaparams->p.bonded_coulomb.prefactor * p1->p.q * p2->p.q / dist; + return 0; +} + +#endif + +#endif diff --git a/src/buckingham.cpp b/src/core/buckingham.cpp similarity index 96% rename from src/buckingham.cpp rename to src/core/buckingham.cpp index ac7edcf1b2e..d6c992ff46b 100644 --- a/src/buckingham.cpp +++ b/src/core/buckingham.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file buckingham.c +/** \file buckingham.cpp * - * Implementation of \ref buckingham.h + * Implementation of \ref buckingham.hpp */ #include "buckingham.hpp" diff --git a/src/buckingham.hpp b/src/core/buckingham.hpp similarity index 98% rename from src/buckingham.hpp rename to src/core/buckingham.hpp index de4b594e5d2..95ec4993d25 100644 --- a/src/buckingham.hpp +++ b/src/core/buckingham.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef BUCKINGHAM_H #define BUCKINGHAM_H -/** \file buckingham.h +/** \file buckingham.hpp * Routines to calculate the Buckingham energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" #include "interaction_data.hpp" diff --git a/src/cells.cpp b/src/core/cells.cpp similarity index 82% rename from src/cells.cpp rename to src/core/cells.cpp index a01a7f539b4..01c683149d8 100644 --- a/src/cells.cpp +++ b/src/core/cells.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file cells.c +/** \file cells.cpp * * This file contains functions for the cell system. * - * For more information on cells, see cells.h + * For more information on cells, see cells.hpp * */ #include #include @@ -38,6 +38,7 @@ #include "verlet.hpp" #include "ghosts.hpp" #include "domain_decomposition.hpp" +#include "lees_edwards_domain_decomposition.hpp" #include "nsquare.hpp" #include "layered.hpp" @@ -64,10 +65,9 @@ int rebuild_verletlist = 0; /************************************************************/ /*@{*/ -#ifdef ADDITIONAL_CHECKS /** Extensive Debug function to check the consistency of the cells and the particles therein. Use with care! */ -static void check_cells_consistency() +void check_cells_consistency() { int c, index; IntList used; @@ -116,7 +116,6 @@ static void check_cells_consistency() } realloc_intlist(&used, 0); } -#endif /** Switch for choosing the topology release function of a certain cell system. */ @@ -187,7 +186,7 @@ void cells_re_init(int new_cs) /* CELL_TRACE({ int p; - for (p = 0; p < n_total_particles; p++) + for (p = 0; p < n_part; p++) if (local_particles[p]) fprintf(stderr, "%d: cells_re_init: got particle %d\n", this_node, p); } @@ -220,7 +219,7 @@ void cells_re_init(int new_cs) /* CELL_TRACE({ int p; - for (p = 0; p < n_total_particles; p++) + for (p = 0; p < n_part; p++) if (local_particles[p]) fprintf(stderr, "%d: cells_re_init: now got particle %d\n", this_node, p); } @@ -305,6 +304,30 @@ void print_local_particle_positions() /*************************************************/ +#ifdef CELL_DEBUG + +static void dump_particle_ordering() +{ + /* Loop local cells */ + for (int c = 0; c < local_cells.n; c++) { + Cell *cell = local_cells.cell[c]; + Particle *p = cell->part; + int np = cell->n; + + fprintf(stderr, "%d: cell %d has particles", this_node, c); + + /* Loop cell particles */ + for(int i=0; i < np; i++) { + fprintf(stderr, " %d", p[i].p.identity); + } + fprintf(stderr, "\n"); + } +} + +#endif // CELL_TRACE + +/*************************************************/ + void cells_resort_particles(int global_flag) { CELL_TRACE(fprintf(stderr, "%d: entering cells_resort_particles %d\n", this_node, global_flag)); @@ -339,19 +362,57 @@ void cells_resort_particles(int global_flag) on_resort_particles(); + CELL_TRACE(dump_particle_ordering()); CELL_TRACE(fprintf(stderr, "%d: leaving cells_resort_particles\n", this_node)); } /*************************************************/ +static int compare_particles(const void *a, const void *b) +{ + int id_a = static_cast(a)->p.identity; + int id_b = static_cast(b)->p.identity; + return id_a - id_b; +} + +void local_sort_particles() +{ + CELL_TRACE(fprintf(stderr, "%d: entering local_sort_particles\n", this_node)); + + /* first distribute strictly on nodes */ + cells_resort_particles(CELL_GLOBAL_EXCHANGE); + + CELL_TRACE(fprintf(stderr, "%d: sorting local cells\n", this_node)); + + /* now sort the local cells */ + for (int c = 0; c < local_cells.n; c++) { + Cell *cell = local_cells.cell[c]; + Particle *p = cell->part; + int np = cell->n; + +#ifdef CELL_DEBUG + for (int id = 0; id < np; ++id) { + Cell *tgt_cell = cell_structure.position_to_cell(p[id].r.p); + if (tgt_cell != cell) { + fprintf(stderr, "%d: particle %d at position %lf %lf %lf is not in its expected cell. Have %ld, expected %ld\n", this_node, p[id].p.identity, p[id].r.p[0], p[id].r.p[1], p[id].r.p[2], (cell - cells)/sizeof(Cell*), (tgt_cell - cells) /sizeof(Cell*)); + } + } +#endif + + qsort(p, np, sizeof(Particle), compare_particles); + update_local_particles(cell); + } + + CELL_TRACE(dump_particle_ordering()); + CELL_TRACE(fprintf(stderr, "%d: leaving local_sort_particles\n", this_node)); +} + +/*************************************************/ + void cells_on_geometry_change(int flags) { if (max_cut > 0.0) { - if (skin >= 0.0) - max_range = max_cut + skin; - else - /* if the skin is not yet set, assume zero. */ - max_range = max_cut; + max_range = max_cut + skin; } else /* if no interactions yet, we also don't need a skin */ @@ -404,8 +465,13 @@ void cells_update_ghosts() resort_particles = 1; if (resort_particles) { +#ifdef LEES_EDWARDS + /* Communication step: number of ghosts and ghost information */ + cells_resort_particles(CELL_GLOBAL_EXCHANGE); +#else /* Communication step: number of ghosts and ghost information */ cells_resort_particles(CELL_NEIGHBOR_EXCHANGE); +#endif } else /* Communication step: ghost information */ diff --git a/src/cells.hpp b/src/core/cells.hpp similarity index 90% rename from src/cells.hpp rename to src/core/cells.hpp index 0a1f7344604..00d81ebf9b0 100644 --- a/src/cells.hpp +++ b/src/core/cells.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _CELLS_H #define _CELLS_H -/** \file cells.h +/** \file cells.hpp This file contains everything related to the cell structure / cell system. @@ -31,18 +31,18 @@
    • domain decomposition: The simulation box is divided spatially - ino cells (see \ref domain_decomposition.h). This is suitable for + ino cells (see \ref domain_decomposition.hpp). This is suitable for short range interctions.
    • nsquare: The particles are distributed equally on all nodes - regardless their spatial position (see \ref nsquare.h). This is + regardless their spatial position (see \ref nsquare.hpp). This is suitable for long range interactions that can not be treated by a - special method like P3M (see \ref p3m.h). + special method like P3M (see \ref p3m.hpp).
    • layered: in x and y directions, it uses a nsquared type of interaction calculation, but in z it has a domain decomposition into layers.
    One can switch between different cell systems with the tcl command - cellsystem implemented in \ref cells.c . + cellsystem implemented in \ref cells.cpp . Some structures are common to all cell systems: @@ -95,9 +95,11 @@ /*@{*/ /** Flag for cells_on_geometry_change: the processor grid has changed. */ -#define CELL_FLAG_GRIDCHANGED 1 +#define CELL_FLAG_GRIDCHANGED 1 /** Flag for cells_on_geometry_change: skip shrinking of cells. */ -#define CELL_FLAG_FAST 2 +#define CELL_FLAG_FAST 2 +/** Flag for cells_on_geometry_change: Lees-Edwards offset has changed. */ +#define CELL_FLAG_LEES_EDWARDS 4 /*@}*/ @@ -237,9 +239,12 @@ void cells_resort_particles(int global_flag); If bit CELL_FLAG_GRIDCHANGED is set, it means the nodes' topology has changed, i. e. the grid or periodicity. In this case a full reorganization is due. + + If bit CELL_FLAG_LEES_EDWARDS is set, it means the nodes' topology + has changed, but only on the period wrap in the y direction. - @param flags a combination of CELL_FLAG_GRIDCHANGED and - CELL_FLAG_FAST, see above. + @param flags a bitmask of CELL_FLAG_GRIDCHANGED, + CELL_FLAG_FAST, and/or CELL_FLAG_LEES_EDWARDS, see above. */ void cells_on_geometry_change(int flags); @@ -261,8 +266,12 @@ void print_ghost_positions(); /** spread the particle resorting criterion across the nodes. */ void announce_resort_particles(); -/* Checks if a particle resorting is required.*/ +/* Checks if a particle resorting is required. */ void check_resort_particles(); + +/* Do a strict particle sorting, including order in the cells. */ +void local_sort_particles(); + /*@}*/ #endif diff --git a/src/collision.cpp b/src/core/collision.cpp similarity index 79% rename from src/collision.cpp rename to src/core/collision.cpp index 34fa1a1aa11..04814216e17 100644 --- a/src/collision.cpp +++ b/src/core/collision.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2011,2012,2013 The ESPResSo project + Copyright (C) 2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -19,9 +19,19 @@ #include "collision.hpp" #include "cells.hpp" -#include "communication.hpp" +#include "communication.hpp" #include "errorhandling.hpp" +using namespace std; + +// #define DEBUG + +#ifdef DEBUG +#define TRACE(a) a +#else +#define TRACE(a) +#endif + #ifdef COLLISION_DETECTION /// Data type holding the info about a single collision @@ -54,7 +64,7 @@ int collision_detection_set_params(int mode, double d, int bond_centers, #endif // Binding so far only works on a single cpu - if (mode && n_nodes != 1) + if ((mode & COLLISION_MODE_VS) && n_nodes != 1) return 2; // Check if bonded ia exist @@ -81,8 +91,8 @@ int collision_detection_set_params(int mode, double d, int bond_centers, collision_params.vs_particle_type=t; make_particle_type_exist(t); - - recalc_forces = 1; + + mpi_bcast_collision_params(); return 0; } @@ -91,21 +101,25 @@ int collision_detection_set_params(int mode, double d, int bond_centers, // Add it to the queue in case virtual sites should be added at the point of collision void detect_collision(Particle* p1, Particle* p2) { - // The check, whether collision detection is actually turned on is performed in forces.h + // The check, whether collision detection is actually turned on is performed in forces.hpp double dist_betw_part, vec21[3]; int part1, part2, size; + TRACE(printf("%d: consider particles %d and %d\n", this_node, p1->p.identity, p2->p.identity)); + // Obtain distance between particles dist_betw_part = sqrt(distance2vec(p1->r.p, p2->r.p, vec21)); if (dist_betw_part > collision_params.distance) return; + TRACE(printf("%d: particles %d and %d on bonding distance %lf\n", this_node, p1->p.identity, p2->p.identity, dist_betw_part)); + part1 = p1->p.identity; part2 = p2->p.identity; // Retrieving the particles from local_particles is necessary, because the particle might be a - // ghost, and those don't contain bonding info + // ghost, and those can't store bonding info. p1 = local_particles[part1]; p2 = local_particles[part2]; @@ -116,42 +130,53 @@ void detect_collision(Particle* p1, Particle* p2) #endif // Check, if there's already a bond between the particles - // First check the bonds of p1 - int i = 0; - while(i < p1->bl.n) { - size = bonded_ia_params[p1->bl.e[i]].num; - - if (p1->bl.e[i] == collision_params.bond_centers && - p1->bl.e[i + 1] == part2) { - // There's a bond, already. Nothing to do for these particles - return; + // First check the bonds of p1 + if (p1->bl.e) { + int i = 0; + while(i < p1->bl.n) { + size = bonded_ia_params[p1->bl.e[i]].num; + + if (p1->bl.e[i] == collision_params.bond_centers && + p1->bl.e[i + 1] == part2) { + // There's a bond, already. Nothing to do for these particles + return; + } + i += size + 1; } - i += size + 1; } - - // Check, if a bond is already stored in p2 - i = 0; - while(i < p2->bl.n) { - size = bonded_ia_params[p2->bl.e[i]].num; + if (p2->bl.e) { + // Check, if a bond is already stored in p2 + int i = 0; + while(i < p2->bl.n) { + size = bonded_ia_params[p2->bl.e[i]].num; - /* COMPARE P2 WITH P1'S BONDED PARTICLES*/ + /* COMPARE P2 WITH P1'S BONDED PARTICLES*/ - if (p2->bl.e[i] == collision_params.bond_centers && - p2->bl.e[i + 1] == part1) { - return; + if (p2->bl.e[i] == collision_params.bond_centers && + p2->bl.e[i + 1] == part1) { + return; + } + i += size + 1; } - i += size + 1; } + TRACE(printf("%d: no previous bond, binding\n", this_node)); + /* If we're still here, there is no previous bond between the particles, we have a new collision */ /* create marking bond between the colliding particles immediately */ if (collision_params.mode & COLLISION_MODE_BOND) { int bondG[2]; + int primary = part1, secondary = part2; + // put the bond to the physical particle; at least one partner always is + if (p1->l.ghost) { + primary = part2; + secondary = part1; + } bondG[0]=collision_params.bond_centers; - bondG[1]=part2; - local_change_bond(part1, bondG, 0); + bondG[1]=secondary; + local_change_bond(primary, bondG, 0); } if (collision_params.mode & (COLLISION_MODE_VS | COLLISION_MODE_EXCEPTION)) { @@ -160,7 +185,7 @@ void detect_collision(Particle* p1, Particle* p2) // Point of collision double new_position[3]; - for (i=0;i<3;i++) { + for (int i=0;i<3;i++) { new_position[i] = p1->r.p[i] - vec21[i] * 0.50; } @@ -172,7 +197,7 @@ void detect_collision(Particle* p1, Particle* p2) // Save the collision collision_queue[number_of_collisions-1].pp1 = part1; collision_queue[number_of_collisions-1].pp2 = part2; - for (i=0;i<3;i++) { + for (int i=0;i<3;i++) { collision_queue[number_of_collisions-1].point_of_collision[i] = new_position[i]; } } @@ -198,8 +223,6 @@ void handle_collisions () if (collision_params.mode & (COLLISION_MODE_EXCEPTION)) { - // if desired, raise a runtime exception (background error) on collision - char *exceptiontxt = runtime_error(128 + 2*ES_INTEGER_SPACE); int id1, id2; if (collision_queue[i].pp1 > collision_queue[i].pp2) { id1 = collision_queue[i].pp2; @@ -209,8 +232,9 @@ void handle_collisions () id1 = collision_queue[i].pp1; id2 = collision_queue[i].pp2; } - ERROR_SPRINTF(exceptiontxt, "{collision between particles %d and %d} ", - id1, id2); + ostringstream msg; + msg << "collision between particles " << id1 << " and " <. */ -/** \file comfixed.c +/** \file comfixed.cpp * - * Implementation of \ref comfixed.h + * Implementation of \ref comfixed.hpp */ #include "utils.hpp" #include "interaction_data.hpp" @@ -43,10 +43,6 @@ int comfixed_set_params(int part_type_a, int part_type_b, int flag) if (n_nodes > 1) return 2; - if (PERIODIC(0) || PERIODIC(1) || PERIODIC(2)) { - return 3; - } - data->COMFIXED_flag = flag; /* broadcast interaction parameters */ diff --git a/src/comfixed.hpp b/src/core/comfixed.hpp similarity index 92% rename from src/comfixed.hpp rename to src/core/comfixed.hpp index 2e5c5731514..a2316815e3d 100644 --- a/src/comfixed.hpp +++ b/src/core/comfixed.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -23,7 +23,7 @@ #include "utils.hpp" -/** \file comfixed.h +/** \file comfixed.hpp * Routines to enable comfixed */ #ifdef COMFIXED diff --git a/src/comforce.cpp b/src/core/comforce.cpp similarity index 96% rename from src/comforce.cpp rename to src/core/comforce.cpp index 8b55d482209..318fa24ae4c 100644 --- a/src/comforce.cpp +++ b/src/core/comforce.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file comforce.c +/** \file comforce.cpp * - * Implementation of \ref comforce.h + * Implementation of \ref comforce.hpp */ #include "utils.hpp" #include "comforce.hpp" diff --git a/src/comforce.hpp b/src/core/comforce.hpp similarity index 93% rename from src/comforce.hpp rename to src/core/comforce.hpp index d27024bb2df..19123c78491 100644 --- a/src/comforce.hpp +++ b/src/core/comforce.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file comforce.h +/** \file comforce.hpp * Routines for center of mass forces */ diff --git a/src/communication.cpp b/src/core/communication.cpp similarity index 92% rename from src/communication.cpp rename to src/core/communication.cpp index 593b5ef7bcc..58ad0d9cdb0 100644 --- a/src/communication.cpp +++ b/src/core/communication.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -51,6 +51,7 @@ #include "mmm1d.hpp" #include "mmm2d.hpp" #include "maggs.hpp" +#include "actor/EwaldgpuForce.hpp" #include "elc.hpp" #include "iccp3m.hpp" #include "statistics_chain.hpp" @@ -62,16 +63,17 @@ #include "mdlc_correction.hpp" #include "reaction.hpp" #include "galilei.hpp" +#include "external_potential.hpp" #include "statistics_correlation.hpp" #include "cuda_interface.hpp" +#include "EspressoSystemInterface.hpp" +#include "statistics_observable.hpp" + +using namespace std; int this_node = -1; int n_nodes = -1; MPI_Comm comm_cart; -/********************************************** - * slave callbacks. - **********************************************/ -typedef void (SlaveCallback)(int node, int param); // if you want to add a callback, add it here, and here only #define CALLBACK_LIST \ @@ -93,6 +95,7 @@ typedef void (SlaveCallback)(int node, int param); CB(mpi_set_time_step_slave) \ CB(mpi_get_particles_slave) \ CB(mpi_bcast_coulomb_params_slave) \ + CB(mpi_bcast_collision_params_slave) \ CB(mpi_send_ext_force_slave) \ CB(mpi_send_ext_torque_slave) \ CB(mpi_place_new_particle_slave) \ @@ -115,7 +118,6 @@ typedef void (SlaveCallback)(int node, int param); CB(mpi_sync_topo_part_info_slave) \ CB(mpi_send_mass_slave) \ CB(mpi_send_solvation_slave) \ - CB(mpi_gather_runtime_errors_slave) \ CB(mpi_send_exclusion_slave) \ CB(mpi_bcast_lb_params_slave) \ CB(mpi_bcast_cuda_global_part_vars_slave) \ @@ -125,7 +127,6 @@ typedef void (SlaveCallback)(int node, int param); CB(mpi_recv_fluid_slave) \ CB(mpi_local_stress_tensor_slave) \ CB(mpi_send_virtual_slave) \ - CB(mpi_bcast_tf_params_slave) \ CB(mpi_iccp3m_iteration_slave) \ CB(mpi_iccp3m_init_slave) \ CB(mpi_send_rotational_inertia_slave) \ @@ -145,6 +146,11 @@ typedef void (SlaveCallback)(int node, int param); CB(mpi_galilei_transform_slave) \ CB(mpi_setup_reaction_slave) \ CB(mpi_send_rotation_slave) \ + CB(mpi_external_potential_broadcast_slave) \ + CB(mpi_external_potential_tabulated_read_potential_file_slave) \ + CB(mpi_external_potential_sum_energies_slave) \ + CB(mpi_observable_lb_radial_velocity_profile_slave) \ + CB(mpiRuntimeErrorCollectorGatherSlave) \ // create the forward declarations #define CB(name) void name(int node, int param); @@ -153,7 +159,7 @@ CALLBACK_LIST // create the list of callbacks #undef CB #define CB(name) name, -static SlaveCallback *slave_callbacks[] = { +static SlaveCallback * const slave_callbacks[] = { CALLBACK_LIST }; @@ -170,7 +176,6 @@ const char *names[] = { // tag which is used by MPI send/recv inside the slave functions #define SOME_TAG 42 - /** The requests are compiled statically here, so that after a crash you can get the last issued request from the debugger. */ static int request[3]; @@ -209,12 +214,15 @@ void mpi_init(int *argc, char ***argv) MPI_Cart_coords(comm_cart, this_node, 3, node_pos); #ifdef MPI_CORE - MPI_Errhandler_create((MPI_Handler_function *)mpi_core, &mpi_errh); - MPI_Errhandler_set(comm_cart, mpi_errh); + MPI_Comm_create_errhandler((MPI_Handler_function *)mpi_core, &mpi_errh); + MPI_Comm_set_errhandler(comm_cart, mpi_errh); #endif + + initRuntimeErrorCollector(); } -static void mpi_call(SlaveCallback cb, int node, int param) { +#ifdef HAVE_MPI +void mpi_call(SlaveCallback cb, int node, int param) { // find req number in callback array int reqcode; for (reqcode = 0; reqcode < N_CALLBACKS; reqcode++) { @@ -238,6 +246,11 @@ static void mpi_call(SlaveCallback cb, int node, int param) { MPI_Bcast(request, 3, MPI_INT, 0, comm_cart); COMM_TRACE(fprintf(stderr, "%d: finished sending.\n", this_node)); } +#else + +void mpi_call(SlaveCallback cb, int node, int param) {} + +#endif /**************** REQ_TERM ************/ @@ -310,27 +323,25 @@ void mpi_who_has() Cell *cell; int *sizes = (int*)malloc(sizeof(int)*n_nodes); int *pdata = NULL; - int pdata_s = 0, i, c; - int pnode; - int n_part; + int pdata_s = 0; mpi_call(mpi_who_has_slave, -1, 0); - n_part = cells_get_n_particles(); + int n_part = cells_get_n_particles(); /* first collect number of particles on each node */ MPI_Gather(&n_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart); - for (i = 0; i <= max_seen_particle; i++) + for (int i = 0; i <= max_seen_particle; i++) particle_node[i] = -1; /* then fetch particle locations */ - for (pnode = 0; pnode < n_nodes; pnode++) { + for (int pnode = 0; pnode < n_nodes; pnode++) { COMM_TRACE(fprintf(stderr, "node %d reports %d particles\n", pnode, sizes[pnode])); if (pnode == this_node) { - for (c = 0; c < local_cells.n; c++) { + for (int c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; - for (i = 0; i < cell->n; i++) + for (int i = 0; i < cell->n; i++) particle_node[cell->part[i].p.identity] = this_node; } } @@ -341,7 +352,7 @@ void mpi_who_has() } MPI_Recv(pdata, sizes[pnode], MPI_INT, pnode, SOME_TAG, comm_cart, MPI_STATUS_IGNORE); - for (i = 0; i < sizes[pnode]; i++) + for (int i = 0; i < sizes[pnode]; i++) particle_node[pdata[i]] = pnode; } } @@ -393,14 +404,12 @@ void mpi_bcast_event_slave(int node, int event) maggs_count_charged_particles(); break; #endif - case INVALIDATE_SYSTEM: - local_invalidate_system(); + case SORT_PARTICLES: + local_sort_particles(); break; -#ifdef ADDITIONAL_CHECKS case CHECK_PARTICLES: check_particles(); break; -#endif #ifdef DP3M case P3M_COUNT_DIPOLES: @@ -615,6 +624,7 @@ void mpi_send_solvation_slave(int pnode, int part) #endif } + /********************* REQ_SET_M ********/ void mpi_send_mass(int pnode, int part, double mass) { @@ -1031,6 +1041,20 @@ void mpi_send_rotation_slave(int pnode, int part) #endif } +void mpi_observable_lb_radial_velocity_profile() +{ +#ifdef LB + mpi_call(mpi_observable_lb_radial_velocity_profile_slave, 0, 0); +#endif +} +void mpi_observable_lb_radial_velocity_profile_slave(int pnode, int part) +{ +#ifdef LB + mpi_observable_lb_radial_velocity_profile_slave_implementation(); +#endif +} + + /********************* REQ_SET_BOND ********/ @@ -1156,7 +1180,7 @@ void mpi_remove_particle(int pnode, int part) void mpi_remove_particle_slave(int pnode, int part) { if (part != -1) { - n_total_particles--; + n_part--; if (pnode == this_node) local_remove_particle(part); @@ -1170,18 +1194,19 @@ void mpi_remove_particle_slave(int pnode, int part) } /********************* REQ_INTEGRATE ********/ -int mpi_integrate(int n_steps) +int mpi_integrate(int n_steps, int reuse_forces) { if (!correlations_autoupdate) { - mpi_call(mpi_integrate_slave, -1, n_steps); - integrate_vv(n_steps); + mpi_call(mpi_integrate_slave, n_steps, reuse_forces); + integrate_vv(n_steps, reuse_forces); COMM_TRACE(fprintf(stderr, "%d: integration task %d done.\n", \ this_node, n_steps)); return check_runtime_errors(); } else { for (int i=0; i=0) { /* non-bonded interaction parameters */ /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */ @@ -1230,16 +1251,6 @@ void mpi_bcast_ia_params(int i, int j) MPI_Bcast(tabulated_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart); MPI_Bcast(tabulated_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart); } -#endif -#ifdef INTERFACE_CORRECTION - if(get_ia_param(i,j)->ADRESS_TAB_maxval > 0) { - MPI_Bcast(&adress_tablesize, 1, MPI_INT, 0, comm_cart); - - /* Communicate the data */ - MPI_Bcast(adress_tab_forces.e, adress_tablesize, MPI_DOUBLE, 0, comm_cart); - MPI_Bcast(adress_tab_energies.e, adress_tablesize, MPI_DOUBLE, 0, comm_cart); - } - /* NO IC FOR TABULATED BONDED INTERACTIONS YET!! */ #endif } else { @@ -1294,20 +1305,7 @@ void mpi_bcast_ia_params_slave(int i, int j) } } #endif -#ifdef INTERFACE_CORRECTION - { - int adress_tabsize=0; - if ( get_ia_param(i,j)->ADRESS_TAB_maxval > 0) { - MPI_Bcast(&adress_tabsize,1,MPI_INT,0,comm_cart); - realloc_doublelist(&adress_tab_forces, adress_tabsize); - realloc_doublelist(&adress_tab_energies, adress_tabsize); - MPI_Bcast(adress_tab_forces.e,adress_tabsize, MPI_DOUBLE, 0, comm_cart); - MPI_Bcast(adress_tab_energies.e,adress_tabsize, MPI_DOUBLE, 0, comm_cart); - } - } -#endif - } - else { /* bonded interaction parameters */ + } else { /* bonded interaction parameters */ make_bond_type_exist(i); /* realloc bonded_ia_params on slave nodes! */ MPI_Bcast(&(bonded_ia_params[i]),sizeof(Bonded_ia_parameters), MPI_BYTE, 0, comm_cart); @@ -1342,61 +1340,6 @@ void mpi_bcast_ia_params_slave(int i, int j) /*************** REQ_BCAST_IA_SIZE ************/ -/* #ifdef THERMODYNAMIC_FORCE */ -void mpi_bcast_tf_params(int i) -{ -#ifdef ADRESS - int tablesize=0; - - mpi_call(mpi_bcast_tf_params_slave, i, i); - tablesize = thermodynamic_forces.max; - - /* thermodynamic force parameters */ - /* non-bonded interaction parameters */ - /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */ - MPI_Bcast(get_tf_param(i), sizeof(TF_parameters), MPI_BYTE, - 0, comm_cart); - - /* If there are tabulated forces broadcast those as well */ - if ( get_tf_param(i)->TF_TAB_maxval > 0) { - /* First let all nodes know the new size for force and energy tables */ - MPI_Bcast(&tablesize, 1, MPI_INT, 0, comm_cart); - MPI_Barrier(comm_cart); // Don't do anything until all nodes have this information - - /* Communicate the data */ - MPI_Bcast(thermodynamic_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart); - MPI_Bcast(thermodynamic_f_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart); - //MPI_Bcast(TF_prefactor, 1, MPI_DOUBLE, 0, comm_cart); - } - - //on_short_range_ia_change(); -#endif -} - -void mpi_bcast_tf_params_slave(int i, int j) -{ -#ifdef ADRESS - int tablesize; - /* INCOMPATIBLE WHEN NODES USE DIFFERENT ARCHITECTURES */ - MPI_Bcast(get_tf_param(i), sizeof(TF_parameters), MPI_BYTE, - 0, comm_cart); - tablesize=0; - /* If there are tabulated forces broadcast those as well */ - if ( get_tf_param(i)->TF_TAB_maxval > 0) { - /* Determine the new size for force and energy tables */ - MPI_Bcast(&tablesize,1,MPI_INT,0,comm_cart); - MPI_Barrier(comm_cart); - /* Allocate sizes accordingly */ - realloc_doublelist(&thermodynamic_forces, tablesize); - realloc_doublelist(&thermodynamic_f_energies, tablesize); - /* Now communicate the data */ - MPI_Bcast(thermodynamic_forces.e,tablesize, MPI_DOUBLE, 0 , comm_cart); - MPI_Bcast(thermodynamic_f_energies.e,tablesize, MPI_DOUBLE, 0 , comm_cart); - } -#endif -} - - void mpi_bcast_n_particle_types(int ns) { mpi_call(mpi_bcast_n_particle_types_slave, -1, ns); @@ -1406,11 +1349,6 @@ void mpi_bcast_n_particle_types(int ns) void mpi_bcast_n_particle_types_slave(int pnode, int ns) { -#ifdef ADRESS - /* #ifdef THERMODYNAMIC_FORCE */ - realloc_tf_params(ns); - /* #endif */ -#endif realloc_ia_params(ns); } @@ -1582,7 +1520,7 @@ void mpi_local_stress_tensor_slave(int ana_num, int job) { void mpi_get_particles(Particle *result, IntList *bi) { IntList local_bi; - int n_part; + int local_part; int tot_size, i, g, pnode; int *sizes; Cell *cell; @@ -1591,17 +1529,17 @@ void mpi_get_particles(Particle *result, IntList *bi) mpi_call(mpi_get_particles_slave, -1, bi != NULL); sizes = (int*)malloc(sizeof(int)*n_nodes); - n_part = cells_get_n_particles(); + local_part = cells_get_n_particles(); /* first collect number of particles on each node */ - MPI_Gather(&n_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart); + MPI_Gather(&local_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart); tot_size = 0; for (i = 0; i < n_nodes; i++) tot_size += sizes[i]; - if (tot_size!=n_total_particles) { - fprintf(stderr,"%d: ERROR: mpi_get_particles: n_total_particles %d, but I counted %d. Exiting...\n", - this_node, n_total_particles, tot_size); + if (tot_size!=n_part) { + fprintf(stderr,"%d: ERROR: mpi_get_particles: n_part %d, but I counted %d. Exiting...\n", + this_node, n_part, tot_size); errexit(); } @@ -1818,10 +1756,10 @@ void mpi_bcast_coulomb_params_slave(int node, int parm) break; #endif case COULOMB_DH: - case COULOMB_DH_PW: MPI_Bcast(&dh_params, sizeof(Debye_hueckel_params), MPI_BYTE, 0, comm_cart); break; case COULOMB_MMM1D: + case COULOMB_MMM1D_GPU: MPI_Bcast(&mmm1d_params, sizeof(MMM1D_struct), MPI_BYTE, 0, comm_cart); break; case COULOMB_MMM2D: @@ -1830,6 +1768,11 @@ void mpi_bcast_coulomb_params_slave(int node, int parm) case COULOMB_MAGGS: MPI_Bcast(&maggs, sizeof(MAGGS_struct), MPI_BYTE, 0, comm_cart); break; +#ifdef EWALD_GPU + case COULOMB_EWALD_GPU: + MPI_Bcast(&ewaldgpu_params, sizeof(Ewaldgpu_params), MPI_BYTE, 0, comm_cart); + break; +#endif case COULOMB_RF: case COULOMB_INTER_RF: MPI_Bcast(&rf_params, sizeof(Reaction_field_params), MPI_BYTE, 0, comm_cart); @@ -1869,6 +1812,24 @@ void mpi_bcast_coulomb_params_slave(int node, int parm) #endif } +/*************** REQ_BCAST_COULOMB ************/ +void mpi_bcast_collision_params() +{ +#ifdef COLLISION_DETECTION + mpi_call(mpi_bcast_collision_params_slave, 1, 0); + mpi_bcast_collision_params_slave(-1, 0); +#endif +} + +void mpi_bcast_collision_params_slave(int node, int parm) +{ +#ifdef COLLISION_DETECTION + MPI_Bcast(&collision_params, sizeof(Collision_parameters), MPI_BYTE, 0, comm_cart); + + recalc_forces = 1; +#endif +} + /****************** REQ_SET_EXT ************/ void mpi_send_ext_torque(int pnode, int part, int flag, int mask, double torque[3]) @@ -2135,6 +2096,7 @@ void mpi_random_stat_slave(int pnode, int cnt) { } } + /*************** REQ_BCAST_LJFORCECAP ************/ /*************** REQ_BCAST_LJANGLEFORCECAP ************/ /*************** REQ_BCAST_MORSEFORCECAP ************/ @@ -2441,60 +2403,11 @@ void mpi_bcast_cuda_global_part_vars_slave(int node, int dummy) { #ifdef CUDA MPI_Bcast(gpu_get_global_particle_vars_pointer_host(), sizeof(CUDA_global_part_vars), MPI_BYTE, 0, comm_cart); + espressoSystemInterface.requestParticleStructGpu(); #endif } - -/******************* REQ_GET_ERRS ********************/ - -int mpi_gather_runtime_errors(char **errors) -{ - // Tell other processors to send their erros - mpi_call(mpi_gather_runtime_errors_slave, -1, 0); - - // If no processor encountered an error, return - if (!check_runtime_errors()) - return ES_OK; - - // gather the maximum length of the error messages - int *errcnt = (int*)malloc(n_nodes*sizeof(int)); - MPI_Gather(&n_error_msg, 1, MPI_INT, errcnt, 1, MPI_INT, 0, comm_cart); - - for (int node = 0; node < n_nodes; node++) { - if (errcnt[node] > 0) { - errors[node] = (char *)malloc(errcnt[node]); - - if (node == 0) - strcpy(errors[node], error_msg); - else - MPI_Recv(errors[node], errcnt[node], MPI_CHAR, node, 0, comm_cart, MPI_STATUS_IGNORE); - } - else - errors[node] = NULL; - } - - /* reset error message on master node */ - error_msg = (char*)realloc(error_msg, n_error_msg = 0); - - free(errcnt); - - return ES_ERROR; -} - -void mpi_gather_runtime_errors_slave(int node, int parm) -{ - if (!check_runtime_errors()) - return; - - MPI_Gather(&n_error_msg, 1, MPI_INT, NULL, 0, MPI_INT, 0, comm_cart); - if (n_error_msg > 0) { - MPI_Send(error_msg, n_error_msg, MPI_CHAR, 0, 0, comm_cart); - /* reset error message on slave node */ - error_msg = (char*)realloc(error_msg, n_error_msg = 0); - } -} - /********************* REQ_SET_EXCL ********/ void mpi_send_exclusion(int part1, int part2, int _delete) { @@ -2521,7 +2434,7 @@ void mpi_send_exclusion_slave(int part1, int part2) void mpi_send_fluid(int node, int index, double rho, double *j, double *pi) { #ifdef LB if (node==this_node) { - lb_calc_n_equilibrium(index, rho, j, pi); + lb_calc_n_from_rho_j_pi(index, rho, j, pi); } else { double data[10] = { rho, j[0], j[1], j[2], pi[0], pi[1], pi[2], pi[3], pi[4], pi[5] }; mpi_call(mpi_send_fluid_slave, node, index); @@ -2536,7 +2449,7 @@ void mpi_send_fluid_slave(int node, int index) { double data[10]; MPI_Recv(data, 10, MPI_DOUBLE, 0, SOME_TAG, comm_cart, MPI_STATUS_IGNORE); - lb_calc_n_equilibrium(index, data[0], &data[1], &data[4]); + lb_calc_n_from_rho_j_pi(index, data[0], &data[1], &data[4]); } #endif } @@ -2965,6 +2878,56 @@ void mpi_loop() slave_callbacks[request[0]](request[1], request[2]); COMM_TRACE(fprintf(stderr, "%d: finished %s %d %d\n", this_node, names[request[0]], request[1], request[2])); + + } +} + +void mpi_external_potential_broadcast(int number) { + mpi_call(mpi_external_potential_broadcast_slave, 0, number); + MPI_Bcast(&external_potentials[number], sizeof(ExternalPotential), MPI_BYTE, 0, comm_cart); + MPI_Bcast(external_potentials[number].scale, external_potentials[number].n_particle_types, MPI_DOUBLE, 0, comm_cart); +} + +void mpi_external_potential_broadcast_slave(int node, int number) { + ExternalPotential E; + MPI_Bcast(&E, sizeof(ExternalPotential), MPI_BYTE, 0, comm_cart); + ExternalPotential* new_; + generate_external_potential(&new_); + external_potentials[number] = E; + external_potentials[number].scale=(double*) malloc(external_potentials[number].n_particle_types); + MPI_Bcast(external_potentials[number].scale, external_potentials[number].n_particle_types, MPI_DOUBLE, 0, comm_cart); +} + +void mpi_external_potential_tabulated_read_potential_file(int number) { + mpi_call(mpi_external_potential_tabulated_read_potential_file_slave, 0, number); + external_potential_tabulated_read_potential_file(number); +} + +void mpi_external_potential_tabulated_read_potential_file_slave(int node, int number) { + external_potential_tabulated_read_potential_file(number); +} + +void mpi_external_potential_sum_energies() { + mpi_call(mpi_external_potential_sum_energies_slave, 0, 0); + double* energies = (double*) malloc(n_external_potentials*sizeof(double)); + for (int i=0; i. */ -#ifndef _COMMUNICATION_H -#define _COMMUNICATION_H -/** \file communication.h +#ifndef _COMMUNICATION_HPP +#define _COMMUNICATION_HPP +/** \file communication.hpp This file contains the asynchronous MPI communication. - It is the header file for \ref communication.c "communication.c". + It is the header file for \ref communication.cpp "communication.c". The asynchronous MPI communication is used during the script evaluation. Except for the master node that interpretes the Tcl @@ -40,7 +40,7 @@ following: - write the mpi_* function that is executed on the master - write the mpi_*_slave function - - Add your slave function to CALLBACK_LIST in communication.c + - Add your slave function to CALLBACK_LIST in communication.cpp After this your procedure is free to do anything. However, it has to be in (MPI) sync with what your new mpi_*_slave does. This @@ -52,7 +52,6 @@ /* from here we borrow the enumeration of the global variables */ -#include "global.hpp" #include "particle_data.hpp" #include "random.hpp" #include "topology.hpp" @@ -77,22 +76,30 @@ extern MPI_Comm comm_cart; * the slave nodes. It is denoted by *_slave. **************************************************/ +/********************************************** + * slave callbacks. + **********************************************/ +typedef void (SlaveCallback)(int node, int param); + /** \name Exported Functions */ /*@{*/ /** Initialize MPI and determine \ref n_nodes and \ref this_node. */ -void mpi_init(int *argc, char ***argv); +void mpi_init(int *argc = NULL, char ***argv = NULL); + +/* Call a slave function. */ +void mpi_call(SlaveCallback cb, int node, int param); /** Process requests from master node. Slave nodes main loop. */ void mpi_loop(); -/** Issue REQ_TERM: stop Espresso, all slave nodes exit. */ +/** Stop Espresso, all slave nodes exit. */ void mpi_stop(); /** Finalize MPI. Called by all nodes upon exit */ void mpi_finalize(); /** Issue REQ_BCAST_PAR: broadcast a parameter from datafield. - @param i the number from \ref global.h "global.h" referencing the datafield. + @param i the number from \ref global.hpp "global.hpp" referencing the datafield. @return nonzero on error */ int mpi_bcast_parameter(int i); @@ -106,7 +113,7 @@ void mpi_who_has();
  • PARTICLE_CHANGED
  • INTERACTION_CHANGED - Then all nodes execute the respective on_* procedure from \ref initialize.c + Then all nodes execute the respective on_* procedure from \ref initialize.cpp Note that not all of these codes are used. Since some actions (like placing a particle) include communication anyways, this is handled by the way. */ @@ -144,8 +151,8 @@ void mpi_send_v(int node, int part, double v[3]); */ void mpi_send_f(int node, int part, double F[3]); -/** Issue REQ_SET_SOLV: send particle solvation free energy - Also calls \ref on_particle_change. +/** issue req_set_solv: send particle solvation free energy + also calls \ref on_particle_change. \param part the particle. \param node the node it is attached to. \param solvation its new solvation free energy. @@ -153,7 +160,6 @@ void mpi_send_f(int node, int part, double F[3]); void mpi_send_solvation(int node, int part, double *solvation); - /** Issue REQ_SET_M: send particle mass. Also calls \ref on_particle_change. \param part the particle. @@ -311,9 +317,10 @@ void mpi_recv_part(int node, int part, Particle *part_data); /** Issue REQ_INTEGRATE: start integrator. @param n_steps how many steps to do. + @param reuse_forces whether to trust the old forces for the first half step @return nonzero on error */ -int mpi_integrate(int n_steps); +int mpi_integrate(int n_steps, int reuse_forces); /** Issue REQ_BCAST_IA: send new ia params. Also calls \ref on_short_range_ia_change. @@ -328,13 +335,6 @@ int mpi_integrate(int n_steps); if negative: flag for bonded interaction */ void mpi_bcast_ia_params(int i, int j); -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -void mpi_bcast_tf_params(int i); -/* #endif */ -#endif - - /** Issue REQ_BCAST_IA_SIZE: send new size of \ref ia_params. \param s the new size for \ref ia_params. */ @@ -405,6 +405,9 @@ void mpi_set_time_step(double time_step); /** Issue REQ_BCAST_COULOMB: send new coulomb parameters. */ void mpi_bcast_coulomb_params(); +/** send new collision parameters. */ +void mpi_bcast_collision_params(); + /** Issue REQ_SEND_EXT_FORCE: send nex external flag and external force. */ void mpi_send_ext_force(int pnode, int part, int flag, int mask, double force[3]); @@ -477,7 +480,7 @@ void mpi_update_mol_ids(void); int mpi_sync_topo_part_info(void); /** Issue REQ_BCAST_LBPAR: Broadcast a parameter for Lattice Boltzmann. - * @param field References the parameter field to be broadcasted. The references are defined in \ref lb.h "lb.h" + * @param field References the parameter field to be broadcasted. The references are defined in \ref lb.hpp "lb.hpp" */ void mpi_bcast_lb_params(int field); @@ -538,14 +541,6 @@ void mpi_send_fluid_populations(int node, int index, double *pop); */ void mpi_bcast_max_mu(); -/** Issue REQ_GET_ERRS: gather all error messages from all nodes and return them - - @param errors contains the errors from all nodes. This has to point to an array - of character pointers, one for each node. - @return \ref ES_OK if no error occured, otherwise \ref ES_ERROR -*/ -int mpi_gather_runtime_errors(char **errors); - /** Galilei and other: set all particle velocities and rotational inertias to zero. set all forces and torques on the particles to zero calculate the centre of mass (CMS) @@ -557,11 +552,18 @@ void mpi_kill_particle_forces( int torque ); void mpi_system_CMS(); void mpi_system_CMS_velocity(); void mpi_galilei_transform(); +void mpi_observable_lb_radial_velocity_profile(); /** Issue REQ_CATALYTIC_REACTIONS: notify the system of changes to the reaction parameters */ void mpi_setup_reaction(); +void mpi_external_potential_broadcast(int number); +void mpi_external_potential_broadcast_slave(int node, int number); +void mpi_external_potential_tabulated_read_potential_file(int number); +void mpi_external_potential_sum_energies(); +void mpi_external_potential_sum_energies_slave(); + /*@}*/ /** \name Event codes for \ref mpi_bcast_event @@ -569,9 +571,9 @@ void mpi_setup_reaction(); of doing something now. */ /*@{*/ -#define P3M_COUNT_CHARGES 0 -#define INVALIDATE_SYSTEM 1 -#define CHECK_PARTICLES 2 +#define P3M_COUNT_CHARGES 0 +#define SORT_PARTICLES 1 +#define CHECK_PARTICLES 2 #define MAGGS_COUNT_CHARGES 3 #define P3M_COUNT_DIPOLES 5 /*@}*/ diff --git a/src/config.hpp b/src/core/config.hpp similarity index 87% rename from src/config.hpp rename to src/core/config.hpp index 8dfe1815379..896b4ffa422 100644 --- a/src/config.hpp +++ b/src/core/config.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,37 +18,31 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef _CONFIG_H -#define _CONFIG_H +#ifndef _CONFIG_HPP +#define _CONFIG_HPP -/** \file config.h +/** \file config.hpp This file contains the defaults for Espresso. To modify them, add - an appropriate line in myconfig.h. To find a list of features that - can be compiled into Espresso, refer to myconfig-sample.h or to + an appropriate line in myconfig.hpp. To find a list of features that + can be compiled into Espresso, refer to myconfig-sample.hpp or to the documentation of the features. */ /* Include the defines created by configure. */ #include -/* Prevent C++ bindings in OpenMPI (there is a DataType called LB in there) */ +/* Prevent C++ bindings in MPI (there is a DataType called LB in there) */ #define OMPI_SKIP_MPICXX +#define MPICH_SKIP_MPICXX -/* doxyconfig.h is used instead of myconfig when doxygen is run */ -/* doxyconfig.h defines all features so that all features are documented */ -#ifndef DOXYGEN_RUN #include "myconfig-final.hpp" -#else -#include "config-doxygen.hpp" -#endif - #include "config-features.hpp" extern const char* ESPRESSO_VERSION; /*********************************************************/ -/** \name Parameters from myconfig.h that need to be set */ +/** \name Parameters from myconfig.hpp that need to be set */ /*********************************************************/ /*@{*/ @@ -142,7 +136,7 @@ extern const char* ESPRESSO_VERSION; #endif -/* Mathematical constants, from gcc's math.h */ +/* Mathematical constants, from gcc's math.hpp */ #ifndef M_PI #define M_E 2.7182818284590452353602874713526625L /* e */ #define M_LOG2E 1.4426950408889634073599246810018921L /* log_2 e */ diff --git a/src/constraint.cpp b/src/core/constraint.cpp similarity index 71% rename from src/constraint.cpp rename to src/core/constraint.cpp index 3cbc4022d76..8877f2a42c4 100644 --- a/src/constraint.cpp +++ b/src/core/constraint.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,13 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file constraint.c - Implementation of \ref constraint.h "constraint.h", here it's just the parsing stuff. +/** \file constraint.cpp + Implementation of \ref constraint.hpp "constraint.hpp", here it's just the parsing stuff. */ +#include #include "constraint.hpp" -#include "energy.hpp" -#include "forces.hpp" +#include "energy_inline.hpp" +#include "forces_inline.hpp" #include "tunable_slip.hpp" // for the charged rod "constraint" @@ -64,10 +65,6 @@ static double sign(double x) { return -1; } -static double max(double x1, double x2) { - return x1>x2?x1:x2; -} - void calculate_wall_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_wall *c, double *dist, double *vec) { int i; @@ -889,7 +886,7 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint double e_z[3], e_r[3]; /* unit vectors in the cylindrical coordinate system */ /* helper variables, for performance reasons should the be move the the * constraint struct*/ - double slope, z_left, z_right; + double slope, slope2, z_left, z_right; /* and another helper that is hopefully optmized out */ double norm; double c1_r, c1_z, c2_r, c2_z; @@ -897,6 +894,7 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint slope = (c->rad_right - c->rad_left)/2./(c->length-c->smoothing_radius); + slope2 = (c->outer_rad_right - c->outer_rad_left)/2./(c->length-c->smoothing_radius); /* compute the position relative to the center of the pore */ for(i=0;i<3;i++) { @@ -946,9 +944,12 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint sqrt( c->smoothing_radius * c->smoothing_radius - SQR( z_right - c2_z ) ); c1_r = c->rad_left+c->smoothing_radius; c2_r = c->rad_right+c->smoothing_radius; + + double c1_or = c->outer_rad_left-c->smoothing_radius; + double c2_or = c->outer_rad_right-c->smoothing_radius; /* Check if we are in the region of the left wall */ - if (( (r >= c1_r) && (z <= c1_z) ) || ( ( z <= 0 ) && (r>=max(c1_r, c2_r)))) { + if (( (r >= c1_r) && (r <= c1_or) && (z <= c1_z) )) { dist_vector_z=-z - c->length; dist_vector_r=0; *dist = -z - c->length; @@ -956,7 +957,7 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint return; } /* Check if we are in the region of the right wall */ - if (( (r >= c2_r) && (z <= c2_z) ) || ( ( z >= 0 ) && (r>=max(c1_r, c2_r)))) { + if (( (r >= c2_r) && (r= c2_z) ) ) { dist_vector_z=-z + c->length; dist_vector_r=0; *dist = +z - c->length; @@ -972,29 +973,38 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint cone_vector_z=1/sqrt(1+slope*slope); cone_vector_r=slope/sqrt(1+slope*slope); + + double cone_vector_z_o=1/sqrt(1+slope2*slope2); + double cone_vector_r_o=slope2/sqrt(1+slope2*slope2); p1_r = c1_r+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_r; p1_z = c1_z+ ( (r-c1_r)*cone_vector_r + (z-c1_z)*cone_vector_z) * cone_vector_z; + double p2_r = c1_or+ ( (r-c1_or)*cone_vector_r_o + (z-c1_z)*cone_vector_z_o) * cone_vector_r_o; + double p2_z = c1_z+ ( (r-c1_or)*cone_vector_r_o + (z-c1_z)*cone_vector_z_o) * cone_vector_z_o; + dist_vector_r = p1_r-r; dist_vector_z = p1_z-z; - if ( p1_z>=c1_z && p1_z<=c2_z ) { - if ( dist_vector_r <= 0 ) { - if (z<0) { - dist_vector_z=-z - c->length; - dist_vector_r=0; - *dist = -z - c->length; - for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; - return; - } else { - dist_vector_z=-z + c->length; - dist_vector_r=0; - *dist = +z - c->length; - for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; - return; - } - } + double dist_vector_r_o = p2_r-r; + double dist_vector_z_o = p2_z-z; + + if ( p1_z>=c1_z && p1_z<=c2_z && dist_vector_r >= 0 ) { + // if ( dist_vector_r <= 0 ) { + // if (z<0) { + // dist_vector_z=-z - c->length; + // dist_vector_r=0; + // *dist = -z - c->length; + // for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; + // return; + // } else { + // dist_vector_z=-z + c->length; + // dist_vector_r=0; + // *dist = +z - c->length; + // for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; + // return; + // } + // } temp=sqrt( dist_vector_r*dist_vector_r + dist_vector_z*dist_vector_z ); *dist=temp-c->smoothing_radius; dist_vector_r-=dist_vector_r/temp*c->smoothing_radius; @@ -1004,8 +1014,33 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint } + if ( p2_z>=c1_z && p2_z<=c2_z && dist_vector_r_o <= 0 ) { + // if ( dist_vector_r <= 0 ) { + // if (z<0) { + // dist_vector_z=-z - c->length; + // dist_vector_r=0; + // *dist = -z - c->length; + // for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; + // return; + // } else { + // dist_vector_z=-z + c->length; + // dist_vector_r=0; + // *dist = +z - c->length; + // for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - 2ist_vector_z*e_z[i]; + // return; + // } + // } + temp=sqrt( dist_vector_r_o*dist_vector_r_o + dist_vector_z_o*dist_vector_z_o ); + *dist=temp-c->smoothing_radius; + dist_vector_r_o-=dist_vector_r_o/temp*c->smoothing_radius; + dist_vector_z_o-=dist_vector_z_o/temp*c->smoothing_radius; + for (i=0; i<3; i++) vec[i]=-dist_vector_r_o*e_r[i] - dist_vector_z_o*e_z[i]; + return; + } + + /* Check if we are in the range of the left smoothing circle */ - if (p1_z <= c1_z ) { + if (p1_z <= c1_z && r <= c1_r ) { /* distance from the smoothing center */ norm = sqrt( (z - c1_z)*(z - c1_z) + (r - c1_r)*(r - c1_r) ); *dist = norm - c->smoothing_radius; @@ -1014,16 +1049,37 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } + /* upper left smoothing circle */ + if (p2_z <= c1_z && r >= c1_or ) { + /* distance from the smoothing center */ + norm = sqrt( (z - c1_z)*(z - c1_z) + (r - c1_or)*(r - c1_or) ); + *dist = norm - c->smoothing_radius; + dist_vector_r=(c->smoothing_radius/norm -1)*(r - c1_or); + dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c1_z); + for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; + return; + } /* Check if we are in the range of the right smoothing circle */ - if (p1_z >= c2_z ) { + if (p1_z >= c2_z && r <= c2_r ) { norm = sqrt( (z - c2_z)*(z - c2_z) + (r - c2_r)*(r - c2_r) ); *dist = norm - c->smoothing_radius; - dist_vector_r=(c->smoothing_radius/norm -1)*(r - c2_r); + dist_vector_r=(c->smoothing_radius/norm -1)*(r - c2_or); dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c2_z); for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; return; } - exit(printf("should never be reached, z %f, r%f\n",z, r)); + /* Check if we are in the range of the upper right smoothing circle */ + if (p2_z >= c2_z && r >= c2_or ) { + norm = sqrt( (z - c2_z)*(z - c2_z) + (r - c2_or)*(r - c2_or) ); + *dist = norm - c->smoothing_radius; + dist_vector_r=(c->smoothing_radius/norm -1)*(r - c2_or); + dist_vector_z=(c->smoothing_radius/norm - 1)*(z - c2_z); + for (i=0; i<3; i++) vec[i]=-dist_vector_r*e_r[i] - dist_vector_z*e_z[i]; + return; + } + *dist=-1e99; + vec[0] = vec[1] = vec[2] = 1e99; +// exit(printf("should never be reached, z %f, r%f\n",z, r)); } void calculate_plane_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_plane *c, double *dist, double *vec) @@ -1591,6 +1647,484 @@ void calculate_stomatocyte_dist( Particle *p1, double ppos [3], // And we are done with the stomatocyte } +void calculate_hollow_cone_dist( Particle *p1, double ppos [3], + Particle *c_p, Constraint_hollow_cone *cons, + double *dist, double *vec ) +{ + // Parameters + + int number; + double r0, r1, w, alpha, xd, yd, zd, + mu, x_2D, y_2D, t0, t1, t2, + time1, time2, time3, time4, + mdst0, mdst1, mdst2, mdst3, + mindist, normalize, x, y, z, + distance, normal_x, normal_y, direction, + xp, yp, zp, xpp, ypp, sin_xy, cos_xy, + normal_x_3D, normal_y_3D, normal_z_3D, + normal_3D_x, normal_3D_y, normal_3D_z; + + double closest_point_3D [3] = { -1.0, -1.0, -1.0 }; + + // Set the dimensions of the hollow cone + + r0 = cons->inner_radius; + r1 = cons->outer_radius; + w = cons->width; + alpha = cons->opening_angle; + + // Set the position and orientation of the hollow cone + + double hollow_cone_3D_position [3] = { cons->position_x, + cons->position_y, + cons->position_z }; + + double hollow_cone_3D_orientation [3] = { cons->orientation_x, + cons->orientation_y, + cons->orientation_z }; + + // Set the point for which we want to know the distance + + double point_3D[3]; + + point_3D[0] = ppos[0]; + point_3D[1] = ppos[1]; + point_3D[2] = ppos[2]; + + /***** Convert 3D coordinates to 2D planar coordinates *****/ + + // Calculate the point on position + mu * orientation, + // where the difference segment is orthogonal + + mu = ( + hollow_cone_3D_orientation[0]*point_3D[0] + + hollow_cone_3D_orientation[1]*point_3D[1] + + hollow_cone_3D_orientation[2]*point_3D[2] + - hollow_cone_3D_position[0]*hollow_cone_3D_orientation[0] + - hollow_cone_3D_position[1]*hollow_cone_3D_orientation[1] + - hollow_cone_3D_position[2]*hollow_cone_3D_orientation[2] + ) / ( + hollow_cone_3D_orientation[0]*hollow_cone_3D_orientation[0] + + hollow_cone_3D_orientation[1]*hollow_cone_3D_orientation[1] + + hollow_cone_3D_orientation[2]*hollow_cone_3D_orientation[2] + ); + + // Then the closest point to the line is + + closest_point_3D[0] = hollow_cone_3D_position[0] + + mu*hollow_cone_3D_orientation[0]; + closest_point_3D[1] = hollow_cone_3D_position[1] + + mu*hollow_cone_3D_orientation[1]; + closest_point_3D[2] = hollow_cone_3D_position[2] + + mu*hollow_cone_3D_orientation[2]; + + // So the shortest distance to the line is + + x_2D = sqrt( + ( closest_point_3D[0] - point_3D[0] ) * + ( closest_point_3D[0] - point_3D[0] ) + + ( closest_point_3D[1] - point_3D[1] ) * + ( closest_point_3D[1] - point_3D[1] ) + + ( closest_point_3D[2] - point_3D[2] ) * + ( closest_point_3D[2] - point_3D[2] ) + ); + + + y_2D = mu*sqrt( + hollow_cone_3D_orientation[0]*hollow_cone_3D_orientation[0] + + hollow_cone_3D_orientation[1]*hollow_cone_3D_orientation[1] + + hollow_cone_3D_orientation[2]*hollow_cone_3D_orientation[2] + ); + + /***** Use the obtained planar coordinates in distance function *****/ + + // Calculate intermediate results which we need to determine + // the distance + + t0 = ( y_2D*cos(alpha) + ( x_2D - r0 )*sin(alpha) )/r1; + t1 = ( w - 2.0*( x_2D - r0 )*cos(alpha) + 2.0*y_2D*sin(alpha) )/( 2.0*w ); + t2 = ( w + 2.0*( x_2D - r0 )*cos(alpha) - 2.0*y_2D*sin(alpha) )/( 2.0*w ); + + if ( t0 >= 0.0 && t0 <= 1.0 ) + { + time1 = t0; + time2 = t0; + } + else if ( t0 > 1.0 ) + { + time1 = 1.0; + time2 = 1.0; + } + else + { + time1 = 0.0; + time2 = 0.0; + } + + if ( t1 >= 0.0 && t1 <= 1.0 ) + { + time3 = t1; + } + else if ( t1 > 1.0 ) + { + time3 = 1.0; + } + else + { + time3 = 0.0; + } + + if ( t2 >= 0.0 && t2 <= 1.0 ) + { + time4 = t2; + } + else if ( t2 > 1.0 ) + { + time4 = 1.0; + } + else + { + time4 = 0.0; + } + + mdst0 = x_2D*x_2D + y_2D*y_2D - 2.0*x_2D*r0 + r0*r0 + r1*r1*time1*time1 + + 0.25*w*w + ( -2.0*y_2D*r1*time1 + ( x_2D - r0 )*w )*cos(alpha) + - ( 2.0*x_2D*r1*time1 - 2.0*r0*r1*time1 + y_2D*w )*sin(alpha); + mdst0 = sqrt(mdst0); + + mdst1 = x_2D*x_2D + y_2D*y_2D - 2.0*x_2D*r0 + r0*r0 + r1*r1*time2*time2 + + 0.25*w*w + ( -2.0*y_2D*r1*time2 + ( -x_2D + r0 )*w )*cos(alpha) + + ( -2.0*x_2D*r1*time2 + 2.0*r0*r1*time2 + y_2D*w )*sin(alpha); + mdst1 = sqrt(mdst1); + + mdst2 = x_2D*x_2D + y_2D*y_2D - 2.0*x_2D*r0 + r0*r0 + + 0.25*w*w - time3*w*w + time3*time3*w*w + + ( x_2D - r0 )*( -1.0 + 2.0*time3 )*w*cos(alpha) + - y_2D*( -1.0 + 2.0*time3 )*w*sin(alpha); + mdst2 = sqrt(mdst2); + + mdst3 = x_2D*x_2D + y_2D*y_2D - 2.0*x_2D*r0 + r0*r0 + + 0.25*w*w - time4*w*w + time4*time4*w*w + - ( x_2D - r0 )*( -1.0 + 2.0*time4 )*w*cos(alpha) + + y_2D*( -1.0 + 2.0*time4 )*w*sin(alpha) + + r1*r1 - 2.0*y_2D*r1*cos(alpha) + + ( -2.0*x_2D*r1 + 2.0*r0*r1 )*sin(alpha); + mdst3 = sqrt(mdst3); + + double distlist[4] = { mdst0, mdst1, mdst2, mdst3 }; + + // Now we only need to determine which distance is minimal + // and remember which one it is + + mindist = -1.0; + + for ( int i = 0; i < 4; i++ ) + { + if ( mindist < 0.0 ) + { + number = i; + mindist = distlist[i]; + } + + if ( mindist > distlist[i] ) + { + number = i; + mindist = distlist[i]; + } + } + + // Now we know the number corresponding to the boundary + // to which the point is closest, we know the distance, + // but we still need the normal + + distance = -1.0; + normal_x = -1.0; + normal_y = -1.0; + + if ( number == 0 ) + { + normal_x = x_2D - r0 + 0.5*w*cos(alpha) - r1*time1*sin(alpha); + normal_y = y_2D - r1*time1*cos(alpha) - 0.5*w*sin(alpha); + normalize = 1.0/sqrt( normal_x*normal_x + normal_y*normal_y ); + normal_x *= normalize; + normal_y *= normalize; + + direction = -normal_x*cos(alpha) + normal_y*sin(alpha); + + if ( fabs(direction) < 1.0e-06 && ( fabs( time1 - 0.0 ) < 1.0e-06 || fabs( time1 - 1.0 ) < 1.0e-06 ) ) + { + if( fabs( time1 - 0.0 ) < 1.0e-06 ) + { + direction = -normal_x*sin(alpha) - normal_y*cos(alpha); + } + else + { + direction = normal_x*sin(alpha) + normal_y*cos(alpha); + } + } + + if ( direction > 0.0 ) + { + distance = mindist; + } + else + { + distance = -mindist; + normal_x *= -1.0; + normal_y *= -1.0; + } + } + else if ( number == 1 ) + { + normal_x = x_2D - r0 - 0.5*w*cos(alpha) - r1*time2*sin(alpha); + normal_y = y_2D - r1*time2*cos(alpha) + 0.5*w*sin(alpha); + normalize = 1.0/sqrt( normal_x*normal_x + normal_y*normal_y ); + normal_x *= normalize; + normal_y *= normalize; + + direction = normal_x*cos(alpha) - normal_y*sin(alpha); + + if ( fabs(direction) < 1.0e-06 && ( fabs( time2 - 0.0 ) < 1.0e-06 || fabs( time2 - 1.0 ) < 1.0e-06 ) ) + { + if( fabs( time2 - 0.0 ) < 1.0e-06 ) + { + direction = -normal_x*sin(alpha) - normal_y*cos(alpha); + } + else + { + direction = normal_x*sin(alpha) + normal_y*cos(alpha); + } + } + + if ( direction > 0.0 ) + { + distance = mindist; + } + else + { + distance = -mindist; + normal_x *= -1.0; + normal_y *= -1.0; + } + } + else if ( number == 2 ) + { + normal_x = x_2D - r0 - 0.5*( 1.0 - 2.0*time3 )*w*cos(alpha); + normal_y = y_2D + 0.5*( 1.0 - 2.0*time3 )*w*sin(alpha); + normalize = 1.0/sqrt( normal_x*normal_x + normal_y*normal_y ); + normal_x *= normalize; + normal_y *= normalize; + + direction = -normal_x*sin(alpha) - normal_y*cos(alpha); + + if ( fabs(direction) < 1.0e-06 && ( fabs( time3 - 0.0 ) < 1.0e-06 || fabs( time3 - 1.0 ) < 1.0e-06 ) ) + { + if( fabs( time3 - 0.0 ) < 1.0e-06 ) + { + direction = normal_x*cos(alpha) - normal_y*sin(alpha); + } + else + { + direction = -normal_x*cos(alpha) + normal_y*sin(alpha); + } + } + + if ( direction > 0.0 ) + { + distance = mindist; + } + else + { + distance = -mindist; + normal_x *= -1.0; + normal_y *= -1.0; + } + } + else if ( number == 3 ) + { + normal_x = x_2D - r0 + 0.5*( 1.0 - 2.0*time4 )*w*cos(alpha) - r1*sin(alpha); + normal_y = y_2D - 0.5*( 1.0 - 2.0*time4 )*w*sin(alpha) - r1*cos(alpha); + normalize = 1.0/sqrt( normal_x*normal_x + normal_y*normal_y ); + normal_x *= normalize; + normal_y *= normalize; + + direction = normal_x*sin(alpha) + normal_y*cos(alpha); + + if ( fabs(direction) < 1.0e-06 && ( fabs( time4 - 0.0 ) < 1.0e-06 || fabs( time4 - 1.0 ) < 1.0e-06 ) ) + { + if( fabs( time4 - 0.0 ) < 1.0e-06 ) + { + direction = -normal_x*cos(alpha) + normal_y*sin(alpha); + } + else + { + direction = normal_x*cos(alpha) - normal_y*sin(alpha); + } + } + + if ( direction > 0.0 ) + { + distance = mindist; + } + else + { + distance = -mindist; + normal_x *= -1.0; + normal_y *= -1.0; + } + } + + /***** Convert 2D normal to 3D coordinates *****/ + + // Now that we have the normal in 2D we need to make a final + // transformation to get it in 3D. The minimum distance stays + // the same though. We first get the normalized direction vector. + + x = hollow_cone_3D_orientation[0]; + y = hollow_cone_3D_orientation[1]; + z = hollow_cone_3D_orientation[2]; + + xd = x/sqrt( x*x + y*y + z*z); + yd = y/sqrt( x*x + y*y + z*z); + zd = z/sqrt( x*x + y*y + z*z); + + // We now establish the rotion matrix required to go + // form {0,0,1} to {xd,yd,zd} + + double matrix [9]; + + if ( xd*xd + yd*yd > 1.e-10 ) + { + // Rotation matrix + + matrix[0] = ( yd*yd + xd*xd*zd )/( xd*xd + yd*yd ); + matrix[1] = ( xd*yd*( zd - 1.0 ) )/( xd*xd + yd*yd ); + matrix[2] = xd; + + matrix[3] = ( xd*yd*( zd - 1.0 ) )/( xd*xd + yd*yd ); + matrix[4] = ( xd*xd + yd*yd*zd )/( xd*xd + yd*yd ); + matrix[5] = yd; + + matrix[6] = -xd; + matrix[7] = -yd; + matrix[8] = zd; + } + else + { + // The matrix is the identity matrix or reverses + // or does a 180 degree rotation to take z -> -z + + if ( zd > 0 ) + { + matrix[0] = 1.0; + matrix[1] = 0.0; + matrix[2] = 0.0; + + matrix[3] = 0.0; + matrix[4] = 1.0; + matrix[5] = 0.0; + + matrix[6] = 0.0; + matrix[7] = 0.0; + matrix[8] = 1.0; + } + else + { + matrix[0] = 1.0; + matrix[1] = 0.0; + matrix[2] = 0.0; + + matrix[3] = 0.0; + matrix[4] = 1.0; + matrix[5] = 0.0; + + matrix[6] = 0.0; + matrix[7] = 0.0; + matrix[8] = -1.0; + } + } + + // Next we determine the 3D vector between the center + // of the hollow cylinder and the point of interest + + xp = point_3D[0] - hollow_cone_3D_position[0]; + yp = point_3D[1] - hollow_cone_3D_position[1]; + zp = point_3D[2] - hollow_cone_3D_position[2]; + + // Now we use the inverse matrix to find the + // position of the point with respect to the origin + // of the z-axis oriented hollow cone located + // in the origin + + xpp = matrix[0]*xp + matrix[3]*yp + matrix[6]*zp; + ypp = matrix[1]*xp + matrix[4]*yp + matrix[7]*zp; + + // Now use this direction to orient the normal + + if ( xpp*xpp + ypp*ypp > 1.0e-10 ) + { + // The point is off the rotational symmetry + // axis of the hollow cone + + sin_xy = ypp/sqrt( xpp*xpp + ypp*ypp ); + cos_xy = xpp/sqrt( xpp*xpp + ypp*ypp ); + + normal_x_3D = cos_xy*normal_x; + normal_y_3D = sin_xy*normal_x; + normal_z_3D = normal_y; + } + else + { + // The point is on the rotational symmetry + // axis of the hollow cone; a finite distance + // away from the center the normal might have + // an x and y component! + + normal_x_3D = 0.0; + normal_y_3D = 0.0; + normal_z_3D = ( normal_y > 0.0 ? 1.0 : -1.0 ); + } + + // Now we need to transform the normal back to + // the real coordinate system + + normal_3D_x = matrix[0]*normal_x_3D + + matrix[1]*normal_y_3D + + matrix[2]*normal_z_3D; + normal_3D_y = matrix[3]*normal_x_3D + + matrix[4]*normal_y_3D + + matrix[5]*normal_z_3D; + normal_3D_z = matrix[6]*normal_x_3D + + matrix[7]*normal_y_3D + + matrix[8]*normal_z_3D; + + // Pass the values we obtained to ESPResSo + + if ( cons->direction == -1 ) + { + // Apply force towards inside hollow cone + + *dist = -distance; + + vec[0] = -normal_3D_x; + vec[1] = -normal_3D_y; + vec[2] = -normal_3D_z; + } + else + { + // Apply force towards inside hollow cone + + *dist = distance; + + vec[0] = normal_3D_x; + vec[1] = normal_3D_y; + vec[2] = normal_3D_z; + } + + // And we are done with the hollow cone +} + + void add_rod_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c) { #ifdef ELECTROSTATICS @@ -1735,7 +2269,6 @@ void add_constraints_forces(Particle *p1) double dist, vec[3], force[3], torque1[3], torque2[3]; IA_parameters *ia_params; - char *errtxt; double folded_pos[3]; int img[3]; @@ -1764,19 +2297,20 @@ void add_constraints_forces(Particle *p1) torque1, torque2); } else if ( dist <= 0 && constraints[n].c.wal.penetrable == 1 ) { - if ( dist < 0 ) { + if ( (constraints[n].c.wal.only_positive != 1) && ( dist < 0 ) ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, - ia_params,vec,-1.0*dist,dist*dist, force, - torque1, torque2); + ia_params,vec,-1.0*dist,dist*dist, force, + torque1, torque2); } } else { - if(constraints[n].c.wal.reflecting){ - reflect_particle(p1, &(vec[0]), constraints[n].c.wal.reflecting); - } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{061 wall constraint %d violated by particle %d} ", n, p1->p.identity); - } + if(constraints[n].c.wal.reflecting){ + reflect_particle(p1, &(vec[0]), constraints[n].c.wal.reflecting); + } else { + ostringstream msg; + msg <<"wall constraint "<< n<<" violated by particle "<p.identity; + runtimeError(msg); + } } } break; @@ -1792,17 +2326,18 @@ void add_constraints_forces(Particle *p1) else if ( dist <= 0 && constraints[n].c.sph.penetrable == 1 ) { if ( dist < 0 ) { calc_non_bonded_pair_force(p1, &constraints[n].part_rep, - ia_params,vec,-1.0*dist,dist*dist, force, - torque1, torque2); + ia_params,vec,-1.0*dist,dist*dist, force, + torque1, torque2); } } else { - if(constraints[n].c.sph.reflecting){ - reflect_particle(p1, &(vec[0]), constraints[n].c.sph.reflecting); - } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{062 sphere constraint %d violated by particle %d} ", n, p1->p.identity); - } + if(constraints[n].c.sph.reflecting){ + reflect_particle(p1, &(vec[0]), constraints[n].c.sph.reflecting); + } else { + ostringstream msg; + msg << "sphere constraint "<< n <<" violated by particle "<p.identity; + runtimeError(msg); + } } } break; @@ -1826,8 +2361,9 @@ void add_constraints_forces(Particle *p1) if(constraints[n].c.cyl.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.cyl.reflecting); } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{063 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); + ostringstream msg; + msg << "cylinder constraint "<< n << " violated by particle "<< p1->p.identity; + runtimeError(msg); } } } @@ -1852,8 +2388,9 @@ void add_constraints_forces(Particle *p1) if(constraints[n].c.rhomboid.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.rhomboid.reflecting); } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{063 rhomboid constraint %d violated by particle %d} ", n, p1->p.identity); + ostringstream msg; + msg << "rhomboid constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } } @@ -1874,9 +2411,10 @@ void add_constraints_forces(Particle *p1) torque1, torque2); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{064 maze constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"maze constraint " << n << " violated by particle "<< p1->p.identity; + runtimeError(msg); } } break; @@ -1893,13 +2431,32 @@ void add_constraints_forces(Particle *p1) if(constraints[n].c.pore.reflecting){ reflect_particle(p1, &(vec[0]), constraints[n].c.pore.reflecting); } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{063 pore constraint %d violated by particle %d} ", n, p1->p.identity); + ostringstream msg; + msg <<"pore constraint " << n << " violated by particle "<< p1->p.identity; + runtimeError(msg); + } + } + } + break; + case CONSTRAINT_SLITPORE: + if(checkIfInteraction(ia_params)) { + calculate_slitpore_dist(p1, folded_pos, &constraints[n].part_rep, &constraints[n].c.slitpore, &dist, vec); + if ( dist >= 0 ) { + calc_non_bonded_pair_force(p1, &constraints[n].part_rep, + ia_params,vec,dist,dist*dist, force, + torque1, torque2); + } + else { + if(constraints[n].c.pore.reflecting){ + reflect_particle(p1, &(vec[0]), constraints[n].c.pore.reflecting); + } else { + ostringstream msg; + msg <<"pore constraint " << n << " violated by particle "<< p1->p.identity; + runtimeError(msg); } } } break; - case CONSTRAINT_STOMATOCYTE: if( checkIfInteraction(ia_params) ) { @@ -1931,9 +2488,48 @@ void add_constraints_forces(Particle *p1) } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{063 stomatocyte constraint %d violated by \ - particle %d} ", n, p1->p.identity); + ostringstream msg; + msg <<"stomatocyte constraint "<< n << " violated by particle " << p1->p.identity; + runtimeError(msg); + } + } + } + break; + + case CONSTRAINT_HOLLOW_CONE: + if( checkIfInteraction(ia_params) ) + { + + calculate_hollow_cone_dist( p1, folded_pos, &constraints[n].part_rep, + &constraints[n].c.hollow_cone, &dist, vec ); + + if ( dist > 0 ) + { + calc_non_bonded_pair_force( p1, &constraints[n].part_rep, + ia_params, vec, dist, dist*dist, + force, torque1, torque2 ); + } + else if ( dist <= 0 && constraints[n].c.hollow_cone.penetrable == 1 ) + { + if ( dist < 0 ) + { + calc_non_bonded_pair_force( p1, &constraints[n].part_rep, + ia_params, vec, -1.0*dist, dist*dist, + force, torque1, torque2 ); + } + } + else + { + if( constraints[n].c.hollow_cone.reflecting ) + { + reflect_particle( p1, &(vec[0]), + constraints[n].c.hollow_cone.reflecting ); + } + else + { + ostringstream msg; + msg <<"hollow_cone constraint "<< n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } } @@ -1965,12 +2561,18 @@ void add_constraints_forces(Particle *p1) add_tunable_slip_pair_force(p1, &constraints[n].part_rep,ia_params,vec,dist,force); #endif } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{063 plane constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"plane constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; + default: + fprintf(stderr, "ERROR: encountered unknown constraint during force computation\n"); + errexit(); + break; + } for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; @@ -1989,7 +2591,6 @@ double add_constraints_energy(Particle *p1) double dist, vec[3]; double nonbonded_en, coulomb_en, magnetic_en; IA_parameters *ia_params; - char *errtxt; double folded_pos[3]; int img[3]; @@ -2018,9 +2619,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, -1.0*dist, dist*dist); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{065 wall constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"wall constraint "<< n << " violated by particle "<< p1->p.identity; + runtimeError(msg); } } break; @@ -2038,9 +2640,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, -1.0*dist, dist*dist); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{066 sphere constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg << "sphere constraint "<< n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2059,9 +2662,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, -1.0*dist, dist*dist); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"cylinder constraint "<< n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2080,9 +2684,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, -1.0*dist, dist*dist); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{067 cylinder constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"cylinder constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2100,9 +2705,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, -1.0*dist, dist*dist); } } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{068 maze constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"maze constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2115,9 +2721,10 @@ double add_constraints_energy(Particle *p1) ia_params, vec, dist, dist*dist); } - else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{067 pore constraint %d violated by particle %d} ", n, p1->p.identity); + else { + ostringstream msg; + msg <<"pore constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2147,9 +2754,41 @@ double add_constraints_energy(Particle *p1) } else { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{066 stomatocyte constraint %d violated by \ - particle %d} ", n, p1->p.identity); + ostringstream msg; + msg <<"stomatocyte constraint "<< n << " violated by particle " << p1->p.identity; + runtimeError(msg); + } + } + break; + + case CONSTRAINT_HOLLOW_CONE: + if( checkIfInteraction(ia_params) ) + { + calculate_hollow_cone_dist( p1, folded_pos, &constraints[n].part_rep, + &constraints[n].c.hollow_cone, &dist, vec ); + + if ( dist > 0 ) + { + nonbonded_en = calc_non_bonded_pair_energy( p1, + &constraints[n].part_rep, + ia_params, vec, dist, + dist*dist ); + } + else if ( dist <= 0 && constraints[n].c.hollow_cone.penetrable == 1 ) + { + if ( dist < 0 ) + { + nonbonded_en = calc_non_bonded_pair_energy(p1, + &constraints[n].part_rep, + ia_params, vec, + -1.0*dist, dist*dist); + } + } + else + { + ostringstream msg; + msg <<"hollow_cone constraint " << n << " violated by particle " << p1->p.identity; + runtimeError(msg); } } break; @@ -2164,6 +2803,23 @@ double add_constraints_energy(Particle *p1) case CONSTRAINT_EXT_MAGN_FIELD: magnetic_en = ext_magn_field_energy(p1, &constraints[n].c.emfield); break; + //@TODO: implement energy of Plane, Slitpore + case CONSTRAINT_PLANE: + { + if (warnings) fprintf(stderr, "WARNING: energy calculated, but PLANE energy not implemented\n"); + } + break; + case CONSTRAINT_SLITPORE: + { + if (warnings) fprintf(stderr, "WARNING: energy calculated, but PLANE energy not implemented\n"); + } + break; + case CONSTRAINT_NONE: + break; + default: + fprintf(stderr, "ERROR: encountered unknown constraint during energy computation\n"); + errexit(); + break; } if (energy.n_coulomb > 0) @@ -2179,5 +2835,102 @@ double add_constraints_energy(Particle *p1) return 0.; } +void calculate_slitpore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_slitpore *c, double *dist, double *vec) { + // the left circles + double box_l_x = box_l[0]; + double c11[2] = { box_l_x/2-c->pore_width/2-c->upper_smoothing_radius, c->pore_mouth - c->upper_smoothing_radius }; + double c12[2] = { box_l_x/2-c->pore_width/2+c->lower_smoothing_radius, c->pore_mouth - c->pore_length + c->lower_smoothing_radius }; + // the right circles + double c21[2] = { box_l_x/2+c->pore_width/2+c->upper_smoothing_radius, c->pore_mouth - c->upper_smoothing_radius }; + double c22[2] = { box_l_x/2+c->pore_width/2-c->lower_smoothing_radius, c->pore_mouth - c->pore_length + c->lower_smoothing_radius }; + +// printf("c11 %f %f\n", c11[0], c11[1]); +// printf("c12 %f %f\n", c12[0], c12[1]); +// printf("c21 %f %f\n", c21[0], c21[1]); +// printf("c22 %f %f\n", c22[0], c22[1]); + + + if (ppos[2] > c->pore_mouth + c->channel_width/2) { +// printf("upper wall\n"); + // Feel the upper wall + *dist = c->pore_mouth + c->channel_width - ppos[2]; + vec[0] = vec[1] = 0; + vec[2] = -*dist; + return; + } + + if (ppos[0] c21[0]) { + // Feel the lower wall of the channel +// printf("lower wall\n"); + *dist = ppos[2] - c->pore_mouth; + vec[0] = vec[1] = 0; + vec[2] = *dist; + return; + } + + if (ppos[2] > c11[1]) { + // Feel the upper smoothing + if (ppos[0] < box_l_x/2) { +// printf("upper smoothing left\n"); + *dist = sqrt( SQR(c11[0] - ppos[0]) + SQR(c11[1] - ppos[2])) - c->upper_smoothing_radius; + vec[0] = -( c11[0] - ppos[0] ) * (*dist)/(*dist+c->upper_smoothing_radius); + vec[1] = 0; + vec[2] = -( c11[1] - ppos[2] ) * (*dist)/(*dist+c->upper_smoothing_radius); + return; + } else { +// printf("upper smoothing right\n"); + *dist = sqrt( SQR(c21[0] - ppos[0]) + SQR(c21[1] - ppos[2])) - c->upper_smoothing_radius; + vec[0] = -( c21[0] - ppos[0] ) * (*dist)/(*dist+c->upper_smoothing_radius); + vec[1] = 0; + vec[2] = -( c21[1] - ppos[2] ) * (*dist)/(*dist+c->upper_smoothing_radius); + return; + } + } + + if (ppos[2] > c12[1]) { + // Feel the pore wall + if (ppos[0] < box_l_x/2) { +// printf("pore left\n"); + *dist = ppos[0] - (box_l_x/2-c->pore_width/2); + vec[0]=*dist; + vec[1]=vec[2]=0; + return; + } else { +// printf("pore right\n"); + *dist = (box_l_x/2+c->pore_width/2) - ppos[0]; + vec[0]=-*dist; + vec[1]=vec[2]=0; + return; + } + } + + if (ppos[0]>c12[0] && ppos[0] < c22[0]) { +// printf("pore end\n"); + // Feel the pore end wall + *dist = ppos[2] - (c->pore_mouth-c->pore_length); + vec[0]=vec[1]=0; + vec[2]=*dist; + return; + } + // Else + // Feel the lower smoothing + if (ppos[0] < box_l_x/2) { +// printf("lower smoothing left\n"); + *dist = -sqrt( SQR(c12[0] - ppos[0]) + SQR(c12[1] - ppos[2])) + c->lower_smoothing_radius; + vec[0] = ( c12[0] - ppos[0] ) * (*dist)/(-*dist+c->lower_smoothing_radius); + vec[1] = 0; + vec[2] = ( c12[1] - ppos[2] ) * (*dist)/(-*dist+c->lower_smoothing_radius); + return; + } else { +// printf("lower smoothing right\n"); + *dist = -sqrt( SQR(c22[0] - ppos[0]) + SQR(c22[1] - ppos[2])) + c->lower_smoothing_radius; + vec[0] = ( c22[0] - ppos[0] ) * (*dist)/(-*dist+c->lower_smoothing_radius); + vec[1] = 0; + vec[2] = ( c22[1] - ppos[2] ) * (*dist)/(-*dist+c->lower_smoothing_radius); + return; + } + + +} #endif diff --git a/src/constraint.hpp b/src/core/constraint.hpp similarity index 88% rename from src/constraint.hpp rename to src/core/constraint.hpp index 92fce081e4a..cb95e3d864c 100644 --- a/src/constraint.hpp +++ b/src/core/constraint.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef _CONSTRAINT_H #define _CONSTRAINT_H -/** \file constraint.h +/** \file constraint.hpp * Routines for handling of constraints. * Only active if the feature CONSTRAINTS is activated. - * see also \ref interaction_data.h + * see also \ref interaction_data.hpp */ #include "particle_data.hpp" @@ -68,6 +68,10 @@ void calculate_pore_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_pore *c, double *dist, double *vec); +void calculate_slitpore_dist(Particle *p1, double ppos[3], + Particle *c_p, Constraint_slitpore *c, + double *dist, double *vec); + void calculate_plane_dist(Particle *p1, double ppos[3], Particle *c_p, Constraint_plane *c, double *dist, double *vec); @@ -76,6 +80,10 @@ void calculate_stomatocyte_dist( Particle *p1, double ppos [3], Particle *c_p, Constraint_stomatocyte *cons, double *dist, double *vec ); +void calculate_hollow_cone_dist( Particle *p1, double ppos [3], + Particle *c_p, Constraint_hollow_cone *cons, + double *dist, double *vec ); + void add_rod_force(Particle *p1, double ppos[3], Particle *c_p, Constraint_rod *c); diff --git a/src/cuda_common_cuda.cu b/src/core/cuda_common_cuda.cu similarity index 72% rename from src/cuda_common_cuda.cu rename to src/core/cuda_common_cuda.cu index c8447d5d83a..23caa03a9c3 100644 --- a/src/cuda_common_cuda.cu +++ b/src/core/cuda_common_cuda.cu @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,7 +17,6 @@ along with this program. If not, see . */ - #include "cuda_utils.hpp" #include "cuda_interface.hpp" #include "config.hpp" @@ -26,6 +25,10 @@ #include "interaction_data.hpp" #include "cuda_init.hpp" +#if defined(OMPI_MPI_H) || defined(_MPI_H) +#error CU-file includes mpi.h! This should not happen! +#endif + static int max_ran = 1000000; static CUDA_global_part_vars global_part_vars_host = {0,0,0}; static __device__ __constant__ CUDA_global_part_vars global_part_vars_device; @@ -36,16 +39,22 @@ static CUDA_particle_force *particle_forces_device = NULL; static CUDA_particle_data *particle_data_device = NULL; /** struct for storing particle rn seed */ static CUDA_particle_seed *particle_seeds_device = NULL; + /** struct for fluid composition */ +static CUDA_fluid_composition *fluid_composition_device = NULL; +/** struct for energies */ +static CUDA_energy *energy_device = NULL; CUDA_particle_data *particle_data_host = NULL; CUDA_particle_force *particle_forces_host = NULL; +CUDA_energy energy_host; +CUDA_fluid_composition *fluid_composition_host = NULL; /**cuda streams for parallel computing on cpu and gpu */ cudaStream_t stream[1]; cudaError_t err; -void _cuda_safe_mem(cudaError_t err, char *file, unsigned int line){ +void _cuda_safe_mem(cudaError_t err, const char *file, unsigned int line){ if( cudaSuccess != err) { fprintf(stderr, "Cuda Memory error at %s:%u.\n", file, line); printf("CUDA error: %s\n", cudaGetErrorString(err)); @@ -65,11 +74,11 @@ void _cuda_safe_mem(cudaError_t err, char *file, unsigned int line){ } void _cuda_check_errors(const dim3 &block, const dim3 &grid, - char *function, char *file, unsigned int line) { + const char *function, const char *file, unsigned int line) { err=cudaGetLastError(); if (err!=cudaSuccess) { fprintf(stderr, "%d: error \"%s\" calling %s with dim %d %d %d, grid %d %d %d in %s:%u\n", - cudaGetErrorString(err), function, block.x, block.y, block.z, grid.x, grid.y, grid.z, + this_node, cudaGetErrorString(err), function, block.x, block.y, block.z, grid.x, grid.y, grid.z, file, line); exit(EXIT_FAILURE); } @@ -102,6 +111,24 @@ __global__ void init_particle_force(CUDA_particle_force *particle_forces_device, } +/** kernel for the initalisation of the fluid composition + * @param *fluid_composition_device Pointer to local fluid composition (Output) +*/ +__global__ void init_fluid_composition(CUDA_fluid_composition *fluid_composition_device){ + + /* Note: these are initialized to zero and not to the fluid density because we cannot assume that + particles have been created after the fluid */ + unsigned int part_index = getThreadIndex(); + + if(part_index. +*/ #include "cells.hpp" #include "communication.hpp" #include "cuda_interface.hpp" @@ -7,6 +25,7 @@ #include "random.hpp" #include "particle_data.hpp" #include "interaction_data.hpp" +#include "energy.hpp" #ifdef CUDA @@ -38,7 +57,7 @@ void cuda_mpi_get_particles(CUDA_particle_data *particle_data_host) sizes = (int*) malloc(sizeof(int)*n_nodes); n_part = cells_get_n_particles(); - + /* first collect number of particles on each node */ MPI_Gather(&n_part, 1, MPI_INT, sizes, 1, MPI_INT, 0, comm_cart); @@ -58,12 +77,19 @@ void cuda_mpi_get_particles(CUDA_particle_data *particle_data_host) int npart; int dummy[3] = {0,0,0}; double pos[3]; +#ifdef LEES_EDWARDS + double dummyV[3]; +#endif cell = local_cells.cell[c]; part = cell->part; npart = cell->n; for (i=0;ipart; npart = cell->n; for (i=0;ipart[i].f.f[0] += (double)host_forces[i+g].f[0]; cell->part[i].f.f[1] += (double)host_forces[i+g].f[1]; cell->part[i].f.f[2] += (double)host_forces[i+g].f[2]; +#ifdef SHANCHEN + for (int ii=0;iipart[i].r.composition[ii] = (double)host_composition[i+g].weight[ii]; + } +#endif } g += npart; } @@ -213,6 +250,9 @@ void cuda_mpi_send_forces(CUDA_particle_force *host_forces){ else { /* and send it back to the slave node */ MPI_Send(&host_forces[g], sizes[pnode]*sizeof(CUDA_particle_force), MPI_BYTE, pnode, REQ_CUDAGETFORCES, comm_cart); +#ifdef SHANCHEN + MPI_Send(&host_composition[g], sizes[pnode]*sizeof(CUDA_fluid_composition), MPI_BYTE, pnode, REQ_CUDAGETPARTS, comm_cart); +#endif g += sizes[pnode]; } } @@ -226,7 +266,10 @@ void cuda_mpi_send_forces(CUDA_particle_force *host_forces){ static void cuda_mpi_send_forces_slave(){ int n_part; - CUDA_particle_force *host_forces_sl; + CUDA_particle_force *host_forces_sl=NULL; +#ifdef SHANCHEN + CUDA_fluid_composition *host_composition_sl=NULL; +#endif Cell *cell; int c, i; MPI_Status status; @@ -242,7 +285,12 @@ static void cuda_mpi_send_forces_slave(){ /* then get the particle information */ host_forces_sl = (CUDA_particle_force *) malloc(n_part*sizeof(CUDA_particle_force)); MPI_Recv(host_forces_sl, n_part*sizeof(CUDA_particle_force), MPI_BYTE, 0, REQ_CUDAGETFORCES, - comm_cart, &status); + comm_cart, &status); +#ifdef SHANCHEN + host_composition_sl = (CUDA_fluid_composition *) malloc(n_part*sizeof(CUDA_fluid_composition)); + MPI_Recv(host_composition_sl, n_part*sizeof(CUDA_particle_force), MPI_BYTE, 0, REQ_CUDAGETPARTS, + comm_cart, &status); +#endif for (c = 0; c < local_cells.n; c++) { int npart; cell = local_cells.cell[c]; @@ -251,11 +299,29 @@ static void cuda_mpi_send_forces_slave(){ cell->part[i].f.f[0] += (double)host_forces_sl[i+g].f[0]; cell->part[i].f.f[1] += (double)host_forces_sl[i+g].f[1]; cell->part[i].f.f[2] += (double)host_forces_sl[i+g].f[2]; +#ifdef SHANCHEN + for (int ii=0;iipart[i].r.composition[ii] = (double)host_composition_sl[i+g].weight[ii]; + } +#endif } g += npart; } free(host_forces_sl); +#ifdef SHANCHEN + free(host_composition_sl); +#endif } } +/** Takes a CUDA_energy struct and adds it to the core energy struct. +This cannot be done from inside cuda_common_cuda.cu:copy_energy_from_GPU() because energy.hpp indirectly includes on mpi.h while .cu files may not depend on mpi.h.*/ +void copy_CUDA_energy_to_energy(CUDA_energy energy_host) +{ + energy.bonded[0] += energy_host.bonded; + energy.non_bonded[0] += energy_host.non_bonded; + energy.coulomb[0] += energy_host.coulomb; + energy.dipolar[0] += energy_host.dipolar; +} + #endif /* ifdef CUDA */ diff --git a/src/cuda_interface.hpp b/src/core/cuda_interface.hpp similarity index 76% rename from src/cuda_interface.hpp rename to src/core/cuda_interface.hpp index d588ebe27fd..a0178f2ddaf 100644 --- a/src/cuda_interface.hpp +++ b/src/core/cuda_interface.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 The ESPResSo project + Copyright (C) 2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -21,6 +21,8 @@ #include "config.hpp" //this is required so that the ifdefs are actually defined +#include "SystemInterface.hpp" + #ifdef CUDA /** data which must be copied from the GPU at each step run on the GPU */ @@ -31,6 +33,14 @@ typedef struct { } CUDA_particle_force; + +typedef struct { + /** fluid composition at the particle given to md part */ + float weight[LB_COMPONENTS]; + +} CUDA_fluid_composition; + + /** data structure which must be copied to the GPU at each step run on the GPU */ typedef struct { /** particle position given from md part*/ @@ -51,6 +61,11 @@ typedef struct { } CUDA_particle_data; +/** data structure for the different kinds of energies */ +typedef struct { + float bonded, non_bonded, coulomb, dipolar; +} CUDA_energy; + /** Note the particle's seed gets its own struct since it doesn't get copied back and forth from the GPU */ typedef struct { @@ -73,18 +88,25 @@ typedef struct { } CUDA_global_part_vars; void copy_forces_from_GPU(); +void copy_energy_from_GPU(); +void copy_CUDA_energy_to_energy(CUDA_energy energy_host); +void clear_energy_on_GPU(); +void copy_composition_from_GPU(); CUDA_global_part_vars* gpu_get_global_particle_vars_pointer_host(); CUDA_global_part_vars* gpu_get_global_particle_vars_pointer(); CUDA_particle_data* gpu_get_particle_pointer(); CUDA_particle_force* gpu_get_particle_force_pointer(); +CUDA_energy* gpu_get_energy_pointer(); +CUDA_fluid_composition* gpu_get_fluid_composition_pointer(); CUDA_particle_seed* gpu_get_particle_seed_pointer(); void gpu_change_number_of_part_to_comm(); void gpu_init_particle_comm(); void cuda_mpi_get_particles(CUDA_particle_data *host_result); void copy_part_data_to_gpu(); -void cuda_mpi_send_forces(CUDA_particle_force *host_forces); +void cuda_mpi_send_forces(CUDA_particle_force *host_forces,CUDA_fluid_composition * host_fluid_composition); void cuda_bcast_global_part_params(); - +void cuda_copy_to_device(void *host_data, void *device_data, size_t n); +void cuda_copy_to_host(void *host_device, void *device_host, size_t n); #endif /* ifdef CUDA */ #endif /* ifdef CUDA_INTERFACE_HPP */ diff --git a/src/cuda_utils.hpp b/src/core/cuda_utils.hpp similarity index 70% rename from src/cuda_utils.hpp rename to src/core/cuda_utils.hpp index 152ef0b5ab9..ec4a2fde14d 100644 --- a/src/cuda_utils.hpp +++ b/src/core/cuda_utils.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 The ESPResSo project + Copyright (C) 2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -38,15 +38,21 @@ extern cudaError_t _err; * @param line line of the file were the error took place */ -void _cuda_safe_mem(cudaError_t err, char *file, unsigned int line); +void _cuda_safe_mem(cudaError_t err, const char *file, unsigned int line); void _cuda_check_errors(const dim3 &block, const dim3 &grid, - char *function, char *file, unsigned int line); + const char *function, const char *file, unsigned int line); #define cuda_safe_mem(a) _cuda_safe_mem((a), __FILE__, __LINE__) -#define KERNELCALL(_f, _a, _b, _params) \ - _f<<<_a, _b, 0, stream[0]>>>_params; \ +#define KERNELCALL_shared(_f, _a, _b, _s, _params) \ + _f<<<_a, _b, _s, stream[0]>>>_params; \ _cuda_check_errors(_a, _b, #_f, __FILE__, __LINE__); +#define KERNELCALL_stream(_function, _grid, _block, _stream, _params) \ + _function<<<_grid, _block, _stream>>>_params; \ + _cuda_check_errors(_grid, _block, _stream, #_function, __FILE__, __LINE__); + +#define KERNELCALL(_f, _a, _b, _params) KERNELCALL_shared(_f, _a, _b, 0, _params) + #endif diff --git a/src/debug.cpp b/src/core/debug.cpp similarity index 98% rename from src/debug.cpp rename to src/core/debug.cpp index 50033026e55..b46c78c8585 100644 --- a/src/debug.cpp +++ b/src/core/debug.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file debug.c - Implements the malloc replacements as described in \ref debug.h "debug.h". +/** \file debug.cpp + Implements the malloc replacements as described in \ref debug.hpp "debug.hpp". */ #include @@ -171,7 +171,7 @@ void check_particle_consistency() fprintf(stderr, "%d: got particle %d in cell %d\n", this_node, local_cells.cell[c]->part[p].p.identity, c); } - for(p = 0; p < n_total_particles; p++) + for(p = 0; p < n_part; p++) if (local_particles[p]) fprintf(stderr, "%d: got particle %d in local_particles\n", this_node, p); @@ -282,7 +282,7 @@ void check_particles() c = 0; for (p = 0; p <= max_seen_particle; p++) if (particle_node[p] != -1) c++; - if (c != n_total_particles) { + if (c != n_part) { fprintf(stderr,"%d: check_particles: #particles in particle_node inconsistent\n", this_node); errexit(); } diff --git a/src/debug.hpp b/src/core/debug.hpp similarity index 98% rename from src/debug.hpp rename to src/core/debug.hpp index c15ad822ae1..4c3daa8da3a 100644 --- a/src/debug.hpp +++ b/src/core/debug.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file debug.h +/** \file debug.hpp This file controls debug facilities. The implementation is found in - \ref debug.c "debug.c". + \ref debug.cpp "debug.c". For every define there exists a macro that can be used to encapsulate short lines (like printf("...",...);) of code that should be executed iff the respective *_DEBUG macro is defined. @@ -57,8 +57,6 @@ void __free(void *p, const char *where, int line); void core(); #endif -#ifdef ADDITIONAL_CHECKS - /** this performs a lot of tests which will very likely detect corruptions of \ref local_particles and the cell structure. */ @@ -69,8 +67,6 @@ void check_particle_consistency(); */ void check_particles(); -#endif - /** Print all particle positions contained in \ref cells::cells array. */ void print_particle_positions(); /** Print all particle forces contained in \ref cells::cells array. */ diff --git a/src/debye_hueckel.cpp b/src/core/debye_hueckel.cpp similarity index 89% rename from src/debye_hueckel.cpp rename to src/core/debye_hueckel.cpp index b2589a4c65c..8f744f7d2bc 100644 --- a/src/debye_hueckel.cpp +++ b/src/core/debye_hueckel.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file debye_hueckel.c +/** \file debye_hueckel.cpp * - * Implementation of \ref debye_hueckel.h + * Implementation of \ref debye_hueckel.hpp */ #include "utils.hpp" #include "debye_hueckel.hpp" diff --git a/src/debye_hueckel.hpp b/src/core/debye_hueckel.hpp similarity index 97% rename from src/debye_hueckel.hpp rename to src/core/debye_hueckel.hpp index 739cead9cba..2ffbae67af7 100644 --- a/src/debye_hueckel.hpp +++ b/src/core/debye_hueckel.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef DEBYE_HUECKEL_H #define DEBYE_HUECKEL_H -/** \file debye_hueckel.h +/** \file debye_hueckel.hpp * Routines to calculate the Debye_Hueckel Energy or/and Debye_Hueckel force * for a particle pair. */ diff --git a/src/dihedral.cpp b/src/core/dihedral.cpp similarity index 91% rename from src/dihedral.cpp rename to src/core/dihedral.cpp index b73f659931e..b3781ed8121 100644 --- a/src/dihedral.cpp +++ b/src/core/dihedral.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file dihedral.c +/** \file dihedral.cpp * - * Implementation of \ref dihedral.h + * Implementation of \ref dihedral.hpp */ #include "dihedral.hpp" diff --git a/src/dihedral.hpp b/src/core/dihedral.hpp similarity index 97% rename from src/dihedral.hpp rename to src/core/dihedral.hpp index 41fce161f21..00f1431c525 100644 --- a/src/dihedral.hpp +++ b/src/core/dihedral.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef DIHEDRAL_H #define DIHEDRAL_H -/** \file dihedral.h Routines to calculate the dihedral energy or/and +/** \file dihedral.hpp Routines to calculate the dihedral energy or/and * and force for a particle quadruple. Note that usage of dihedrals * increases the interaction range of bonded interactions to 2 times - * the maximal bond length! \ref forces.c + * the maximal bond length! \ref forces.cpp */ #include "utils.hpp" diff --git a/src/domain_decomposition.cpp b/src/core/domain_decomposition.cpp similarity index 64% rename from src/domain_decomposition.cpp rename to src/core/domain_decomposition.cpp index dd91d62b2a6..9aae89aa576 100644 --- a/src/domain_decomposition.cpp +++ b/src/core/domain_decomposition.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,19 +18,23 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file domain_decomposition.c +/** \file domain_decomposition.cpp * * This file contains everything related to the cell system: domain decomposition. - * See also \ref domain_decomposition.h + * See also \ref domain_decomposition.hpp */ #include "domain_decomposition.hpp" +#include "lees_edwards_domain_decomposition.hpp" +#include "lees_edwards_comms_manager.hpp" +#include "lees_edwards.hpp" #include "errorhandling.hpp" #include "forces.hpp" #include "pressure.hpp" -#include "energy.hpp" +#include "energy_inline.hpp" #include "constraint.hpp" #include "initialize.hpp" +#include "external_potential.hpp" /************************************************/ /** \name Defines */ @@ -47,6 +51,9 @@ /************************************************/ /*@{*/ +#ifdef LEES_EDWARDS +le_dd_comms_manager le_mgr; +#endif DomainDecomposition dd = { 1, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, NULL }; int max_num_cells = CELLS_MAX_NUM_CELLS; @@ -56,7 +63,7 @@ double max_skin = 0.0; /*@}*/ /************************************************************/ -/** \name Privat Functions */ +/** \name Private Functions */ /************************************************************/ /*@{*/ @@ -73,16 +80,30 @@ double max_skin = 0.0; for(m=1; m 0 && m <= dd.cell_grid[0] && \ + n > 0 && n <= dd.cell_grid[1] && \ + o > 0 && o <= dd.cell_grid[2] ) +#else #define DD_IS_LOCAL_CELL(m,n,o) \ ( m > 0 && m < dd.ghost_cell_grid[0] - 1 && \ n > 0 && n < dd.ghost_cell_grid[1] - 1 && \ - o > 0 && o < dd.ghost_cell_grid[2] - 1 ) + o > 0 && o < dd.ghost_cell_grid[2] - 1 ) +#endif /** Convenient replace for ghost cell check. usage: if(DD_IS_GHOST_CELL(m,n,o)) {...} */ +#ifdef LEES_EDWARDS +#define DD_IS_GHOST_CELL(m,n,o) \ + ( m == 0 || m == dd.ghost_cell_grid[0] - 1 || \ + n == 0 || (n == dd.ghost_cell_grid[1] - 1 || n == dd.ghost_cell_grid[1] - 2) || \ + o == 0 || o == dd.ghost_cell_grid[2] - 1 ) +#else #define DD_IS_GHOST_CELL(m,n,o) \ ( m == 0 || m == dd.ghost_cell_grid[0] - 1 || \ - n == 0 || n == dd.ghost_cell_grid[1] - 1 || \ - o == 0 || o == dd.ghost_cell_grid[2] - 1 ) + n == 0 || n >= dd.ghost_cell_grid[1] - 1 || \ + o == 0 || o == dd.ghost_cell_grid[2] - 1 ) +#endif /** Calculate cell grid dimensions, cell sizes and number of cells. * Calculates the cell grid, based on \ref local_box_l and \ref @@ -106,7 +127,14 @@ void dd_create_cell_grid() if (max_range < ROUND_ERROR_PREC*box_l[0]) { /* this is the initialization case */ +#ifdef LEES_EDWARDS + dd.cell_grid[0] = 2; + dd.cell_grid[1] = 1; + dd.cell_grid[2] = 1; + n_local_cells = 2; +#else n_local_cells = dd.cell_grid[0] = dd.cell_grid[1] = dd.cell_grid[2]=1; +#endif } else { /* Calculate initial cell grid */ @@ -122,11 +150,21 @@ void dd_create_cell_grid() /* ok, too many cells for this direction, set to minimum */ dd.cell_grid[i] = (int)floor(local_box_l[i]/max_range); if ( dd.cell_grid[i] < 1 ) { - char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128); - ERROR_SPRINTF(error_msg, "{002 interaction range %g in direction %d is larger than the local box size %g} ", - max_range, i, local_box_l[i]); + ostringstream msg; + msg << "interaction range " << max_range << " in direction " + << i << " is larger than the local box size " << local_box_l[i]; + runtimeError(msg); dd.cell_grid[i] = 1; } +#ifdef LEES_EDWARDS + if ( (i == 0) && (dd.cell_grid[0] < 2) ) { + ostringstream msg; + msg << "interaction range " << max_range << " in direction " + << i << " is larger than the local box size " << local_box_l[i]; + runtimeError(msg); + dd.cell_grid[0] = 2; + } +#endif cell_range[i] = local_box_l[i]/dd.cell_grid[i]; } } @@ -134,22 +172,27 @@ void dd_create_cell_grid() /* It may be necessary to asymmetrically assign the scaling to the coordinates, which the above approach will not do. For a symmetric box, it gives a symmetric result. Here we correct that. */ for (;;) { - n_local_cells = dd.cell_grid[0]; - for (i = 1; i < 3; i++) - n_local_cells *= dd.cell_grid[i]; + + n_local_cells = dd.cell_grid[0] * dd.cell_grid[1] * dd.cell_grid[2]; /* done */ if (n_local_cells <= max_num_cells) - break; + break; /* find coordinate with the smallest cell range */ min_ind = 0; min_size = cell_range[0]; - for (i = 1; i < 3; i++) - if (dd.cell_grid[i] > 1 && cell_range[i] < min_size) { - min_ind = i; - min_size = cell_range[i]; - } + +#ifdef LEES_EDWARDS + for (i = 2; i >= 1; i--) {/*preferably have thin slices in z or y... this is more efficient for Lees Edwards*/ +#else + for (i = 1; i < 3; i++) { +#endif + if (dd.cell_grid[i] > 1 && cell_range[i] < min_size) { + min_ind = i; + min_size = cell_range[i]; + } + } CELL_TRACE(fprintf(stderr, "%d: minimal coordinate %d, size %f, grid %d\n", this_node,min_ind, min_size, dd.cell_grid[min_ind])); dd.cell_grid[min_ind]--; @@ -159,23 +202,30 @@ void dd_create_cell_grid() /* sanity check */ if (n_local_cells < min_num_cells) { - char *error_msg = runtime_error(ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE + 128); - ERROR_SPRINTF(error_msg, "{001 number of cells %d is smaller than minimum %d (interaction range too large or min_num_cells too large)} ", - n_local_cells, min_num_cells); + ostringstream msg; + msg << "number of cells "<< n_local_cells << " is smaller than minimum " << min_num_cells << + " (interaction range too large or min_num_cells too large)"; + runtimeError(msg); } } /* quit program if unsuccesful */ if(n_local_cells > max_num_cells) { - char *error_msg = runtime_error(128); - ERROR_SPRINTF(error_msg, "{003 no suitable cell grid found} "); + ostringstream msg; + msg << "no suitable cell grid found "; + runtimeError(msg); } /* now set all dependent variables */ new_cells=1; for(i=0;i<3;i++) { - dd.ghost_cell_grid[i] = dd.cell_grid[i]+2; - new_cells *= dd.ghost_cell_grid[i]; + dd.ghost_cell_grid[i] = dd.cell_grid[i]+2; +#ifdef LEES_EDWARDS + //Hack alert: only the boundary y-layers actually need the extra-thick ghost cell grid, + //so some memory (and copies) are wasted in the name of simpler code. + if( i == 0 ){dd.ghost_cell_grid[i]++;} +#endif + new_cells *= dd.ghost_cell_grid[i]; dd.cell_size[i] = local_box_l[i]/(double)dd.cell_grid[i]; dd.inv_cell_size[i] = 1.0 / dd.cell_size[i]; } @@ -195,10 +245,20 @@ void dd_create_cell_grid() void dd_mark_cells() { int m,n,o,cnt_c=0,cnt_l=0,cnt_g=0; + DD_CELLS_LOOP(m,n,o) { + +#ifdef LEES_EDWARDS + /* convenient for LE if a cell knows where it is*/ + cells[cnt_c].myIndex[0] = m; + cells[cnt_c].myIndex[1] = n; + cells[cnt_c].myIndex[2] = o; +#endif + if(DD_IS_LOCAL_CELL(m,n,o)) local_cells.cell[cnt_l++] = &cells[cnt_c++]; else ghost_cells.cell[cnt_g++] = &cells[cnt_c++]; } + } /** Fill a communication cell pointer list. Fill the cell pointers of @@ -223,10 +283,10 @@ int dd_fill_comm_cell_lists(Cell **part_lists, int lc[3], int hc[3]) for(o=lc[0]; o<=hc[0]; o++) for(n=lc[1]; n<=hc[1]; n++) for(m=lc[2]; m<=hc[2]; m++) { - i = get_linear_index(o,n,m,dd.ghost_cell_grid); - CELL_TRACE(fprintf(stderr,"%d: dd_fill_comm_cell_list: add cell %d\n",this_node,i)); - part_lists[c] = &cells[i]; - c++; + i = get_linear_index(o,n,m,dd.ghost_cell_grid); + CELL_TRACE(fprintf(stderr,"%d: dd_fill_comm_cell_list: add cell %d\n",this_node,i)); + part_lists[c] = &cells[i]; + c++; } return c; } @@ -245,10 +305,10 @@ void dd_prepare_comm(GhostCommunicator *comm, int data_parts) /* No communication for border of non periodic direction */ if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) #endif - { - if(node_grid[dir] == 1 ) num++; - else num += 2; - } + { + if(node_grid[dir] == 1 ) num++; + else num += 2; + } } } @@ -274,71 +334,79 @@ void dd_prepare_comm(GhostCommunicator *comm, int data_parts) value */ for(lr=0; lr<2; lr++) { if(node_grid[dir] == 1) { - /* just copy cells on a single node */ + /* just copy cells on a single node */ #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) + if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) #endif - { - comm->comm[cnt].type = GHOST_LOCL; - comm->comm[cnt].node = this_node; - /* Buffer has to contain Send and Recv cells -> factor 2 */ - comm->comm[cnt].part_lists = (ParticleList**)malloc(2*n_comm_cells[dir]*sizeof(ParticleList *)); - comm->comm[cnt].n_part_lists = 2*n_comm_cells[dir]; - /* prepare folding of ghost positions */ - if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) - comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - /* fill send comm cells */ - lc[(dir+0)%3] = hc[(dir+0)%3] = 1+lr*(dd.cell_grid[(dir+0)%3]-1); - dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); - CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy to grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, - lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); - /* fill recv comm cells */ - lc[(dir+0)%3] = hc[(dir+0)%3] = 0+(1-lr)*(dd.cell_grid[(dir+0)%3]+1); - /* place recieve cells after send cells */ - dd_fill_comm_cell_lists(&comm->comm[cnt].part_lists[n_comm_cells[dir]],lc,hc); - CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy from grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); - cnt++; - } + { + comm->comm[cnt].type = GHOST_LOCL; + comm->comm[cnt].node = this_node; + + /* Buffer has to contain Send and Recv cells -> factor 2 */ + comm->comm[cnt].part_lists = (ParticleList**)malloc(2*n_comm_cells[dir]*sizeof(ParticleList *)); + comm->comm[cnt].n_part_lists = 2*n_comm_cells[dir]; + /* prepare folding of ghost positions */ + if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) { + comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + } + + /* fill send comm cells */ + lc[dir] = hc[dir] = 1 + lr * (dd.cell_grid[dir]-1); + + dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy to grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, + lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); + + /* fill recv comm cells */ + lc[dir] = hc[dir] = 0 +( 1 - lr ) * ( dd.cell_grid[dir] + 1 ); + + /* place recieve cells after send cells */ + dd_fill_comm_cell_lists(&comm->comm[cnt].part_lists[n_comm_cells[dir]],lc,hc); + CELL_TRACE(fprintf(stderr,"%d: prep_comm %d copy from grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); + cnt++; + } } else { - /* i: send/recv loop */ - for(i=0; i<2; i++) { + /* i: send/recv loop */ + for(i=0; i<2; i++) { #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) + if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) #endif - if((node_pos[dir]+i)%2==0) { - comm->comm[cnt].type = GHOST_SEND; - comm->comm[cnt].node = node_neighbors[2*dir+lr]; - comm->comm[cnt].part_lists = (ParticleList**)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); - comm->comm[cnt].n_part_lists = n_comm_cells[dir]; - /* prepare folding of ghost positions */ - if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) - comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - - lc[(dir+0)%3] = hc[(dir+0)%3] = 1+lr*(dd.cell_grid[(dir+0)%3]-1); - dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); - - CELL_TRACE(fprintf(stderr,"%d: prep_comm %d send to node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, - comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); - cnt++; - } + if((node_pos[dir]+i)%2==0) { + comm->comm[cnt].type = GHOST_SEND; + comm->comm[cnt].node = node_neighbors[2*dir+lr]; + comm->comm[cnt].part_lists = (ParticleList**)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); + comm->comm[cnt].n_part_lists = n_comm_cells[dir]; + /* prepare folding of ghost positions */ + if((data_parts & GHOSTTRANS_POSSHFTD) && boundary[2*dir+lr] != 0) { + comm->comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + } + + lc[dir] = hc[dir] = 1 + lr * ( dd.cell_grid[dir] - 1 ); + + dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + + CELL_TRACE(fprintf(stderr,"%d: prep_comm %d send to node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, + comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); + cnt++; + } #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) + if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) #endif - if((node_pos[dir]+(1-i))%2==0) { - comm->comm[cnt].type = GHOST_RECV; - comm->comm[cnt].node = node_neighbors[2*dir+(1-lr)]; - comm->comm[cnt].part_lists = (ParticleList**)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); - comm->comm[cnt].n_part_lists = n_comm_cells[dir]; - - lc[(dir+0)%3] = hc[(dir+0)%3] = 0+(1-lr)*(dd.cell_grid[(dir+0)%3]+1); - dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); - - CELL_TRACE(fprintf(stderr,"%d: prep_comm %d recv from node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, - comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); - cnt++; - } - } + if((node_pos[dir]+(1-i))%2==0) { + comm->comm[cnt].type = GHOST_RECV; + comm->comm[cnt].node = node_neighbors[2*dir+(1-lr)]; + comm->comm[cnt].part_lists = (ParticleList**)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); + comm->comm[cnt].n_part_lists = n_comm_cells[dir]; + + lc[dir] = hc[dir] = ( 1 - lr ) * ( dd.cell_grid[dir] + 1 ); + + dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + CELL_TRACE(fprintf(stderr,"%d: prep_comm %d recv from node %d grid (%d,%d,%d)-(%d,%d,%d)\n",this_node,cnt, + comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2])); + cnt++; + } + } } done[dir]=1; } @@ -369,9 +437,9 @@ void dd_revert_comm_order(GhostCommunicator *comm) else if(comm->comm[i].type == GHOST_LOCL) { nlist2=comm->comm[i].n_part_lists/2; for(j=0;jcomm[i].part_lists[j]; - comm->comm[i].part_lists[j] = comm->comm[i].part_lists[j+nlist2]; - comm->comm[i].part_lists[j+nlist2] = tmplist; + tmplist = comm->comm[i].part_lists[j]; + comm->comm[i].part_lists[j] = comm->comm[i].part_lists[j+nlist2]; + comm->comm[i].part_lists[j+nlist2] = tmplist; } } } @@ -398,44 +466,45 @@ void dd_assign_prefetches(GhostCommunicator *comm) void dd_update_communicators_w_boxl() { int cnt=0; + /* direction loop: x, y, z */ for(int dir=0; dir<3; dir++) { /* lr loop: left right */ for(int lr=0; lr<2; lr++) { if(node_grid[dir] == 1) { #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) + if( PERIODIC(dir ) || (boundary[2*dir+lr] == 0) ) #endif - { - /* prepare folding of ghost positions */ - if(boundary[2*dir+lr] != 0) { - cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - } - cnt++; - } + { + /* prepare folding of ghost positions */ + if(boundary[2*dir+lr] != 0) { + cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + } + cnt++; + } } else { - /* i: send/recv loop */ - for(int i=0; i<2; i++) { + /* i: send/recv loop */ + for(int i=0; i<2; i++) { #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) + if( PERIODIC(dir) || (boundary[2*dir+lr] == 0) ) #endif - if((node_pos[dir]+i)%2==0) { - /* prepare folding of ghost positions */ - if(boundary[2*dir+lr] != 0) { - cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; - } - cnt++; - } + if((node_pos[dir]+i)%2==0) { + /* prepare folding of ghost positions */ + if(boundary[2*dir+lr] != 0) { + cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = boundary[2*dir+lr]*box_l[dir]; + } + cnt++; + } #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) + if( PERIODIC(dir) || (boundary[2*dir+(1-lr)] == 0) ) #endif - if((node_pos[dir]+(1-i))%2==0) { - cnt++; - } - } + if((node_pos[dir]+(1-i))%2==0) { + cnt++; + } + } } } } @@ -444,7 +513,7 @@ void dd_update_communicators_w_boxl() /** Init cell interactions for cell system domain decomposition. * initializes the interacting neighbor cell list of a cell The * created list of interacting neighbor cells is used by the verlet - * algorithm (see verlet.c) to build the verlet lists. + * algorithm (see verlet.cpp) to build the verlet lists. */ void dd_init_cell_interactions() { @@ -460,24 +529,62 @@ void dd_init_cell_interactions() /* loop all local cells */ DD_LOCAL_CELLS_LOOP(m,n,o) { dd.cell_inter[c_cnt].nList = (IA_Neighbor *) realloc(dd.cell_inter[c_cnt].nList, CELLS_MAX_NEIGHBORS*sizeof(IA_Neighbor)); - dd.cell_inter[c_cnt].n_neighbors = CELLS_MAX_NEIGHBORS; - + n_cnt=0; ind1 = get_linear_index(m,n,o,dd.ghost_cell_grid); /* loop all neighbor cells */ - for(p=o-1; p<=o+1; p++) + for(p=o-1; p<=o+1; p++) for(q=n-1; q<=n+1; q++) - for(r=m-1; r<=m+1; r++) { - ind2 = get_linear_index(r,q,p,dd.ghost_cell_grid); - if(ind2 >= ind1) { - dd.cell_inter[c_cnt].nList[n_cnt].cell_ind = ind2; - dd.cell_inter[c_cnt].nList[n_cnt].pList = &cells[ind2]; - init_pairList(&dd.cell_inter[c_cnt].nList[n_cnt].vList); - n_cnt++; - } - } + for(r=m-1; r<=m+1; r++) { + ind2 = get_linear_index(r,q,p,dd.ghost_cell_grid); + if(ind2 >= ind1) { + dd.cell_inter[c_cnt].nList[n_cnt].cell_ind = ind2; + dd.cell_inter[c_cnt].nList[n_cnt].pList = &cells[ind2]; + init_pairList(&dd.cell_inter[c_cnt].nList[n_cnt].vList); +#ifdef CELL_DEBUG + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[0] = my_left[0] + r * dd.cell_size[0]; + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[1] = my_left[1] + q * dd.cell_size[1]; + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[2] = my_left[2] + p * dd.cell_size[2]; +#endif + n_cnt++; + } + } + + + dd.cell_inter[c_cnt].n_neighbors = n_cnt; c_cnt++; } + +#ifdef CELL_DEBUG + FILE *cells_fp; + char cLogName[64]; + int c,nn,this_n; + double myPos[3], nPos[3]; + sprintf(cLogName, "cells_map%i.dat", this_node); + cells_fp = fopen(cLogName,"w"); + + + for(c=0;c -ROUND_ERROR_PREC*box_l[i] #ifdef PARTIAL_PERIODIC - || (!PERIODIC(i) && boundary[2*i]) + || (!PERIODIC(i) && boundary[2*i]) #endif - ) - cpos[i] = 1; + ) + cpos[i] = 1; else - return NULL; + return NULL; } else if (cpos[i] > dd.cell_grid[i]) { if (lpos < local_box_l[i] + ROUND_ERROR_PREC*box_l[i] #ifdef PARTIAL_PERIODIC - || (!PERIODIC(i) && boundary[2*i+1]) + || (!PERIODIC(i) && boundary[2*i+1]) #endif - ) - cpos[i] = dd.cell_grid[i]; + ) + cpos[i] = dd.cell_grid[i]; else - return NULL; + return NULL; } } i = get_linear_index(cpos[0],cpos[1],cpos[2], dd.ghost_cell_grid); @@ -536,8 +643,9 @@ Cell *dd_position_to_cell(double pos[3]) cpos[i] = 1; #ifdef ADDITIONAL_CHECKS if (PERIODIC(i) && lpos < -ROUND_ERROR_PREC*box_l[i]) { - char *errtext = runtime_error(128 + 3*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtext, "{005 particle @ (%g, %g, %g) is outside of the allowed cell grid} ", pos[0], pos[1], pos[2]); + ostringstream msg; + msg << "particle @ (" << pos[0] << ", " << pos[1] << ", " << pos[2] << ") is outside of the allowed cell grid"; + runtimeError(msg); } #endif } @@ -545,8 +653,9 @@ Cell *dd_position_to_cell(double pos[3]) cpos[i] = dd.cell_grid[i]; #ifdef ADDITIONAL_CHECKS if (PERIODIC(i) && lpos > local_box_l[i] + ROUND_ERROR_PREC*box_l[i]) { - char *errtext = runtime_error(128 + 3*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtext, "{005 particle @ (%g, %g, %g) is outside of the allowed cell grid} ", pos[0], pos[1], pos[2]); + ostringstream msg; + msg << "particle @ (" << pos[0] << ", " << pos[1] << ", " << pos[2] << ") is outside of the allowed cell grid"; + runtimeError(msg); } #endif } @@ -566,31 +675,36 @@ int dd_append_particles(ParticleList *pl, int fold_dir) CELL_TRACE(fprintf(stderr, "%d: dd_append_particles %d\n", this_node, pl->n)); for(p=0; pn; p++) { - if(boundary[fold_dir] != 0) + if(boundary[fold_dir] != 0){ +#ifdef LEES_EDWARDS + fold_coordinate(pl->part[p].r.p, pl->part[p].m.v, pl->part[p].l.i, fold_coord); +#else fold_coordinate(pl->part[p].r.p, pl->part[p].l.i, fold_coord); - +#endif + } + for(dir=0;dir<3;dir++) { cpos[dir] = (int)((pl->part[p].r.p[dir]-my_left[dir])*dd.inv_cell_size[dir])+1; if (cpos[dir] < 1) { - cpos[dir] = 1; + cpos[dir] = 1; #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) ) + if( PERIODIC(dir) ) #endif - { - flag=1; - CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);}); - } + { + flag=1; + CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);}); + } } else if (cpos[dir] > dd.cell_grid[dir]) { - cpos[dir] = dd.cell_grid[dir]; + cpos[dir] = dd.cell_grid[dir]; #ifdef PARTIAL_PERIODIC - if( PERIODIC(dir) ) + if( PERIODIC(dir) ) #endif - { - flag=1; - CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);}); - } + { + flag=1; + CELL_TRACE(if(fold_coord==2){fprintf(stderr, "%d: dd_append_particles: particle %d (%f,%f,%f) not inside node domain.\n", this_node,pl->part[p].p.identity,pl->part[p].r.p[0],pl->part[p].r.p[1],pl->part[p].r.p[2]);}); + } } } c = get_linear_index(cpos[0],cpos[1],cpos[2], dd.ghost_cell_grid); @@ -607,11 +721,45 @@ int dd_append_particles(ParticleList *pl, int fold_dir) /************************************************************/ void dd_on_geometry_change(int flags) { + + /* Realignment of comms along the periodic y-direction is needed */ + if (flags & CELL_FLAG_LEES_EDWARDS) { + CELL_TRACE(fprintf(stderr,"%d: dd_on_geometry_change responding to Lees-Edwards offset change.\n", this_node);) + +#ifdef LEES_EDWARDS + le_mgr.update_on_le_offset_change(); + + le_dd_dynamic_update_comm(&le_mgr, &cell_structure.ghost_cells_comm, + GHOSTTRANS_PARTNUM, + LE_COMM_FORWARDS); + le_dd_dynamic_update_comm(&le_mgr, &cell_structure.exchange_ghosts_comm, + (GHOSTTRANS_PROPRTS | GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD), + LE_COMM_FORWARDS); + le_dd_dynamic_update_comm(&le_mgr, &cell_structure.update_ghost_pos_comm, + (GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD), + LE_COMM_FORWARDS); + le_dd_dynamic_update_comm(&le_mgr, &cell_structure.collect_ghost_force_comm, + GHOSTTRANS_FORCE, + LE_COMM_BACKWARDS); +#ifdef LB + le_dd_dynamic_update_comm(&cell_structure.ghost_lbcoupling_comm, GHOSTTRANS_COUPLING); +#endif + + /* prefetch status may have changed? */ + dd_assign_prefetches(&cell_structure.ghost_cells_comm); + dd_assign_prefetches(&cell_structure.exchange_ghosts_comm); + dd_assign_prefetches(&cell_structure.update_ghost_pos_comm); + dd_assign_prefetches(&cell_structure.collect_ghost_force_comm); +#endif + + } + /* check that the CPU domains are still sufficiently large. */ for (int i = 0; i < 3; i++) if (local_box_l[i] < max_range) { - char *errtext = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{013 box_l in direction %d is too small} ", i); + ostringstream msg; + msg <<"box_l in direction " << i << " is too small"; + runtimeError(msg); } /* A full resorting is necessary if the grid has changed. We simply @@ -659,9 +807,11 @@ void dd_on_geometry_change(int flags) { return; } } - +#ifdef LEES_EDWARDS + le_dd_update_communicators_w_boxl(&le_mgr); +#else dd_update_communicators_w_boxl(); - +#endif /* tell other algorithms that the box length might have changed. */ on_boxl_change(); } @@ -686,15 +836,28 @@ void dd_topology_init(CellPList *old) dd_create_cell_grid(); /* mark cells */ dd_mark_cells(); + /* create communicators */ - dd_prepare_comm(&cell_structure.ghost_cells_comm, GHOSTTRANS_PARTNUM); +#ifdef LEES_EDWARDS + le_mgr.init(my_neighbor_count); + le_dd_prepare_comm(&le_mgr, &cell_structure.ghost_cells_comm, GHOSTTRANS_PARTNUM); +#else + dd_prepare_comm(&cell_structure.ghost_cells_comm, GHOSTTRANS_PARTNUM); +#endif exchange_data = (GHOSTTRANS_PROPRTS | GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD); update_data = (GHOSTTRANS_POSITION | GHOSTTRANS_POSSHFTD); + +#ifdef LEES_EDWARDS + le_dd_prepare_comm(&le_mgr, &cell_structure.exchange_ghosts_comm, exchange_data); + le_dd_prepare_comm(&le_mgr, &cell_structure.update_ghost_pos_comm, update_data); + le_dd_prepare_comm(&le_mgr, &cell_structure.collect_ghost_force_comm, GHOSTTRANS_FORCE); +#else dd_prepare_comm(&cell_structure.exchange_ghosts_comm, exchange_data); dd_prepare_comm(&cell_structure.update_ghost_pos_comm, update_data); - dd_prepare_comm(&cell_structure.collect_ghost_force_comm, GHOSTTRANS_FORCE); +#endif + /* collect forces has to be done in reverted order! */ dd_revert_comm_order(&cell_structure.collect_ghost_force_comm); @@ -709,7 +872,11 @@ void dd_topology_init(CellPList *old) #endif /* initialize cell neighbor structures */ +#ifdef LEES_EDWARDS + le_dd_init_cell_interactions(); +#else dd_init_cell_interactions(); +#endif /* copy particles */ for (c = 0; c < old->n; c++) { @@ -718,9 +885,9 @@ void dd_topology_init(CellPList *old) for (p = 0; p < np; p++) { Cell *nc = dd_save_position_to_cell(part[p].r.p); /* particle does not belong to this node. Just stow away - somewhere for the moment */ + somewhere for the moment */ if (nc == NULL) - nc = local_cells.cell[0]; + nc = local_cells.cell[0]; append_unindexed_particle(nc, &part[p]); } } @@ -761,6 +928,9 @@ void dd_exchange_and_sort_particles(int global_flag) ParticleList *cell,*sort_cell, send_buf_l, send_buf_r, recv_buf_l, recv_buf_r; Particle *part; CELL_TRACE(fprintf(stderr,"%d: dd_exchange_and_sort_particles(%d):\n",this_node,global_flag)); + CELL_TRACE(fprintf(stderr,"%d: node_neighbors are %d %d %d %d %d %d\n",this_node, + node_neighbors[0], node_neighbors[1], node_neighbors[2], + node_neighbors[3], node_neighbors[4], node_neighbors[5])); init_particlelist(&send_buf_l); init_particlelist(&send_buf_r); @@ -778,7 +948,9 @@ void dd_exchange_and_sort_particles(int global_flag) for (p = 0; p < cell->n; p++) { part = &cell->part[p]; /* Move particles to the left side */ - if(part->r.p[dir] - my_left[dir] < -ROUND_ERROR_PREC*box_l[dir]) { + // Without the factor 0.5 in front of ROUND_ERROR_PREC, particles sitting exactly on the boundary + // may be accepted (i.e. not sent) here and rejected later on by dd_save_position_to_cell + if(part->r.p[dir] - my_left[dir] < -0.5*ROUND_ERROR_PREC*box_l[dir]) { #ifdef PARTIAL_PERIODIC if( PERIODIC(dir) || (boundary[2*dir]==0) ) #endif @@ -790,7 +962,8 @@ void dd_exchange_and_sort_particles(int global_flag) } } /* Move particles to the right side */ - else if(part->r.p[dir] - my_right[dir] >= ROUND_ERROR_PREC*box_l[dir]) { + // Factor 0.5 see above + else if(part->r.p[dir] - my_right[dir] >= 0.5*ROUND_ERROR_PREC*box_l[dir]) { #ifdef PARTIAL_PERIODIC if( PERIODIC(dir) || (boundary[2*dir+1]==0) ) #endif @@ -825,27 +998,57 @@ void dd_exchange_and_sort_particles(int global_flag) } } - /* Exchange particles */ - if(node_pos[dir]%2==0) { - send_particles(&send_buf_l, node_neighbors[2*dir]); - recv_particles(&recv_buf_r, node_neighbors[2*dir+1]); - send_particles(&send_buf_r, node_neighbors[2*dir+1]); - recv_particles(&recv_buf_l, node_neighbors[2*dir]); - } - else { - recv_particles(&recv_buf_r, node_neighbors[2*dir+1]); - send_particles(&send_buf_l, node_neighbors[2*dir]); - recv_particles(&recv_buf_l, node_neighbors[2*dir]); - send_particles(&send_buf_r, node_neighbors[2*dir+1]); - } - /* sort received particles to cells */ - if(dd_append_particles(&recv_buf_l, 2*dir ) && dir == 2) finished = 0; - if(dd_append_particles(&recv_buf_r, 2*dir+1) && dir == 2) finished = 0; - /* reset send/recv buffers */ - send_buf_l.n = 0; - send_buf_r.n = 0; - recv_buf_l.n = 0; - recv_buf_r.n = 0; + /* Exchange particles */ +#ifndef LEES_EDWARDS + CELL_TRACE(fprintf(stderr,"%d: send receive %d\n",this_node, dir)); + + if(node_pos[dir]%2==0) { + send_particles(&send_buf_l, node_neighbors[2*dir]); + recv_particles(&recv_buf_r, node_neighbors[2*dir+1]); + send_particles(&send_buf_r, node_neighbors[2*dir+1]); + recv_particles(&recv_buf_l, node_neighbors[2*dir]); + } + else { + recv_particles(&recv_buf_r, node_neighbors[2*dir+1]); + send_particles(&send_buf_l, node_neighbors[2*dir]); + recv_particles(&recv_buf_l, node_neighbors[2*dir]); + send_particles(&send_buf_r, node_neighbors[2*dir+1]); + } +#else + int ii, nn, lr; + for( ii = 0; ii <2; ii++){ + + nn = node_neighbors[2*dir+ii]; + lr = node_neighbor_lr[2*dir+ii]; + + if( lr == 1 ){ + if( nn > this_node ){ + send_particles(&send_buf_r, nn); + recv_particles(&recv_buf_r, nn); + }else{ + recv_particles(&recv_buf_r, nn); + send_particles(&send_buf_r, nn); + } + }else{ + if( nn > this_node ){ + send_particles(&send_buf_l, nn); + recv_particles(&recv_buf_l, nn); + }else{ + recv_particles(&recv_buf_l, nn); + send_particles(&send_buf_l, nn); + } + } + } +#endif + + /* sort received particles to cells, folding of coordinates also happens in here. */ + if(dd_append_particles(&recv_buf_l, 2*dir ) && dir == 2) finished = 0; + if(dd_append_particles(&recv_buf_r, 2*dir+1) && dir == 2) finished = 0; + /* reset send/recv buffers */ + send_buf_l.n = 0; + send_buf_r.n = 0; + recv_buf_l.n = 0; + recv_buf_r.n = 0; } else { /* Single node direction case (no communication) */ @@ -859,7 +1062,11 @@ void dd_exchange_and_sort_particles(int global_flag) if( PERIODIC(dir) ) #endif { - fold_coordinate(part->r.p, part->l.i, dir); +#ifdef LEES_EDWARDS + fold_coordinate(part->r.p, part->m.v, part->l.i, dir); +#else + fold_coordinate(part->r.p, part->l.i, dir); +#endif } if (dir==2) { sort_cell = dd_save_position_to_cell(part->r.p); @@ -898,8 +1105,9 @@ void dd_exchange_and_sort_particles(int global_flag) MPI_Bcast(&finished, 1, MPI_INT, 0, comm_cart); } else { if(finished == 0) { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{004 some particles moved more than min_local_box_l, reduce the time step} "); + ostringstream msg; + msg << "some particles moved more than min_local_box_l, reduce the time step"; + runtimeError(msg); /* the bad guys are all in cell 0, but probably their interactions are of no importance anyways. However, their positions have to be made valid again. */ finished = 1; @@ -971,6 +1179,7 @@ void calc_link_cell() #ifdef CONSTRAINTS add_constraints_forces(&p1[i]); #endif + add_external_potential_forces(&p1[i]); if (rebuild_verletlist) memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double)); @@ -1016,6 +1225,7 @@ void calculate_link_cell_energies() #ifdef CONSTRAINTS add_constraints_energy(&p1[i]); #endif + add_external_potential_energy(&p1[i]); if (rebuild_verletlist) memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double)); diff --git a/src/domain_decomposition.hpp b/src/core/domain_decomposition.hpp similarity index 86% rename from src/domain_decomposition.hpp rename to src/core/domain_decomposition.hpp index e6a963971fa..b9ca24ee367 100644 --- a/src/domain_decomposition.hpp +++ b/src/core/domain_decomposition.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _DOMAIN_DECOMPOSITION_H #define _DOMAIN_DECOMPOSITION_H -/** \file domain_decomposition.h +/** \file domain_decomposition.hpp * * This file contains everything related to the cell system: domain decomposition. * @@ -52,7 +52,7 @@ * some ghost-ghost cell interaction as well, which we do not need! * * For more information on cells, - * see \ref cells.h + * see \ref cells.hpp */ #include "utils.hpp" @@ -70,6 +70,11 @@ typedef struct { ParticleList *pList; /** Verlet list for non bonded interactions of a cell with a neighbor cell. */ PairList vList; + +#ifdef CELL_DEBUG + double my_pos[3]; /* position of the cell corner, only here for debug */ +#endif + } IA_Neighbor; @@ -134,7 +139,7 @@ extern double max_skin; * n_cells, is larger than max_num_cells the cell grid is * reduced. max_num_cells has to be larger than 27, e.g one inner * cell. max_num_cells is initialized with the default value - * specified in \ref config.h as \ref CELLS_MAX_NUM_CELLS. + * specified in \ref config.hpp as \ref CELLS_MAX_NUM_CELLS. */ extern int max_num_cells; @@ -207,6 +212,25 @@ void calculate_link_cell_energies(); /** Nonbonded and bonded virials calculation using link-cell method */ void calculate_link_cell_virials(int v_comp); +/** Fill a communication cell pointer list. Fill the cell pointers of + all cells which are inside a rectangular subgrid of the 3D cell + grid (\ref DomainDecomposition::ghost_cell_grid) starting from the + lower left corner lc up to the high top corner hc. The cell + pointer list part_lists must already be large enough. + \param part_lists List of cell pointers to store the result. + \param lc lower left corner of the subgrid. + \param hc high up corner of the subgrid. + */ +int dd_fill_comm_cell_lists(Cell **part_lists, int lc[3], int hc[3]); + + +/** Returns pointer to the cell which corresponds to the position if + the position is in the nodes spatial domain otherwise a NULL + pointer. */ +Cell *dd_save_position_to_cell(double pos[3]); + +/** Of every two communication rounds, set the first receivers to prefetch and poststore */ +void dd_assign_prefetches(GhostCommunicator *comm); /*@}*/ #endif diff --git a/src/dpd.cpp b/src/core/dpd.cpp similarity index 96% rename from src/dpd.cpp rename to src/core/dpd.cpp index 7342ec0d4fa..711ea2b3baf 100644 --- a/src/dpd.cpp +++ b/src/core/dpd.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,11 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file dpd.c - Implementation of \ref dpd.h "dpd.h" +/** \file dpd.cpp + Implementation of \ref dpd.hpp "dpd.hpp" */ #include "dpd.hpp" +/** Flag to decide wether to allow for fixed particles with DPD */ +int dpd_ignore_fixed_particles=1; + /* DPD THERMOSTAT */ /* DPD longitudinal friction coefficient gamma. */ double dpd_gamma = 0.0; diff --git a/src/dpd.hpp b/src/core/dpd.hpp similarity index 87% rename from src/dpd.hpp rename to src/core/dpd.hpp index 9ccdfad37a7..c5b907ac640 100644 --- a/src/dpd.hpp +++ b/src/core/dpd.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef DPD_H #define DPD_H -/** \file dpd.h +/** \file dpd.hpp * Routines to use dpd as thermostat or pair force * T. Soddemann, B. Duenweg and K. Kremer, Phys. Rev. E 68, 046702 (2003) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -32,6 +32,9 @@ #include "particle_data.hpp" #include "virtual_sites.hpp" +/** Flag to decide wether to allow for fixed particles with DPD */ +extern int dpd_ignore_fixed_particles; + /** DPD Friction coefficient gamma. */ extern double dpd_gamma; /** DPD thermostat cutoff */ @@ -62,6 +65,24 @@ void thermo_init_dpd(); void dpd_heat_up(); void dpd_cool_down(); +/** Chatterjee 2007 proposes that for DPD with Lees Edwards BCs, + * it is better not to count interactions with Ghost particles. */ +inline int le_chatterjee_test_pair(Particle *p1, Particle *p2){ +#ifdef LEES_EDWARDS + /* cannot assume that we have a flag set to mark ghost particles, + * but can assume (for LE) that non-ghost + * particle y-coords are always imaged inside the box */ + + if( p1->r.p[1] < 0 ) return(0); + if( p1->r.p[1] > box_l[1] ) return(0); + if( p2->r.p[1] < 0 ) return(0); + if( p2->r.p[1] > box_l[1] ) return(0); +#endif + return(1); +} + + + /** Calculate Random Force and Friction Force acting between particle p1 and p2 and add them to their forces. */ inline void add_dpd_thermo_pair_force(Particle *p1, Particle *p2, double d[3], double dist, double dist2) @@ -91,11 +112,16 @@ inline void add_dpd_thermo_pair_force(Particle *p1, Particle *p2, double d[3], d double massf; #endif +#ifdef LEES_EDWARDS + if( le_chatterjee_test_pair(p1, p2) == 0 ) return; +#endif + #ifdef EXTERNAL_FORCES // if any of the two particles is fixed in some direction then // do not add any dissipative or stochastic dpd force part // because dissipation-fluctuation theorem is violated - if ( (p1->l.ext_flag | p2->l.ext_flag) & COORDS_FIX_MASK) return; + if (dpd_ignore_fixed_particles) + if ( (p1->l.ext_flag | p2->l.ext_flag) & COORDS_FIX_MASK) return; #endif #ifdef VIRTUAL_SITES @@ -219,9 +245,14 @@ inline void add_inter_dpd_pair_force(Particle *p1, Particle *p2, IA_parameters * // if any of the two particles is fixed in some direction then // do not add any dissipative or stochastic dpd force part // because dissipation-fluctuation theorem is violated - if ( (p1->l.ext_flag | p2->l.ext_flag) & COORDS_FIX_MASK) return; + if (dpd_ignore_fixed_particles) + if ( (p1->l.ext_flag | p2->l.ext_flag) & COORDS_FIX_MASK) return; #endif +#ifdef LEES_EDWARDS + if( le_chatterjee_test_pair(p1, p2) == 0 ) return; +#endif + #ifdef DPD_MASS_RED massf=2*PMASS(*p1)*PMASS(*p2)/(PMASS(*p1)+PMASS(*p2)); #endif diff --git a/src/elc.cpp b/src/core/elc.cpp similarity index 79% rename from src/elc.cpp rename to src/core/elc.cpp index 8fc13185091..17975490ff3 100644 --- a/src/elc.cpp +++ b/src/core/elc.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file elc.c +/** \file elc.cpp * - * For more information about ELC, see \ref elc.h "elc.h". + * For more information about ELC, see \ref elc.hpp "elc.hpp". */ #include #include @@ -53,10 +53,10 @@ /** \name Inverse box dimensions and derived constants */ /*@{*/ -static double ux, ux2, uy, uy2, uz; +static double ux, ux2, uy, uy2, uz, height_inverse; /*@}*/ -ELC_struct elc_params = { 1e100, 10, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 }; +ELC_struct elc_params = { 1e100, 10, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0 }; /**************************************** * LOCAL ARRAYS @@ -149,6 +149,8 @@ void ELC_setup_constants() uy = 1/box_l[1]; uy2 = uy*uy; uz = 1/box_l[2]; + + height_inverse = 1/elc_params.h; } /* SC Cache */ @@ -309,168 +311,138 @@ static void clear_log_forces(char *where) static void add_dipole_force() { - int np, c, i; - Particle *part; double pref = coulomb.prefactor*4*M_PI*ux*uy*uz; + int size = 3; + /* for nonneutral systems, this shift gives the background contribution (rsp. for this shift, the DM of the background is zero) */ double shift = 0.5*box_l[2]; + double field_tot = 0; - gblcblk[0] = 0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { + // collect moments + + gblcblk[0] = 0; // sum q_i (z_i - L/2) + gblcblk[1] = 0; // sum q_i z_i + gblcblk[2] = 0; // sum q_i + + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { gblcblk[0] += part[i].p.q*(part[i].r.p[2] - shift); + gblcblk[1] += part[i].p.q*part[i].r.p[2]; + gblcblk[2] += part[i].p.q; if(elc_params.dielectric_contrast_on) { - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) + gblcblk[2] +=elc_params.di_mid_bot*part[i].p.q; + } + if(part[i].r.p[2]>(elc_params.h-elc_params.space_layer)) { gblcblk[0] +=elc_params.di_mid_top*part[i].p.q*(2*elc_params.h-part[i].r.p[2] - shift); + gblcblk[2] +=elc_params.di_mid_top*part[i].p.q; + } } } } gblcblk[0] *= pref; + gblcblk[1] *= pref*height_inverse/uz; + gblcblk[2] *= pref; - distribute(1); - - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) - part[i].f.f[2] -= gblcblk[0]*part[i].p.q; + distribute(size); + + // Yeh+Berkowitz dipole term + field_tot = gblcblk[0]; + + // Const. potential contribution + if (elc_params.const_pot_on) { + field_induced = gblcblk[1]; + field_applied = elc_params.pot_diff * height_inverse; + field_tot -= field_applied + field_induced; } - - if (!elc_params.neutralize) { - /* SUBTRACT the forces of the neutralizing background - looks very close to the code above, but is still different. - */ - gblcblk[0] = 0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q; - if(elc_params.dielectric_contrast_on) { - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) - gblcblk[0] +=elc_params.di_mid_top*part[i].p.q; - } + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + part[i].f.f[2] -= field_tot*part[i].p.q; + + if (!elc_params.neutralize) { + // SUBTRACT the forces of the P3M homogeneous neutralizing background + part[i].f.f[2] += gblcblk[2]*part[i].p.q*(part[i].r.p[2] - shift); } } - gblcblk[0] *= pref; - - distribute(1); - - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) - part[i].f.f[2] += gblcblk[0]*part[i].p.q*(part[i].r.p[2] - shift); - } } } static double dipole_energy() { - int np, c, i; - Particle *part; double pref = coulomb.prefactor*2*M_PI*ux*uy*uz; - double eng, eng1, eng2, eng3; + int size = 7; /* for nonneutral systems, this shift gives the background contribution (rsp. for this shift, the DM of the background is zero) */ double shift = 0.5*box_l[2]; - gblcblk[0] = 0;gblcblk[1]=0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q*(part[i].r.p[2] - shift); + // collect moments + + gblcblk[0] = 0; // sum q_i primary box + gblcblk[1] = 0; // sum q_i boundary layers + gblcblk[2] = 0; // sum q_i (z_i - L/2) primary box + gblcblk[3] = 0; // sum q_i (z_i - L/2) boundary layers + gblcblk[4] = 0; // sum q_i (z_i - L/2)^2 primary box + gblcblk[5] = 0; // sum q_i (z_i - L/2)^2 boundary layers + gblcblk[6] = 0; // sum q_i z_i primary box + + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + gblcblk[0] += part[i].p.q; + gblcblk[2] += part[i].p.q*(part[i].r.p[2] - shift); + gblcblk[4] += part[i].p.q*(SQR(part[i].r.p[2]- shift)); + gblcblk[6] += part[i].p.q*part[i].r.p[2]; if(elc_params.dielectric_contrast_on) { - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) - gblcblk[1] +=elc_params.di_mid_top*part[i].p.q*(2*elc_params.h-part[i].r.p[2] - shift); + if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { + gblcblk[1] +=elc_params.di_mid_top*part[i].p.q; + gblcblk[3] +=elc_params.di_mid_top*part[i].p.q*(2*elc_params.h-part[i].r.p[2] - shift); + gblcblk[5] +=elc_params.di_mid_top*part[i].p.q*(SQR(2*elc_params.h-part[i].r.p[2] - shift)); + } } } } - distribute(2); - - eng = (this_node == 0) ? pref*(SQR(gblcblk[0])+gblcblk[0]*gblcblk[1]) : 0; + distribute(size); + // Yeh + Berkowitz term + double eng = 2*pref*(SQR(gblcblk[2])+gblcblk[2]*gblcblk[3]); + if (!elc_params.neutralize) { - /* SUBTRACT the energy of the neutralizing background */ - gblcblk[0] = 0; gblcblk[1] = 0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q; - gblcblk[1] += part[i].p.q*(SQR(part[i].r.p[2]- shift)); - } + // SUBTRACT the energy of the P3M homogeneous neutralizing background + eng += 2*pref*(-gblcblk[0]*gblcblk[4] - (.25 - .5/3.)*SQR(gblcblk[0]*box_l[2])); + } + + if (elc_params.dielectric_contrast_on) { + if (elc_params.const_pot_on) { + // zero potential difference contribution + eng += pref*height_inverse/uz*SQR(gblcblk[6]); + // external potential shift contribution + eng += elc_params.pot_diff * height_inverse * gblcblk[6]; } - - distribute(2); - - eng1 = (this_node == 0) ? pref*(-gblcblk[1]*gblcblk[0] - (.25 - .5/3.)*SQR(gblcblk[0]*box_l[2])) : 0; - if(!elc_params.dielectric_contrast_on) - eng += eng1; - else { - gblcblk[0] = 0; gblcblk[1] = 0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q; - gblcblk[1] += part[i].p.q*(SQR(part[i].r.p[2]-shift)); - - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { - gblcblk[0] +=elc_params.di_mid_top*part[i].p.q; - gblcblk[1] +=elc_params.di_mid_top*part[i].p.q*(SQR(2*elc_params.h-part[i].r.p[2]-shift)); - } - } - } - - distribute(2); - - eng2 = (this_node == 0) ? pref*(-gblcblk[1]*gblcblk[0] - (.25 - .5/3.)*SQR(gblcblk[0]*box_l[2])) : 0; - - gblcblk[0] = 0; gblcblk[1] = 0; - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { - gblcblk[0] +=elc_params.di_mid_top*part[i].p.q; - gblcblk[1] +=elc_params.di_mid_top*part[i].p.q*(SQR(2*elc_params.h-part[i].r.p[2]-shift)); - } - } - } - distribute(2); - - eng3 = (this_node == 0) ? pref*(-gblcblk[1]*gblcblk[0] - (.25 - .5/3.)*SQR(gblcblk[0]*box_l[2])) : 0; - - if (this_node == 0) eng+=(eng1+eng2-eng3)/2.0; - } + /* counter the P3M homogeneous background contribution to the + boundaries. We never need that, since a homogeneous background + spanning the artifical boundary layers is aphysical. */ + eng += pref*(-(gblcblk[1]*gblcblk[4] + gblcblk[0]*gblcblk[5]) + - (1. - 2./3.)*gblcblk[0]*gblcblk[1]*SQR(box_l[2])); } - return eng; + return this_node == 0 ? eng : 0; } /*****************************************************************/ @@ -480,7 +452,6 @@ inline double image_sum_b(double q, double z) double shift = 0.5*box_l[2]; double fac=elc_params.di_mid_top*elc_params.di_mid_bot; double image_sum=(q/(1.0-fac)*(z-2.0*fac*box_l[2]/(1.0-fac)))-q*shift/(1-fac); - // double image_sum=q*(z-shift); return image_sum; } @@ -495,59 +466,77 @@ inline double image_sum_t(double q, double z) /*****************************************************************/ static double z_energy() { - int np, c, i; - Particle *part; double pref = coulomb.prefactor*2*M_PI*ux*uy; + int size = 4; + double eng=0; /* for nonneutral systems, this shift gives the background contribution (rsp. for this shift, the DM of the background is zero) */ double shift = 0.5*box_l[2]; - double q_m_t=0.0,q_m_b=0.0,q=0.0; - double fac_delta_mid_bot=1,fac_delta_mid_top=1,fac_delta=1; - if(elc_params.dielectric_contrast_on) { - fac_delta_mid_bot=elc_params.di_mid_bot/(1-elc_params.di_mid_top*elc_params.di_mid_bot); - fac_delta_mid_top=elc_params.di_mid_top/(1-elc_params.di_mid_top*elc_params.di_mid_bot); - fac_delta=fac_delta_mid_bot*elc_params.di_mid_top; - q_m_t=elc_params.di_mid_top; - q_m_b=elc_params.di_mid_bot; - q=q_m_t*q_m_b; - } - - clear_vec(gblcblk, 4); - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q; //q_i - gblcblk[1] += part[i].p.q*(part[i].r.p[2] - shift); //q_i z_ - if(elc_params.dielectric_contrast_on) { - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { - //note the minus sign here which is required due to |z_i-z_j| - gblcblk[2] -= fac_delta*(1+elc_params.di_mid_top)*part[i].p.q; - gblcblk[3] -= part[i].p.q*(image_sum_t(q_m_t*q,4*elc_params.h-part[i].r.p[2]) - +image_sum_t(q,2*elc_params.h+part[i].r.p[2])); - } else { - //note the minus sign here which is required due to |z_i-z_j| - gblcblk[2] -= fac_delta_mid_top*(1+elc_params.di_mid_bot)*part[i].p.q; - gblcblk[3] -= part[i].p.q*(image_sum_t(q_m_t,2*elc_params.h-part[i].r.p[2]) - +image_sum_t(q,2*elc_params.h+part[i].r.p[2])); - } - } + if(elc_params.const_pot_on) { + clear_vec(gblcblk, size); + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + gblcblk[0] += part[i].p.q; + gblcblk[1] += part[i].p.q*(part[i].r.p[2] - shift); + if(elc_params.dielectric_contrast_on) { + if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { + gblcblk[2] += elc_params.di_mid_top*part[i].p.q; + gblcblk[3] += elc_params.di_mid_top*part[i].p.q*(2*elc_params.h - part[i].r.p[2] - shift); + } + } + } + } + } + else { + double delta = elc_params.di_mid_top*elc_params.di_mid_bot; + double fac_delta_mid_bot = elc_params.di_mid_bot /(1 - delta); + double fac_delta_mid_top = elc_params.di_mid_top /(1 - delta); + double fac_delta = delta /(1 - delta); + + clear_vec(gblcblk, size); + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + gblcblk[0] += part[i].p.q; + gblcblk[1] += part[i].p.q*(part[i].r.p[2] - shift); + if(elc_params.dielectric_contrast_on) { + if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { + //note the minus sign here which is required due to |z_i-z_j| + gblcblk[2] -= fac_delta*(elc_params.di_mid_top+1)*part[i].p.q; + gblcblk[3] -= part[i].p.q*(image_sum_t(elc_params.di_mid_top*delta,4*elc_params.h-part[i].r.p[2]) + +image_sum_t(delta,2*elc_params.h+part[i].r.p[2])); + } else { + //note the minus sign here which is required due to |z_i-z_j| + gblcblk[2] -= fac_delta_mid_top*(1+elc_params.di_mid_bot)*part[i].p.q; + gblcblk[3] -= part[i].p.q*(image_sum_t(elc_params.di_mid_top,2*elc_params.h-part[i].r.p[2]) + +image_sum_t(delta,2*elc_params.h+part[i].r.p[2])); + } + } + } + } } } - distribute(4); - + distribute(size); + if (this_node == 0) eng -= pref*(gblcblk[1]*gblcblk[2]-gblcblk[0]*gblcblk[3]); @@ -557,48 +546,61 @@ static double z_energy() /*****************************************************************/ static void add_z_force() { - int np, c, i; - Particle *part; double pref = coulomb.prefactor*2*M_PI*ux*uy; - int size = 2; - double fac_delta_mid_bot=1,fac_delta_mid_top=1,fac_delta=1; - if(elc_params.dielectric_contrast_on) { - double fac_elc=1.0/(1-elc_params.di_mid_top*elc_params.di_mid_bot); - fac_delta_mid_bot=elc_params.di_mid_bot*fac_elc; - fac_delta_mid_top=elc_params.di_mid_top*fac_elc; - fac_delta=fac_delta_mid_bot*elc_params.di_mid_top; + int size = 1; - clear_vec(gblcblk, size); - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - gblcblk[0] += part[i].p.q; - if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { - //note the minus sign here which is required due to |z_i-z_j| - gblcblk[1] -= fac_delta*(1+elc_params.di_mid_top)*part[i].p.q; - } else { - //note the minus sign here which is required due to |z_i-z_j| - gblcblk[1] -= fac_delta_mid_top*(1+elc_params.di_mid_bot)*part[i].p.q; - } + if(elc_params.dielectric_contrast_on) { + if (elc_params.const_pot_on) { + clear_vec(gblcblk, size); + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + /* just counter the 2 pi |z| contribution stemming from P3M */ + for (int i = 0; i < np; i++) { + if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) + gblcblk[0] += elc_params.di_mid_top*part[i].p.q; + } } } - + else { + double delta = elc_params.di_mid_top*elc_params.di_mid_bot; + double fac_delta_mid_bot = elc_params.di_mid_bot /(1 - delta); + double fac_delta_mid_top = elc_params.di_mid_top /(1 - delta); + double fac_delta = delta /(1 - delta); + + clear_vec(gblcblk, size); + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + if(part[i].r.p[2](elc_params.h-elc_params.space_layer)) { + //note the minus sign here which is required due to |z_i-z_j| + gblcblk[0] -= fac_delta*(elc_params.di_mid_top + 1)*part[i].p.q; + } else { + //note the minus sign here which is required due to |z_i-z_j| + gblcblk[0] -= fac_delta_mid_top*(1+elc_params.di_mid_bot)*part[i].p.q; + } + } + } + } + gblcblk[0] *= pref; - gblcblk[1] *= pref; - - distribute(2); - - for (c = 0; c < local_cells.n; c++) { - np = local_cells.cell[c]->n; - part = local_cells.cell[c]->part; - for (i = 0; i < np; i++) { - part[i].f.f[2] += gblcblk[1]*part[i].p.q; + + distribute(size); + + for (int c = 0; c < local_cells.n; c++) { + int np = local_cells.cell[c]->n; + Particle *part = local_cells.cell[c]->part; + for (int i = 0; i < np; i++) { + part[i].f.f[2] += gblcblk[0]*part[i].p.q; } } } @@ -1127,8 +1129,8 @@ double ELC_energy() int p, q; double omega; - eng = 2*dipole_energy(); - eng+=z_energy(); + eng = dipole_energy(); + eng += z_energy(); prepare_scx_cache(); prepare_scy_cache(); @@ -1200,18 +1202,27 @@ int ELC_tune(double error) int ELC_sanity_checks() { - char *errtxt; if (!PERIODIC(0) || !PERIODIC(1) || !PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{006 ELC requires periodicity 1 1 1} "); + ostringstream msg; + msg <<"ELC requires periodicity 1 1 1"; + runtimeError(msg); return 1; } + /* The product of the two dielectric contrasts should be < 1 for ELC to work. This is not the case for + two parallel boundaries, which can only be treated by the constant potential code */ + if (elc_params.dielectric_contrast_on && (fabs(1.0 - elc_params.di_mid_top*elc_params.di_mid_bot) < ROUND_ERROR_PREC) + && !elc_params.const_pot_on) { + ostringstream msg; + msg <<"ELC with two parallel metallic boundaries requires the capacitor option"; + runtimeError(msg); + return 1; + } + return 0; } void ELC_init() { - char *errtxt; double maxsl; ELC_setup_constants(); @@ -1228,8 +1239,9 @@ void ELC_init() if (maxsl > .5*elc_params.h) maxsl = .5*elc_params.h; if (elc_params.space_layer > maxsl) { if (maxsl <= 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{007 P3M real space cutoff too large for ELC w/ dielectric contrast} "); + ostringstream msg; + msg <<"P3M real space cutoff too large for ELC w/ dielectric contrast"; + runtimeError(msg); } else elc_params.space_layer = maxsl; @@ -1244,8 +1256,9 @@ void ELC_init() if (elc_params.far_calculated && (coulomb.method == COULOMB_ELC_P3M && elc_params.dielectric_contrast_on)) { if (ELC_tune(elc_params.maxPWerror) == ES_ERROR) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{008 ELC auto-retuning failed, gap size too small} "); + ostringstream msg; + msg <<"ELC auto-retuning failed, gap size too small"; + runtimeError(msg); } } if (coulomb.method == COULOMB_ELC_P3M && elc_params.dielectric_contrast_on) { @@ -1266,20 +1279,17 @@ void ELC_on_resort_particles() } int ELC_set_params(double maxPWerror, double gap_size, double far_cut, int neutralize, - double top, double mid, double bot) + double delta_top, double delta_bot, int const_pot_on, double pot_diff) { elc_params.maxPWerror = maxPWerror; elc_params.gap_size = gap_size; elc_params.h = box_l[2] - gap_size; - if (mid != top || mid != bot) { + if (delta_top != 0.0 || delta_bot != 0.0) { elc_params.dielectric_contrast_on = 1; - elc_params.di_top = top; - elc_params.di_mid = mid; - elc_params.di_bot = bot; - elc_params.di_mid_top = (elc_params.di_mid-elc_params.di_top)/(elc_params.di_mid+elc_params.di_top); - elc_params.di_mid_bot = (elc_params.di_mid-elc_params.di_bot)/(elc_params.di_mid+elc_params.di_bot); + elc_params.di_mid_top = delta_top; + elc_params.di_mid_bot = delta_bot; // neutralize is automatical with dielectric contrast elc_params.neutralize = 0; @@ -1290,26 +1300,36 @@ int ELC_set_params(double maxPWerror, double gap_size, double far_cut, int neutr elc_params.space_box = gap_size - 2*elc_params.space_layer; // reset minimal_dist for tuning elc_params.minimal_dist = dmin(elc_params.space_box, elc_params.space_layer); + + //Constant potential parameter setup + if (const_pot_on) + { + elc_params.const_pot_on = 1; + elc_params.pot_diff = pot_diff; + } } else { // setup without dielectric contrast elc_params.dielectric_contrast_on = 0; - + elc_params.const_pot_on = 0; + elc_params.di_mid_top = 0; + elc_params.di_mid_bot = 0; elc_params.neutralize = neutralize; elc_params.space_layer=0; elc_params.space_box = elc_params.minimal_dist = gap_size; } ELC_setup_constants(); - - char *errtxt; + switch (coulomb.method) { case COULOMB_P3M_GPU: - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{009 ELC tuning failed, ELC is not set up to work with the GPU P3M} "); - return ES_ERROR; - + { + ostringstream msg; + msg <<"ELC tuning failed, ELC is not set up to work with the GPU P3M"; + runtimeError(msg); + return ES_ERROR; + } case COULOMB_ELC_P3M: case COULOMB_P3M: @@ -1328,8 +1348,9 @@ int ELC_set_params(double maxPWerror, double gap_size, double far_cut, int neutr else { elc_params.far_calculated = 1; if (ELC_tune(elc_params.maxPWerror) == ES_ERROR) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{009 ELC tuning failed, gap size too small} "); + ostringstream msg; + msg <<"ELC tuning failed, gap size too small"; + runtimeError(msg); } } mpi_bcast_coulomb_params(); @@ -1606,6 +1627,10 @@ void ELC_P3M_modify_p3m_sums_both() for(i=0;in; for(i=0;i(elc_params.h-elc_params.space_layer)) { - - node_sums[0] += 1.0; - node_sums[1] += SQR(elc_params.di_mid_top*part[i].p.q); - node_sums[2] += elc_params.di_mid_top*part[i].p.q; - - } - } + + node_sums[0] += 1.0; + node_sums[1] += SQR(part[i].p.q); + node_sums[2] += part[i].p.q; } } } MPI_Allreduce(node_sums, tot_sums, 3, MPI_DOUBLE, MPI_SUM, comm_cart); - p3m.sum_qpart -= (int)(tot_sums[0]+0.1); - p3m.sum_q2 -= tot_sums[1]; - p3m.square_sum_q -= SQR(tot_sums[2]); + p3m.sum_qpart = (int)(tot_sums[0]+0.1); + p3m.sum_q2 = tot_sums[1]; + p3m.square_sum_q = SQR(tot_sums[2]); } #endif + diff --git a/src/elc.hpp b/src/core/elc.hpp similarity index 92% rename from src/elc.hpp rename to src/core/elc.hpp index 54bde17104d..6d9cd8698a2 100644 --- a/src/elc.hpp +++ b/src/core/elc.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file elc.h ELC algorithm for long range coulomb interactions. +/** \file elc.hpp ELC algorithm for long range coulomb interactions. Implementation of the ELC method for the calculation of the electrostatic interaction in two dimensional periodic systems. For details on the method see MMM in general. The ELC method works together with any three dimensional method, which in Espresso is - for example \ref p3m.h "P3M", with metallic boundary conditions. */ + for example \ref p3m.hpp "P3M", with metallic boundary conditions. */ #ifndef _ELC_H #define _ELC_H @@ -56,10 +56,12 @@ typedef struct { /// flag whether there is any dielectric contrast in the system int dielectric_contrast_on; - /// dielectric constants - double di_top, di_mid, di_bot; /// dielectric prefactors - double di_mid_top, di_mid_bot, di_fac; + double di_mid_top,di_mid_bot; + + /// const. potential parameters + int const_pot_on; + double pot_diff; /** minimal distance of two charges for which the far formula is used. For plain ELC, this equals gap_size, but for dielectric ELC it is only 1./3. of that. */ @@ -87,7 +89,7 @@ extern ELC_struct elc_params; @param bottom dielectric constant of lower part */ int ELC_set_params(double maxPWerror, double min_dist, double far_cut, int neutralize, - double top, double mid, double bottom); + double top, double bottom, int const_pot_on, double pot_diff); /// the force calculation void ELC_add_force(); @@ -114,17 +116,17 @@ double ELC_P3M_dielectric_layers_energy_self(); /// forces of particles in border layers with themselves void ELC_P3M_self_forces(); -/// assign the additional, virtual charges, used only in energy.c +/// assign the additional, virtual charges, used only in energy.cpp void ELC_p3m_charge_assign_both(); -/// assign the additional, virtual charges, used only in energy.c +/// assign the additional, virtual charges, used only in energy.cpp void ELC_p3m_charge_assign_image(); -/// take into account the virtual charges in the charge sums, used in energy.c +/// take into account the virtual charges in the charge sums, used in energy.cpp void ELC_P3M_modify_p3m_sums_both(); -/// take into account the virtual charges in the charge sums, used in energy.c +/// take into account the virtual charges in the charge sums, used in energy.cpp void ELC_P3M_modify_p3m_sums_image(); -/// assign the additional, virtual charges, used only in energy.c +/// assign the additional, virtual charges, used only in energy.cpp void ELC_P3M_restore_p3m_sums(); #endif diff --git a/src/core/electrokinetics.hpp b/src/core/electrokinetics.hpp new file mode 100644 index 00000000000..37daa8b8d15 --- /dev/null +++ b/src/core/electrokinetics.hpp @@ -0,0 +1,179 @@ +/* + Copyright (C) 2010,2011,2012,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _ELECTROKINETICS_HPP +#define _ELECTROKINETICS_HPP + +#include "config.hpp" +#include "lb-boundaries.hpp" + +//note that we need to declare the ek_parameters struct and instantiate it for LB_GPU +//to compile when electrokinetics is not compiled in. This seemed more elegant than +//ifdeffing multiple versions of the kernel integrate. +#ifdef CUDA + +#define MAX_NUMBER_OF_SPECIES 10 + +#ifdef __CUDACC__ +#include +#else +typedef void cufftComplex; +typedef void cufftReal; +#endif + +/* Data structure holding parameters and memory pointers for the link flux system. */ + +typedef struct { + float agrid; + float time_step; //MD time step + float lb_density; + unsigned int dim_x; + unsigned int dim_y; + unsigned int dim_z; + unsigned int number_of_nodes; + float viscosity; + float bulk_viscosity; + float gamma_odd; + float gamma_even; + float friction; + float T; + float bjerrumlength; + unsigned int number_of_species; + float ext_acceleration_force[3]; + int reaction_species[3]; + float rho_reactant_reservoir; + float rho_product0_reservoir; + float rho_product1_reservoir; + float reaction_ct_rate; + float reaction_fraction_0; + float reaction_fraction_1; + float mass_reactant; + float mass_product0; + float mass_product1; + cufftReal* greensfcn; + cufftComplex* charge_potential; + float* j; + float* lb_force_previous; + float* rho[MAX_NUMBER_OF_SPECIES]; + int species_index[MAX_NUMBER_OF_SPECIES]; + float density[MAX_NUMBER_OF_SPECIES]; + float D[MAX_NUMBER_OF_SPECIES]; + float d[MAX_NUMBER_OF_SPECIES]; + float valency[MAX_NUMBER_OF_SPECIES]; + float ext_force[3][MAX_NUMBER_OF_SPECIES]; + char* node_is_catalyst; +#ifdef EK_REACTION + float* pressure; +#endif +} EK_parameters; + +#endif + +#ifdef ELECTROKINETICS + + +/* Constants enumerating the links of a node in the link flux system EK_LINK_xyz + is the number of the link in direction (x, y, z), where x, y and z can be 0, + U or D representing 0 and one agrid in direction of or against the x, y or z + axis. The numbering differs from the one used in the LB since the LB + velocities are directed but the links are not. Links 0 - 8 represent + the odd LB velocities and numbers 13 - 21 represent the even LB velocities + (without the 0). In between there are the links connecting the corners, which + represent the 3rd shell not used in the LB but in the advection. The + following 13 constants are only defined for the sake of completeness.*/ + +#define EK_LINK_U00 0 +#define EK_LINK_0U0 1 +#define EK_LINK_00U 2 +#define EK_LINK_UU0 3 +#define EK_LINK_UD0 4 +#define EK_LINK_U0U 5 +#define EK_LINK_U0D 6 +#define EK_LINK_0UU 7 +#define EK_LINK_0UD 8 + +#define EK_LINK_UUU 9 +#define EK_LINK_UUD 10 +#define EK_LINK_UDU 11 +#define EK_LINK_UDD 12 + +#define EK_LINK_D00 13 +#define EK_LINK_0D0 14 +#define EK_LINK_00D 15 +#define EK_LINK_DD0 16 +#define EK_LINK_DU0 17 +#define EK_LINK_D0D 18 +#define EK_LINK_D0U 19 +#define EK_LINK_0DD 20 +#define EK_LINK_0DU 21 + +#define EK_LINK_DDD 22 +#define EK_LINK_DDU 23 +#define EK_LINK_DUD 24 +#define EK_LINK_DUU 25 + + +extern EK_parameters ek_parameters; +extern int ek_initialized; + +void ek_integrate(); +void ek_print_parameters(); +void ek_print_lbpar(); +void lb_set_ek_pointer(EK_parameters* pointeradress); +unsigned int ek_calculate_boundary_mass(); +int ek_print_vtk_density(int species, char* filename); +int ek_print_vtk_flux(int species, char* filename); +int ek_print_vtk_potential(char* filename); +int ek_print_vtk_lbforce(char* filename); +int ek_print_vtk_reaction_tags(char* filename); +int ek_lb_print_vtk_density(char* filename); +int ek_lb_print_vtk_velocity(char* filename); +int ek_init(); +int ek_set_agrid(double agrid); +int ek_set_lb_density(double lb_density); +int ek_set_viscosity(double viscosity); +int ek_set_friction(double friction); +int ek_set_T(double T); +int ek_set_bjerrumlength(double bjerrumlength); +int ek_set_bulk_viscosity(double bulk_viscosity); +int ek_set_gamma_odd(double gamma_odd); +int ek_set_gamma_even(double gamma_even); +int ek_set_density(int species, double density); +int ek_set_D(int species, double D); +int ek_set_valency(int species, double valency); +int ek_set_ext_force(int species, double ext_force_x, double ext_force_y, double ext_force_z); +int ek_node_print_velocity( int x, int y, int z, double* velocity ); +int ek_node_print_density( int species, int x, int y, int z, double* density ); + +#ifdef EK_BOUNDARIES +void ek_init_species_density_wallcharge(float* wallcharge_species_density, int wallcharge_species); +#endif + +#ifdef EK_REACTION +int ek_set_reaction( int reactant, int product0, int product1, + float rho_reactant_reservoir, float rho_product0_reservoir, float rho_product1_reservoir, + float reaction_ct_rate, float reaction_fraction_0, float reaction_fraction_1, + float mass_reactant, float mass_product0, float mass_product1 ); +int ek_print_vtk_pressure(char* filename); +int ek_tag_reaction_nodes( LB_Boundary* lbboundary, char reaction_type ); +#endif + +#endif /* CUDA */ + +#endif /* ELECTROKINETICS_H */ diff --git a/src/core/electrokinetics_cuda.cu b/src/core/electrokinetics_cuda.cu new file mode 100644 index 00000000000..c38e419cdeb --- /dev/null +++ b/src/core/electrokinetics_cuda.cu @@ -0,0 +1,2866 @@ +/* + Copyright (C) 2010,2011,2012,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "config.hpp" +#ifdef CUDA /* Terminates at end of file */ + +#include +#include +#include +#include +#include "errorhandling.hpp" +#include "lb-boundaries.hpp" +#include "electrokinetics.hpp" +#include "cuda_interface.hpp" +#include "cuda_utils.hpp" +#include "lbgpu.hpp" +#include "constraint.hpp" + +#ifdef ELECTROKINETICS /* Terminates at end of file */ + + /* TODO: get rid of this code duplication with lb-boundaries.h by solving the + cuda-mpi incompatibility */ + +#define LATTICE_OFF 0 +#define LATTICE_LB_CPU 1 +#define LATTICE_LB_GPU 2 +extern int lattice_switch; +extern int ek_initialized; +extern EK_parameters* lb_ek_parameters_gpu; + +// Used to limit register use for the pressure calculation +#define EK_LINK_U00_pressure 0 +#define EK_LINK_0U0_pressure 1 +#define EK_LINK_00U_pressure 2 +#define EK_LINK_D00_pressure 3 +#define EK_LINK_0D0_pressure 4 +#define EK_LINK_00D_pressure 5 + +#ifdef EK_BOUNDARIES + extern int n_lb_boundaries; + extern LB_Boundary *lb_boundaries; + + void lb_init_boundaries(); +#endif + /* end of code duplication */ + + #define PI_FLOAT 3.14159265358979323846f + + EK_parameters ek_parameters = { -1.0, -1.0, -1.0, + 0, 0, 0, + 0, + -1.0, -1.0, 0.0, + 0.0, 0.0, -1.0, + -1.0, + 0, + { -1, -1, -1}, + -1.0, -1.0, -1.0, + -1.0, -1.0, -1.0, + -1.0, -1.0, -1.0 + }; + + static __device__ __constant__ EK_parameters ek_parameters_gpu; + EK_parameters *ek_parameters_gpu_pointer; + LB_parameters_gpu *ek_lbparameters_gpu; + CUDA_particle_data *particle_data_gpu; + float *ek_lb_boundary_force; + char *ek_node_is_catalyst; + unsigned int old_number_of_species = 0; + unsigned int old_number_of_boundaries = 0; + + cufftHandle plan_fft; + cufftHandle plan_ifft; + + bool initialized = false; + + extern LB_parameters_gpu lbpar_gpu; + extern LB_node_force_gpu node_f; + extern LB_nodes_gpu *current_nodes; + extern EK_parameters *lb_ek_parameters; + + LB_rho_v_gpu *ek_lb_device_values; + + + +__device__ inline void atomicadd( float* address, + float value + ) { + +#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 // for Fermi, atomicAdd supports floats + atomicAdd(address, value); +#elif __CUDA_ARCH__ >= 110 + + #warning Using slower atomicAdd emulation + + //float-atomic-add from + //[url="http://forums.nvidia.com/index.php?showtopic=158039&view=findpost&p=991561"] + + float old = value; + while( ( old = atomicExch( address, atomicExch( address, 0.0f ) + old ) ) != 0.0f ); + +#else + #error CUDA compute capability 1.1 or higher required +#endif +} + + +__device__ unsigned int ek_getThreadIndex() { + + return blockIdx.y * gridDim.x * blockDim.x + + blockDim.x * blockIdx.x + + threadIdx.x; +} + + +__device__ void rhoindex_linear2cartesian( unsigned int index, + unsigned int * coord + ) { + + coord[0] = index % ek_parameters_gpu.dim_x; + index /= ek_parameters_gpu.dim_x; + coord[1] = index % ek_parameters_gpu.dim_y; + coord[2] = index / ek_parameters_gpu.dim_y; +} + + +__device__ unsigned int rhoindex_cartesian2linear( unsigned int x, + unsigned int y, + unsigned int z + ) { + + return z * ek_parameters_gpu.dim_y * ek_parameters_gpu.dim_x + + y * ek_parameters_gpu.dim_x + + x; +} + + +__device__ void jindex_linear2cartesian( unsigned int index, + unsigned int * coord, + unsigned int * c + ) { + + coord[0] = index % ek_parameters_gpu.dim_x; + index /= ek_parameters_gpu.dim_x; + coord[1] = index % ek_parameters_gpu.dim_y; + index /= ek_parameters_gpu.dim_y; + coord[2] = index % ek_parameters_gpu.dim_z; + *c = index / ek_parameters_gpu.dim_z; +} + + +__device__ unsigned int jindex_cartesian2linear( unsigned int x, + unsigned int y, + unsigned int z, + unsigned int c + ) { + + return c * ek_parameters_gpu.number_of_nodes + + z * ek_parameters_gpu.dim_y * ek_parameters_gpu.dim_x + + y * ek_parameters_gpu.dim_x + + x; +} + + +//TODO fluxindex fastest running might improve caching +__device__ unsigned int jindex_getByRhoLinear( unsigned int rho_index, + unsigned int c + ) { + + return c * ek_parameters_gpu.number_of_nodes + + rho_index; +} + + +__device__ void ek_displacement( float * dx, + LB_nodes_gpu n, + unsigned int node_index, + LB_parameters_gpu * ek_lbparameters_gpu + ) { + + float rho = ek_lbparameters_gpu->rho[0] * + ek_lbparameters_gpu->agrid * + ek_lbparameters_gpu->agrid * + ek_lbparameters_gpu->agrid; + + float mode [19]; + + for ( int i = 0; i < 19; i++ ) + { + mode[i] = n.vd[ i * ek_lbparameters_gpu->number_of_nodes + node_index ]; + } + + rho += mode[ 0 ] + + mode[ 1 ] + + mode[ 2 ] + + mode[ 3 ] + + mode[ 4 ] + + mode[ 5 ] + + mode[ 6 ] + + mode[ 7 ] + + mode[ 8 ] + + mode[ 9 ] + + mode[ 10 ] + + mode[ 11 ] + + mode[ 12 ] + + mode[ 13 ] + + mode[ 14 ] + + mode[ 15 ] + + mode[ 16 ] + + mode[ 17 ] + + mode[ 18 ]; + + dx[0] = ( mode[ 1 ] - mode[ 2 ] ) + + ( mode[ 7 ] - mode[ 8 ] ) + + ( mode[ 9 ] - mode[ 10 ] ) + + ( mode[ 11 ] - mode[ 12 ] ) + + ( mode[ 13 ] - mode[ 14 ] ); + + dx[1] = ( mode[ 3 ] - mode[ 4 ] ) + + ( mode[ 7 ] - mode[ 8 ] ) - + ( mode[ 9 ] - mode[ 10 ] ) + + ( mode[ 15 ] - mode[ 16 ] ) + + ( mode[ 17 ] - mode[ 18 ] ); + + dx[2] = ( mode[ 5 ] - mode[ 6 ] ) + + ( mode[ 11 ] - mode[ 12 ] ) - + ( mode[ 13 ] - mode[ 14 ] ) + + ( mode[ 15 ] - mode[ 16 ] ) - + ( mode[ 17 ] - mode[ 18 ] ); + + // Velocity requires half the force in the previous time step + + dx[0] += 0.5f * ek_parameters_gpu.lb_force_previous[ node_index ]; + dx[1] += 0.5f * ek_parameters_gpu.lb_force_previous[ ek_parameters_gpu.number_of_nodes + node_index ]; + dx[2] += 0.5f * ek_parameters_gpu.lb_force_previous[ 2 * ek_parameters_gpu.number_of_nodes + node_index ]; + + dx[0] *= 1.0f / rho; + dx[1] *= 1.0f / rho; + dx[2] *= 1.0f / rho; +} + +#ifdef EK_REACTION +__global__ void ek_pressure( + LB_nodes_gpu n_a, + LB_parameters_gpu *ek_lbparameters_gpu, + LB_rho_v_gpu *d_v + ) +{ + unsigned int index = ek_getThreadIndex (); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + ek_parameters_gpu.pressure[ index ] = 0.0f; + + // Add the ideal-gas contribution f from the EK + // species, which is given by n_i * k. In MD units + // the proper expression is n_i * T / ag^2, where + // there is a 1/ag^3 factor coming from converting the + // internal EK particle number back to a density, + // and an ag factor that is required to get the + // proper pressure difference + + for ( int i = 0; i < ek_parameters_gpu.number_of_species; i++ ) + { + ek_parameters_gpu.pressure[ index ] += ek_parameters_gpu.rho[ i ][ index ] * + ek_parameters_gpu.T / + powf(ek_parameters_gpu.agrid, 2); + } + + // Set pressure to zero inside boundary + + ek_parameters_gpu.pressure[ index ] *= (n_a.boundary[index] == 0); + } +} + +__global__ void ek_add_ideal_pressure_to_lb_force( + LB_nodes_gpu lb_node, + LB_node_force_gpu node_f, + LB_parameters_gpu *ek_lbparameters_gpu + ) +{ + unsigned int coord[3]; + unsigned int neighborindex[6]; + unsigned int index = ek_getThreadIndex (); + + if(index < ek_parameters_gpu.number_of_nodes) + { + float pressure_gradient; + + rhoindex_linear2cartesian( index, coord ); + + // Calculate the indices of the neighbours to which + // the force is to be applied + + neighborindex[EK_LINK_U00_pressure] = + rhoindex_cartesian2linear( + (coord[0] + 1) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + neighborindex[EK_LINK_0U0_pressure] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + 1) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_00U_pressure] = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] + 1) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_D00_pressure] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + neighborindex[EK_LINK_0D0_pressure] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_00D_pressure] = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + // Force in x direction (multiplicative factor + // comes from converting MD force into LB force) + + pressure_gradient = ( ek_parameters_gpu.pressure[ neighborindex[EK_LINK_D00_pressure] ] + - ek_parameters_gpu.pressure[ neighborindex[EK_LINK_U00_pressure] ] )/ + ( 2.0f * ek_parameters_gpu.agrid ); + + pressure_gradient *= powf(ek_parameters_gpu.agrid, 3) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + pressure_gradient *= ( ( lb_node.boundary[ neighborindex[EK_LINK_U00_pressure] ] + + lb_node.boundary[ index ] + + lb_node.boundary[ neighborindex[EK_LINK_D00_pressure] ] ) == 0 ); + + atomicadd( &node_f.force[index], pressure_gradient ); + + // Force in y direction + + pressure_gradient = ( ek_parameters_gpu.pressure[ neighborindex[EK_LINK_0D0_pressure] ] + - ek_parameters_gpu.pressure[ neighborindex[EK_LINK_0U0_pressure] ] )/ + ( 2.0f * ek_parameters_gpu.agrid ); + + pressure_gradient *= powf(ek_parameters_gpu.agrid, 3) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + pressure_gradient *= ( ( lb_node.boundary[ neighborindex[EK_LINK_0U0_pressure] ] + + lb_node.boundary[ index ] + + lb_node.boundary[ neighborindex[EK_LINK_0D0_pressure] ] ) == 0 ); + + atomicadd( &node_f.force[ek_parameters_gpu.number_of_nodes + index], pressure_gradient ); + + // Force in z direction + + pressure_gradient = ( ek_parameters_gpu.pressure[ neighborindex[EK_LINK_00D_pressure] ] + - ek_parameters_gpu.pressure[ neighborindex[EK_LINK_00U_pressure] ] )/ + ( 2.0f * ek_parameters_gpu.agrid ); + + pressure_gradient *= powf(ek_parameters_gpu.agrid, 3) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + pressure_gradient *= ( ( lb_node.boundary[ neighborindex[EK_LINK_00U_pressure] ] + + lb_node.boundary[ index ] + + lb_node.boundary[ neighborindex[EK_LINK_00D_pressure] ] ) == 0 ); + + atomicadd( &node_f.force[2*ek_parameters_gpu.number_of_nodes + index], pressure_gradient ); + } +} +#endif + +__global__ void ek_calculate_quantities( unsigned int species_index, + LB_nodes_gpu lb_node, + LB_node_force_gpu node_f, + LB_parameters_gpu *ek_lbparameters_gpu, + LB_rho_v_gpu *d_v + ) { + + unsigned int index = ek_getThreadIndex (); + + if(index < ek_parameters_gpu.number_of_nodes) + { + + unsigned int coord[3]; + unsigned int neighborindex[9]; + float dx[3]; + int di[3]; + int node; + float flux, force; + float boltzmannfactor_local, boltzmannfactor_neighbor; + + rhoindex_linear2cartesian( index, coord ); + + /* Calculate the diffusive fluxes between this node and its neighbors. Only + the 9 fluxes along the directions of the LB velocities c_i with i odd are + stored with a node to avoid redundencies. */ + + neighborindex[EK_LINK_U00] = + rhoindex_cartesian2linear( + (coord[0] + 1) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + neighborindex[EK_LINK_0U0] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + 1) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_00U] = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] + 1) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_UU0] = + rhoindex_cartesian2linear( + (coord[0] + 1) % ek_parameters_gpu.dim_x, + (coord[1] + 1) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_UD0] = + rhoindex_cartesian2linear( + (coord[0] + 1 ) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_U0U] = + rhoindex_cartesian2linear( + (coord[0] + 1) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] + 1) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_U0D] = + rhoindex_cartesian2linear( + (coord[0] + 1 ) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0UU] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + 1) % ek_parameters_gpu.dim_y, + (coord[2] + 1) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0UD] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + + /* diffusive contribution to flux and LB force*/ + + /* TODO: take out all of the boltzmann factor based calculations and replace + them with direct gradient evaluations. */ + + boltzmannfactor_local = + exp( 1.0f / ek_parameters_gpu.T * + ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[index] + ); + + //face in x + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_U00]] - + ek_parameters_gpu.ext_force[0][species_index] * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_U00]] * + boltzmannfactor_neighbor + ) / ek_parameters_gpu.agrid; + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_U00)], + flux * ek_parameters_gpu.time_step ); + + force = -1.0f * ek_parameters_gpu.valency[species_index] * + ( ((cufftReal*)ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_U00]] - + ((cufftReal*)ek_parameters_gpu.charge_potential)[index] + ) / ek_parameters_gpu.agrid; + + force *= powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + atomicadd( &node_f.force[index], + ek_parameters_gpu.rho[species_index][index] * + ( + force / 2.0f + + ek_parameters_gpu.ext_force[0][species_index] * + ( + powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step + ) + ) + ); + + atomicadd( &node_f.force[neighborindex[EK_LINK_U00]], + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_U00]] * + force / 2.0f ); + + //face in y + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_0U0]] - + ek_parameters_gpu.ext_force[1][species_index] * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_0U0]] * + boltzmannfactor_neighbor + ) / ek_parameters_gpu.agrid; + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_0U0)], + flux * ek_parameters_gpu.time_step ); + + force = -1.0f * ek_parameters_gpu.valency[species_index] * + ( ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_0U0]] - + ((cufftReal*) ek_parameters_gpu.charge_potential)[index] + ) / ek_parameters_gpu.agrid; + + force *= powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + atomicadd( &node_f.force[ek_parameters_gpu.number_of_nodes + index], + ek_parameters_gpu.rho[species_index][index] * + ( + force / 2.0f + + ek_parameters_gpu.ext_force[1][species_index] * + ( + powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step + ) + ) + ); + + atomicadd( &node_f.force[ek_parameters_gpu.number_of_nodes + neighborindex[EK_LINK_0U0]], + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_0U0]] * + force / 2.0f ); + + //face in z + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ( (cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_00U]] - + ek_parameters_gpu.ext_force[2][species_index] * + ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_00U]] * + boltzmannfactor_neighbor + ) / ek_parameters_gpu.agrid; + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_00U)], + flux * ek_parameters_gpu.time_step ); + + force = -1.0f * ek_parameters_gpu.valency[species_index] * + ( ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_00U]] - + ((cufftReal*) ek_parameters_gpu.charge_potential)[index] + ) / ek_parameters_gpu.agrid; + + force *= powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step; + + atomicadd( &node_f.force[2*ek_parameters_gpu.number_of_nodes + index], + ek_parameters_gpu.rho[species_index][index] * + ( + force / 2.0f + + ek_parameters_gpu.ext_force[2][species_index] * + ( + powf(ek_parameters_gpu.agrid, 1) * + ek_parameters_gpu.time_step * + ek_parameters_gpu.time_step + ) + ) + ); + + atomicadd( &node_f.force[2*ek_parameters_gpu.number_of_nodes + neighborindex[EK_LINK_00U]], + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_00U]] * + force / 2.0f ); + + //edge in z + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_UU0]] - + ( ek_parameters_gpu.ext_force[0][species_index] + + ek_parameters_gpu.ext_force[1][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f/boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_UU0]] * + boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_UU0)], + flux * ek_parameters_gpu.time_step + ); + + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_UD0]] - + ( ek_parameters_gpu.ext_force[0][species_index] - + ek_parameters_gpu.ext_force[1][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_UD0]] * + boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_UD0)], + flux * ek_parameters_gpu.time_step ); + + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_U0U]] - + ( ek_parameters_gpu.ext_force[0][species_index] + + ek_parameters_gpu.ext_force[2][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_U0U]] + * boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_U0U)], + flux * ek_parameters_gpu.time_step ); + + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_U0D]] - + ( ek_parameters_gpu.ext_force[0][species_index] - + ek_parameters_gpu.ext_force[2][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_U0D]] * + boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_U0D)], + flux * ek_parameters_gpu.time_step ); + + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_0UU]] - + ( ek_parameters_gpu.ext_force[1][species_index] + + ek_parameters_gpu.ext_force[2][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_0UU]] * + boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_0UU)], + flux * ek_parameters_gpu.time_step ); + + boltzmannfactor_neighbor = + exp( 1.0f / ek_parameters_gpu.T * + ( ek_parameters_gpu.valency[species_index] * + ((cufftReal*) ek_parameters_gpu.charge_potential)[neighborindex[EK_LINK_0UD]] - + ( ek_parameters_gpu.ext_force[1][species_index] - + ek_parameters_gpu.ext_force[2][species_index] + ) * ek_parameters_gpu.agrid + ) + ); + + flux = ( ek_parameters_gpu.d[species_index] / ek_parameters_gpu.agrid ) * + ( 1.0f / boltzmannfactor_local + + 1.0f / boltzmannfactor_neighbor + ) / 2.0f * + ( ek_parameters_gpu.rho[species_index][index] * + boltzmannfactor_local - + ek_parameters_gpu.rho[species_index][neighborindex[EK_LINK_0UD]] * + boltzmannfactor_neighbor + ) / + ( sqrt(2.0f) * ek_parameters_gpu.agrid ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear(index, EK_LINK_0UD)], + flux * ek_parameters_gpu.time_step ); + + /* advective contribution to flux */ + + ek_displacement( dx, lb_node, index, ek_lbparameters_gpu ); + + di[0] = 1 - signbit(dx[0]); + di[1] = 1 - signbit(dx[1]); + di[2] = 1 - signbit(dx[2]); + + dx[0] = fabs(dx[0]); + dx[1] = fabs(dx[1]); + dx[2] = fabs(dx[2]); + + //face in x + node = + rhoindex_cartesian2linear( + (coord[0] + di[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_U00 )], + (2 * di[0] - 1) * ek_parameters_gpu.rho[species_index][index] * + dx[0] * (1.0f - dx[1]) * (1.0f - dx[2]) + ); + + //face in y + node = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + di[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_0U0 )], + (2 * di[1] - 1) * ek_parameters_gpu.rho[species_index][index] * + (1.0f - dx[0]) * dx[1] * (1.0f - dx[2]) ); + + //face in z + node = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] + di[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_00U )], + (2 * di[2] - 1) * ek_parameters_gpu.rho[species_index][index] * + (1.0f - dx[0]) * (1.0f - dx[1]) * dx[2] ); + + //edge in x + node = + rhoindex_cartesian2linear( + coord[0], + (coord[1] + di[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + (1 - di[1]) * (2*di[2] - 1) + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_0UU + (di[1] + di[2] == 1) )], + (2 * di[1] - 1) * ek_parameters_gpu.rho[species_index][index] * + (1.0f - dx[0]) * dx[1] * dx[2] + ); + + //edge in y + node = + rhoindex_cartesian2linear( + (coord[0] + di[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] + (1 - di[0]) * (2*di[2] - 1) + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_U0U + (di[0] + di[2] == 1) )], + (2 * di[0] - 1) * ek_parameters_gpu.rho[species_index][index] * + dx[0] * (1.0f - dx[1]) * dx[2] ); + + //edge in z + node = + rhoindex_cartesian2linear( + (coord[0] + di[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + (1 - di[0]) * (2*di[1] - 1) + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + atomicadd( &ek_parameters_gpu.j[jindex_getByRhoLinear( node, EK_LINK_UU0 + (di[0] + di[1] == 1) )], + (2 * di[0] - 1) * ek_parameters_gpu.rho[species_index][index] * + dx[0] * dx[1] * (1.0f - dx[2]) ); + + //corner + node = + rhoindex_cartesian2linear( + (coord[0] + di[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + (1 - di[0]) * (2*di[1] - 1) + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + (1 - di[0]) * (2*di[2] - 1) + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + atomicadd( &ek_parameters_gpu.j[ + jindex_getByRhoLinear( node, (1 - di[0]) * + (EK_LINK_UUU + 2*di[1] + di[2]) + + di[0] * (EK_LINK_UDD - 2*di[1] - di[2]) + ) ], + (2 * di[0] - 1) * ek_parameters_gpu.rho[species_index][index] * + dx[0] * dx[1] * dx[2] ); + } +} + + +__global__ void ek_propagate_densities( unsigned int species_index + ) { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + + unsigned int neighborindex[13]; + unsigned int coord[3]; + + rhoindex_linear2cartesian(index, coord); + + /* Indices of the neighbors storing the other half + of the fluxes associated with this link */ + neighborindex[EK_LINK_D00-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + neighborindex[EK_LINK_0D0-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_00D-13] = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DD0-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_DU0-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_D0D-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_D0U-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0DD-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0DU-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + + neighborindex[EK_LINK_DDD-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DDU-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DUD-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DUU-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + + /* Calculate change of densities due to diffusive fluxes */ + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_U00 ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_D00-13], EK_LINK_U00 ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_0U0 ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_0D0-13], EK_LINK_0U0 ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_00U ) ]; + ek_parameters_gpu.rho[species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_00D-13], EK_LINK_00U ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UU0 ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DD0-13], EK_LINK_UU0 ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UD0 ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DU0-13], EK_LINK_UD0 ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_U0U ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_D0D-13], EK_LINK_U0U ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_U0D ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_D0U-13], EK_LINK_U0D ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_0UU ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_0DD-13], EK_LINK_0UU ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_0UD ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_0DU-13], EK_LINK_0UD ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UUU ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DDD-13], EK_LINK_UUU ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UUD ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DDU-13], EK_LINK_UUD ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UDU ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DUD-13], EK_LINK_UDU ) ]; + + ek_parameters_gpu.rho[ species_index ][index] -= + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, EK_LINK_UDD ) ]; + ek_parameters_gpu.rho[ species_index ][index] += + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[EK_LINK_DUU-13], EK_LINK_UDD ) ]; + } +} + + +__global__ void ek_apply_boundaries( unsigned int species_index, + LB_nodes_gpu lbnode, + LB_node_force_gpu node_f + ) { + + unsigned int index = ek_getThreadIndex(); + unsigned int neighborindex[22]; + unsigned int coord[3]; + + if( index < ek_parameters_gpu.number_of_nodes ) + { + if( lbnode.boundary[index] ) + { + + rhoindex_linear2cartesian(index, coord); + + /* Indices of the neighbors */ + neighborindex[EK_LINK_D00-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + coord[2] + ); + + neighborindex[EK_LINK_0D0-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_00D-13] = + rhoindex_cartesian2linear( + coord[0], + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DD0-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_DU0-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + coord[2] + ); + + neighborindex[EK_LINK_D0D-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_D0U-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + coord[1], + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0DD-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_0DU-13] = + rhoindex_cartesian2linear( + coord[0], + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DDD-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DDU-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] - 1 + ek_parameters_gpu.dim_y) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DUD-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + (coord[2] - 1 + ek_parameters_gpu.dim_z) % ek_parameters_gpu.dim_z + ); + + neighborindex[EK_LINK_DUU-13] = + rhoindex_cartesian2linear( + (coord[0] - 1 + ek_parameters_gpu.dim_x) % ek_parameters_gpu.dim_x, + (coord[1] + 1 ) % ek_parameters_gpu.dim_y, + (coord[2] + 1 ) % ek_parameters_gpu.dim_z + ); + + /* Clear fluxes on links connecting a boundary node */ + for( int i = 0; i < 13; i++ ) + ek_parameters_gpu.j[jindex_getByRhoLinear(index, i)] = 0.0f; + + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_D00-13 ], EK_LINK_U00 ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_0D0-13 ], EK_LINK_0U0 ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_00D-13 ], EK_LINK_00U ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DD0-13 ], EK_LINK_UU0 ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DU0-13 ], EK_LINK_UD0 ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_D0D-13 ], EK_LINK_U0U ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_D0U-13 ], EK_LINK_U0D ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_0DD-13 ], EK_LINK_0UU ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_0DU-13 ], EK_LINK_0UD ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DDD-13 ], EK_LINK_UUU ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DDU-13 ], EK_LINK_UUD ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DUD-13 ], EK_LINK_UDU ) ] = 0.0f; + ek_parameters_gpu.j[ jindex_getByRhoLinear( neighborindex[ EK_LINK_DUU-13 ], EK_LINK_UDD ) ] = 0.0f; + } + } +} + + +//TODO maybe make this obsolete by a multiplication in the advective fluxes, just as it's done for the diffusive ones +__global__ void ek_clear_fluxes() { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + for( int i = 0; i < 13; i++ ) + { + ek_parameters_gpu.j[ jindex_getByRhoLinear( index, i ) ] = 0.0f; + } + } +} + + +__global__ void ek_init_species_density_homogeneous() { + + unsigned int index = ek_getThreadIndex(); + + if(index < ek_parameters_gpu.number_of_nodes) + { + for(int i = 0; i < ek_parameters_gpu.number_of_species; i++) + { + ek_parameters_gpu.rho[ i ][ index ] = ek_parameters_gpu.density[ i ] * + ek_parameters_gpu.agrid * + ek_parameters_gpu.agrid * + ek_parameters_gpu.agrid; + } + } +} + + +__global__ void ek_multiply_greensfcn() { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.dim_z * + ek_parameters_gpu.dim_y * + (ek_parameters_gpu.dim_x / 2 + 1) ) + { + ek_parameters_gpu.charge_potential[ index ].x *= ek_parameters_gpu.greensfcn[ index ]; + ek_parameters_gpu.charge_potential[ index ].y *= ek_parameters_gpu.greensfcn[ index ]; + } +} + + +__global__ void ek_gather_species_charge_density() { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + ((cufftReal*) ek_parameters_gpu.charge_potential)[ index ] = 0.0f; + + for( int i = 0; i < ek_parameters_gpu.number_of_species; i++ ) + { + + ((cufftReal*) ek_parameters_gpu.charge_potential)[ index ] += + ek_parameters_gpu.valency[ i ] * ek_parameters_gpu.rho[ i ][ index ] / + powf( ek_parameters_gpu.agrid, 3 ); + } + } +} + + +__global__ void ek_gather_particle_charge_density( CUDA_particle_data * particle_data, + LB_parameters_gpu * ek_lbparameters_gpu + ) { + + unsigned int index = ek_getThreadIndex(); + unsigned int lowernode[3]; + float cellpos[3]; + float gridpos; + + if( index < ek_lbparameters_gpu->number_of_particles ) + { + gridpos = particle_data[ index ].p[0] / ek_parameters_gpu.agrid - 0.5f; + lowernode[0] = (int) floorf( gridpos ); + cellpos[0] = gridpos - lowernode[0]; + + gridpos = particle_data[ index ].p[1] / ek_parameters_gpu.agrid - 0.5f; + lowernode[1] = (int) floorf( gridpos ); + cellpos[1] = gridpos - lowernode[1]; + + gridpos = particle_data[ index ].p[2] / ek_parameters_gpu.agrid - 0.5f; + lowernode[2] = (int) floorf( gridpos ); + cellpos[2] = gridpos - lowernode[2]; + + lowernode[0] = (lowernode[0] + ek_lbparameters_gpu->dim_x) % ek_lbparameters_gpu->dim_x; + lowernode[1] = (lowernode[1] + ek_lbparameters_gpu->dim_y) % ek_lbparameters_gpu->dim_y; + lowernode[2] = (lowernode[2] + ek_lbparameters_gpu->dim_z) % ek_lbparameters_gpu->dim_z; + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( lowernode[0], + lowernode[1], + lowernode[2] ) + ], + particle_data[ index ].q * + ( 1 - cellpos[0] ) * ( 1 - cellpos[1] ) * ( 1 - cellpos[2] ) + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters_gpu.dim_x, + lowernode[1], + lowernode[2] ) + ], + particle_data[ index ].q * + cellpos[0] * ( 1 - cellpos[1] ) * ( 1 - cellpos[2] ) + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( lowernode[0], + ( lowernode[1] + 1 ) % ek_parameters_gpu.dim_y, + lowernode[2] ) + ], + particle_data[ index ].q * + ( 1 - cellpos[0] ) * cellpos[1] * ( 1 - cellpos[2] ) + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( lowernode[0], + lowernode[1], + ( lowernode[2] + 1 ) % ek_parameters_gpu.dim_z ) + ], + particle_data[ index ].q * + ( 1 - cellpos[0] ) * ( 1 - cellpos[1] ) * cellpos[2] + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters_gpu.dim_x, + ( lowernode[1] + 1 ) % ek_parameters_gpu.dim_y, + lowernode[2] ) + ], + particle_data[ index ].q * + cellpos[0] * cellpos[1] * ( 1 - cellpos[2] ) + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters_gpu.dim_x, + lowernode[1], + ( lowernode[2] + 1 ) % ek_parameters_gpu.dim_z ) + ], + particle_data[ index ].q * + cellpos[0] * ( 1 - cellpos[1] ) * cellpos[2] + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( lowernode[0], + ( lowernode[1] + 1 ) % ek_parameters_gpu.dim_y, + ( lowernode[2] + 1 ) % ek_parameters_gpu.dim_z ) + ], + particle_data[ index ].q * + ( 1 - cellpos[0] ) * cellpos[1] * cellpos[2] + ); + + atomicadd( &((cufftReal*) ek_parameters_gpu.charge_potential)[ + rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters_gpu.dim_x, + ( lowernode[1] + 1 ) % ek_parameters_gpu.dim_y, + ( lowernode[2] + 1 ) % ek_parameters_gpu.dim_z ) + ], + particle_data[ index ].q * + cellpos[0] * cellpos[1] * cellpos[2] + ); + + //((cufftReal*) ek_parameters_gpu.charge_potential)[ index ] = 0.0f; + //printf("particle %d (%d):\n charge %f\n pos %f %f %f\n lowernode %d %d %d\n cellpos %f %f %f\n\n", index, ek_lbparameters_gpu->number_of_particles, particle_data[index].q, particle_data[index].p[0], particle_data[index].p[1], particle_data[index].p[2], lowernode[0], lowernode[1], lowernode[2], cellpos[0], cellpos[1], cellpos[2]); //TODO delete + } +} + + +__global__ void ek_create_greensfcn() { + + unsigned int index = ek_getThreadIndex(); + unsigned int tmp; + unsigned int coord[3]; + + coord[0] = index % ( ek_parameters_gpu.dim_x / 2 + 1 ); + tmp = index / ( ek_parameters_gpu.dim_x / 2 + 1 ); + coord[1] = tmp % ek_parameters_gpu.dim_y; + coord[2] = tmp / ek_parameters_gpu.dim_y; + + if( index < ek_parameters_gpu.dim_z * + ek_parameters_gpu.dim_y * + ( ek_parameters_gpu.dim_x / 2 + 1 ) ) + { + + if( index == 0 ) + { + + //setting 0th fourier mode to 0 enforces charge neutrality + ek_parameters_gpu.greensfcn[index] = 0.0f; + } + else + { + + ek_parameters_gpu.greensfcn[ index ] = + -4.0f * PI_FLOAT * ek_parameters_gpu.bjerrumlength * + ek_parameters_gpu.T * ek_parameters_gpu.agrid * ek_parameters_gpu.agrid * + 0.5f / + ( cos( 2.0f * PI_FLOAT * coord[0] / (cufftReal) ek_parameters_gpu.dim_x ) + + cos( 2.0f * PI_FLOAT * coord[1] / (cufftReal) ek_parameters_gpu.dim_y ) + + cos( 2.0f * PI_FLOAT * coord[2] / (cufftReal) ek_parameters_gpu.dim_z ) - + 3.0f + ) / + ( ek_parameters_gpu.dim_x * + ek_parameters_gpu.dim_y * + ek_parameters_gpu.dim_z + ); + } + } +} + + +__global__ void ek_clear_boundary_densities( LB_nodes_gpu lbnode ) { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + if( lbnode.boundary[ index ] ) + { + + for( int i = 0; i < ek_parameters_gpu.number_of_species; i++ ) + { + ek_parameters_gpu.rho[ i ][ index ] = 0.0f; + } + } + } +} + + +//TODO delete ?? (it has the previous step setting now) +__global__ void ek_clear_node_force( LB_node_force_gpu node_f ) { + + unsigned int index = ek_getThreadIndex(); + + if( index < ek_parameters_gpu.number_of_nodes ) + { + ek_parameters_gpu.lb_force_previous[ index ] = + node_f.force[ index ]; + ek_parameters_gpu.lb_force_previous[ ek_parameters_gpu.number_of_nodes + index ] = + node_f.force[ ek_parameters_gpu.number_of_nodes + index ]; + ek_parameters_gpu.lb_force_previous[ 2 * ek_parameters_gpu.number_of_nodes + index ] = + node_f.force[ 2 * ek_parameters_gpu.number_of_nodes + index ]; + + node_f.force[ index ] = 0.0f; + node_f.force[ ek_parameters_gpu.number_of_nodes + index ] = 0.0f; + node_f.force[ 2 * ek_parameters_gpu.number_of_nodes + index ] = 0.0f; + } +} + + +#ifdef EK_REACTION +__global__ void ek_reaction( ) { + + unsigned int index = ek_getThreadIndex(); + unsigned int coord[3]; + + float* rho_reactant = &ek_parameters_gpu.rho[ek_parameters_gpu.reaction_species[0]][index]; + float* rho_product0 = &ek_parameters_gpu.rho[ek_parameters_gpu.reaction_species[1]][index]; + float* rho_product1 = &ek_parameters_gpu.rho[ek_parameters_gpu.reaction_species[2]][index]; + + float dt = ek_parameters_gpu.time_step; + float ct_rate = ek_parameters_gpu.reaction_ct_rate; + float fraction_0 = ek_parameters_gpu.reaction_fraction_0; + float fraction_1 = ek_parameters_gpu.reaction_fraction_1; + + float rho_change = *rho_reactant * ( 1.0f - expf(-dt*ct_rate) ); + + rhoindex_linear2cartesian(index, coord); + + if ( index < ek_parameters_gpu.number_of_nodes ) + { + if ( ek_parameters_gpu.node_is_catalyst[index] == 1 ) + { + *rho_reactant -= rho_change; + *rho_product0 += rho_change * fraction_0; + *rho_product1 += rho_change * fraction_1; + } + else if ( ek_parameters_gpu.node_is_catalyst[index] == 2 ) + { + *rho_reactant = ek_parameters_gpu.rho_reactant_reservoir * powf(ek_parameters_gpu.agrid,3); + *rho_product0 = ek_parameters_gpu.rho_product0_reservoir * powf(ek_parameters_gpu.agrid,3); + *rho_product1 = ek_parameters_gpu.rho_product1_reservoir * powf(ek_parameters_gpu.agrid,3); + } + } +} +#endif + + +void ek_integrate_electrostatics() { + + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = + ( ek_parameters.number_of_nodes + threads_per_block * blocks_per_grid_y - 1 ) / + ( threads_per_block * blocks_per_grid_y ); + dim3 dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + KERNELCALL( ek_gather_species_charge_density, dim_grid, threads_per_block, () ); + + if ( lbpar_gpu.number_of_particles != 0 ) //TODO make it an if number_of_charged_particles != 0 + { + + blocks_per_grid_x = + ( lbpar_gpu.number_of_particles + threads_per_block * blocks_per_grid_y - 1 ) / + ( threads_per_block * blocks_per_grid_y ); + dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + particle_data_gpu = gpu_get_particle_pointer(); + + KERNELCALL( ek_gather_particle_charge_density, + dim_grid, threads_per_block, + ( particle_data_gpu, ek_lbparameters_gpu ) ); + } + + if( cufftExecR2C( plan_fft, + (cufftReal*) ek_parameters.charge_potential, + ek_parameters.charge_potential ) != CUFFT_SUCCESS ) + { + + fprintf(stderr, "ERROR: Unable to execute FFT plan\n"); + } + + blocks_per_grid_x = + ( ek_parameters.dim_z * ek_parameters.dim_y * ( ek_parameters.dim_x / 2 + 1 ) + + threads_per_block * blocks_per_grid_y - 1) / + ( threads_per_block * blocks_per_grid_y ); + dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + KERNELCALL( ek_multiply_greensfcn, dim_grid, threads_per_block, () ); + + if( cufftExecC2R( plan_ifft, + ek_parameters.charge_potential, + (cufftReal*) ek_parameters.charge_potential ) != CUFFT_SUCCESS ) + { + + fprintf(stderr, "ERROR: Unable to execute iFFT plan\n"); + } +} + + +void ek_integrate() { + + /** values for the kernel call */ + + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = + ( ek_parameters.number_of_nodes + threads_per_block * blocks_per_grid_y - 1 ) + / (threads_per_block * blocks_per_grid_y ); + dim3 dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + + + /* Clears the force on the nodes and must be called before fluxes are calculated, + since in the reaction set up the previous-step LB force is added to the flux + (in ek_calculate_quantities / ek_displacement), which is copied in this routine */ + + KERNELCALL( ek_clear_node_force, dim_grid, threads_per_block, ( node_f ) ); + + + +#ifdef EK_REACTION + if ( ek_parameters.reaction_species[0] != -1 && + ek_parameters.reaction_species[1] != -1 && + ek_parameters.reaction_species[2] != -1 ) + { + /* Performs the catalytic reaction and sets the reservoir densities at + the boundary of the simulation box */ + + KERNELCALL( ek_reaction, dim_grid, threads_per_block, ()); + + /* Determines the excess pressure that follows from the creation of + species by the reaction */ + + KERNELCALL( ek_pressure, dim_grid, threads_per_block, ( *current_nodes, + ek_lbparameters_gpu, + ek_lb_device_values ) ); + } +#endif + + + /* Integrate diffusion-advection */ + + for( int i = 0; i < ek_parameters.number_of_species; i++ ) + { + + KERNELCALL( ek_clear_fluxes, dim_grid, threads_per_block, () ); + KERNELCALL( ek_calculate_quantities, dim_grid, threads_per_block, + ( i, *current_nodes, node_f, ek_lbparameters_gpu, ek_lb_device_values ) ); + +#ifdef EK_BOUNDARIES + KERNELCALL( ek_apply_boundaries, dim_grid, threads_per_block, + ( i, *current_nodes, node_f ) ); +#endif + + KERNELCALL( ek_propagate_densities, dim_grid, threads_per_block, ( i ) ); + } + + + +#ifdef EK_REACTION + if ( ek_parameters.reaction_species[0] != -1 && + ek_parameters.reaction_species[1] != -1 && + ek_parameters.reaction_species[2] != -1 ) + { + /* Add pressure force to LB must be done outside of loop, + otherwise the force gets added several times */ + + KERNELCALL( ek_add_ideal_pressure_to_lb_force, dim_grid, threads_per_block, + ( *current_nodes, node_f, ek_lbparameters_gpu ) ); + } +#endif + + + + /* Integrate electrostatics */ + + ek_integrate_electrostatics(); + + /* Integrate Navier-Stokes */ + + lb_integrate_GPU(); + + + //TODO delete - needed for printfs + //cudaDeviceSynchronize(); +} + + +#ifdef EK_BOUNDARIES +void ek_init_species_density_wallcharge( float* wallcharge_species_density, + int wallcharge_species ) { + + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = + ( ek_parameters.number_of_nodes + threads_per_block * blocks_per_grid_y - 1 ) + / ( threads_per_block * blocks_per_grid_y ); + dim3 dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + KERNELCALL( ek_init_species_density_homogeneous, dim_grid, threads_per_block, () ); + KERNELCALL( ek_clear_boundary_densities, dim_grid, threads_per_block, ( *current_nodes ) ); + + if( wallcharge_species != -1 ) + { + cuda_safe_mem( cudaMemcpy( ek_parameters.rho[wallcharge_species], + wallcharge_species_density, + ek_parameters.number_of_nodes * sizeof( float ), + cudaMemcpyHostToDevice ) + ); + } +} +#endif + + +void ek_init_species( int species ) { + + if( !initialized ) + { + ek_init(); + } + + if( ek_parameters.species_index[ species ] == -1 ) + { + ek_parameters.species_index[ species ] = ek_parameters.number_of_species; + ek_parameters.number_of_species++; + + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.rho[ ek_parameters.species_index[ species ] ], + ek_parameters.number_of_nodes * sizeof( float ) ) ); + + ek_parameters.density[ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.D[ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.valency[ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.ext_force[0][ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.ext_force[1][ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.ext_force[2][ ek_parameters.species_index[ species ] ] = 0.0; + ek_parameters.d[ ek_parameters.species_index[ species ] ] = + ek_parameters.D[ ek_parameters.species_index[ species ] ] / ( 1.0 + 2.0 * sqrt( 2.0 ) ); + } +} + + +int ek_init() { + + if( ek_parameters.agrid < 0.0 || + ek_parameters.viscosity < 0.0 || + ek_parameters.T < 0.0 || + ek_parameters.bjerrumlength < 0.0 ) + { + + fprintf( stderr, "ERROR: invalid agrid, viscosity, T or bjerrum_length\n" ); + + return 1; + } + + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x; + dim3 dim_grid; + + if(!initialized) + { + if( cudaGetSymbolAddress( (void**) &ek_parameters_gpu_pointer, ek_parameters_gpu ) != cudaSuccess) + { + fprintf( stderr, "ERROR: Fetching constant memory pointer\n" ); + + return 1; + } + + for( int i = 0; i < MAX_NUMBER_OF_SPECIES; i++ ) + { + ek_parameters.species_index[i] = -1; + } + + if ( lattice_switch != LATTICE_OFF ) + { + fprintf( stderr, "ERROR: Electrokinetics automatically intializes the LB on the GPU and can therefore not be used in conjunction with LB.\n"); + fprintf( stderr, "ERROR: Please run either electrokinetics or LB.\n"); + + return 1; + } + + lattice_switch = LATTICE_LB_GPU; + ek_initialized = 1; + + lbpar_gpu.agrid = ek_parameters.agrid; + lbpar_gpu.viscosity[0] = ek_parameters.viscosity; + lbpar_gpu.bulk_viscosity[0] = ek_parameters.bulk_viscosity; + lbpar_gpu.friction[0] = ek_parameters.friction; + + lbpar_gpu.rho[0] = ( ek_parameters.lb_density < 0.0 ? 1.0 : ek_parameters.lb_density ); + lb_reinit_parameters_gpu(); + + lbpar_gpu.external_force = 0; + lbpar_gpu.ext_force[0] = 0.0; + lbpar_gpu.ext_force[1] = 0.0; + lbpar_gpu.ext_force[2] = 0.0; + + lb_init_gpu(); + + ek_parameters.dim_x = lbpar_gpu.dim_x; + ek_parameters.dim_y = lbpar_gpu.dim_y; + ek_parameters.dim_z = lbpar_gpu.dim_z; + ek_parameters.time_step = lbpar_gpu.time_step; + ek_parameters.number_of_nodes = ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z; + + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.j, + ek_parameters.number_of_nodes * 13 * sizeof( float ) ) ); + cuda_safe_mem( cudaMemcpyToSymbol( ek_parameters_gpu, &ek_parameters, sizeof( EK_parameters ) ) ); + + lb_get_para_pointer( &ek_lbparameters_gpu ); + lb_set_ek_pointer( ek_parameters_gpu_pointer ); + + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.lb_force_previous, + ek_parameters.number_of_nodes * 3 * sizeof( float ) ) ); + +#ifdef EK_REACTION + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.pressure, + ek_parameters.number_of_nodes * sizeof( float ) ) ); + ek_node_is_catalyst = (char*) calloc( ek_parameters.number_of_nodes , sizeof( char ) ); +#endif + + lb_get_device_values_pointer( &ek_lb_device_values ); + + if( cudaGetLastError() != cudaSuccess ) + { + fprintf(stderr, "ERROR: Failed to allocate\n"); + return 1; + } + + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.greensfcn, + sizeof( cufftReal ) * + ek_parameters.dim_z * ek_parameters.dim_y * ( ek_parameters.dim_x / 2 + 1 ) ) ); + + if( cudaGetLastError() != cudaSuccess ) + { + fprintf(stderr, "ERROR: Failed to allocate\n"); + return 1; + } + + cudaMallocHost((void**) &ek_parameters.node_is_catalyst, + sizeof( char ) * + ek_parameters.dim_z*ek_parameters.dim_y*ek_parameters.dim_x ); + + if(cudaGetLastError() != cudaSuccess) + { + fprintf(stderr, "ERROR: Failed to allocate\n"); + return 1; + } + + cuda_safe_mem( cudaMemcpyToSymbol( ek_parameters_gpu, &ek_parameters, sizeof( EK_parameters ) ) ); + + blocks_per_grid_x = + ( ek_parameters.dim_z * ek_parameters.dim_y * (ek_parameters.dim_x / 2 + 1) + + threads_per_block * blocks_per_grid_y - 1 + ) / ( threads_per_block * blocks_per_grid_y ); + dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + KERNELCALL( ek_create_greensfcn, dim_grid, threads_per_block, () ); + + /* create 3D FFT plans */ + + if( cufftPlan3d( &plan_fft, + ek_parameters.dim_z, + ek_parameters.dim_y, + ek_parameters.dim_x, + CUFFT_R2C ) != CUFFT_SUCCESS ) + { + fprintf(stderr, "ERROR: Unable to create fft plan\n"); + return 1; + } + + if( cufftSetCompatibilityMode( plan_fft, CUFFT_COMPATIBILITY_NATIVE ) != CUFFT_SUCCESS ) + { + fprintf(stderr, "ERROR: Unable to set fft compatibility mode to native\n"); + return 1; + } + + if( cufftSetStream( plan_fft, stream[0]) != CUFFT_SUCCESS ) + { + fprintf(stderr, "ERROR: Unable to assign FFT to cuda stream\n"); + return 1; + } + + if( cufftPlan3d( &plan_ifft, + ek_parameters.dim_z, + ek_parameters.dim_y, + ek_parameters.dim_x, + CUFFT_C2R ) != CUFFT_SUCCESS ) + { + fprintf(stderr, "ERROR: Unable to create ifft plan\n"); + return 1; + } + + if( cufftSetCompatibilityMode( plan_ifft, CUFFT_COMPATIBILITY_NATIVE ) != CUFFT_SUCCESS) + { + fprintf(stderr, "ERROR: Unable to set ifft compatibility mode to native\n"); + return 1; + } + + if( cufftSetStream( plan_ifft, stream[0] ) != CUFFT_SUCCESS ) + { + fprintf(stderr, "ERROR: Unable to assign FFT to cuda stream\n"); + return 1; + } + + blocks_per_grid_x = + ( ek_parameters.dim_z * ek_parameters.dim_y * (ek_parameters.dim_x ) + + threads_per_block * blocks_per_grid_y - 1 + ) / ( threads_per_block * blocks_per_grid_y ); + dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + KERNELCALL( ek_clear_node_force, dim_grid, threads_per_block, ( node_f ) ); + + cuda_safe_mem( cudaMalloc( (void**) &ek_parameters.charge_potential, + sizeof( cufftComplex ) * + ek_parameters.dim_z * ek_parameters.dim_y * ( ek_parameters.dim_x / 2 + 1 ) ) ); + + initialized = true; + + cuda_safe_mem( cudaMemcpyToSymbol( ek_parameters_gpu, &ek_parameters, sizeof( EK_parameters ) ) ); + } + else + { + if ( lbpar_gpu.agrid != ek_parameters.agrid || + lbpar_gpu.viscosity[0] != ek_parameters.viscosity || + lbpar_gpu.bulk_viscosity[0] != ek_parameters.bulk_viscosity || + lbpar_gpu.friction[0] != ek_parameters.friction || + ( ( lbpar_gpu.rho[0] != 1.0 ) && ( lbpar_gpu.rho[0] != ek_parameters.lb_density ) ) + ) + { + fprintf( stderr, "ERROR: The LB parameters on the GPU cannot be reinitialized.\n"); + + return 1; + } + else + { + cuda_safe_mem( cudaMemcpyToSymbol( ek_parameters_gpu, &ek_parameters, sizeof( EK_parameters ) ) ); + +#ifdef EK_BOUNDARIES + if ( old_number_of_boundaries != n_lb_boundaries || old_number_of_species != ek_parameters.number_of_species) + { + lb_init_boundaries(); + lb_get_boundary_force_pointer( &ek_lb_boundary_force ); + old_number_of_boundaries = n_lb_boundaries; + old_number_of_species = ek_parameters.number_of_species; + } + + cuda_safe_mem( cudaMemcpyToSymbol( ek_parameters_gpu, &ek_parameters, sizeof( EK_parameters ) ) ); +#else + blocks_per_grid_x = + ( ek_parameters.number_of_nodes + threads_per_block * blocks_per_grid_y - 1 ) + / (threads_per_block * blocks_per_grid_y ); + dim_grid = make_uint3( blocks_per_grid_x, blocks_per_grid_y, 1 ); + + + if ( old_number_of_species != ek_parameters.number_of_species ) + { + KERNELCALL( ek_init_species_density_homogeneous, dim_grid, threads_per_block, () ); + old_number_of_species = ek_parameters.number_of_species; + } +#endif + +#ifdef EK_REACTION + // added to ensure that the pressure is set to the proper value in the first time step + blocks_per_grid_x = (ek_parameters.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) / (threads_per_block * blocks_per_grid_y); + dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + KERNELCALL( ek_pressure, dim_grid, threads_per_block, ( *current_nodes, ek_lbparameters_gpu, ek_lb_device_values ) ); +#endif + + ek_integrate_electrostatics(); + } + } + + //ek_print_parameters(); //TODO delete + + return 0; +} + + +void lb_set_ek_pointer(EK_parameters* pointeradress) { + lb_ek_parameters_gpu = pointeradress; +} + + +unsigned int ek_calculate_boundary_mass( ) +{ + unsigned int* bound_array = (unsigned int*) malloc( lbpar_gpu.number_of_nodes*sizeof(unsigned int) ); + + lb_get_boundary_flags_GPU(bound_array); + + unsigned int boundary_node_number = 0; + + for( int j=0; jtype) + { + case LB_BOUNDARY_WAL: + calculate_wall_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.wal, &dist, dist_vec); + break; + + case LB_BOUNDARY_SPH: + calculate_sphere_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.sph, &dist, dist_vec); + break; + + case LB_BOUNDARY_CYL: + calculate_cylinder_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.cyl, &dist, dist_vec); + break; + + case LB_BOUNDARY_RHOMBOID: + calculate_rhomboid_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.rhomboid, &dist, dist_vec); + break; + + case LB_BOUNDARY_POR: + calculate_pore_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.pore, &dist, dist_vec); + break; + + case LB_BOUNDARY_STOMATOCYTE: + calculate_stomatocyte_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.stomatocyte, &dist, dist_vec); + break; + + case LB_BOUNDARY_BOX: + dist = -1.0; + break; + + case LB_BOUNDARY_HOLLOW_CONE: + calculate_hollow_cone_dist((Particle*) NULL, pos, (Particle*) NULL, &boundary->c.hollow_cone, &dist, dist_vec); + break; + + default: + std::ostringstream msg; + msg << "lbboundary type " << boundary->type << " not implemented"; + runtimeError(msg); + } + + if( dist <= 0.0 ) + { + ek_node_is_catalyst[ + z * ek_parameters.dim_y * ek_parameters.dim_x + + y * ek_parameters.dim_x + + x + ] = reaction_type; + } + + }}} + + cuda_safe_mem( cudaMemcpy( ek_parameters.node_is_catalyst, + ek_node_is_catalyst, + ek_parameters.number_of_nodes * sizeof( char ), + cudaMemcpyHostToDevice ) + ); + + return 0; +#else + printf("ERROR: Need boundaries (EK_BOUNDARIES) for the catalytic reaction tagging.\n"); + return 1; +#endif + +} +#endif + + +#endif /* ELECTROKINETICS */ + +#endif /* CUDA */ diff --git a/src/core/electrokinetics_pdb_parse.cpp b/src/core/electrokinetics_pdb_parse.cpp new file mode 100644 index 00000000000..b55c6af08bb --- /dev/null +++ b/src/core/electrokinetics_pdb_parse.cpp @@ -0,0 +1,450 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/* vim: set ts=8 sts=2 sw=2 et: */ +#include +#include +#include +#include +#include +#include +#include +#include "electrokinetics_pdb_parse.hpp" + +#ifdef EK_BOUNDARIES + +/* Replacements for bool variables */ +const int pdb_SUCCESS = 0; +const int pdb_ERROR = 1; + +float* pdb_charge_lattice = NULL; +int* pdb_boundary_lattice = NULL; + +typedef struct { + int i; // index + int m; // model index + float x,y,z; +} pdb_ATOM; + +typedef struct { + int i; + char type[2]; + float charge; +} itp_atoms; + +typedef struct { + char type[2]; + float sigma,epsilon; +} itp_atomtypes; + +typedef struct { + unsigned int pdb_n_particles; + pdb_ATOM* pdb_array_ATOM; + unsigned int itp_n_particles; + itp_atoms* itp_array_atoms; + unsigned int itp_n_parameters; + itp_atomtypes* itp_array_atomtypes; +} particle_data; + +typedef struct { + float max_x; + float max_y; + float max_z; + float min_x; + float min_y; + float min_z; + float center[3]; +} bounding_box; + +/* BEGIN CODE */ + +void galloc(void** ptr, size_t size) { + if (!*ptr) { + if (size > 0) { + *ptr = (void*) malloc(size); + } + else { + printf("You cannot malloc to size 0\n"); + } + } + else { + if (size > 0) { + *ptr = (void*) realloc(*ptr, size); + } + else { + free(*ptr); + } + } +} + +unsigned int pdb_rhoindex_cartesian2linear(unsigned int x, unsigned int y, unsigned int z) { + return z * ek_parameters.dim_y * ek_parameters.dim_x + y * ek_parameters.dim_x + x; +} + +int print_charge_field(char* filename) { + FILE* fp; + if ((fp = fopen(filename,"w")) == NULL) return pdb_ERROR; + + if( fp == NULL ) { + return 1; + } + + fprintf( fp, "\ +# vtk DataFile Version 2.0\n\ +charge_density\n\ +ASCII\n\ +\n\ +DATASET STRUCTURED_POINTS\n\ +DIMENSIONS %u %u %u\n\ +ORIGIN %f %f %f\n\ +SPACING %f %f %f\n\ +\n\ +POINT_DATA %u\n\ +SCALARS charge_density float 1\n\ +LOOKUP_TABLE default\n", + ek_parameters.dim_x, ek_parameters.dim_y, ek_parameters.dim_z, + ek_parameters.agrid*0.5f, ek_parameters.agrid*0.5f, ek_parameters.agrid*0.5f, + ek_parameters.agrid, ek_parameters.agrid, ek_parameters.agrid, + ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z); + + for( unsigned int i = 0; i < (ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z); i++ ) { + fprintf( fp, "%e ", pdb_charge_lattice[i] ); + } + + fclose( fp ); + return pdb_SUCCESS; +} + +int print_boundary_lattice(char* filename) { + FILE* fp; + if ((fp = fopen(filename,"w")) == NULL) return pdb_ERROR; + + if( fp == NULL ) { + return 1; + } + + fprintf( fp, "\ +# vtk DataFile Version 2.0\n\ +boundary_flag\n\ +ASCII\n\ +\n\ +DATASET STRUCTURED_POINTS\n\ +DIMENSIONS %u %u %u\n\ +ORIGIN %f %f %f\n\ +SPACING %f %f %f\n\ +\n\ +POINT_DATA %u\n\ +SCALARS boundary_flag float 1\n\ +LOOKUP_TABLE default\n", + ek_parameters.dim_x, ek_parameters.dim_y, ek_parameters.dim_z, + ek_parameters.agrid*0.5f, ek_parameters.agrid*0.5f, ek_parameters.agrid*0.5f, + ek_parameters.agrid, ek_parameters.agrid, ek_parameters.agrid, + ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z); + + for( unsigned int i = 0; i < (ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z); i++ ) { + fprintf( fp, "%d ", pdb_boundary_lattice[i] ); + } + + fclose( fp ); + return pdb_SUCCESS; +} + +int pdb_parse_files(char* pdb_filename, char* itp_filename, particle_data* atom_data) { + /* + * This routine parses the pdb- and itp-file to extract + * the relevant parameters. These are stored in arrays. + */ + + // Parse pdb-file + int model = 0; + char pdb_line[256]; + FILE* pdb_file; + if ((pdb_file = fopen(pdb_filename,"r")) == NULL) return pdb_ERROR; +#ifdef DEBUG + printf("### Reading pdb-file \"%s\" ###\n",pdb_filename); +#endif + while (fgets(pdb_line, sizeof(pdb_line), pdb_file)) { + if (strncmp(pdb_line,"MODEL",5) == 0) { + // read the MODEL identifier + sscanf(pdb_line,"MODEL %d",&model); +#ifdef DEBUG + printf("MODEL m=%d\n", model); +#endif + } + if ( strncmp(pdb_line,"ATOM",4) == 0) { + // read all ATOMs + galloc( (void**) &atom_data->pdb_array_ATOM , (atom_data->pdb_n_particles+1)*sizeof(pdb_ATOM) ); + pdb_ATOM* a = &atom_data->pdb_array_ATOM[atom_data->pdb_n_particles]; + // See http://deposit.rcsb.org/adit/docs/pdb_atom_format.html#ATOM for the meaning of the format string + // sscanf(pdb_line,"ATOM %6d %*4s%*c%*4s%*c%*4d%*c %8f %8f %8f %*6f %*6f %*4s%*2s%*2s",&a->i,&a->x,&a->y,&a->z); + std::istringstream str(pdb_line); + + std::string tmp; + + str.ignore(246,' '); + str >> a->i; + str >> tmp >> tmp >> tmp >> tmp; + str >> a->x >> a->y >> a->z; + + a->x /= 10.0; + a->y /= 10.0; + a->z /= 10.0; +#ifdef DEBUG + // Print all local variables + printf("ATOM i=%d x=%f y=%f z=%f\n",a->i,a->x,a->y,a->z); +#endif + atom_data->pdb_n_particles++; + } + } + fclose(pdb_file); + + // Parse itp-file + char itp_line[256]; + FILE* itp_file; + if ((itp_file = fopen(itp_filename,"r")) == NULL) return pdb_ERROR; +#ifdef DEBUG + printf("### Reading itp-file \"%s\" ###\n",itp_filename); +#endif + while (fgets(itp_line, sizeof(itp_line), itp_file)) { + // get section + char section[256]; + sscanf(itp_line,"[ %s ]",section); + // only read non-comment, non-section and non-empty lines + // TODO: Handling of lines consiting whitespace only (e.g. '\t' and ' ') + if (itp_line[0] != '[' && itp_line[0] != ';' && itp_line[0] != '\r' && itp_line[0] != '\n') { + if (strcmp(section,"atoms") == 0) { + // section [ atoms ] + galloc( (void**) &atom_data->itp_array_atoms , (atom_data->itp_n_particles+1)*sizeof(pdb_ATOM) ); + itp_atoms* a = &atom_data->itp_array_atoms[atom_data->itp_n_particles]; + // FIXME: no source :( Reverse engineered from the itp-file + sscanf(itp_line," %d %2s %*d %*s %*s %*d %f %*f ; %*s %*f",&a->i,a->type,&a->charge); +#ifdef DEBUG + // Print all local variables + printf("[ atoms ] i=%d type=%s charge=%f\n",a->i,a->type,a->charge); +#endif + atom_data->itp_n_particles++; + } + if (strcmp(section,"atomtypes") == 0) { + // section [ atomtypes ] + galloc( (void**) &atom_data->itp_array_atomtypes , (atom_data->itp_n_parameters+1)*sizeof(pdb_ATOM) ); + itp_atomtypes* a = &atom_data->itp_array_atomtypes[atom_data->itp_n_parameters]; + // FIXME: no source :( Reverse engineered from the itp-file + sscanf(itp_line," %2s %*s %*f %*f %*c %f %f ; %*f %*f",a->type,&a->sigma,&a->epsilon); +#ifdef DEBUG + // Print all local variables + printf("[ atomtypes ] name=%s sigma=%f epsilon=%f\n",a->type,a->sigma,a->epsilon); +#endif + atom_data->itp_n_parameters++; + } + } + } + fclose(itp_file); + + if (atom_data->pdb_n_particles != atom_data->itp_n_particles) return pdb_ERROR; + return pdb_SUCCESS; +} + +int calculate_bounding_box(bounding_box* bbox, particle_data* atom_data) { + // prototype for joining the arrays + if (atom_data->pdb_n_particles-1 == 0) return pdb_ERROR; + pdb_ATOM* a = &atom_data->pdb_array_ATOM[0]; + bbox->max_x = a->x; + bbox->max_y = a->y; + bbox->max_z = a->z; + bbox->min_x = a->x; + bbox->min_y = a->y; + bbox->min_z = a->z; + + for (unsigned int i = 1; i <= atom_data->pdb_n_particles-1; i++) { + a = &atom_data->pdb_array_ATOM[i]; + if (bbox->max_x < a->x) bbox->max_x = a->x; + if (bbox->max_y < a->y) bbox->max_y = a->y; + if (bbox->max_z < a->z) bbox->max_z = a->z; + if (bbox->min_x > a->x) bbox->min_x = a->x; + if (bbox->min_y > a->y) bbox->min_y = a->y; + if (bbox->min_z > a->z) bbox->min_z = a->z; + } + + bbox->center[0] = ( bbox->max_x + bbox->min_x )/2; + bbox->center[1] = ( bbox->max_y + bbox->min_y )/2; + bbox->center[2] = ( bbox->max_z + bbox->min_z )/2; + + return pdb_SUCCESS; +} + +int populate_lattice(particle_data* atom_data) { + /* + * This routine will populate the lattice using the + * values read from the pdb and itp files. + * WARNING: It contains much logic and interpolation stuff! + */ +#ifdef DEBUG + printf("pdb_n_particles=%u, itp_n_particles=%u, itp_n_parameters=%u\n",atom_data->pdb_n_particles,atom_data->itp_n_particles,atom_data->itp_n_parameters); +#endif + // TODO: Check if bounding box fits into simbox + bounding_box bbox; + calculate_bounding_box(&bbox, atom_data); + + // calculate the shift of the bounding box + float shift[3]; + shift[0] = ek_parameters.agrid / 2.0 * ek_parameters.dim_x - bbox.center[0]; + shift[1] = ek_parameters.agrid / 2.0 * ek_parameters.dim_y - bbox.center[1]; + shift[2] = ek_parameters.agrid / 2.0 * ek_parameters.dim_z - bbox.center[2]; + +#ifdef DEBUG + printf("bbox.max_x=%f, bbox.max_y=%f, bbox.max_z=%f, bbox.min_x=%f, bbox.min_y=%f, bbox.min_z=%f, bbox->center=[%f; %f; %f]\n", bbox.max_x, bbox.max_y, bbox.max_z, bbox.min_x, bbox.min_y, bbox.min_z, bbox.center[0], bbox.center[1], bbox.center[2]); + printf("agrid=%f, dim_x=%d, dim_y=%d, dim_z=%d\n",ek_parameters.agrid, ek_parameters.dim_x, ek_parameters.dim_y, ek_parameters.dim_z); + printf("shift=[%f; %f; %f]\n",shift[0], shift[1], shift[2]); +#endif + + // joining the array + int lowernode[3]; + float cellpos[3]; + float gridpos; + float a_x_shifted, a_y_shifted, a_z_shifted; + + for (unsigned int i = 0; i <= atom_data->pdb_n_particles-1; i++) { + pdb_ATOM* a = &atom_data->pdb_array_ATOM[i]; + itp_atoms* b; + itp_atomtypes* c; + for (unsigned int j = 0; j <= atom_data->itp_n_particles-1; j++) { + b = &atom_data->itp_array_atoms[j]; + if (a->i == b->i) { + for (unsigned int k = 0; k <= atom_data->itp_n_parameters-1; k++) { + c = &atom_data->itp_array_atomtypes[k]; + if (strcmp(b->type,c->type) == 0) { +#ifdef DEBUG + printf("i=%d x=%f y=%f z=%f type=%s charge=%f sigma=%f epsilon=%f\n",a->i,a->x,a->y,a->z,b->type,b->charge,c->sigma,c->epsilon); +#endif + + // Interpolate the charge to the lattice + gridpos = (a->x + shift[0]) / ek_parameters.agrid - 0.5f; + lowernode[0] = (int) floorf( gridpos ); + cellpos[0] = gridpos - lowernode[0]; + + gridpos = (a->y + shift[1]) / ek_parameters.agrid - 0.5f; + lowernode[1] = (int) floorf( gridpos ); + cellpos[1] = gridpos - lowernode[1]; + + gridpos = (a->z + shift[2]) / ek_parameters.agrid - 0.5f; + lowernode[2] = (int) floorf( gridpos ); + cellpos[2] = gridpos - lowernode[2]; + + lowernode[0] = (lowernode[0] + ek_parameters.dim_x) % ek_parameters.dim_x; + lowernode[1] = (lowernode[1] + ek_parameters.dim_y) % ek_parameters.dim_y; + lowernode[2] = (lowernode[2] + ek_parameters.dim_z) % ek_parameters.dim_z; + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( lowernode[0],lowernode[1],lowernode[2] )] + += b->charge * ( 1 - cellpos[0] ) * ( 1 - cellpos[1] ) * ( 1 - cellpos[2] ); + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters.dim_x,lowernode[1],lowernode[2] )] + += b->charge * cellpos[0] * ( 1 - cellpos[1] ) * ( 1 - cellpos[2] ); + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( lowernode[0],( lowernode[1] + 1 ) % ek_parameters.dim_y,lowernode[2] )] + += b->charge * ( 1 - cellpos[0] ) * cellpos[1] * ( 1 - cellpos[2] ); + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( lowernode[0],lowernode[1],( lowernode[2] + 1 ) % ek_parameters.dim_z )] + += b->charge * ( 1 - cellpos[0] ) * ( 1 - cellpos[1] ) * cellpos[2]; + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters.dim_x,( lowernode[1] + 1 ) % ek_parameters.dim_y,lowernode[2] )] + += b->charge * cellpos[0] * cellpos[1] * ( 1 - cellpos[2] ); + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters.dim_x,lowernode[1],( lowernode[2] + 1 ) % ek_parameters.dim_z )] + += b->charge * cellpos[0] * ( 1 - cellpos[1] ) * cellpos[2]; + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( lowernode[0],( lowernode[1] + 1 ) % ek_parameters.dim_y,( lowernode[2] + 1 ) % ek_parameters.dim_z )] + += b->charge * ( 1 - cellpos[0] ) * cellpos[1] * cellpos[2]; + + pdb_charge_lattice[pdb_rhoindex_cartesian2linear( ( lowernode[0] + 1 ) % ek_parameters.dim_x,( lowernode[1] + 1 ) % ek_parameters.dim_y,( lowernode[2] + 1 ) % ek_parameters.dim_z )] + += b->charge * cellpos[0] * cellpos[1] * cellpos[2]; + // Interpolate lennard-jones parameters to boundary + float r = pow(2,1./6.)*c->sigma; + + a_x_shifted = (a->x + shift[0]) / ek_parameters.agrid - 0.5f; + a_y_shifted = (a->y + shift[1]) / ek_parameters.agrid - 0.5f; + a_z_shifted = (a->z + shift[2]) / ek_parameters.agrid - 0.5f; + + for (float z = a->z - r; z <= a->z + r + ek_parameters.agrid; z += ek_parameters.agrid) { + for (float y = a->y - r; y <= a->y + r + ek_parameters.agrid; y += ek_parameters.agrid) { + for (float x = a->x - r; x <= a->x + r + ek_parameters.agrid; x += ek_parameters.agrid) { + gridpos = (x + shift[0]) / ek_parameters.agrid - 0.5f; + lowernode[0] = (int) floorf( gridpos ); + + gridpos = (y + shift[1]) / ek_parameters.agrid - 0.5f; + lowernode[1] = (int) floorf( gridpos ); + + gridpos = (z + shift[2]) / ek_parameters.agrid - 0.5f; + lowernode[2] = (int) floorf( gridpos ); + + lowernode[0] = (lowernode[0] + ek_parameters.dim_x) % ek_parameters.dim_x; + lowernode[1] = (lowernode[1] + ek_parameters.dim_y) % ek_parameters.dim_y; + lowernode[2] = (lowernode[2] + ek_parameters.dim_z) % ek_parameters.dim_z; +#ifdef DEBUG + printf("shifted: %f %f %f\n", a_x_shifted, a_y_shifted, a_z_shifted); + printf("lowernode: %d %d %d\n", lowernode[0], lowernode[1], lowernode[2]); + printf("distance: %f %f %f\n", lowernode[0] - a_x_shifted, lowernode[1] - a_y_shifted, lowernode[2] - a_z_shifted); + printf("distance: %f <= %f\n\n", pow(lowernode[0] - a_x_shifted,2) + pow(lowernode[1] - a_y_shifted,2) + pow(lowernode[2] - a_z_shifted,2), pow(r/ek_parameters.agrid,2)); +#endif + if ( pow(lowernode[0] - a_x_shifted,2) + pow(lowernode[1] - a_y_shifted,2) + pow(lowernode[2] - a_z_shifted,2) <= pow(r/ek_parameters.agrid,2) ) { + pdb_boundary_lattice[ek_parameters.dim_y*ek_parameters.dim_x*lowernode[2] + ek_parameters.dim_x*lowernode[1] + lowernode[0]] = 1; + } + } + } + } + + break; + } + } + } + } + } + + return pdb_SUCCESS; +} + +int pdb_parse(char* pdb_filename, char* itp_filename) { + /* + * This is the main parsing routine, which is visible to the outside + * through the header electrokinetics_pdb_parse.h. It doesn't contain any logic and just + * deploys the input to the subroutines. + */ + + /* BEGIN DEPLOY */ + galloc( (void**) &pdb_charge_lattice, ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z * sizeof(float)); + galloc( (void**) &pdb_boundary_lattice, ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z * sizeof(int)); + for ( unsigned int i = 0; i < ek_parameters.dim_x * ek_parameters.dim_y * ek_parameters.dim_z; i++ ) { + pdb_charge_lattice[i] = 0.0; + pdb_boundary_lattice[i] = 0; + } + + particle_data atom_data; + atom_data.pdb_n_particles = 0; + atom_data.pdb_array_ATOM = NULL; + atom_data.itp_n_particles = 0; + atom_data.itp_array_atoms = NULL; + atom_data.itp_n_parameters = 0; + atom_data.itp_array_atomtypes = NULL; + + pdb_parse_files(pdb_filename, itp_filename, &atom_data); + + populate_lattice(&atom_data); + + return pdb_SUCCESS; +} + +#endif diff --git a/src/core/electrokinetics_pdb_parse.hpp b/src/core/electrokinetics_pdb_parse.hpp new file mode 100644 index 00000000000..71fa53b63bd --- /dev/null +++ b/src/core/electrokinetics_pdb_parse.hpp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/* vim: set ts=8 sts=2 sw=2 et: */ +#ifndef _ELECTROKINETICS_PDB_PARSE_HPP +#define _ELECTROKINETICS_PDB_PARSE_HPP + +#include "electrokinetics.hpp" + +#ifdef ELECTROKINETICS + +extern float* pdb_charge_lattice; +extern int* pdb_boundary_lattice; + +/* Returns 0/1 if reading the files was successful/unsuccessful */ +int pdb_parse(char* pdb_filename, char* itp_filename); + +int print_charge_field(char* filename); + +int print_boundary_lattice(char* filename); + +#else +/* that is tested for in a number of places, make sure that pdb + appears disabled if not compiled in. + */ +#define pdb_boundary_lattice 0 + +#endif + +#endif diff --git a/src/endangledist.cpp b/src/core/endangledist.cpp similarity index 87% rename from src/endangledist.cpp rename to src/core/endangledist.cpp index c27295a9c82..404665f374a 100644 --- a/src/endangledist.cpp +++ b/src/core/endangledist.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file endangledist.c +/** \file endangledist.cpp * - * Implementation of \ref endangledist.h + * Implementation of \ref endangledist.hpp */ #include "utils.hpp" #include "interaction_data.hpp" @@ -74,22 +74,19 @@ static double calc_pwdist(Particle *p1, Bonded_ia_parameters *iaparams, int *clc /* Gets and tests wall data */ for(k=0;kp.identity==check_id) fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2],p2->p.identity,dist,fac_b)); - ONEPART_TRACE(if(p2->p.identity==check_id) fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2],p1->p.identity,dist,fac_b)); + ONEPART_TRACE(if(p1->p.identity==check_id) \ + fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e) " \ + "with part id=%d at dist %f fac %.3e %.3e\n", \ + this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2], \ + p2->p.identity,dist,fac_a,fac_b) \ + ); + ONEPART_TRACE(if(p2->p.identity==check_id) \ + fprintf(stderr,"%d: OPT: ENDANGLEDIST f = (%.3e,%.3e,%.3e)" \ + " with part id=%d at dist %f fac %.3e\n", \ + this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2], \ + p1->p.identity,dist,fac_a,fac_b)); return 0; } diff --git a/src/endangledist.hpp b/src/core/endangledist.hpp similarity index 95% rename from src/endangledist.hpp rename to src/core/endangledist.hpp index 84bcb9c9947..0c56369e8b7 100644 --- a/src/endangledist.hpp +++ b/src/core/endangledist.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file endangledist.h +/** \file endangledist.hpp * Routines which apply an angle potential between two particles and a wall constraint * At distmax the angle potential is slowly switched on to a maximum at distmin * phi0 is constant but could easily be implemented to depend on the distance diff --git a/src/energy.cpp b/src/core/energy.cpp similarity index 60% rename from src/energy.cpp rename to src/core/energy.cpp index c4b9d93b3fa..0129ded7094 100644 --- a/src/energy.cpp +++ b/src/core/energy.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,39 +18,105 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file energy.c - Implementation of \ref energy.h "energy.h". +/** \file energy.cpp + Implementation of \ref energy.hpp "energy.hpp". */ -#include "energy.hpp" + +/* #include "cells.hpp" #include "integrate.hpp" -#include "initialize.hpp" #include "domain_decomposition.hpp" #include "nsquare.hpp" #include "layered.hpp" #include "elc.hpp" +#include "external_potential.hpp" +*/ +#include "energy_inline.hpp" +#include "maggs.hpp" +#include "initialize.hpp" #include "magnetic_non_p3m_methods.hpp" #include "mdlc_correction.hpp" +#include "cuda_interface.hpp" +#include "forces.hpp" +#include "EspressoSystemInterface.hpp" + +ActorList energyActors; Observable_stat energy = {0, {NULL,0,0}, 0,0,0}; Observable_stat total_energy = {0, {NULL,0,0}, 0,0,0}; /************************************************************/ -/* local prototypes */ + +void init_energies(Observable_stat *stat) +{ + int n_pre, n_non_bonded, n_coulomb, n_dipolar; + + n_pre = 1; + n_non_bonded = (n_particle_types*(n_particle_types+1))/2; + + n_coulomb = 0; +#ifdef ELECTROSTATICS + switch (coulomb.method) { + case COULOMB_NONE: n_coulomb = 0; break; +#ifdef P3M + case COULOMB_ELC_P3M: n_coulomb = 3; break; + case COULOMB_P3M_GPU: + case COULOMB_P3M: n_coulomb = 2; break; +#endif + default: n_coulomb = 1; + } +#endif + + n_dipolar = 0; +#ifdef DIPOLES + + switch (coulomb.Dmethod) { + case DIPOLAR_NONE: n_dipolar = 1; break; +#ifdef DP3M + case DIPOLAR_MDLC_P3M: n_dipolar=3; break; + case DIPOLAR_P3M: n_dipolar = 2; break; +#endif + case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: n_dipolar = 2; break; + case DIPOLAR_MDLC_DS: n_dipolar=3; break; + case DIPOLAR_DS: n_dipolar = 2; break; + } + +#endif + + obsstat_realloc_and_clear(stat, n_pre, n_bonded_ia, n_non_bonded, n_coulomb, n_dipolar, 0, 1); + stat->init_status = 0; + + external_potential_init_energies(); +} + /************************************************************/ -/** Calculate long range energies (P3M, MMM2d...). */ -void calc_long_range_energies(); +void master_energy_calc() { + mpi_gather_stats(1, total_energy.data.e, NULL, NULL, NULL); + + total_energy.init_status=1; +} /************************************************************/ void energy_calc(double *result) { - if (!check_obs_calc_initialized()) + if (!interactions_sanity_checks()) return; init_energies(&energy); +#ifdef CUDA + clear_energy_on_GPU(); +#endif + + espressoSystemInterface.update(); + + // Compute the energies from the energyActors + for (ActorList::iterator actor= energyActors.begin(); + actor != energyActors.end(); ++actor) + (*actor)->computeEnergy(espressoSystemInterface); + on_observable_calc(); switch (cell_structure.type) { @@ -73,9 +139,28 @@ void energy_calc(double *result) energy.data.e[0] /= (2.0*time_step*time_step); calc_long_range_energies(); + +#ifdef CUDA + copy_energy_from_GPU(); +#endif /* gather data */ MPI_Reduce(energy.data.e, result, energy.data.n, MPI_DOUBLE, MPI_SUM, 0, comm_cart); + + if (n_external_potentials > 0) { + double* energies = (double*) malloc(n_external_potentials*sizeof(double)); + for (int i=0; iinit_status = 0; -} - -/************************************************************/ - -void master_energy_calc() { - mpi_gather_stats(1, total_energy.data.e, NULL, NULL, NULL); - - total_energy.init_status=1; -} diff --git a/src/core/energy.hpp b/src/core/energy.hpp new file mode 100644 index 00000000000..db51b8ae2b9 --- /dev/null +++ b/src/core/energy.hpp @@ -0,0 +1,71 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file energy.hpp + Implementation of the energy calculation. +*/ +/* +#include "utils.hpp" +#include "integrate.hpp" +#include "object-in-fluid/stretching_force.hpp" +#include "object-in-fluid/stretchlin_force.hpp" +#include "object-in-fluid/area_force_local.hpp" +#include "object-in-fluid/area_force_global.hpp" +#include "object-in-fluid/bending_force.hpp" +#include "object-in-fluid/volume_force.hpp" +#include "dihedral.hpp" +#include "mdlc_correction.hpp" +*/ +#ifndef _ENERGY_H +#define _ENERGY_H + +/* include the energy files */ +#include "statistics.hpp" +#include "actor/ActorList.hpp" + +/** \name Exported Variables */ +/************************************************************/ +/*@{*/ +/// +extern Observable_stat energy, total_energy; + +extern ActorList energyActors; +/*@}*/ + +/** \name Exported Functions */ +/************************************************************/ +/*@{*/ + +/** allocate energy arrays and initialize with zero */ +void init_energies(Observable_stat *stat); + +/** on the master node: calc energies only if necessary */ +void master_energy_calc(); + +/** parallel energy calculation. + @param result non-zero only on master node; will contain the cumulative over all nodes. */ +void energy_calc(double *result); + +/** Calculate long range energies (P3M, MMM2d...). */ +void calc_long_range_energies(); + +/*@}*/ + +#endif diff --git a/src/energy.hpp b/src/core/energy_inline.hpp similarity index 72% rename from src/energy.hpp rename to src/core/energy_inline.hpp index 3adce7583ae..05106985fe7 100644 --- a/src/energy.hpp +++ b/src/core/energy_inline.hpp @@ -1,34 +1,31 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group - + This file is part of ESPResSo. - + ESPResSo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + ESPResSo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . */ -/** \file energy.h +/** \file energy_inline.hpp Implementation of the energy calculation. */ -#ifndef _ENERGY_H -#define _ENERGY_H -#include "utils.hpp" -#include "integrate.hpp" +#ifndef ENERGY_INLINE_HPP +#define ENERGY_INLINE_HPP + #include "statistics.hpp" #include "thermostat.hpp" - -/* include the energy files */ #include "p3m.hpp" #include "p3m-dipolar.hpp" #include "lj.hpp" @@ -47,63 +44,41 @@ #include "overlap.hpp" #include "gb.hpp" #include "fene.hpp" -#include "object-in-fluid/stretching_force.hpp" -#include "object-in-fluid/stretchlin_force.hpp" -#include "object-in-fluid/area_force_local.hpp" -#include "object-in-fluid/area_force_global.hpp" -#include "object-in-fluid/bending_force.hpp" -#include "object-in-fluid/volume_force.hpp" #include "harmonic.hpp" +#include "quartic.hpp" +#ifdef ELECTROSTATICS +#include "bonded_coulomb.hpp" +#endif #include "subt_lj.hpp" #include "angle.hpp" #include "angle_harmonic.hpp" #include "angle_cosine.hpp" #include "angle_cossquare.hpp" #include "angledist.hpp" -#include "dihedral.hpp" #include "debye_hueckel.hpp" #include "endangledist.hpp" #include "reaction_field.hpp" #include "mmm1d.hpp" #include "mmm2d.hpp" -#include "maggs.hpp" #include "morse.hpp" #include "elc.hpp" -#include "mdlc_correction.hpp" - -/** \name Exported Variables */ -/************************************************************/ -/*@{*/ -/// -extern Observable_stat energy, total_energy; -/*@}*/ +#include "actor/EwaldgpuForce_ShortRange.hpp" -/** \name Exported Functions */ -/************************************************************/ -/*@{*/ -/** allocate energy arrays and initialize with zero */ -void init_energies(Observable_stat *stat); - -/** on the master node: calc energies only if necessary */ -void master_energy_calc(); - -/** parallel energy calculation. - @param result non-zero only on master node; will contain the cumulative over all nodes. */ -void energy_calc(double *result); +#include "energy.hpp" /** Calculate non bonded energies between a pair of particles. @param p1 pointer to particle 1. @param p2 pointer to particle 2. @param ia_params the interaction parameters between the two particles - @param d vector between p1 and p2. + @param d vector between p1 and p2. @param dist distance between p1 and p2. @param dist2 distance squared between p1 and p2. @return the short ranged interaction energy between the two particles */ inline double calc_non_bonded_pair_energy(Particle *p1, Particle *p2, - IA_parameters *ia_params, - double d[3], double dist, double dist2) + IA_parameters *ia_params, + double d[3], double dist, double dist2) { double ret = 0; @@ -185,7 +160,7 @@ inline double calc_non_bonded_pair_energy(Particle *p1, Particle *p2, /* lennard jones cosine */ ret += ljcos_pair_energy(p1,p2,ia_params,d,dist); #endif - + #ifdef GAY_BERNE /* Gay-Berne */ ret += gb_pair_energy(p1,p2,ia_params,d,dist); @@ -201,11 +176,12 @@ inline double calc_non_bonded_pair_energy(Particle *p1, Particle *p2, /** Add non bonded energies and short range coulomb between a pair of particles. @param p1 pointer to particle 1. @param p2 pointer to particle 2. - @param d vector between p1 and p2. + @param d vector between p1 and p2. @param dist distance between p1 and p2. - @param dist2 distance squared between p1 and p2. */ + @param dist2 distance squared between p1 and p2. +*/ inline void add_non_bonded_pair_energy(Particle *p1, Particle *p2, double d[3], - double dist, double dist2) + double dist, double dist2) { IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); @@ -247,6 +223,11 @@ inline void add_non_bonded_pair_energy(Particle *p1, Particle *p2, double d[3], case COULOMB_MMM2D: ret = mmm2d_coulomb_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); break; +#ifdef EWALD_GPU + case COULOMB_EWALD_GPU: + ret = ewaldgpu_coulomb_pair_energy(p1->p.q*p2->p.q,d,dist2,dist); + break; +#endif default : ret = 0.; } @@ -256,15 +237,17 @@ inline void add_non_bonded_pair_energy(Particle *p1, Particle *p2, double d[3], #ifdef DIPOLES if (coulomb.Dmethod != DIPOLAR_NONE) { - ret=0; + //ret=0; switch (coulomb.Dmethod) { #ifdef DP3M - case DIPOLAR_MDLC_P3M: + case DIPOLAR_MDLC_P3M: //fall trough case DIPOLAR_P3M: - ret = dp3m_pair_energy(p1,p2,d,dist2,dist); + ret = dp3m_pair_energy(p1,p2,d,dist2,dist); break; -#endif +#endif + default: + ret=0; } energy.dipolar[0] += ret; } @@ -277,10 +260,10 @@ inline void add_non_bonded_pair_energy(Particle *p1, Particle *p2, double d[3], */ inline void add_bonded_energy(Particle *p1) { - char *errtxt; Particle *p2, *p3 = NULL, *p4 = NULL; Bonded_ia_parameters *iaparams; - int i, type_num, type, n_partners, bond_broken; + int i, type_num, n_partners, bond_broken; + BondedInteraction type; double ret=0, dx[3] = {0, 0, 0}; i = 0; @@ -289,13 +272,14 @@ inline void add_bonded_energy(Particle *p1) iaparams = &bonded_ia_params[type_num]; type = iaparams->type; n_partners = iaparams->num; - + /* fetch particle 2, which is always needed */ p2 = local_particles[p1->bl.e[i++]]; if (!p2) { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{069 bond broken between particles %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-1]); + ostringstream msg; + msg <<"bond broken between particles " << p1->p.identity << " and " << p1->bl.e[i-1] + <<" (particles not stored on the same node)"; + runtimeError(msg); return; } @@ -303,10 +287,11 @@ inline void add_bonded_energy(Particle *p1) if (n_partners >= 2) { p3 = local_particles[p1->bl.e[i++]]; if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{070 bond broken between particles %d, %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-2], p1->bl.e[i-1]); - return; + ostringstream msg; + msg <<"bond broken between particles " << p1->p.identity <<", "<< p1->bl.e[i-2] << " and " << p1->bl.e[i-1] + <<" (particles not stored on the same node)"; + runtimeError(msg); + return; } } @@ -314,10 +299,11 @@ inline void add_bonded_energy(Particle *p1) if (n_partners >= 3) { p4 = local_particles[p1->bl.e[i++]]; if (!p4) { - errtxt = runtime_error(128 + 4*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{071 bond broken between particles %d, %d, %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-3], p1->bl.e[i-2], p1->bl.e[i-1]); - return; + ostringstream msg; + msg <<"bond broken between particles " << p1->p.identity <<", "<< p1->bl.e[i-3] <<", "<< p1->bl.e[i-2] + << " and " << p1->bl.e[i-1] << " (particles not stored on the same node)"; + runtimeError(msg); + return; } } @@ -332,16 +318,24 @@ inline void add_bonded_energy(Particle *p1) case BONDED_IA_HARMONIC: bond_broken = harmonic_pair_energy(p1, p2, iaparams, dx, &ret); break; + case BONDED_IA_QUARTIC: + bond_broken = quartic_pair_energy(p1, p2, iaparams, dx, &ret); + break; +#ifdef ELECTROSTATICS + case BONDED_IA_BONDED_COULOMB: + bond_broken = bonded_coulomb_pair_energy(p1, p2, iaparams, dx, &ret); + break; +#endif #ifdef LENNARD_JONES case BONDED_IA_SUBT_LJ: bond_broken = subt_lj_pair_energy(p1, p2, iaparams, dx, &ret); break; #endif #ifdef BOND_ANGLE_OLD - /* the first case is not needed and should not be called */ + /* the first case is not needed and should not be called */ case BONDED_IA_ANGLE_OLD: bond_broken = angle_energy(p1, p2, p3, iaparams, &ret); - break; + break; #endif #ifdef BOND_ANGLE case BONDED_IA_ANGLE_HARMONIC: @@ -377,18 +371,19 @@ inline void add_bonded_energy(Particle *p1) case BONDED_IA_TABULATED: switch(iaparams->p.tab.type) { case TAB_BOND_LENGTH: - bond_broken = tab_bond_energy(p1, p2, iaparams, dx, &ret); - break; + bond_broken = tab_bond_energy(p1, p2, iaparams, dx, &ret); + break; case TAB_BOND_ANGLE: - bond_broken = tab_angle_energy(p1, p2, p3, iaparams, &ret); - break; + bond_broken = tab_angle_energy(p1, p2, p3, iaparams, &ret); + break; case TAB_BOND_DIHEDRAL: - bond_broken = tab_dihedral_energy(p2, p1, p3, p4, iaparams, &ret); - break; + bond_broken = tab_dihedral_energy(p2, p1, p3, p4, iaparams, &ret); + break; default : - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{072 add_bonded_energy: tabulated bond type of atom %d unknown\n", p1->p.identity); - return; + ostringstream msg; + msg << "add_bonded_energy: tabulated bond type of atom " << p1->p.identity << " unknown\n"; + runtimeError(msg); + return; } break; #endif @@ -405,8 +400,9 @@ inline void add_bonded_energy(Particle *p1) bond_broken = overlap_dihedral_energy(p2, p1, p3, p4, iaparams, &ret); break; default : - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{072 add_bonded_energy: overlapped bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg << "add_bonded_energy: overlapped bond type of atom " << p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -418,30 +414,32 @@ inline void add_bonded_energy(Particle *p1) break; #endif default : - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{073 add_bonded_energy: bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg <<"add_bonded_energy: bond type of atom "<< p1->p.identity << " unknown\n"; + runtimeError(msg); return; } if (bond_broken) { switch (n_partners) { case 1: { - char *errtext = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{083 bond broken between particles %d and %d} ", - p1->p.identity, p2->p.identity); - break; + ostringstream msg; + msg <<"bond broken between particles "<< p1->p.identity << " and " << p2->p.identity; + runtimeError(msg); + break; } case 2: { - char *errtext = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{084 bond broken between particles %d, %d and %d} ", - p1->p.identity, p2->p.identity, p3->p.identity); - break; + ostringstream msg; + msg <<"bond broken between particles "<< p1->p.identity << ", " << p2->p.identity << " and " << p3->p.identity; + runtimeError(msg); + break; } case 3: { - char *errtext = runtime_error(128 + 4*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{085 bond broken between particles %d, %d, %d and %d} ", - p1->p.identity, p2->p.identity, p3->p.identity, p4->p.identity); - break; + ostringstream msg; + msg <<"bond broken between particles "<< p1->p.identity << ", " << p2->p.identity + << ", " << p3->p.identity << " and " << p4->p.identity; + runtimeError(msg); + break; } } // bond broken, don't add whatever we find in the energy @@ -474,17 +472,15 @@ if (p1->p.rotation) Here we use the rotational inertia */ energy.data.e[0] += (SQR(p1->m.omega[0])*p1->p.rinertia[0] + - SQR(p1->m.omega[1])*p1->p.rinertia[1] + - SQR(p1->m.omega[2])*p1->p.rinertia[2])*time_step*time_step; + SQR(p1->m.omega[1])*p1->p.rinertia[1] + + SQR(p1->m.omega[2])*p1->p.rinertia[2])*time_step*time_step; #else /* the rotational part is added to the total kinetic energy; at the moment, we assume unit inertia tensor I=(1,1,1) */ energy.data.e[0] += (SQR(p1->m.omega[0]) + SQR(p1->m.omega[1]) + SQR(p1->m.omega[2]))*time_step*time_step; #endif } -#endif +#endif } -/*@}*/ - -#endif +#endif // ENERGY_INLINE_HPP diff --git a/src/core/errorhandling.cpp b/src/core/errorhandling.cpp new file mode 100644 index 00000000000..fb712b83fc4 --- /dev/null +++ b/src/core/errorhandling.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2010,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file errorhandling.cpp + Implementation of \ref errorhandling.hpp. +*/ +#include +#include +#include +#include +#include "utils.hpp" +#include "errorhandling.hpp" +#include "communication.hpp" +#include "RuntimeErrorCollector.hpp" + +using namespace std; + +static void sigint_handler(int sig) { + /* without this exit handler the nodes might exit asynchronously + * without calling MPI_Finalize, which may cause MPI to hang + * (e.g. this handler makes CTRL-c work properly with poe) + * + * NOTE: mpirun installs its own handler for SIGINT/SIGTERM + * and takes care of proper cleanup and exit */ + + + static int numcalls = 0; + if (numcalls++ > 0) exit(sig); // catch sig only once + + /* we use runtime_error to indicate that sig was called; + * upon next call of mpi_gather_runtime_errors all nodes + * will clean up and exit. */ + ostringstream msg; + msg <<"caught signal "<< sig ; + runtimeError(msg); +} + +void register_sigint_handler() { + signal(SIGINT, sigint_handler); +} + +/* NEW RUNTIME ERROR HANDLING. */ + +/** list that contains the runtime error messages */ +RuntimeErrorCollector *runtimeErrorCollector = NULL; + +void +initRuntimeErrorCollector() { + runtimeErrorCollector = new RuntimeErrorCollector(MPI_COMM_WORLD); +} + +void _runtimeWarning(const std::string &msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->warning(msg, function, file, line); +} + +void _runtimeWarning(const char* msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->warning(msg, function, file, line); +} + +void _runtimeWarning(const std::ostringstream &msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->warning(msg, function, file, line); +} + +void _runtimeError(const std::string &msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->error(msg, function, file, line); +} + +void _runtimeError(const char* msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->error(msg, function, file, line); +} + +void _runtimeError(const std::ostringstream &msg, + const char* function, const char* file, const int line) { + runtimeErrorCollector->error(msg, function, file, line); +} + +int check_runtime_errors() { + return runtimeErrorCollector->count(); +} + +list +mpiRuntimeErrorCollectorGather() { + // Tell other processors to send their erros + mpi_call(mpiRuntimeErrorCollectorGatherSlave, -1, 0); + return runtimeErrorCollector->gather(); +} + +void +mpiRuntimeErrorCollectorGatherSlave(int node, int parm) { + runtimeErrorCollector->gatherSlave(); +} + + + diff --git a/src/core/errorhandling.hpp b/src/core/errorhandling.hpp new file mode 100644 index 00000000000..17ab5003176 --- /dev/null +++ b/src/core/errorhandling.hpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 2010,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file errorhandling.hpp + This file contains the errorhandling code for severe errors, like + a broken bond or illegal parameter combinations. See section + "Errorhandling for developers" for details on the error format and + how to use this. +*/ +#ifndef _ERRORHANDLING_HPP +#define _ERRORHANDLING_HPP + +#include "config.hpp" +#include +#include +#include + +/** exit ungracefully, core dump if switched on. */ +void errexit(); + +/** register a handler for sigint that translates it into an runtime error. */ +void register_sigint_handler(); + +/* NEW RUNTIME ERROR HANDLING. */ + +// Functions to report runtime errors +void initRuntimeErrorCollector(); + +void _runtimeWarning(const char* msg, const char* function, const char* file, const int line); +void _runtimeWarning(const std::string &msg, const char* function, const char* file, const int line); +void _runtimeWarning(const std::ostringstream &msg, const char* function, const char* file, const int line); + +void _runtimeError(const char* msg, const char* function, const char* file, const int line); +void _runtimeError(const std::string &msg, const char* function, const char* file, const int line); +void _runtimeError(const std::ostringstream &msg, const char* function, const char* file, const int line); + +#define runtimeWarning(msg) \ + _runtimeWarning(msg, __PRETTYFUNC__, __FILE__, __LINE__) +#define runtimeError(msg) \ + _runtimeError(msg, __PRETTYFUNC__, __FILE__, __LINE__) + +/** check for runtime errors on all nodes. This has to be called on all nodes synchronously. + @return the number of characters in the error messages of all nodes together. */ +int check_runtime_errors(); + +std::list mpiRuntimeErrorCollectorGather(); +void mpiRuntimeErrorCollectorGatherSlave(int node, int parm); + +#endif diff --git a/src/core/external_potential.cpp b/src/core/external_potential.cpp new file mode 100644 index 00000000000..aa07e0bfc86 --- /dev/null +++ b/src/core/external_potential.cpp @@ -0,0 +1,326 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "external_potential.hpp" +#include "lattice.hpp" +#include "communication.hpp" +#include "integrate.hpp" + +ExternalPotential* external_potentials; +int n_external_potentials; + +void external_potential_pre_init() { + external_potentials = NULL; + n_external_potentials = 0; +} + + +int generate_external_potential(ExternalPotential** e) { + external_potentials = (ExternalPotential*) realloc(external_potentials, + (n_external_potentials+1) * sizeof(ExternalPotential)); + *e = &external_potentials[n_external_potentials]; + n_external_potentials++; + (*e)->energy = 0; + + +// e = &external_potentials[n_external_potentials-1]; + return ES_OK; +} + +int external_potential_tabulated_init(int number, char* filename, int n_particle_types, double* scale) { + ExternalPotentialTabulated* e = &external_potentials[number].tabulated; + + if (strlen(filename)>MAX_FILENAME_SIZE) + return ES_ERROR; + strcpy((char*)&(e->filename), filename); + external_potentials[number].type=EXTERNAL_POTENTIAL_TYPE_TABULATED; + external_potentials[number].scale = (double*) malloc(n_particle_types*sizeof(double)); + external_potentials[number].n_particle_types = n_particle_types; + for (int i = 0; i < n_particle_types; i++) { + external_potentials[number].scale[i]=scale[i]; + } + mpi_external_potential_broadcast(number); + mpi_external_potential_tabulated_read_potential_file(number); + return ES_OK; +} + +int lattice_read_file(Lattice* lattice, char* filename); + +int external_potential_tabulated_read_potential_file(int number) { + return lattice_read_file(&(external_potentials[number].tabulated.potential), + external_potentials[number].tabulated.filename); +} + +int lattice_read_file(Lattice* lattice, char* filename) { + // ExternalPotentialTabulated *e = &(external_potentials[number].e.tabulated); + FILE* infile = fopen(filename, "r"); + + if (!infile) { + ostringstream msg; + msg <<"Could not open file "<< filename << "\n"; + runtimeError(msg); + return ES_ERROR; + } + char first_line[100]; + char* token; + double res[3]; + double size[3]; + double offset[3]={0,0,0}; + int dim=0; + if (fgets(first_line, 100, infile) == NULL) { + fprintf(stderr, "Nothing read from file\n"); + return ES_ERROR; + } + + token = strtok(first_line, " \t"); + if (!token) { fprintf(stderr, "Error reading dimensionality\n"); return ES_ERROR; } + dim = atoi(token); + if (dim<=0) { fprintf(stderr, "Error reading dimensionality\n"); return ES_ERROR; } + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read box_l[0]\n"); return ES_ERROR; } + size[0] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read box_l[1]\n"); return ES_ERROR; } + size[1] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read box_l[2]\n"); return ES_ERROR;} + size[2] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read res[0]\n"); return ES_ERROR;} + res[0] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read res[1]\n"); return ES_ERROR;} + res[1] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read res[2]\n"); return ES_ERROR;} + res[2] = atof(token); + + token = strtok(NULL, " \t"); + if (token) { + offset[0]=atof(token); + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read offset[1]\n"); return ES_ERROR;} + offset[1] = atof(token); + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read offset[2]\n"); return ES_ERROR;} + offset[2] = atof(token); + } + lattice->offset[0]=offset[0]; + lattice->offset[1]=offset[1]; + lattice->offset[2]=offset[2]; + + int halosize=1; + + if (size[0] > 0 && abs(size[0] - box_l[0]) > ROUND_ERROR_PREC) { + ostringstream msg; + msg <<"Box size in x is wrong "<< size[0] << " vs " << box_l[0] <<"\n"; + runtimeError(msg); + return ES_ERROR; + } + if (size[1] > 0 && abs(size[1] - box_l[1]) > ROUND_ERROR_PREC) { + ostringstream msg; + msg <<"Box size in y is wrong "<< size[1] << " vs " << box_l[1] <<"\n"; + runtimeError(msg); + return ES_ERROR; + } + if (size[2] > 0 && abs(size[2] - box_l[2]) > ROUND_ERROR_PREC) { + ostringstream msg; + msg <<"Box size in z is wrong "<< size[2] << " vs " << box_l[2] <<"\n"; + runtimeError(msg); + return ES_ERROR; + } + + + if (res[0] > 0) + if (skin/res[0]>halosize) halosize = (int)ceil(skin/res[0]); + if (res[1] > 0) + if (skin/res[1]>halosize) halosize = (int)ceil(skin/res[1]); + if (res[2] > 0) + if (skin/res[2]>halosize) halosize = (int)ceil(skin/res[2]); + + // Now we count how many entries we have: + + lattice->init(res, offset, halosize, dim); + lattice->interpolation_type = INTERPOLATION_LINEAR; + + char* line = (char*) malloc((3+dim)*ES_DOUBLE_SPACE); + double pos[3]; + double f[3]; + int i; + + while (fgets(line, 200, infile)) { + if (strlen(line)<2) + continue; + token = strtok(line, " \t"); + if (!token) { fprintf(stderr, "Could not read pos[0]\n"); return ES_ERROR; } + pos[0] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read pos[1] in line:\n%s\n", line); return ES_ERROR; } + pos[1] = atof(token); + + token = strtok(NULL, " \t"); + if (!token) { fprintf(stderr, "Could not read pos[1]\n"); return ES_ERROR; } + pos[2] = atof(token); + for (i=0; iset_data_for_global_position_with_periodic_image(pos, f); + } + free(line); + + write_local_lattice_to_file("lattice", lattice); + + if (check_runtime_errors()!=0) + return ES_ERROR; + return ES_OK; +} + + +int write_local_lattice_to_file(const char* filename_prefix, Lattice* lattice) { + index_t index[3]; + double pos[3]; + int i,j,k; + double *d; + + char filename[60]; + //Lattice* l = lattice; + sprintf(filename, "%s_%02d.dat", filename_prefix, this_node); + FILE* outfile = fopen(filename , "w"); + fprintf(outfile,"grid %d %d %d\n", lattice->grid[0], lattice->grid[1], lattice->grid[2]); + fprintf(outfile,"halo_grid %d %d %d\n", lattice->halo_grid[0], lattice->halo_grid[1], lattice->halo_grid[2]); + fprintf(outfile,"halo_size %d\n", lattice->halo_size); + + fprintf(outfile,"grid_volume %ld\n", lattice->grid_volume); + fprintf(outfile,"halo_grid_volume %ld\n", lattice->halo_grid_volume); + fprintf(outfile,"halo_grid_surface %ld\n", lattice->halo_grid_surface); + fprintf(outfile,"halo_offset %ld\n", lattice->halo_offset); + + fprintf(outfile,"dim %d\n", lattice->dim); + + fprintf(outfile,"agrid %f %f %f\n", lattice->agrid[0], lattice->agrid[1], lattice->agrid[2]); + + fprintf(outfile,"offset %f %f %f\n", lattice->offset[0], lattice->offset[1], lattice->offset[2]); + fprintf(outfile,"local_offset %f %f %f\n", lattice->local_offset[0], lattice->local_offset[1], lattice->local_offset[2]); + fprintf(outfile,"local_index_offset %d %d %d\n", lattice->local_index_offset[0], lattice->local_index_offset[1], lattice->local_index_offset[2]); + + + fprintf(outfile, "element_size %lu\n", lattice->element_size); + + + for (i=0; ihalo_grid[0]; i++) + for (j=0; jhalo_grid[1]; j++) + for (k=0; khalo_grid[2]; k++) { + index[0]=i; index[1] = j; index[2] = k; + lattice->get_data_for_halo_index(index, (void**) &d); + lattice->map_halo_index_to_pos(index, pos); +// map_local_index_to_pos(&e->lattice, index, pos); + fprintf(outfile, "%f %f %f %f \n",pos[0], pos[1], pos[2], d[0]); + } + fclose(outfile); + return ES_OK; +} + +void add_external_potential_tabulated_forces(ExternalPotential* e, Particle* p) { + if (p->p.type >= e->n_particle_types || e->scale[p->p.type] == 0 ) { + return; + } + double field[3]; + double ppos[3]; +#ifdef LEES_EDWARDS + double dummyV[3]; +#endif + int img[3]; + memcpy(ppos, p->r.p, 3*sizeof(double)); + memcpy(img, p->r.p, 3*sizeof(int)); +#ifdef LEES_EDWARDS + fold_position(ppos, dummyV, img); +#else + fold_position(ppos, img); +#endif + + e->tabulated.potential.interpolate_gradient(p->r.p, field); + p->f.f[0]-=e->scale[p->p.type]*field[0]; + p->f.f[1]-=e->scale[p->p.type]*field[1]; + p->f.f[2]-=e->scale[p->p.type]*field[2]; +// printf("%d %f force: %f %f %f\n", p->p.type, e->scale[p->p.type], e->scale[p->p.type]*field[0], e->scale[p->p.type]*field[1], e->scale[p->p.type]*field[2]); +} + +void add_external_potential_forces(Particle* p) { + for (int i = 0; i < n_external_potentials; i++) { + if (external_potentials[i].type==EXTERNAL_POTENTIAL_TYPE_TABULATED) { + add_external_potential_tabulated_forces(&external_potentials[i], p); + } else { + ostringstream msg; + msg <<"unknown external potential type"; + runtimeError(msg); + return; + } + } +} + + +void add_external_potential_tabulated_energy(ExternalPotential* e, Particle* p) { + if (p->p.type >= e->n_particle_types) { + return; + } + double potential; + double ppos[3]; +#ifdef LEES_EDWARDS + double dummyV[3]; +#endif + int img[3]; + memcpy(ppos, p->r.p, 3*sizeof(double)); + memcpy(img, p->r.p, 3*sizeof(int)); +#ifdef LEES_EDWARDS + fold_position(ppos, dummyV, img); +#else + fold_position(ppos, img); +#endif + + e->tabulated.potential.interpolate(p->r.p, &potential); + e->energy += e->scale[p->p.type] * potential; +} + +void add_external_potential_energy(Particle* p) { + for (int i=0; i. +*/ +#ifndef _EXTERNAL_POTENTIAL_HPP +#define _EXTERNAL_POTENTIAL_HPP + +#include "lattice.hpp" + +#define MAX_FILENAME_SIZE 32 + +#define EXTERNAL_POTENTIAL_TYPE_TABULATED 0 +#define EXTERNAL_POTENTIAL_TYPE_ROD 1 + +void external_potential_pre_init(); + +typedef struct { + char filename[MAX_FILENAME_SIZE]; + Lattice potential; +} ExternalPotentialTabulated; + +typedef struct { + int dummy; + int type; + double* scale; + int n_particle_types; + ExternalPotentialTabulated tabulated; + double energy; +} ExternalPotential; + +extern ExternalPotential* external_potentials; +extern int n_external_potentials; + +int external_potential_tabulated_init(int number, char* filename, int n_particle_types, double* scale); + +void external_potential_init_energies(); + +int generate_external_potential(ExternalPotential** externalPotential); + +int external_potential_init(int number, char* filename, int n_particle_types, double* scale); + +int external_potential_tabulated_read_potential_file(int number); + +void add_external_potential_forces(Particle* p); +void add_external_potential_energy(Particle* p); + +int write_local_lattice_to_file(const char* filename_prefix, Lattice* lattice); + + +#endif + diff --git a/src/fene.cpp b/src/core/fene.cpp similarity index 93% rename from src/fene.cpp rename to src/core/fene.cpp index 9111f084ffa..a51130bd4b9 100644 --- a/src/fene.cpp +++ b/src/core/fene.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file fene.c +/** \file fene.cpp * - * Implementation of \ref fene.h + * Implementation of \ref fene.hpp */ #include "fene.hpp" diff --git a/src/fene.hpp b/src/core/fene.hpp similarity index 68% rename from src/fene.hpp rename to src/core/fene.hpp index 7dba813289d..e722308e606 100644 --- a/src/fene.hpp +++ b/src/core/fene.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,18 +18,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef FENE_H -#define FENE_H -/** \file fene.h +#ifndef _FENE_HPP +#define _FENE_HPP +/** \file fene.hpp * Routines to calculate the FENE Energy or/and FENE force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" #include "interaction_data.hpp" #include "particle_data.hpp" #include "random.hpp" +#include "errorhandling.hpp" + +using namespace std; /************************************************************/ @@ -37,32 +40,31 @@ int fene_set_params(int bond_type, double k, double drmax, double r0); /** Computes the FENE pair force and adds this - force to the particle forces (see \ref interaction_data.c). + force to the particle forces (see \ref interaction_data.cpp). @param p1 Pointer to first particle. @param p2 Pointer to second/middle particle. - @param iaparams bond type number of the angle interaction (see \ref interaction_data.c). + @param iaparams bond type number of the angle interaction (see \ref interaction_data.cpp). @param dx particle distance vector @param force returns force of particle 1 @return true if the bond is broken */ -inline int calc_fene_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force[3]) -{ +inline int calc_fene_pair_force(Particle *p1, Particle *p2, + Bonded_ia_parameters *iaparams, + double dx[3], double force[3]) { int i; - double fac, dr, len2, len; - len2 = sqrlen(dx); - len = sqrt(len2); - dr = len - iaparams->p.fene.r0; + const double len2 = sqrlen(dx); + const double len = sqrt(len2); + const double dr = len - iaparams->p.fene.r0; - if(dr >= iaparams->p.fene.drmax) - return 1; + if (dr >= iaparams->p.fene.drmax) return 1; - fac = -iaparams->p.fene.k * dr / ((1.0 - dr*dr*iaparams->p.fene.drmax2i)); + double fac = -iaparams->p.fene.k * dr / ((1.0 - dr*dr*iaparams->p.fene.drmax2i)); if (fabs(dr) > ROUND_ERROR_PREC) { if(len > ROUND_ERROR_PREC) { /* Regular case */ fac /= len ; } else { /* dx[] == 0: the force is undefined. Let's use a random direction */ - for(i=0;i<3;i++) dx[i] = d_random()-0.5; + for(int i = 0;i < 3;i++) dx[i] = d_random()-0.5; fac /= sqrt(sqrlen(dx)); } } else { @@ -80,21 +82,21 @@ inline int calc_fene_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters return 0; } -inline int fene_pair_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy) -{ - double energy, dr; - +inline int fene_pair_energy(Particle *p1, Particle *p2, + Bonded_ia_parameters *iaparams, + double dx[3], double *_energy) { /* compute bond stretching (r-r0) */ - dr = sqrt(sqrlen(dx))-iaparams->p.fene.r0; + double dr = sqrt(sqrlen(dx))-iaparams->p.fene.r0; /* check bond stretching */ if(dr >= iaparams->p.fene.drmax) { - char *errtext = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{077 FENE bond broken between particles %d and %d} ", p1->p.identity, p2->p.identity); + ostringstream msg; + msg <<"FENE bond broken between particles "<< p1->p.identity << " and " << p2->p.identity; + runtimeError(msg); return 1; } - energy = -0.5*iaparams->p.fene.k*iaparams->p.fene.drmax2; + double energy = -0.5*iaparams->p.fene.k*iaparams->p.fene.drmax2; energy *= log((1.0 - dr*dr*iaparams->p.fene.drmax2i)); *_energy = energy; return 0; diff --git a/src/fft-common.cpp b/src/core/fft-common.cpp similarity index 99% rename from src/fft-common.cpp rename to src/core/fft-common.cpp index 570f180c3fc..3b6a95dbca8 100644 --- a/src/fft-common.cpp +++ b/src/core/fft-common.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file fft-common.c +/** \file fft-common.cpp * * Routines, row decomposition, data structures and communication for the 3D-FFT. * diff --git a/src/fft-common.hpp b/src/core/fft-common.hpp similarity index 98% rename from src/fft-common.hpp rename to src/core/fft-common.hpp index 6fc06d46099..a55ec85e9e7 100644 --- a/src/fft-common.hpp +++ b/src/core/fft-common.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -147,7 +147,7 @@ void fft_common_pre_init(fft_data_struct *fft); * and grid2. The return value is the size of the communication * group. It gives -1 if the two grids do not fit to each other * (grid1 and grid2 have to be component wise multiples of each - * other. see e.g. \ref calc_2d_grid in \ref grid.c for how to do + * other. see e.g. \ref calc_2d_grid in \ref grid.cpp for how to do * this.). * * \param grid1 The node grid you start with (Input). diff --git a/src/fft-dipolar.cpp b/src/core/fft-dipolar.cpp similarity index 99% rename from src/fft-dipolar.cpp rename to src/core/fft-dipolar.cpp index 6af135e980c..9b5d5ff53ad 100644 --- a/src/fft-dipolar.cpp +++ b/src/core/fft-dipolar.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file fft.c +/** \file fft.cpp * * Routines, row decomposition, data structures and communication for the 3D-FFT. * diff --git a/src/fft-dipolar.hpp b/src/core/fft-dipolar.hpp similarity index 94% rename from src/fft-dipolar.hpp rename to src/core/fft-dipolar.hpp index 17427f50e8a..fc3cdca7c0d 100644 --- a/src/fft-dipolar.hpp +++ b/src/core/fft-dipolar.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -22,7 +22,7 @@ #ifndef _FFT_MAGNETOSTATICS_H #define _FFT_MAGNETOSTATICS_H -/** \file fft-dipolar.h +/** \file fft-dipolar.hpp * * Routines, row decomposition, data structures and communication for the 3D-FFT. * @@ -37,7 +37,7 @@ * sufficient) * * \todo Combine the forward and backward structures. - * \todo The packing routines could be moved to utils.h when they are needed elsewhere. + * \todo The packing routines could be moved to utils.hpp when they are needed elsewhere. */ #include "config.hpp" diff --git a/src/fft.cpp b/src/core/fft.cpp similarity index 99% rename from src/fft.cpp rename to src/core/fft.cpp index 7ae4109b163..2a3f097fec3 100644 --- a/src/fft.cpp +++ b/src/core/fft.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file fft.c +/** \file fft.cpp * * Routines, row decomposition, data structures and communication for the 3D-FFT. * diff --git a/src/fft.hpp b/src/core/fft.hpp similarity index 91% rename from src/fft.hpp rename to src/core/fft.hpp index 781e81398b4..efad47e9bc3 100644 --- a/src/fft.hpp +++ b/src/core/fft.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _FFT_H #define _FFT_H -/** \file fft.h +/** \file fft.hpp * * Routines, row decomposition, data structures and communication for the 3D-FFT. * @@ -35,9 +35,9 @@ * sufficient) * * \todo Combine the forward and backward structures. - * \todo The packing routines could be moved to utils.h when they are needed elsewhere. + * \todo The packing routines could be moved to utils.hpp when they are needed elsewhere. * - * For more information about FFT usage, see \ref fft.c "fft.c". + * For more information about FFT usage, see \ref fft.cpp "fft.c". */ #include "config.hpp" diff --git a/src/forcecap.cpp b/src/core/forcecap.cpp similarity index 85% rename from src/forcecap.cpp rename to src/core/forcecap.cpp index 36d8d3818df..6a1a8f1f74f 100644 --- a/src/forcecap.cpp +++ b/src/core/forcecap.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file forcecap.c force cap calculation. +/** \file forcecap.cpp force cap calculation. * - * For more information see \ref forcecap.h "forcecap.h". + * For more information see \ref forcecap.hpp "forcecap.h". */ #include "forcecap.hpp" diff --git a/src/forcecap.hpp b/src/core/forcecap.hpp similarity index 94% rename from src/forcecap.hpp rename to src/core/forcecap.hpp index 97c559afd98..5bb8843afa0 100644 --- a/src/forcecap.hpp +++ b/src/core/forcecap.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/core/forces.cpp b/src/core/forces.cpp new file mode 100644 index 00000000000..5fe53f650a4 --- /dev/null +++ b/src/core/forces.cpp @@ -0,0 +1,271 @@ + +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file forces.cpp Force calculation. + * + * For more information see \ref forces.hpp "forces.h". +*/ +/*#include +#include "forces_inline.hpp" +#include +#include +#include +#include +#include "utils.hpp" +#include "thermostat.hpp" +#include "pressure.hpp" +#include "communication.hpp" +#include "ghosts.hpp" +#include "verlet.hpp" +#include "grid.hpp" +#include "cells.hpp" +#include "particle_data.hpp" +#include "interaction_data.hpp" +#include "rotation.hpp" +#include "forces.hpp" +#include "elc.hpp" +#include "lattice.hpp" +#include "lb.hpp" +#include "nsquare.hpp" +#include "layered.hpp" +#include "domain_decomposition.hpp" +#include "magnetic_non_p3m_methods.hpp" +#include "mdlc_correction.hpp" +#include "virtual_sites.hpp" +#include "constraint.hpp" +#include "lbgpu.hpp" +#include "iccp3m.hpp" +#include "p3m_gpu.hpp" +#include "cuda_interface.hpp" + +#include "EspressoSystemInterface.hpp"*/ + +#include "p3m_gpu.hpp" +#include "maggs.hpp" +#include "forces_inline.hpp" +ActorList forceActors; + + +void init_forces() +{ + Cell *cell; + Particle *p; + int np, c, i; + + /* The force initialization depends on the used thermostat and the + thermodynamic ensemble */ + +#ifdef NPT + /* reset virial part of instantaneous pressure */ + if(integ_switch == INTEG_METHOD_NPT_ISO) + nptiso.p_vir[0] = nptiso.p_vir[1] = nptiso.p_vir[2] = 0.0; +#endif + + + /* initialize forces with langevin thermostat forces + or zero depending on the thermostat + set torque to zero for all and rescale quaternions + */ + for (c = 0; c < local_cells.n; c++) { + cell = local_cells.cell[c]; + p = cell->part; + np = cell->n; + for (i = 0; i < np; i++) + init_local_particle_force(&p[i]); + } + + /* initialize ghost forces with zero + set torque to zero for all and rescale quaternions + */ + for (c = 0; c < ghost_cells.n; c++) { + cell = ghost_cells.cell[c]; + p = cell->part; + np = cell->n; + for (i = 0; i < np; i++) + init_ghost_force(&p[i]); + } + +#ifdef CONSTRAINTS + init_constraint_forces(); +#endif +} + +void init_forces_ghosts() +{ + Cell *cell; + Particle *p; + int np, c, i; + + for (c = 0; c < ghost_cells.n; c++) { + cell = ghost_cells.cell[c]; + p = cell->part; + np = cell->n; + for (i = 0; i < np; i++) + init_ghost_force(&p[i]); + } +} + +// This function is no longer called from force_calc(). +// The check was moved to rescale_fores() to avoid an additional iteration over all particles +void check_forces() +{ + Cell *cell; + Particle *p; + int np, c, i; + + for (c = 0; c < local_cells.n; c++) { + cell = local_cells.cell[c]; + p = cell->part; + np = cell->n; + for (i = 0; i < np; i++) { + check_particle_force(&p[i]); + } + } + + for (c = 0; c < ghost_cells.n; c++) { + cell = ghost_cells.cell[c]; + p = cell->part; + np = cell->n; + for (i = 0; i < np; i++) + check_particle_force(&p[i]); + } +} + +void calc_long_range_forces() +{ +#ifdef ELECTROSTATICS + /* calculate k-space part of electrostatic interaction. */ + switch (coulomb.method) { +#ifdef P3M + case COULOMB_ELC_P3M: + if (elc_params.dielectric_contrast_on) { + ELC_P3M_modify_p3m_sums_both(); + ELC_p3m_charge_assign_both(); + ELC_P3M_self_forces(); + } + else + p3m_charge_assign(); + + p3m_calc_kspace_forces(1,0); + + if (elc_params.dielectric_contrast_on) + ELC_P3M_restore_p3m_sums(); + + ELC_add_force(); + + break; +#endif +#ifdef CUDA + case COULOMB_P3M_GPU: + if (this_node == 0) { + FORCE_TRACE(printf("Computing GPU P3M forces.\n")); + p3m_gpu_add_farfield_force(); + } + /* there is no NPT handling here as long as we cannot compute energies. + This is checked in integrator_npt_sanity_checks() when integration starts. */ + break; +#endif +#ifdef P3M + case COULOMB_P3M: + FORCE_TRACE(printf("%d: Computing P3M forces.\n", this_node)); + p3m_charge_assign(); +#ifdef NPT + if (integ_switch == INTEG_METHOD_NPT_ISO) + nptiso.p_vir[0] += p3m_calc_kspace_forces(1,1); + else +#endif + p3m_calc_kspace_forces(1, 0); + break; +#endif + case COULOMB_MAGGS: + maggs_calc_forces(); + break; + case COULOMB_MMM2D: + MMM2D_add_far_force(); + MMM2D_dielectric_layers_force_contribution(); + break; + default: + break; + } +#endif /*ifdef ELECTROSTATICS */ + +#ifdef DIPOLES + /* calculate k-space part of the magnetostatic interaction. */ + switch (coulomb.Dmethod) { +#ifdef DP3M + case DIPOLAR_MDLC_P3M: + add_mdlc_force_corrections(); + //fall through + case DIPOLAR_P3M: + dp3m_dipole_assign(); +#ifdef NPT + if(integ_switch == INTEG_METHOD_NPT_ISO) { + nptiso.p_vir[0] += dp3m_calc_kspace_forces(1,1); + fprintf(stderr,"dipolar_P3M at this moment is added to p_vir[0]\n"); + } else +#endif + dp3m_calc_kspace_forces(1,0); + + break; +#endif + case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: + dawaanr_calculations(1,0); + break; + case DIPOLAR_MDLC_DS: + add_mdlc_force_corrections(); + //fall through + case DIPOLAR_DS: + magnetic_dipolar_direct_sum_calculations(1,0); + break; + case DIPOLAR_NONE: + break; + default: + ostringstream msg; + msg <<"unknown dipolar method"; + runtimeError(msg); + break; + } +#endif /*ifdef DIPOLES */ +} + +void +calc_non_bonded_pair_force_from_partcfg(Particle *p1, Particle *p2, IA_parameters *ia_params, + double d[3], double dist, double dist2, + double force[3], + double torque1[3], double torque2[3]) { +#ifdef MOL_CUT + //You may want to put a correction factor and correction term for smoothing function else then theta + if (checkIfParticlesInteractViaMolCut_partcfg(p1,p2,ia_params)==1) +#endif + { + calc_non_bonded_pair_force_parts(p1, p2, ia_params, + d, dist, dist2, force, torque1, torque2); + } +} + +void calc_non_bonded_pair_force_from_partcfg_simple(Particle *p1,Particle *p2,double d[3],double dist,double dist2,double force[3]){ + IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); + double torque1[3],torque2[3]; + calc_non_bonded_pair_force_from_partcfg(p1, p2, ia_params, d, dist, dist2, + force, torque1, torque2); +} + + diff --git a/src/core/forces.hpp b/src/core/forces.hpp new file mode 100644 index 00000000000..e723aa4c1bb --- /dev/null +++ b/src/core/forces.hpp @@ -0,0 +1,79 @@ +/* + Copyright (C) 2010,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _FORCES_HPP +#define _FORCES_HPP +/** \file forces.hpp Force calculation. + * + * \todo Preprocessor switches for all forces (Default: everything is turned on). + * \todo Implement more flexible thermostat, %e.g. which thermostat to use. + * + * For more information see forces.cpp . + */ + +//#include "config.hpp" +//#include "interaction_data.hpp" + +/*#include "iccp3m.hpp" +#include "external_potential.hpp" +#include "actor/Actor.hpp" +#include "actor/ActorList.hpp"*/ + +#include "iccp3m.hpp" +#include "external_potential.hpp" +#include "actor/Actor.hpp" +#include "actor/ActorList.hpp" +extern ActorList forceActors; + +/** \name Exported Functions */ +/************************************************************/ +/*@{*/ + +/******************* forces.cpp *******************/ + +/** initialize real particle forces with thermostat forces and + ghost particle forces with zero. */ +void init_forces(); + +/** Set forces of all ghosts to zero +*/ +void init_forces_ghosts(); + +/** Check if forces are NAN +*/ +void check_forces(); + +/** Calculate long range forces (P3M, MMM2d...). */ +void calc_long_range_forces(); + +void +calc_non_bonded_pair_force_from_partcfg(Particle *p1, Particle *p2, + IA_parameters *ia_params, + double d[3], double dist, double dist2, + double force[3], + double torque1[3] = NULL, + double torque2[3] = NULL); + +void calc_non_bonded_pair_force_from_partcfg_simple(Particle *p1,Particle *p2,double d[3],double dist,double dist2,double force[3]); + + +/*@}*/ + +#endif diff --git a/src/forces.hpp b/src/core/forces_inline.hpp similarity index 58% rename from src/forces.hpp rename to src/core/forces_inline.hpp index 99ce012982d..0db3e0093b5 100644 --- a/src/forces.hpp +++ b/src/core/forces_inline.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,27 +18,20 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef _FORCES_H -#define _FORCES_H -/** \file forces.h Force calculation. - * - * \todo Preprocessor switches for all forces (Default: everything is turned on). - * \todo Implement more flexible thermostat, %e.g. which thermostat to use. - * - * For more information see forces.c . - */ -#include "utils.hpp" -#include "thermostat.hpp" +#ifndef _FORCES_INLINE_HPP +#define _FORCES_INLINE_HPP + #ifdef MOLFORCES #include "topology.hpp" #endif -#include "npt.hpp" -#include "adresso.hpp" -#include "virtual_sites.hpp" -#include "metadynamics.hpp" -/* include the force files */ -#include "p3m.hpp" +#include "magnetic_non_p3m_methods.hpp" +#include "mdlc_correction.hpp" +#include "constraint.hpp" +#include "EspressoSystemInterface.hpp" +#include "forces.hpp" + +#include "npt.hpp" #include "p3m-dipolar.hpp" #include "lj.hpp" #include "ljgen.hpp" @@ -49,7 +42,6 @@ #include "buckingham.hpp" #include "soft_sphere.hpp" #include "hat.hpp" -#include "maggs.hpp" #include "tab.hpp" #include "overlap.hpp" #include "ljcos.hpp" @@ -65,29 +57,99 @@ #include "object-in-fluid/volume_force.hpp" #include "harmonic.hpp" #include "subt_lj.hpp" -#include "angle.hpp" #include "angle_harmonic.hpp" #include "angle_cosine.hpp" #include "angle_cossquare.hpp" #include "angledist.hpp" -#include "dihedral.hpp" #include "debye_hueckel.hpp" #include "endangledist.hpp" #include "reaction_field.hpp" -#include "mmm1d.hpp" -#include "mmm2d.hpp" #include "comforce.hpp" #include "comfixed.hpp" #include "molforces.hpp" #include "morse.hpp" #include "elc.hpp" -#include "iccp3m.hpp" -#include "collision.hpp" -/* end of force files */ +#include "collision.hpp" +#include "metadynamics.hpp" +#include "angle.hpp" +#include "quartic.hpp" +#ifdef ELECTROSTATICS +#include "bonded_coulomb.hpp" +#endif +#include "actor/EwaldgpuForce_ShortRange.hpp" -/** \name Exported Functions */ -/************************************************************/ -/*@{*/ +using namespace std; + +/** initialize the forces for a ghost particle */ +inline void init_ghost_force(Particle *part) +{ + part->f.f[0] = 0; + part->f.f[1] = 0; + part->f.f[2] = 0; + +#ifdef ROTATION + { + double scale; + /* set torque to zero */ + part->f.torque[0] = 0; + part->f.torque[1] = 0; + part->f.torque[2] = 0; + + /* and rescale quaternion, so it is exactly of unit length */ + scale = sqrt( SQR(part->r.quat[0]) + SQR(part->r.quat[1]) + + SQR(part->r.quat[2]) + SQR(part->r.quat[3])); + part->r.quat[0]/= scale; + part->r.quat[1]/= scale; + part->r.quat[2]/= scale; + part->r.quat[3]/= scale; + } +#endif +} + +/** initialize the forces for a real particle */ +inline void init_local_particle_force(Particle *part) { + if ( thermo_switch & THERMO_LANGEVIN ) + friction_thermo_langevin(part); + else { + part->f.f[0] = 0; + part->f.f[1] = 0; + part->f.f[2] = 0; + } + +#ifdef EXTERNAL_FORCES + if(part->l.ext_flag & PARTICLE_EXT_FORCE) { + part->f.f[0] += part->l.ext_force[0]; + part->f.f[1] += part->l.ext_force[1]; + part->f.f[2] += part->l.ext_force[2]; + } +#endif + +#ifdef ROTATION + { + double scale; + /* set torque to zero */ + part->f.torque[0] = 0; + part->f.torque[1] = 0; + part->f.torque[2] = 0; + + #ifdef EXTERNAL_FORCES + if(part->l.ext_flag & PARTICLE_EXT_TORQUE) { + part->f.torque[0] += part->l.ext_torque[0]; + part->f.torque[1] += part->l.ext_torque[1]; + part->f.torque[2] += part->l.ext_torque[2]; + } + #endif + + /* and rescale quaternion, so it is exactly of unit length */ + scale = sqrt( SQR(part->r.quat[0]) + SQR(part->r.quat[1]) + + SQR(part->r.quat[2]) + SQR(part->r.quat[3])); + part->r.quat[0]/= scale; + part->r.quat[1]/= scale; + part->r.quat[2]/= scale; + part->r.quat[3]/= scale; + } +#endif +} /** Calculate forces. * @@ -95,7 +157,7 @@ *
      *
    1. Initialize forces with: \ref friction_thermo_langevin (ghost forces with zero). *
    2. Calculate bonded interaction forces:
      - * Loop all local particles (not the ghosts). + * Loop all local particles (not the ghosts). *
    */ -void force_calc(); +inline void force_calc() +{ + // Communication step: distribute ghost positions + cells_update_ghosts(); -/** Set forces of all ghosts to zero -*/ -void init_forces_ghosts(); + // VIRTUAL_SITES pos (and vel for DPD) update for security reason !!! +#ifdef VIRTUAL_SITES + update_mol_vel_pos(); + ghost_communicator(&cell_structure.update_ghost_pos_comm); +#endif -/** Check if forces are NAN -*/ -void check_forces(); +#if defined(VIRTUAL_SITES_RELATIVE) && defined(LB) + // This is on a workaround stage: + // When using virtual sites relative and LB at the same time, it is necessary + // to reassemble the cell lists after all position updates, also of virtual + // particles. + if ((lattice_switch & LATTICE_LB) && cell_structure.type == CELL_STRUCTURE_DOMDEC && (!dd.use_vList) ) + cells_update_ghosts(); +#endif +#ifdef COLLISION_DETECTION + prepare_collision_queue(); +#endif -inline void calc_non_bonded_pair_force_parts(Particle *p1, Particle *p2, IA_parameters *ia_params,double d[3], - double dist, double dist2, double force[3],double torgue1[3],double torgue2[3]) -{ + espressoSystemInterface.update(); + + // Compute the forces from the force objects + for (ActorList::iterator actor = forceActors.begin(); + actor != forceActors.end(); ++actor) + (*actor)->computeForces(espressoSystemInterface); + +#ifdef LB_GPU +#ifdef SHANCHEN + if (lattice_switch & LATTICE_LB_GPU && this_node == 0) lattice_boltzmann_calc_shanchen_gpu(); +#endif // SHANCHEN + + // transfer_momentum_gpu check makes sure the LB fluid doesn't get updated on integrate 0 + // this_node==0 makes sure it is the master node where the gpu exists + if (lattice_switch & LATTICE_LB_GPU && transfer_momentum_gpu && (this_node == 0) ) lb_calc_particle_lattice_ia_gpu(); +#endif // LB_GPU + +#ifdef ELECTROSTATICS + if (iccp3m_initialized && iccp3m_cfg.set_flag) + iccp3m_iteration(); +#endif + init_forces(); + + switch (cell_structure.type) { + case CELL_STRUCTURE_LAYERED: + layered_calculate_ia(); + break; + case CELL_STRUCTURE_DOMDEC: + if(dd.use_vList) { + if (rebuild_verletlist) + build_verlet_lists_and_calc_verlet_ia(); + else + calculate_verlet_ia(); + } + else + calc_link_cell(); + break; + case CELL_STRUCTURE_NSQUARE: + nsq_calculate_ia(); + + } + +#ifdef VOLUME_FORCE + double volume=0.; + + for (int i=0;i< MAX_OBJECTS_IN_FLUID;i++){ + calc_volume(&volume,i); + if (volume<1e-100) break; + add_volume_force(volume,i); + } +#endif + +#ifdef AREA_FORCE_GLOBAL + double area=0.; + + for (int i=0;i< MAX_OBJECTS_IN_FLUID;i++){ + calc_area_global(&area,i); + if (area<1e-100) break; + add_area_global_force(area,i); + } +#endif + + calc_long_range_forces(); + +#ifdef LB + if (lattice_switch & LATTICE_LB) calc_particle_lattice_ia() ; +#endif + +#ifdef COMFORCE + calc_comforce(); +#endif + +#ifdef METADYNAMICS + /* Metadynamics main function */ + meta_perform(); +#endif + +#ifdef CUDA + copy_forces_from_GPU(); +#endif + + // VIRTUAL_SITES distribute forces +#ifdef VIRTUAL_SITES + ghost_communicator(&cell_structure.collect_ghost_force_comm); + init_forces_ghosts(); + distribute_mol_force(); +#endif + + // Communication Step: ghost forces + ghost_communicator(&cell_structure.collect_ghost_force_comm); + + // apply trap forces to trapped molecules +#ifdef MOLFORCES + calc_and_apply_mol_constraints(); +#endif + + // should be pretty late, since it needs to zero out the total force +#ifdef COMFIXED + calc_comfixed(); +#endif + + // mark that forces are now up-to-date + recalc_forces = 0; + +#ifdef COLLISION_DETECTION + handle_collisions(); +#endif +} + + +inline void +calc_non_bonded_pair_force_parts(Particle *p1, Particle *p2, IA_parameters *ia_params, + double d[3], double dist, double dist2, + double force[3], + double torque1[3] = NULL, double torque2[3] = NULL) { #ifdef NO_INTRA_NB if (p1->p.mol_id==p2->p.mol_id) return; #endif @@ -140,19 +327,19 @@ inline void calc_non_bonded_pair_force_parts(Particle *p1, Particle *p2, IA_para /* Directional LJ */ #ifdef LJ_ANGLE /* The forces are propagated within the function */ - add_ljangle_pair_force(p1,p2,ia_params,d,dist); + add_ljangle_pair_force(p1, p2, ia_params, d, dist); #endif /* smooth step */ #ifdef SMOOTH_STEP - add_SmSt_pair_force(p1,p2,ia_params,d,dist,dist2, force); + add_SmSt_pair_force(p1, p2, ia_params, d, dist, dist2, force); #endif /* Hertzian force */ #ifdef HERTZIAN - add_hertzian_pair_force(p1,p2,ia_params,d,dist,dist2, force); + add_hertzian_pair_force(p1, p2, ia_params, d, dist, dist2, force); #endif /* Gaussian force */ #ifdef GAUSSIAN - add_gaussian_pair_force(p1,p2,ia_params,d,dist,dist2, force); + add_gaussian_pair_force(p1, p2, ia_params, d, dist, dist2, force); #endif /* BMHTF NaCl */ #ifdef BMHTF_NACL @@ -188,59 +375,36 @@ inline void calc_non_bonded_pair_force_parts(Particle *p1, Particle *p2, IA_para #endif /* Gay-Berne */ #ifdef GAY_BERNE - add_gb_pair_force(p1,p2,ia_params,d,dist,force,torgue1,torgue2); + add_gb_pair_force(p1,p2,ia_params,d,dist,force,torque1,torque2); #endif #ifdef INTER_RF add_interrf_pair_force(p1,p2,ia_params,d,dist, force); #endif -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION - add_adress_tab_pair_force(p1,p2,ia_params,d,dist,force); -#endif -#endif } -inline void calc_non_bonded_pair_force(Particle *p1,Particle *p2,IA_parameters *ia_params,double d[3],double dist,double dist2,double force[3],double t1[3],double t2[3]){ +inline void +calc_non_bonded_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_params, + double d[3], double dist, double dist2, + double force[3], + double torque1[3] = NULL, double torque2[3] = NULL) { #ifdef MOL_CUT - //You may want to put a correction factor and correction term for smoothing function else then theta + // You may want to put a correction factor and correction term for smoothing function else then theta if (checkIfParticlesInteractViaMolCut(p1,p2,ia_params)==1) #endif { - calc_non_bonded_pair_force_parts(p1, p2, ia_params,d, dist, dist2,force,t1,t2); + calc_non_bonded_pair_force_parts(p1, p2, ia_params, d, dist, dist2, + force, torque1, torque2); } } -inline void calc_non_bonded_pair_force_simple(Particle *p1,Particle *p2,double d[3],double dist,double dist2,double force[3]){ - IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); - double t1[3],t2[3]; -#ifdef ADRESS - int j; - double force_weight=adress_non_bonded_force_weight(p1,p2); - if (force_weightp.type,p2->p.type); + calc_non_bonded_pair_force(p1, p2, ia_params, d, dist, dist2, force); } -inline void calc_non_bonded_pair_force_from_partcfg_simple(Particle *p1,Particle *p2,double d[3],double dist,double dist2,double force[3]){ - IA_parameters *ia_params = get_ia_param(p1->p.type,p2->p.type); - double t1[3],t2[3]; - calc_non_bonded_pair_force_from_partcfg(p1,p2,ia_params,d,dist,dist2,force,t1,t2); -} /** Calculate non bonded forces between a pair of particles. @param p1 pointer to particle 1. @@ -263,11 +427,6 @@ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, detect_collision(p1,p2); #endif -#ifdef ADRESS - double tmp,force_weight=adress_non_bonded_force_weight(p1,p2); - if (force_weight%d dist %f\n", this_node, p1->p.identity, p2->p.identity, dist)); /***********************************************/ @@ -280,7 +439,7 @@ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, #endif #ifdef INTER_DPD - if ( thermo_switch == THERMO_INTER_DPD ) add_inter_dpd_pair_force(p1,p2,ia_params,d,dist,dist2); + if ( thermo_switch & THERMO_INTER_DPD ) add_inter_dpd_pair_force(p1,p2,ia_params,d,dist,dist2); #endif /***********************************************/ @@ -319,43 +478,46 @@ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, /* real space coulomb */ double q1q2 = p1->p.q*p2->p.q; - if (!(iccp3m_initialized && iccp3m_cfg.set_flag)) { - switch (coulomb.method) { - #ifdef P3M - case COULOMB_ELC_P3M: { - if (q1q2) { - p3m_add_pair_force(q1q2,d,dist2,dist,force); - - // forces from the virtual charges - // they go directly onto the particles, since they are not pairwise forces - if (elc_params.dielectric_contrast_on) - ELC_P3M_dielectric_layers_force_contribution(p1, p2, p1->f.f, p2->f.f); - } - break; - } - case COULOMB_P3M_GPU: - case COULOMB_P3M: { - #ifdef NPT - if (q1q2) { - double eng = p3m_add_pair_force(q1q2,d,dist2,dist,force); - if(integ_switch == INTEG_METHOD_NPT_ISO) - nptiso.p_vir[0] += eng; - } - #else - if (q1q2) p3m_add_pair_force(q1q2,d,dist2,dist,force); - #endif - break; - } - #endif - case COULOMB_MMM1D: - if (q1q2) add_mmm1d_coulomb_pair_force(q1q2,d,dist2,dist,force); - break; - case COULOMB_MMM2D: - if (q1q2) add_mmm2d_coulomb_pair_force(q1q2,d,dist2,dist,force); - break; - case COULOMB_NONE: - break; - } + switch (coulomb.method) { +#ifdef P3M + case COULOMB_ELC_P3M: { + if (q1q2) { + p3m_add_pair_force(q1q2,d,dist2,dist,force); + + // forces from the virtual charges + // they go directly onto the particles, since they are not pairwise forces + if (elc_params.dielectric_contrast_on) + ELC_P3M_dielectric_layers_force_contribution(p1, p2, p1->f.f, p2->f.f); + } + break; + } + case COULOMB_P3M_GPU: + case COULOMB_P3M: { +#ifdef NPT + if (q1q2) { + double eng = p3m_add_pair_force(q1q2,d,dist2,dist,force); + if(integ_switch == INTEG_METHOD_NPT_ISO) + nptiso.p_vir[0] += eng; + } +#else + if (q1q2) p3m_add_pair_force(q1q2,d,dist2,dist,force); +#endif + break; + } +#endif + case COULOMB_MMM1D: + if (q1q2) add_mmm1d_coulomb_pair_force(q1q2,d,dist2,dist,force); + break; + case COULOMB_MMM2D: + if (q1q2) add_mmm2d_coulomb_pair_force(q1q2,d,dist2,dist,force); + break; +#ifdef EWALD_GPU + case COULOMB_EWALD_GPU: + if (q1q2) add_ewald_gpu_coulomb_pair_force(p1,p2,d,dist,force); + break; +#endif + default: + break; } #endif /*ifdef ELECTROSTATICS */ @@ -383,6 +545,8 @@ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, break; } #endif /*ifdef DP3M */ + default: + break; } #endif /* ifdef DIPOLES */ @@ -391,14 +555,8 @@ inline void add_non_bonded_pair_force(Particle *p1, Particle *p2, /***********************************************/ for (j = 0; j < 3; j++) { -#ifdef ADRESS - tmp=force_weight*force[j]; - p1->f.f[j] += tmp; - p2->f.f[j] -= tmp; -#else p1->f.f[j] += force[j]; p2->f.f[j] -= force[j]; -#endif #ifdef ROTATION p1->f.torque[j] += torque1[j]; p2->f.torque[j] += torque2[j]; @@ -419,19 +577,13 @@ inline void add_bonded_force(Particle *p1) double torque1[3] = { 0., 0., 0. }; double torque2[3] = { 0., 0., 0. }; #endif - char *errtxt; Particle *p2, *p3 = NULL, *p4 = NULL; Bonded_ia_parameters *iaparams; - int i, j, type_num, type, n_partners, bond_broken; - -#ifdef ADRESS - double tmp, force_weight=1; - //double tmp,force_weight=adress_bonded_force_weight(p1); - //if (force_weightbl.n) { + while (ibl.n) { type_num = p1->bl.e[i++]; iaparams = &bonded_ia_params[type_num]; type = iaparams->type; @@ -440,9 +592,10 @@ inline void add_bonded_force(Particle *p1) /* fetch particle 2, which is always needed */ p2 = local_particles[p1->bl.e[i++]]; if (!p2) { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{078 bond broken between particles %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-1]); + ostringstream msg; + msg << "bond broken between particles " << p1->p.identity << " and " + << p1->bl.e[i-1] << " (particles are not stored on the same node)"; + runtimeError(msg); return; } @@ -450,9 +603,12 @@ inline void add_bonded_force(Particle *p1) if (n_partners >= 2) { p3 = local_particles[p1->bl.e[i++]]; if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{079 bond broken between particles %d, %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-2], p1->bl.e[i-1]); + ostringstream msg; + msg << "bond broken between particles " + << p1->p.identity << ", " + << p1->bl.e[i-2] << " and " + << p1->bl.e[i-1] << " (particles are not stored on the same node)"; + runtimeError(msg); return; } } @@ -461,9 +617,10 @@ inline void add_bonded_force(Particle *p1) if (n_partners >= 3) { p4 = local_particles[p1->bl.e[i++]]; if (!p4) { - errtxt = runtime_error(128 + 4*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{080 bond broken between particles %d, %d, %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-3], p1->bl.e[i-2], p1->bl.e[i-1]); + ostringstream msg; + msg <<"bond broken between particles "<< p1->p.identity << ", " << p1->bl.e[i-3] << ", " << p1->bl.e[i-2] + << " and " << p1->bl.e[i-1] << " (particles not stored on the same node)"; + runtimeError(msg); return; } } @@ -482,6 +639,14 @@ inline void add_bonded_force(Particle *p1) case BONDED_IA_HARMONIC: bond_broken = calc_harmonic_pair_force(p1, p2, iaparams, dx, force); break; + case BONDED_IA_QUARTIC: + bond_broken = calc_quartic_pair_force(p1, p2, iaparams, dx, force); + break; +#ifdef ELECTROSTATICS + case BONDED_IA_BONDED_COULOMB: + bond_broken = calc_bonded_coulomb_pair_force(p1, p2, iaparams, dx, force); + break; +#endif case BONDED_IA_STRETCHING_FORCE: bond_broken = calc_stretching_force_pair_force(p1, p2, iaparams, dx, force); break; @@ -559,8 +724,9 @@ inline void add_bonded_force(Particle *p1) bond_broken = calc_tab_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{081 add_bonded_force: tabulated bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg << "add_bonded_force: tabulated bond type of atom "<< p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -578,8 +744,9 @@ inline void add_bonded_force(Particle *p1) bond_broken = calc_overlap_dihedral_force(p1, p2, p3, p4, iaparams, force, force2, force3); break; default: - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{081 add_bonded_force: overlapped bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg <<"add_bonded_force: overlapped bond type of atom "<< p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -591,31 +758,22 @@ inline void add_bonded_force(Particle *p1) break; #endif default : - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{082 add_bonded_force: bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg <<"add_bonded_force: bond type of atom "<< p1->p.identity << " unknown\n"; + runtimeError(msg); return; } switch (n_partners) { case 1: if (bond_broken) { - char *errtext = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{083 bond broken between particles %d and %d} ", - p1->p.identity, p2->p.identity); - continue; + ostringstream msg; + msg <<"bond broken between particles " << p1->p.identity << " and " << p2->p.identity; + runtimeError(msg); + continue; } -#ifdef ADRESS - force_weight = adress_bonded_force_weight(p1,p2); -#endif - for (j = 0; j < 3; j++) { -#ifdef ADRESS - tmp=force_weight*force[j]; - p1->f.f[j] += tmp; - p2->f.f[j] -= tmp; -#else // ADRESS - switch (type) { #ifdef BOND_ENDANGLEDIST case BONDED_IA_ENDANGLEDIST: @@ -631,7 +789,6 @@ inline void add_bonded_force(Particle *p1) p2->f.torque[j] += torque2[j]; #endif } -#endif // NOT ADRESS #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) @@ -641,21 +798,14 @@ inline void add_bonded_force(Particle *p1) break; case 2: if (bond_broken) { - char *errtext = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{084 bond broken between particles %d, %d and %d} ", - p1->p.identity, p2->p.identity, p3->p.identity); + ostringstream msg; + msg << "bond broken between particles "<< p1->p.identity << ", " << p2->p.identity << " and " + << p3->p.identity; + runtimeError(msg); continue; } -#ifdef ADRESS - force_weight=adress_angle_force_weight(p1,p2,p3); -#endif for (j = 0; j < 3; j++) { -#ifdef ADRESS - p1->f.f[j] += force_weight*force[j]; - p2->f.f[j] += force_weight*force2[j]; - p3->f.f[j] -= force_weight*(force[j] + force2[j]); -#else switch (type) { case BONDED_IA_AREA_FORCE_LOCAL: p1->f.f[j] += force[j]; @@ -675,27 +825,17 @@ switch (type) { p2->f.f[j] += force2[j]; p3->f.f[j] -= (force[j] + force2[j]); } -#endif } break; case 3: if (bond_broken) { - char *errtext = runtime_error(128 + 4*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtext,"{085 bond broken between particles %d, %d, %d and %d} ", - p1->p.identity, p2->p.identity, p3->p.identity, p4->p.identity); + ostringstream msg; + msg << "bond broken between particles "<< p1->p.identity << ", " << p2->p.identity + << ", " << p3->p.identity << " and " << p4->p.identity; + runtimeError(msg); continue; } -#ifdef ADRESS - force_weight=adress_dihedral_force_weight(p1,p2,p3,p4); -#endif for (j = 0; j < 3; j++) { -#ifdef ADRESS - p1->f.f[j] += force_weight*force[j]; - p2->f.f[j] += force_weight*force2[j]; - p3->f.f[j] += force_weight*force3[j]; - p4->f.f[j] -= force_weight*(force[j] + force2[j] + force3[j]); -#else - switch (type) { case BONDED_IA_BENDING_FORCE: p1->f.f[j] -= (force[j]*0.5+force2[j]*0.5); @@ -709,8 +849,6 @@ switch (type) { p3->f.f[j] += force3[j]; p4->f.f[j] -= (force[j] + force2[j] + force3[j]); } - -#endif } break; } @@ -720,36 +858,32 @@ switch (type) { /** add force to another. This is used when collecting ghost forces. */ inline void add_force(ParticleForce *F_to, ParticleForce *F_add) { - int i; - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) F_to->f[i] += F_add->f[i]; #ifdef ROTATION - for (i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) F_to->torque[i] += F_add->torque[i]; #endif } -inline void check_particle_force(Particle *part) -{ - - int i; - for (i=0; i< 3; i++) { +inline void check_particle_force(Particle *part) { + for (int i=0; i< 3; i++) { if (isnan(part->f.f[i])) { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{999 force on particle was NAN.} "); + ostringstream msg; + msg << "force on particle "<< part->p.identity << " was NAN."; + runtimeError(msg); } } #ifdef ROTATION - for (i=0; i< 3; i++) { + for (int i=0; i< 3; i++) { if (isnan(part->f.torque[i])) { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{999 force on particle was NAN.} "); + ostringstream msg; + msg << "force on particle "<< part->p.identity << " was NAN."; + runtimeError(msg); } } #endif } -/*@}*/ - #endif diff --git a/src/galilei.cpp b/src/core/galilei.cpp similarity index 91% rename from src/galilei.cpp rename to src/core/galilei.cpp index 2e2772dabc7..1c66850bb25 100644 --- a/src/galilei.cpp +++ b/src/core/galilei.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file galilei.c +/** \file galilei.cpp * */ #include "galilei.hpp" #include "utils.hpp" +#include "cells.hpp" +#include "grid.hpp" #include "initialize.hpp" #include "forces.hpp" @@ -112,7 +114,15 @@ void local_system_CMS( double *sdata ) { memcpy(ppos, part[i].r.p, 3*sizeof(double)); memcpy(img, part[i].l.i, 3*sizeof(int)); +#ifdef LEES_EDWARDS +{ + double pv[3]; + memcpy(pv, part[i].m.v, 3*sizeof(double)); + unfold_position(ppos, pv, img); +} +#else unfold_position(ppos, img); +#endif x += M*ppos[0]; y += M*ppos[1]; @@ -139,7 +149,15 @@ void local_system_CMS( double *sdata ) { memcpy(ppos, part[i].r.p, 3*sizeof(double)); memcpy(img, part[i].l.i, 3*sizeof(int)); +#ifdef LEES_EDWARDS +{ + double pv[3]; + memcpy(pv, part[i].m.v, 3*sizeof(double)); + unfold_position(ppos, pv, img); +} +#else unfold_position(ppos, img); +#endif x += ppos[0]; y += ppos[1]; diff --git a/src/galilei.hpp b/src/core/galilei.hpp similarity index 94% rename from src/galilei.hpp rename to src/core/galilei.hpp index 33f99790c63..4888527c807 100644 --- a/src/galilei.hpp +++ b/src/core/galilei.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef GALILEI_H #define GALILEI_H -/** \file galilei.h +/** \file galilei.hpp * */ diff --git a/src/gaussian.cpp b/src/core/gaussian.cpp similarity index 91% rename from src/gaussian.cpp rename to src/core/gaussian.cpp index 9bb9285976d..1044fa5f1a0 100644 --- a/src/gaussian.cpp +++ b/src/core/gaussian.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file gaussian.c +/** \file gaussian.cpp * - * Implementation of \ref gaussian.h + * Implementation of \ref gaussian.hpp */ #include "gaussian.hpp" #include "communication.hpp" diff --git a/src/gaussian.hpp b/src/core/gaussian.hpp similarity index 96% rename from src/gaussian.hpp rename to src/core/gaussian.hpp index 32b264bf5f2..2fd9b85fb12 100644 --- a/src/gaussian.hpp +++ b/src/core/gaussian.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef GAUSSIAN_H #define GAUSSIAN_H -/** \file gaussian.h +/** \file gaussian.hpp * Routines to calculate the Gaussian energy and/or force * for a particle pair. */ diff --git a/src/gb.cpp b/src/core/gb.cpp similarity index 93% rename from src/gb.cpp rename to src/core/gb.cpp index 34076c96ea7..dafd5290aa8 100644 --- a/src/gb.cpp +++ b/src/core/gb.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file gb.c +/** \file gb.cpp * - * Implementation of \ref gb.h + * Implementation of \ref gb.hpp */ #include "gb.hpp" #include "communication.hpp" diff --git a/src/gb.hpp b/src/core/gb.hpp similarity index 90% rename from src/gb.hpp rename to src/core/gb.hpp index 51477102ceb..6b6547238cd 100644 --- a/src/gb.hpp +++ b/src/core/gb.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,13 +18,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef GB_H -#define GB_H +#ifndef _GB_HPP +#define _GB_HPP -/** \file gb.h +/** \file gb.hpp * Routines to calculate the Gay-Berne energy and force * for a pair of particles. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -41,7 +41,8 @@ int gay_berne_set_params(int part_type_a, int part_type_b, double mu, double nu); inline void add_gb_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_params, - double d[3], double dist, double force[3], double torque1[3], double torque2[3]) + double d[3], double dist, double force[3], + double torque1[3], double torque2[3]) { if (!CUTOFF_CHECK(dist < ia_params->GB_cut)) @@ -117,6 +118,7 @@ inline void add_gb_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_para force[1] += FikY; force[2] += FikZ; + if (torque1 != NULL) { /* calculate torque: torque = u_1 x G */ Gx = -dU_da*d[0] - dU_dc*u2x; @@ -127,15 +129,18 @@ inline void add_gb_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_para torque1[1]+= u1z*Gx - u1x*Gz; torque1[2]+= u1x*Gy - u1y*Gx; - /* calculate torque: torque = u_2 x G */ - - Gx = -dU_db*d[0] - dU_dc*u1x; - Gy = -dU_db*d[1] - dU_dc*u1y; - Gz = -dU_db*d[2] - dU_dc*u1z; - - torque2[0]+= u2y*Gz - u2z*Gy; - torque2[1]+= u2z*Gx - u2x*Gz; - torque2[2]+= u2x*Gy - u2y*Gx; + if (torque2 != NULL) { + /* calculate torque: torque = u_2 x G */ + + Gx = -dU_db*d[0] - dU_dc*u1x; + Gy = -dU_db*d[1] - dU_dc*u1y; + Gz = -dU_db*d[2] - dU_dc*u1z; + + torque2[0]+= u2y*Gz - u2z*Gy; + torque2[1]+= u2z*Gx - u2x*Gz; + torque2[2]+= u2x*Gy - u2y*Gx; + } + } } else { /* the particles are too close to each other */ Koef1 = 100; diff --git a/config/gen_featureconfig.py b/src/core/gen_featureconfig.py similarity index 69% rename from config/gen_featureconfig.py rename to src/core/gen_featureconfig.py index 165ff3b009c..e8ef9424e6d 100644 --- a/config/gen_featureconfig.py +++ b/src/core/gen_featureconfig.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -18,20 +18,26 @@ # # This script generates the files featureconfig.h and featureconfig.c. # -import sys, featuredefs, time, string +from __future__ import print_function +import time, string +import inspect, sys, os +# find featuredefs.py +moduledir = os.path.dirname(inspect.getfile(inspect.currentframe())) +sys.path.append(os.path.join(moduledir, '..')) +import featuredefs if len(sys.argv) != 4: - print >> sys.stderr, "Usage: %s DEFFILE HPPFILE CPPFILE" % sys.argv[0] + print("Usage: {} DEFFILE HPPFILE CPPFILE".format(sys.argv[0]), file=sys.stderr) exit(2) -deffilename, hfilename, cfilename = sys.argv[1:4] +deffilename, hfilename, cfilename = sys.argv[1:5] -print "Reading definitions from " + deffilename + "..." +print("Reading definitions from " + deffilename + "...") defs = featuredefs.defs(deffilename) -print "Done." +print("Done.") -print "Writing " + hfilename + "..." -hfile = file(hfilename, 'w'); +print("Writing " + hfilename + "...") +hfile = open(hfilename, 'w'); hfile.write("""/* WARNING: This file was autogenerated by @@ -78,17 +84,19 @@ #endif /* of _FEATURECONFIG_HPP */""") hfile.close() -print "Done." +print("Done.") -print "Writing " + cfilename + "..." -cfile = file(cfilename, 'w'); +print("Writing " + cfilename + "...") +cfile = open(cfilename, 'w'); # handle requirements cfile.write("""/* WARNING: This file was autogenerated by - %s on %s + {script} + on + {date} Do not modify it or your changes will be overwritten! Modify features.def instead. @@ -97,18 +105,20 @@ /* config.hpp includes config-features.hpp and myconfig.hpp */ #include "config.hpp" -""" % (sys.argv[0], time.asctime())) +""".format(script=sys.argv[0], date=time.asctime())) cfile.write('/* Handle requirements */') -requirement_template = string.Template(""" -// $feature requires $expr -#if defined($feature) && !($cppexpr) -#error Feature $feature requires $expr +requirement_string = """ +// {feature} requires {expr} +#if defined({feature}) && !({cppexpr}) +#error Feature {feature} requires {expr} #endif -""") +""" for feature, expr, cppexpr in defs.requirements: - cfile.write(requirement_template.substitute(feature=feature, cppexpr=cppexpr, expr=expr)) + cfile.write( + requirement_string.format( + feature=feature, cppexpr=cppexpr, expr=expr)) cfile.write(""" @@ -116,15 +126,14 @@ const char* FEATURES[] = { """) -featurestring_template = string.Template( -"""#ifdef $feature - "$feature", +feature_string = """ +#ifdef {feature} + "{feature}", #endif -""") -for feature in defs.externals: - cfile.write(featurestring_template.substitute(feature=feature)) -for feature in defs.features: - cfile.write(featurestring_template.substitute(feature=feature)) +""" + +for feature in defs.externals.union(defs.features, defs.derived): + cfile.write(feature_string.format(feature=feature)) cfile.write(""" }; @@ -133,4 +142,4 @@ """); cfile.close() -print "Done." +print("Done.") diff --git a/src/ghmc.cpp b/src/core/ghmc.cpp similarity index 98% rename from src/ghmc.cpp rename to src/core/ghmc.cpp index 005122f0323..a889e2ffbd2 100644 --- a/src/ghmc.cpp +++ b/src/core/ghmc.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany This file is part of ESPResSo. @@ -17,13 +17,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file ghmc.c +/** \file ghmc.cpp - For more information see \ref ghmc.h + For more information see \ref ghmc.hpp */ #include #include "utils.hpp" +#include "integrate.hpp" +#include "thermostat.hpp" #include "ghmc.hpp" #include "random.hpp" @@ -282,8 +284,8 @@ void tscale_momentum_update() double tempt, tempr; calc_kinetic(&tempt, &tempr); - tempt /= (1.5*n_total_particles); - tempr /= (1.5*n_total_particles); + tempt /= (1.5*n_part); + tempr /= (1.5*n_part); double scalet = sqrt(temperature / tempt); #ifdef ROTATION @@ -524,4 +526,4 @@ void ghmc_mc() /*@}*/ -#endif \ No newline at end of file +#endif diff --git a/src/ghmc.hpp b/src/core/ghmc.hpp similarity index 97% rename from src/ghmc.hpp rename to src/core/ghmc.hpp index 64caff305a0..ae39487d3f7 100644 --- a/src/ghmc.hpp +++ b/src/core/ghmc.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany This file is part of ESPResSo. @@ -19,7 +19,7 @@ */ #ifndef GHMC_H #define GHMC_H -/** \file ghmc.h +/** \file ghmc.hpp This file contains the implementation of the GHMC (Generalized Hybrid Monte Carlo) thermostat. diff --git a/src/ghosts.cpp b/src/core/ghosts.cpp similarity index 63% rename from src/ghosts.cpp rename to src/core/ghosts.cpp index 10092834919..72c7dec41d0 100644 --- a/src/ghosts.cpp +++ b/src/core/ghosts.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,15 +18,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file ghosts.c Ghost particles and particle exchange. +/** \file ghosts.cpp Ghost particles and particle exchange. * * For more information on ghosts, - * see \ref ghosts.h "ghosts.h" + * see \ref ghosts.hpp "ghosts.hpp" */ #include #include #include #include +#include +#include #include "utils.hpp" #include "ghosts.hpp" #include "global.hpp" @@ -34,7 +36,7 @@ #include "communication.hpp" #include "grid.hpp" #include "particle_data.hpp" -#include "forces.hpp" +#include "forces_inline.hpp" /** Tag for communication in ghost_comm. */ #define REQ_GHOST_SEND 100 @@ -44,23 +46,23 @@ static int max_s_buffer = 0; /** send buffer. Just grows, which should be ok */ static char *s_buffer = NULL; +std::vector s_bondbuffer; + static int n_r_buffer = 0; static int max_r_buffer = 0; /** recv buffer. Just grows, which should be ok */ static char *r_buffer = NULL; +std::vector r_bondbuffer; + static MPI_Op MPI_FORCES_SUM; -/** wether the ghosts should also have velocity information, e. g. for DPD or RATTLE. +/** whether the ghosts should also have velocity information, e. g. for DPD or RATTLE. You need this whenever you need the relative velocity of two particles. NO CHANGES OF THIS VALUE OUTSIDE OF \ref on_ghost_flags_change !!!! */ int ghosts_have_v = 0; -/************************************************************ - * Exported Functions - ************************************************************/ - void prepare_comm(GhostCommunicator *comm, int data_parts, int num) { int i; @@ -92,7 +94,7 @@ int calc_transmit_size(GhostCommunication *gc, int data_parts) { int p, n_buffer_new; - if (data_parts == GHOSTTRANS_PARTNUM) + if (data_parts & GHOSTTRANS_PARTNUM) n_buffer_new = sizeof(int)*gc->n_part_lists; else { int count = 0; @@ -100,8 +102,16 @@ int calc_transmit_size(GhostCommunication *gc, int data_parts) count += gc->part_lists[p]->n; n_buffer_new = 0; - if (data_parts & GHOSTTRANS_PROPRTS) + if (data_parts & GHOSTTRANS_PROPRTS) { n_buffer_new += sizeof(ParticleProperties); + // sending size of bond/exclusion lists +#ifdef GHOSTS_HAVE_BONDS + n_buffer_new += sizeof(int); +#ifdef EXCLUSIONS + n_buffer_new += sizeof(int); +#endif +#endif + } if (data_parts & GHOSTTRANS_POSITION) n_buffer_new += sizeof(ParticlePosition); if (data_parts & GHOSTTRANS_MOMENTUM) @@ -114,15 +124,14 @@ int calc_transmit_size(GhostCommunication *gc, int data_parts) #endif n_buffer_new *= count; } + // also sending length of bond buffer + if (data_parts & GHOSTTRANS_PROPRTS) + n_buffer_new += sizeof(int); return n_buffer_new; } void prepare_send_buffer(GhostCommunication *gc, int data_parts) { - char *insert; - int pl, p, np; - Particle *part, *pt; - GHOST_TRACE(fprintf(stderr, "%d: prepare sending to/bcast from %d\n", this_node, gc->node)); /* reallocate send buffer */ @@ -133,32 +142,50 @@ void prepare_send_buffer(GhostCommunication *gc, int data_parts) } GHOST_TRACE(fprintf(stderr, "%d: will send %d\n", this_node, n_s_buffer)); + s_bondbuffer.resize(0); + /* put in data */ - insert = s_buffer; - for (pl = 0; pl < gc->n_part_lists; pl++) { - np = gc->part_lists[pl]->n; - if (data_parts == GHOSTTRANS_PARTNUM) { + char *insert = s_buffer; + for (int pl = 0; pl < gc->n_part_lists; pl++) { + int np = gc->part_lists[pl]->n; + if (data_parts & GHOSTTRANS_PARTNUM) { *(int *)insert = np; insert += sizeof(int); GHOST_TRACE(fprintf(stderr, "%d: %d particles assigned\n", this_node, np)); } else { - part = gc->part_lists[pl]->part; - for (p = 0; p < np; p++) { - pt = &part[p]; + Particle *part = gc->part_lists[pl]->part; + for (int p = 0; p < np; p++) { + Particle *pt = &part[p]; if (data_parts & GHOSTTRANS_PROPRTS) { memcpy(insert, &pt->p, sizeof(ParticleProperties)); insert += sizeof(ParticleProperties); +#ifdef GHOSTS_HAVE_BONDS + *(int *)insert = pt->bl.n; + insert += sizeof(int); + if (pt->bl.n) { + s_bondbuffer.insert(s_bondbuffer.end(), pt->bl.e, pt->bl.e + pt->bl.n); + } +#ifdef EXCLUSIONS + *(int *)insert = pt->el.n; + insert += sizeof(int); + if (pt->el.n) { + s_bondbuffer.insert(s_bondbuffer.end(), pt->el.e, pt->el.e + pt->el.n); + } +#endif +#endif } if (data_parts & GHOSTTRANS_POSSHFTD) { /* ok, this is not nice, but perhaps fast */ ParticlePosition *pp = (ParticlePosition *)insert; int i; memcpy(pp, &pt->r, sizeof(ParticlePosition)); - //fprintf(stderr,"%d prep_send_buf: ghost %d shift %f,%f,%f\n",this_node,pt->p.identity,gc->shift[0],gc->shift[1],gc->shift[2]); for (i = 0; i < 3; i++) pp->p[i] += gc->shift[i]; + /* No special wrapping for Lees-Edwards here: + * LE wrap-on-receive instead, for convenience in + * mapping to local cell geometry. */ insert += sizeof(ParticlePosition); } else if (data_parts & GHOSTTRANS_POSITION) { @@ -182,14 +209,55 @@ void prepare_send_buffer(GhostCommunication *gc, int data_parts) } } } -#ifdef ADDITIONAL_CHECKS + if (data_parts & GHOSTTRANS_PROPRTS) { + GHOST_TRACE(fprintf(stderr, "%d: bond buffer size is %ld\n", + this_node, s_bondbuffer.size())); + *(int *)insert = int(s_bondbuffer.size()); + insert += sizeof(int); + } + if (insert - s_buffer != n_s_buffer) { fprintf(stderr, "%d: INTERNAL ERROR: send buffer size %d " - "differs from what I put in %ld\n", + "differs from what I put in (%ld)\n", this_node, n_s_buffer, insert - s_buffer); errexit(); } +} + +static void prepare_ghost_cell(Cell *cell, int size) +{ +#ifdef GHOSTS_HAVE_BONDS + // free all allocated information, will be resent + { + int np = cell->n; + Particle *part = cell->part; + for (int p = 0; p < np; p++) { + free_particle(part + p); + } + } +#endif + realloc_particlelist(cell, cell->n = size); + // invalidate pointers etc + { + int np = cell->n; + Particle *part = cell->part; + for (int p = 0; p < np; p++) { + Particle *pt = &part[p]; + // no bonds or exclusions + pt->bl.e = 0; + pt->bl.n = 0; + pt->bl.max = 0; +#ifdef EXCLUSIONS + pt->el.e = 0; + pt->el.n = 0; + pt->el.max = 0; #endif +#ifdef GHOST_FLAG + //init ghost variable + pt->l.ghost=1; +#endif + } + } } void prepare_recv_buffer(GhostCommunication *gc, int data_parts) @@ -206,54 +274,78 @@ void prepare_recv_buffer(GhostCommunication *gc, int data_parts) void put_recv_buffer(GhostCommunication *gc, int data_parts) { - int pl, p, np; - Particle *part, *pt; - char *retrieve; - /* put back data */ - retrieve = r_buffer; - for (pl = 0; pl < gc->n_part_lists; pl++) { - if (data_parts == GHOSTTRANS_PARTNUM) { + char *retrieve = r_buffer; + + std::vector::const_iterator bond_retrieve = r_bondbuffer.begin(); + + for (int pl = 0; pl < gc->n_part_lists; pl++) { + ParticleList *cur_list = gc->part_lists[pl]; + if (data_parts & GHOSTTRANS_PARTNUM) { GHOST_TRACE(fprintf(stderr, "%d: reallocating cell %p to size %d, assigned to node %d\n", - this_node, gc->part_lists[pl], *(int *)retrieve, gc->node)); - realloc_particlelist(gc->part_lists[pl], gc->part_lists[pl]->n = *(int *)retrieve); -#ifdef GHOST_FLAG - { - //init ghost variable - int i; - for (i=0;ipart_lists[pl]->n;i++){ - gc->part_lists[pl]->part[i].l.ghost=1; - } - } -#endif + this_node, cur_list, *(int *)retrieve, gc->node)); + prepare_ghost_cell(cur_list, *(int *)retrieve); retrieve += sizeof(int); } else { - np = gc->part_lists[pl]->n; - part = gc->part_lists[pl]->part; - for (p = 0; p < np; p++) { - pt = &part[p]; + int np = cur_list->n; + Particle *part = cur_list->part; + for (int p = 0; p < np; p++) { + Particle *pt = &part[p]; if (data_parts & GHOSTTRANS_PROPRTS) { memcpy(&pt->p, retrieve, sizeof(ParticleProperties)); retrieve += sizeof(ParticleProperties); - /* GHOST_TRACE(fprintf(stderr, "%d: received ghost %d", this_node, pt->p.identity)); */ +#ifdef GHOSTS_HAVE_BONDS + int n_bonds; + memcpy(&n_bonds, retrieve, sizeof(int)); + retrieve += sizeof(int); + if (n_bonds) { + realloc_intlist(&pt->bl, pt->bl.n = n_bonds); + std::copy(bond_retrieve, bond_retrieve + n_bonds, pt->bl.e); + bond_retrieve += n_bonds; + } +#ifdef EXCLUSIONS + memcpy(&n_bonds, retrieve, sizeof(int)); + retrieve += sizeof(int); + if (n_bonds) { + realloc_intlist(&pt->el, pt->el.n = n_bonds); + std::copy(bond_retrieve, bond_retrieve + n_bonds, pt->el.e); + bond_retrieve += n_bonds; + } +#endif +#endif if (local_particles[pt->p.identity] == NULL) { - /* GHOST_TRACE(fprintf(stderr, ", using.\n")); */ local_particles[pt->p.identity] = pt; } - /* - else { - GHOST_TRACE(fprintf(stderr, ", already here.\n")); - } - */ } if (data_parts & GHOSTTRANS_POSITION) { memcpy(&pt->r, retrieve, sizeof(ParticlePosition)); retrieve += sizeof(ParticlePosition); +#ifdef LEES_EDWARDS + /* special wrapping conditions for x component of y LE shift */ + if( gc->shift[1] != 0.0 ){ + /* LE transforms are wrapped + ---Using this method because its a shortcut to getting a neat-looking verlet list. */ + if( pt->r.p[0] + - (my_left[0] + cur_list->myIndex[0]*dd.cell_size[0]) > 2*dd.cell_size[0] ) + pt->r.p[0]-=box_l[0]; + if( pt->r.p[0] + - (my_left[0] + cur_list->myIndex[0]*dd.cell_size[0]) < -2*dd.cell_size[0] ) + pt->r.p[0]+=box_l[0]; + } +#endif } if (data_parts & GHOSTTRANS_MOMENTUM) { memcpy(&pt->m, retrieve, sizeof(ParticleMomentum)); retrieve += sizeof(ParticleMomentum); +#ifdef LEES_EDWARDS + /* give ghost particles correct velocity for the main + * non-ghost LE reference frame */ + if( gc->shift[1] > 0.0 ) + pt->m.v[0] += lees_edwards_rate; + else if( gc->shift[1] < 0.0 ) + pt->m.v[0] -= lees_edwards_rate; +#endif } if (data_parts & GHOSTTRANS_FORCE) { memcpy(&pt->f, retrieve, sizeof(ParticleForce)); @@ -268,14 +360,24 @@ void put_recv_buffer(GhostCommunication *gc, int data_parts) } } } -#ifdef ADDITIONAL_CHECKS + + if (data_parts & GHOSTTRANS_PROPRTS) { + // skip the final information on bonds to be sent in a second round + retrieve += sizeof(int); + } + if (retrieve - r_buffer != n_r_buffer) { fprintf(stderr, "%d: recv buffer size %d differs " - "from what I put in %ld\n", + "from what I read out (%ld)\n", this_node, n_r_buffer, retrieve - r_buffer); errexit(); } -#endif + if (bond_retrieve != r_bondbuffer.end()) { + fprintf(stderr, "%d: recv bond buffer was not used up, %ld elements remain\n", + this_node, r_bondbuffer.end() - bond_retrieve ); + errexit(); + } + r_bondbuffer.resize(0); } void add_forces_from_recv_buffer(GhostCommunication *gc) @@ -295,19 +397,17 @@ void add_forces_from_recv_buffer(GhostCommunication *gc) retrieve += sizeof(ParticleForce); } } -#ifdef ADDITIONAL_CHECKS if (retrieve - r_buffer != n_r_buffer) { fprintf(stderr, "%d: recv buffer size %d differs " - "from what I put in %ld\n", + "from what I put in %ld\n", this_node, n_r_buffer, retrieve - r_buffer); errexit(); } -#endif } void cell_cell_transfer(GhostCommunication *gc, int data_parts) { - int pl, p, np, offset; + int pl, p, offset; Particle *part1, *part2, *pt1, *pt2; GHOST_TRACE(fprintf(stderr, "%d: local_transfer: type %d data_parts %d\n", this_node,gc->type,data_parts)); @@ -315,39 +415,61 @@ void cell_cell_transfer(GhostCommunication *gc, int data_parts) /* transfer data */ offset = gc->n_part_lists/2; for (pl = 0; pl < offset; pl++) { - np = gc->part_lists[pl]->n; - if (data_parts == GHOSTTRANS_PARTNUM) { - realloc_particlelist(gc->part_lists[pl + offset], - gc->part_lists[pl + offset]->n = gc->part_lists[pl]->n); -#ifdef GHOST_FLAG - { - //init ghost variable - int i; - for (i=0;ipart_lists[pl + offset]->n;i++){ - gc->part_lists[pl + offset]->part[i].l.ghost=1; - } - } -#endif + Cell *src_list = gc->part_lists[pl]; + Cell *dst_list = gc->part_lists[pl + offset]; + + if (data_parts & GHOSTTRANS_PARTNUM) { + prepare_ghost_cell(dst_list, src_list->n); } else { - part1 = gc->part_lists[pl]->part; - part2 = gc->part_lists[pl + offset]->part; + int np = src_list->n; + part1 = src_list->part; + part2 = dst_list->part; for (p = 0; p < np; p++) { pt1 = &part1[p]; pt2 = &part2[p]; - if (data_parts & GHOSTTRANS_PROPRTS) + if (data_parts & GHOSTTRANS_PROPRTS) { memcpy(&pt2->p, &pt1->p, sizeof(ParticleProperties)); +#ifdef GHOSTS_HAVE_BONDS + realloc_intlist(&(pt2->bl), pt2->bl.n = pt1->bl.n); + memcpy(&pt2->bl.e, &pt1->bl.e, pt1->bl.n*sizeof(int)); +#ifdef EXCLUSIONS + realloc_intlist(&(pt2->el), pt2->el.n = pt1->el.n); + memcpy(&pt2->el.e, &pt1->el.e, pt1->el.n*sizeof(int)); +#endif +#endif + } if (data_parts & GHOSTTRANS_POSSHFTD) { /* ok, this is not nice, but perhaps fast */ int i; memcpy(&pt2->r, &pt1->r, sizeof(ParticlePosition)); for (i = 0; i < 3; i++) pt2->r.p[i] += gc->shift[i]; +#ifdef LEES_EDWARDS + /* special wrapping conditions for x component of y LE shift */ + if( gc->shift[1] != 0.0 ){ + /* LE transforms are wrapped */ + if( pt2->r.p[0] + - (my_left[0] + dst_list->myIndex[0]*dd.cell_size[0]) > 2*dd.cell_size[0] ) + pt2->r.p[0]-=box_l[0]; + if( pt2->r.p[0] + - (my_left[0] + dst_list->myIndex[0]*dd.cell_size[0]) < -2*dd.cell_size[0] ) + pt2->r.p[0]+=box_l[0]; + } +#endif } else if (data_parts & GHOSTTRANS_POSITION) memcpy(&pt2->r, &pt1->r, sizeof(ParticlePosition)); - if (data_parts & GHOSTTRANS_MOMENTUM) + if (data_parts & GHOSTTRANS_MOMENTUM) { memcpy(&pt2->m, &pt1->m, sizeof(ParticleMomentum)); +#ifdef LEES_EDWARDS + /* special wrapping conditions for x component of y LE shift */ + if( gc->shift[1] > 0.0 ) + pt2->m.v[0] += lees_edwards_rate; + else if( gc->shift[1] < 0.0 ) + pt2->m.v[0] -= lees_edwards_rate; +#endif + } if (data_parts & GHOSTTRANS_FORCE) add_force(&pt2->f, &pt1->f); #ifdef LB @@ -366,12 +488,10 @@ void reduce_forces_sum(void *add, void *to, int *len, MPI_Datatype *type) *cto = (ParticleForce*)to; int i, clen = *len/sizeof(ParticleForce); -#ifdef ADDITIONAL_CHECKS if (*type != MPI_BYTE || (*len % sizeof(ParticleForce)) != 0) { fprintf(stderr, "%d: transfer data type wrong\n", this_node); errexit(); } -#endif for (i = 0; i < clen; i++) add_force(&cto[i], &cadd[i]); @@ -380,14 +500,14 @@ void reduce_forces_sum(void *add, void *to, int *len, MPI_Datatype *type) static int is_send_op(int comm_type, int node) { return ((comm_type == GHOST_SEND) || (comm_type == GHOST_RDCE) || - (comm_type == GHOST_BCST && node == this_node)); + (comm_type == GHOST_BCST && node == this_node)); } static int is_recv_op(int comm_type, int node) { return ((comm_type == GHOST_RECV) || - (comm_type == GHOST_BCST && node != this_node) || - (comm_type == GHOST_RDCE && node == this_node)); + (comm_type == GHOST_BCST && node != this_node) || + (comm_type == GHOST_RDCE && node == this_node)); } void ghost_communicator(GhostCommunicator *gc) @@ -445,25 +565,61 @@ void ghost_communicator(GhostCommunicator *gc) /* recv buffer for recv and multinode operations to this node */ if (is_recv_op(comm_type, node)) - prepare_recv_buffer(gcn, data_parts); + prepare_recv_buffer(gcn, data_parts); /* transfer data */ switch (comm_type) { - case GHOST_RECV: + case GHOST_RECV: { GHOST_TRACE(fprintf(stderr, "%d: ghost_comm receive from %d (%d bytes)\n", this_node, node, n_r_buffer)); MPI_Recv(r_buffer, n_r_buffer, MPI_BYTE, node, REQ_GHOST_SEND, comm_cart, &status); + if (data_parts & GHOSTTRANS_PROPRTS) { + int n_bonds = *(int *)(r_buffer + n_r_buffer - sizeof(int)); + GHOST_TRACE(fprintf(stderr, "%d: ghost_comm receive from %d (%d bonds)\n", this_node, node, n_bonds)); + if (n_bonds) { + r_bondbuffer.resize(n_bonds); + MPI_Recv(&r_bondbuffer[0], n_bonds, MPI_INT, node, REQ_GHOST_SEND, comm_cart, &status); + } + } break; - case GHOST_SEND: + } + case GHOST_SEND: { GHOST_TRACE(fprintf(stderr, "%d: ghost_comm send to %d (%d bytes)\n", this_node, node, n_s_buffer)); MPI_Send(s_buffer, n_s_buffer, MPI_BYTE, node, REQ_GHOST_SEND, comm_cart); - break; + int n_bonds = s_bondbuffer.size(); + if (!(data_parts & GHOSTTRANS_PROPRTS) && n_bonds > 0) { + fprintf(stderr, "%d: INTERNAL ERROR: not sending properties, but bond buffer not empty\n", this_node); + errexit(); + } + GHOST_TRACE(fprintf(stderr, "%d: ghost_comm send to %d (%d ints)\n", this_node, node, n_bonds)); + if (n_bonds) { + MPI_Send(&s_bondbuffer[0], n_bonds, MPI_INT, node, REQ_GHOST_SEND, comm_cart); + } + break; + } case GHOST_BCST: GHOST_TRACE(fprintf(stderr, "%d: ghost_comm bcast from %d (%d bytes)\n", this_node, node, (node == this_node) ? n_s_buffer : n_r_buffer)); - if (node == this_node) + if (node == this_node) { MPI_Bcast(s_buffer, n_s_buffer, MPI_BYTE, node, comm_cart); - else + int n_bonds = s_bondbuffer.size(); + if (!(data_parts & GHOSTTRANS_PROPRTS) && n_bonds > 0) { + fprintf(stderr, "%d: INTERNAL ERROR: not sending properties, but bond buffer not empty\n", this_node); + errexit(); + } + if (n_bonds) { + MPI_Bcast(&s_bondbuffer[0], n_bonds, MPI_INT, node, comm_cart); + } + } + else { MPI_Bcast(r_buffer, n_r_buffer, MPI_BYTE, node, comm_cart); + if (data_parts & GHOSTTRANS_PROPRTS) { + int n_bonds = *(int *)(r_buffer + n_r_buffer - sizeof(int)); + if (n_bonds) { + r_bondbuffer.resize(n_bonds); + MPI_Bcast(&r_bondbuffer[0], n_bonds, MPI_INT, node, comm_cart); + } + } + } break; case GHOST_RDCE: GHOST_TRACE(fprintf(stderr, "%d: ghost_comm reduce to %d (%d bytes)\n", this_node, node, n_s_buffer)); diff --git a/src/ghosts.hpp b/src/core/ghosts.hpp similarity index 98% rename from src/ghosts.hpp rename to src/core/ghosts.hpp index d424529a283..aebe9ebc4ed 100644 --- a/src/ghosts.hpp +++ b/src/core/ghosts.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _GHOSTS_H #define _GHOSTS_H -/** \file ghosts.h Ghost particles and particle exchange. +/** \file ghosts.hpp Ghost particles and particle exchange. In this file you find everything concerning the exchange of particle data (particles, ghosts, positions and forces) for short diff --git a/src/global.cpp b/src/core/global.cpp similarity index 60% rename from src/global.cpp rename to src/core/global.cpp index 51f91c20a33..e26eae9aedb 100644 --- a/src/global.cpp +++ b/src/core/global.cpp @@ -1,7 +1,7 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group + Max-Planck-Institute for Polymer Research, Theory Group This file is part of ESPResSo. @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file global.c - Implementation of \ref global.h "global.h". +/** \file global.cpp + Implementation of \ref global.hpp "global.h". */ #include "utils.hpp" #include "global.hpp" @@ -27,9 +27,9 @@ #include "domain_decomposition.hpp" #include "dpd.hpp" #include "layered.hpp" +#include "lees_edwards.hpp" #include "npt.hpp" #include "tuning.hpp" -#include "adresso.hpp" #include "rattle.hpp" #include "imd.hpp" #include "ghmc.hpp" @@ -40,57 +40,61 @@ Please declare where the variables come from. */ const Datafield fields[] = { - {box_l, TYPE_DOUBLE, 3, "box_l", 1 }, /* 0 from grid.c */ - {dd.cell_grid, TYPE_INT, 3, "cell_grid", 6 }, /* 1 from cells.c */ - {dd.cell_size, TYPE_DOUBLE, 3, "cell_size", 6 }, /* 2 from cells.c */ - {&dpd_gamma, TYPE_DOUBLE, 1, "dpd_gamma", 5 }, /* 3 from thermostat.c */ - {&dpd_r_cut, TYPE_DOUBLE, 1, "dpd_r_cut", 5 }, /* 4 from thermostat.c */ - {&langevin_gamma, TYPE_DOUBLE, 1, "gamma", 1 }, /* 5 from thermostat.c */ - {&integ_switch, TYPE_INT, 1, "integ_switch", 1 }, /* 6 from integrate.c */ - {local_box_l, TYPE_DOUBLE, 3, "local_box_l", 2 }, /* 7 from global.c */ - {&max_cut, TYPE_DOUBLE, 1, "max_cut", 7 }, /* 8 from interaction_data.c */ - {&max_num_cells, TYPE_INT, 1, "max_num_cells", 5 }, /* 9 from cells.c */ - {&max_seen_particle, TYPE_INT, 1, "max_part", 5 }, /* 10 from particle_data.c */ - {&max_range, TYPE_DOUBLE, 1, "max_range", 5 }, /* 11 from integrate.c */ - {&max_skin, TYPE_DOUBLE, 1, "max_skin", 5 }, /* 12 from integrate.c */ - {&min_num_cells, TYPE_INT, 1, "min_num_cells", 5 }, /* 13 from cells.c */ - {&n_layers, TYPE_INT, 1, "n_layers", 3 }, /* 14 from layered.c */ - {&n_nodes, TYPE_INT, 1, "n_nodes", 3 }, /* 15 from communication.c */ - {&n_total_particles, TYPE_INT, 1, "n_part", 6 }, /* 16 from particle.c */ - {&n_particle_types, TYPE_INT, 1, "n_part_types", 8 }, /* 17 from interaction_data.c */ - {&n_rigidbonds, TYPE_INT, 1, "n_rigidbonds", 5 }, /* 18 from rattle.c */ - {node_grid, TYPE_INT, 3, "node_grid", 2 }, /* 19 from grid.c */ - {&nptiso_gamma0, TYPE_DOUBLE, 1, "nptiso_gamma0", 13 }, /* 20 from thermostat.c */ - {&nptiso_gammav, TYPE_DOUBLE, 1, "nptiso_gammav", 13 }, /* 21 from thermostat.c */ - {&nptiso.p_ext, TYPE_DOUBLE, 1, "npt_p_ext", 7 }, /* 22 from pressure.c */ - {&nptiso.p_inst, TYPE_DOUBLE, 1, "npt_p_inst", 10 }, /* 23 from pressure.c */ - {&nptiso.p_inst_av,TYPE_DOUBLE, 1, "npt_p_inst_av", 10 }, /* 24 from pressure.c */ - {&nptiso.p_diff, TYPE_DOUBLE, 1, "npt_p_diff", 7 }, /* 25 from pressure.c */ - {&nptiso.piston, TYPE_DOUBLE, 1, "npt_piston", 6 }, /* 26 from pressure.c */ - {&periodic, TYPE_BOOL, 3, "periodicity", 1 }, /* 27 from grid.c */ - {&skin, TYPE_DOUBLE, 1, "skin", 2 }, /* 28 from integrate.c */ - {&temperature, TYPE_DOUBLE, 1, "temperature", 2 }, /* 29 from thermostat.c */ - {&thermo_switch, TYPE_INT, 1, "thermo_switch", 2 }, /* 30 from thermostat.c */ - {&sim_time, TYPE_DOUBLE, 1, "time", 4 }, /* 31 from integrate.c */ - {&time_step, TYPE_DOUBLE, 1, "time_step", 5 }, /* 32 from integrate.c */ - {&timing_samples, TYPE_INT, 1, "timings", 4 }, /* 33 from tuning.c */ - {&transfer_rate, TYPE_INT, 1, "transfer_rate", 2 }, /* 34 from imd.c */ - {&max_cut_nonbonded,TYPE_DOUBLE, 1, "max_cut_nonbonded",9 }, /* 35 from interaction_data.c */ - {&verlet_reuse, TYPE_DOUBLE, 1, "verlet_reuse", 8 }, /* 36 from integrate.c */ - {&lattice_switch, TYPE_INT, 1, "lattice_switch", 2 }, /* 37 from lattice.c */ - {&dpd_tgamma, TYPE_DOUBLE, 1, "dpd_tgamma", 6 }, /* 38 from thermostat.c */ - {&dpd_tr_cut, TYPE_DOUBLE, 1, "dpd_tr_cut", 6 }, /* 39 from thermostat.c */ - {&dpd_twf, TYPE_INT, 1, "dpd_twf", 6 }, /* 40 from thermostat.c */ - {&dpd_wf, TYPE_INT, 1, "dpd_wf", 5 }, /* 41 from thermostat.c */ - {adress_vars, TYPE_DOUBLE, 7, "adress_vars", 1 }, /* 42 from adresso.c */ - {&max_cut_bonded, TYPE_DOUBLE, 1, "max_cut_bonded", 9 }, /* 43 from interaction_data.c */ - {&transfer_rate, TYPE_INT, 1, "vmd_transfer_rate", 5 }, /* 44 from imd_tcl.c */ - {&min_global_cut, TYPE_DOUBLE, 1, "min_global_cut", 5 }, /* 45 from interaction_data.c */ - {&ghmc_nmd, TYPE_INT, 1, "ghmc_nmd", 6 }, /* 46 from thermostat.c */ - {&ghmc_phi, TYPE_DOUBLE, 1, "ghmc_phi", 6 }, /* 47 from thermostat.c */ - {&ghmc_mc_res, TYPE_INT, 1, "ghmc_mc_res", 7 }, /* 48 from ghmc.c */ - {&ghmc_mflip, TYPE_INT, 1, "ghmc_mflip", 7 }, /* 49 from ghmc.c */ - {&ghmc_tscale, TYPE_INT, 1, "ghmc_tscale", 6 }, /* 50 from ghmc.c */ - {&lb_components, TYPE_INT, 1, "lb_components", 2 }, /* 51 from ghmc.c */ + {box_l, TYPE_DOUBLE, 3, "box_l", 1 }, /* 0 from grid.cpp */ + {dd.cell_grid, TYPE_INT, 3, "cell_grid", 6 }, /* 1 from cells.cpp */ + {dd.cell_size, TYPE_DOUBLE, 3, "cell_size", 6 }, /* 2 from cells.cpp */ + {&dpd_gamma, TYPE_DOUBLE, 1, "dpd_gamma", 5 }, /* 3 from thermostat.cpp */ + {&dpd_r_cut, TYPE_DOUBLE, 1, "dpd_r_cut", 5 }, /* 4 from thermostat.cpp */ + {&langevin_gamma, TYPE_DOUBLE, 1, "gamma", 1 }, /* 5 from thermostat.cpp */ + {&lees_edwards_offset, TYPE_DOUBLE, 1, "lees_edwards_offset", 2 }, /* 6 from lees_edwards.cpp */ + {&integ_switch, TYPE_INT, 1, "integ_switch", 1 }, /* 7 from integrate.cpp */ + {local_box_l, TYPE_DOUBLE, 3, "local_box_l", 2 }, /* 8 from global.cpp */ + {&max_cut, TYPE_DOUBLE, 1, "max_cut", 7 }, /* 9 from interaction_data.cpp */ + {&max_num_cells, TYPE_INT, 1, "max_num_cells", 5 }, /* 10 from cells.cpp */ + {&max_seen_particle, TYPE_INT, 1, "max_part", 5 }, /* 11 from particle_data.cpp */ + {&max_range, TYPE_DOUBLE, 1, "max_range", 5 }, /* 12 from integrate.cpp */ + {&max_skin, TYPE_DOUBLE, 1, "max_skin", 5 }, /* 13 from integrate.cpp */ + {&min_num_cells, TYPE_INT, 1, "min_num_cells", 5 }, /* 14 from cells.cpp */ + {&n_layers, TYPE_INT, 1, "n_layers", 3 }, /* 15 from layered.cpp */ + {&n_nodes, TYPE_INT, 1, "n_nodes", 3 }, /* 16 from communication.cpp */ + {&n_part, TYPE_INT, 1, "n_part", 6 }, /* 17 from particle.cpp */ + {&n_particle_types, TYPE_INT, 1, "n_part_types", 8 }, /* 18 from interaction_data.cpp */ + {&n_rigidbonds, TYPE_INT, 1, "n_rigidbonds", 5 }, /* 19 from rattle.cpp */ + {node_grid, TYPE_INT, 3, "node_grid", 2 }, /* 20 from grid.cpp */ + {&nptiso_gamma0, TYPE_DOUBLE, 1, "nptiso_gamma0", 13 }, /* 21 from thermostat.cpp */ + {&nptiso_gammav, TYPE_DOUBLE, 1, "nptiso_gammav", 13 }, /* 22 from thermostat.cpp */ + {&nptiso.p_ext, TYPE_DOUBLE, 1, "npt_p_ext", 7 }, /* 23 from pressure.cpp */ + {&nptiso.p_inst, TYPE_DOUBLE, 1, "npt_p_inst", 10 }, /* 24 from pressure.cpp */ + {&nptiso.p_inst_av,TYPE_DOUBLE, 1, "npt_p_inst_av", 10 }, /* 25 from pressure.cpp */ + {&nptiso.p_diff, TYPE_DOUBLE, 1, "npt_p_diff", 7 }, /* 26 from pressure.cpp */ + {&nptiso.piston, TYPE_DOUBLE, 1, "npt_piston", 6 }, /* 27 from pressure.cpp */ + {&periodic, TYPE_BOOL, 3, "periodicity", 1 }, /* 28 from grid.cpp */ + {&skin, TYPE_DOUBLE, 1, "skin", 2 }, /* 29 from integrate.cpp */ + {&temperature, TYPE_DOUBLE, 1, "temperature", 2 }, /* 30 from thermostat.cpp */ + {&thermo_switch, TYPE_INT, 1, "thermo_switch", 2 }, /* 31 from thermostat.cpp */ + {&sim_time, TYPE_DOUBLE, 1, "time", 4 }, /* 32 from integrate.cpp */ + {&time_step, TYPE_DOUBLE, 1, "time_step", 5 }, /* 33 from integrate.cpp */ + {&timing_samples, TYPE_INT, 1, "timings", 4 }, /* 34 from tuning.cpp */ + {&transfer_rate, TYPE_INT, 1, "transfer_rate", 2 }, /* 35 from imd.cpp */ + {&max_cut_nonbonded,TYPE_DOUBLE, 1, "max_cut_nonbonded",9 }, /* 36 from interaction_data.cpp */ + {&verlet_reuse, TYPE_DOUBLE, 1, "verlet_reuse", 8 }, /* 37 from integrate.cpp */ + {&lattice_switch, TYPE_INT, 1, "lattice_switch", 2 }, /* 38 from lattice.cpp */ + {&dpd_tgamma, TYPE_DOUBLE, 1, "dpd_tgamma", 6 }, /* 39 from thermostat.cpp */ + {&dpd_tr_cut, TYPE_DOUBLE, 1, "dpd_tr_cut", 6 }, /* 40 from thermostat.cpp */ + {&dpd_twf, TYPE_INT, 1, "dpd_twf", 6 }, /* 41 from thermostat.cpp */ + {&dpd_wf, TYPE_INT, 1, "dpd_wf", 5 }, /* 42 from thermostat.cpp */ + {&max_cut_bonded, TYPE_DOUBLE, 1, "max_cut_bonded", 9 }, /* 43 from interaction_data.cpp */ + {&transfer_rate, TYPE_INT, 1, "vmd_transfer_rate", 5 }, /* 44 from imd_tcl.cpp */ + {&min_global_cut, TYPE_DOUBLE, 1, "min_global_cut", 5 }, /* 45 from interaction_data.cpp */ + {&ghmc_nmd, TYPE_INT, 1, "ghmc_nmd", 6 }, /* 46 from thermostat.cpp */ + {&ghmc_phi, TYPE_DOUBLE, 1, "ghmc_phi", 6 }, /* 47 from thermostat.cpp */ + {&ghmc_mc_res, TYPE_INT, 1, "ghmc_mc_res", 7 }, /* 48 from ghmc.cpp */ + {&ghmc_mflip, TYPE_INT, 1, "ghmc_mflip", 7 }, /* 49 from ghmc.cpp */ + {&ghmc_tscale, TYPE_INT, 1, "ghmc_tscale", 6 }, /* 50 from ghmc.cpp */ + {&lb_components, TYPE_INT, 1, "lb_components", 2 }, /* 51 from ghmc.cpp */ + {&warnings, TYPE_INT, 1, "warnings", 1 }, /* 52 from global.cpp */ + {&dpd_ignore_fixed_particles, TYPE_INT, 1, "dpd_ignore_fixed_particles", 1 }, /* 53 from global.cpp */ { NULL, 0, 0, NULL, 0 } }; + +int warnings = 1; diff --git a/src/global.hpp b/src/core/global.hpp similarity index 74% rename from src/global.hpp rename to src/core/global.hpp index 541cf6923cc..745df40e49c 100644 --- a/src/global.hpp +++ b/src/core/global.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef GLOBAL_H -#define GLOBAL_H -/** \file global.h This file contains the code for access to globally +#ifndef _GLOBAL_HPP +#define _GLOBAL_HPP +/** \file global.hpp This file contains the code for access to globally defined variables using the script command setmd. Please refer to the Developer's guide, section "Adding global variables", for details on how to add new variables in the interpreter's @@ -29,7 +29,7 @@ /********************************************** * description of global variables * add any variable that should be handled - * automatically in global.c. This includes + * automatically in global.cpp. This includes * distribution to other nodes and * read/user-defined access from Tcl. **********************************************/ @@ -66,7 +66,7 @@ typedef struct { /** This array contains the description of all global variables that are synchronized across nodes and that can be changed/adressed via the TCL command setmd. read the documentation of \ref Datafield - befor you add new features. */ + before you add new features. */ extern const Datafield fields[]; /** \name Field Enumeration @@ -86,80 +86,80 @@ extern const Datafield fields[]; #define FIELD_DPD_RCUT 4 /** index of \ref langevin_gamma in \ref #fields */ #define FIELD_LANGEVIN_GAMMA 5 +/** index of \ref lees_edwards_offset in \ref #fields */ +#define FIELD_LEES_EDWARDS_OFFSET 6 /** index of \ref integ_switch in \ref #fields */ -#define FIELD_INTEG_SWITCH 6 +#define FIELD_INTEG_SWITCH 7 /** index of \ref local_box_l in \ref #fields */ -#define FIELD_LBOXL 7 +#define FIELD_LBOXL 8 /** index of \ref max_cut in \ref #fields */ -#define FIELD_MCUT 8 +#define FIELD_MCUT 9 /** index of \ref max_num_cells in \ref #fields */ -#define FIELD_MAXNUMCELLS 9 +#define FIELD_MAXNUMCELLS 10 /** index of \ref max_seen_particle in \ref #fields */ -#define FIELD_MAXPART 10 +#define FIELD_MAXPART 11 /** index of \ref max_range in \ref #fields */ -#define FIELD_MAXRANGE 11 +#define FIELD_MAXRANGE 12 /** index of \ref max_skin in \ref #fields */ -#define FIELD_MAXSKIN 12 +#define FIELD_MAXSKIN 13 /** index of \ref min_num_cells in \ref #fields */ -#define FIELD_MINNUMCELLS 13 +#define FIELD_MINNUMCELLS 14 /** index of \ref n_layers in \ref #fields */ -#define FIELD_NLAYERS 14 +#define FIELD_NLAYERS 15 /** index of \ref n_nodes in \ref #fields */ -#define FIELD_NNODES 15 -/** index of \ref n_total_particles in \ref #fields */ -#define FIELD_NPART 16 +#define FIELD_NNODES 16 +/** index of \ref n_part in \ref #fields */ +#define FIELD_NPART 17 /** index of \ref n_particle_types in \ref #fields */ -#define FIELD_NPARTTYPE 17 +#define FIELD_NPARTTYPE 18 /** index of \ref n_rigidbonds in \ref #fields */ -#define FIELD_RIGIDBONDS 18 +#define FIELD_RIGIDBONDS 19 /** index of \ref node_grid in \ref #fields */ -#define FIELD_NODEGRID 19 +#define FIELD_NODEGRID 20 /** index of \ref nptiso_gamma0 in \ref #fields */ -#define FIELD_NPTISO_G0 20 +#define FIELD_NPTISO_G0 21 /** index of \ref nptiso_gammav in \ref #fields */ -#define FIELD_NPTISO_GV 21 +#define FIELD_NPTISO_GV 22 /** index of \ref nptiso_struct::p_ext in \ref #fields */ -#define FIELD_NPTISO_PEXT 22 +#define FIELD_NPTISO_PEXT 23 /** index of \ref nptiso_struct::p_inst in \ref #fields */ -#define FIELD_NPTISO_PINST 23 +#define FIELD_NPTISO_PINST 24 /** index of \ref nptiso_struct::p_inst_av in \ref #fields */ -#define FIELD_NPTISO_PINSTAV 24 +#define FIELD_NPTISO_PINSTAV 25 /** index of \ref nptiso_struct::p_diff in \ref #fields */ -#define FIELD_NPTISO_PDIFF 25 +#define FIELD_NPTISO_PDIFF 26 /** index of \ref nptiso_struct::piston in \ref #fields */ -#define FIELD_NPTISO_PISTON 26 +#define FIELD_NPTISO_PISTON 27 /** index of \ref #periodic in \ref #fields */ -#define FIELD_PERIODIC 27 +#define FIELD_PERIODIC 28 /** index of \ref #skin in \ref #fields */ -#define FIELD_SKIN 28 +#define FIELD_SKIN 29 /** index of \ref #temperature in \ref #fields */ -#define FIELD_TEMPERATURE 29 +#define FIELD_TEMPERATURE 30 /** index of \ref thermo_switch in \ref #fields */ -#define FIELD_THERMO_SWITCH 30 +#define FIELD_THERMO_SWITCH 31 /** index of \ref sim_time in \ref #fields */ -#define FIELD_SIMTIME 31 +#define FIELD_SIMTIME 32 /** index of \ref time_step in \ref #fields */ -#define FIELD_TIMESTEP 32 +#define FIELD_TIMESTEP 33 /** index of \ref timing_samples in \ref #fields */ -#define FIELD_TIMINGSAMP 33 +#define FIELD_TIMINGSAMP 34 /** index of \ref transfer_rate in \ref #fields */ -#define FIELD_TRANSFERRATE 34 +#define FIELD_TRANSFERRATE 35 /** index of \ref max_cut_nonbonded in \ref #fields */ -#define FIELD_MCUT_NONBONDED 35 +#define FIELD_MCUT_NONBONDED 36 /** index of \ref verlet_reuse in \ref #fields */ -#define FIELD_VERLETREUSE 36 +#define FIELD_VERLETREUSE 37 /** index of \ref lattice_switch in \ref #fields */ -#define FIELD_LATTICE_SWITCH 37 +#define FIELD_LATTICE_SWITCH 38 /** index of \ref dpd_tgamma in \ref #fields */ -#define FIELD_DPD_TGAMMA 38 +#define FIELD_DPD_TGAMMA 39 /** index of \ref dpd_tr_cut in \ref #fields */ -#define FIELD_DPD_TRCUT 39 +#define FIELD_DPD_TRCUT 40 /** index of \ref dpd_twf in \ref #fields */ -#define FIELD_DPD_TWF 40 +#define FIELD_DPD_TWF 41 /** index of \ref dpd_wf in \ref #fields */ -#define FIELD_DPD_WF 41 -/** index of address variable in \ref #fields */ -#define FIELD_ADRESS 42 +#define FIELD_DPD_WF 42 /** index of \ref max_cut_bonded in \ref #fields */ #define FIELD_MCUT_BONDED 43 /** index of \ref transfer_rate in \ref #fields */ @@ -178,6 +178,13 @@ extern const Datafield fields[]; #define FIELD_GHMC_SCALE 50 /** index of \ref lb_components in \ref #fields */ #define FIELD_LB_COMPONENTS 51 +/** index of \ref warnings in \ref #fields */ +#define FIELD_WARNINGS 52 +/** DPD_IGNORE_FIXED_PARTICLES */ +#define FIELD_DPD_IGNORE_FIXED_PARTICLES 53 /*@}*/ +/** bool: whether to write out warnings or not */ +extern int warnings; + #endif diff --git a/src/grid.cpp b/src/core/grid.cpp similarity index 55% rename from src/grid.cpp rename to src/core/grid.cpp index e790f1b3a1a..48e8854c3b6 100644 --- a/src/grid.cpp +++ b/src/core/grid.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file grid.c Domain decomposition for parallel computing. +/** \file grid.cpp Domain decomposition for parallel computing. * * For more information on the domain decomposition, - * see \ref grid.h "grid.h". + * see \ref grid.hpp "grid.h". */ #include #include @@ -29,6 +29,7 @@ #include #include #include "utils.hpp" +#include "global.hpp" #include "grid.hpp" #include "communication.hpp" #include "verlet.hpp" @@ -47,8 +48,15 @@ int node_grid[3] = { 0, 0, 0}; int node_pos[3] = {-1,-1,-1}; +#ifdef LEES_EDWARDS +int *node_neighbors; +int *node_neighbor_wrap; +int *node_neighbor_lr; +int my_neighbor_count; +#else int node_neighbors[6] = {0, 0, 0, 0, 0, 0}; -int boundary[6] = {0, 0, 0, 0, 0, 0}; +#endif +int boundary[6] = {0, 0, 0, 0, 0, 0}; int periodic = 7; double box_l[3] = {1, 1, 1}; @@ -79,8 +87,13 @@ int map_position_node_array(double pos[3]) for (i = 0; i < 3; i++) f_pos[i] = pos[i]; - + +#ifdef LEES_EDWARDS + double vel_scratch[3]={0.,0.,0.}; + fold_position(f_pos, vel_scratch, im); +#else fold_position(f_pos, im); +#endif for (i = 0; i < 3; i++) { im[i] = (int)floor(node_grid[i]*f_pos[i]*box_l_i[i]); @@ -93,15 +106,45 @@ int map_position_node_array(double pos[3]) return map_array_node(im); } -void calc_node_neighbors(int node) +int calc_node_neighbors(int node) { - int dir; - + + int dir, neighbor_count; +#ifdef LEES_EDWARDS + node_neighbors = (int *)realloc(node_neighbors, 6 * sizeof(int)); + node_neighbor_lr = (int *)realloc(node_neighbor_lr, 6 * sizeof(int)); + node_neighbor_wrap = (int *)realloc(node_neighbor_wrap, 6 * sizeof(int)); +#endif + map_node_array(node,node_pos); for(dir=0;dir<3;dir++) { int buf; - MPI_Cart_shift(comm_cart, dir, -1, &buf, node_neighbors + 2*dir); - MPI_Cart_shift(comm_cart, dir, 1, &buf, node_neighbors + 2*dir + 1); + +#ifndef LEES_EDWARDS + + MPI_Cart_shift(comm_cart, dir, -1, &buf, &(node_neighbors[2*dir])); + MPI_Cart_shift(comm_cart, dir, 1, &buf, &(node_neighbors[2*dir + 1])); + +#else + + /* Writes to node_neighbors[] the integer rank of that neighbor + * ... the 'buf' stores own rank, which is discarded. */ + if( node_pos[dir] % 2 == 0 ){ + MPI_Cart_shift(comm_cart, dir, -1, &buf, &(node_neighbors[2*dir])); + MPI_Cart_shift(comm_cart, dir, 1, &buf, &(node_neighbors[2*dir + 1])); + + node_neighbor_lr[2*dir] = 0; + node_neighbor_lr[2*dir+1] = 1; + + }else{ + MPI_Cart_shift(comm_cart, dir, 1, &buf, &(node_neighbors[2*dir])); + MPI_Cart_shift(comm_cart, dir, -1, &buf, &(node_neighbors[2*dir + 1])); + + node_neighbor_lr[2*dir] = 1; + node_neighbor_lr[2*dir+1] = 0; + } + +#endif /* left boundary ? */ if (node_pos[dir] == 0) { @@ -111,14 +154,97 @@ void calc_node_neighbors(int node) boundary[2*dir] = 0; } /* right boundary ? */ - if (node_pos[dir] == node_grid[dir]-1) { + if (node_pos[dir] == node_grid[dir]-1) { boundary[2*dir+1] = -1; } else { boundary[2*dir+1] = 0; } } + + + neighbor_count = 6; +#ifdef LEES_EDWARDS + if( boundary[2] == 1 || boundary[3] == -1 ){ + + int x_index, abs_coords[3]; + + abs_coords[2] = node_pos[2]; /* z constant */ + + if( ( boundary[2] == 1 && boundary[3] != -1) || ( boundary[3] == -1 && boundary[2] != 1) ){ + node_neighbors = (int *)realloc(node_neighbors, (neighbor_count + node_grid[0] - 1)*sizeof(int)); + node_neighbor_lr = (int *)realloc(node_neighbor_lr, (neighbor_count + node_grid[0] - 1)*sizeof(int)); + node_neighbor_wrap = (int *)realloc(node_neighbor_wrap, (neighbor_count + node_grid[0] - 1)*sizeof(int)); + }else if( boundary[3] == -1 && boundary[2] == 1){ + node_neighbors = (int *)realloc(node_neighbors, (neighbor_count + 2 * node_grid[0] - 2)*sizeof(int)); + node_neighbor_lr = (int *)realloc(node_neighbor_lr, (neighbor_count + 2 * node_grid[0] - 2)*sizeof(int)); + node_neighbor_wrap = (int *)realloc(node_neighbor_wrap, (neighbor_count + 2 * node_grid[0] - 2)*sizeof(int)); + } + + + for( x_index = 0; x_index < node_grid[0]; x_index++){ + if( x_index != node_pos[0] ){ + abs_coords[0] = x_index; + if( x_index > node_pos[0] ){ + if( boundary[2] == 1 ){ + abs_coords[1] = node_grid[1] - 1; /* wraps to upper y */ + node_neighbors[neighbor_count] = map_array_node(abs_coords); + node_neighbor_lr[neighbor_count] = 0; + neighbor_count++; + } + if( boundary[3] == -1 ){ + abs_coords[1] = 0; /* wraps to lower y */ + node_neighbors[neighbor_count] = map_array_node(abs_coords); + node_neighbor_lr[neighbor_count] = 1; + neighbor_count++; + } + }else{ + if( boundary[3] == -1 ){ + abs_coords[1] = 0; /* wraps to lower y */ + node_neighbors[neighbor_count] = map_array_node(abs_coords); + node_neighbor_lr[neighbor_count] = 1; + neighbor_count++; + } + if( boundary[2] == 1 ){ + abs_coords[1] = node_grid[1] - 1; /* wraps to upper y */ + node_neighbors[neighbor_count] = map_array_node(abs_coords); + node_neighbor_lr[neighbor_count] = 0; + neighbor_count++; + } + } + } + } + } +#else GRID_TRACE(printf("%d: node_grid %d %d %d, pos %d %d %d, node_neighbors ", this_node, node_grid[0], node_grid[1], node_grid[2], node_pos[0], node_pos[1], node_pos[2])); +#endif + + +#ifdef LEES_EDWARDS + my_neighbor_count = neighbor_count;/* set the global neighbor count */ + for(neighbor_count = 0; neighbor_count < my_neighbor_count; neighbor_count++ ){ + + if( neighbor_count < 6 ) dir = neighbor_count / 2; + else dir = 1; + + if( boundary[2*dir] == 1 && node_neighbor_lr[neighbor_count] == 0 ){ + node_neighbor_wrap[neighbor_count] = 1; + } + else if(boundary[2*dir + 1] == -1 && node_neighbor_lr[neighbor_count] == 1 ){ + node_neighbor_wrap[neighbor_count] = -1; + }else{ + node_neighbor_wrap[neighbor_count] = 0; + } + + } + GRID_TRACE( + for( dir=0; dir < my_neighbor_count; dir++){ fprintf(stderr, "%d: neighbour %d --> %d lr: %i wrap: %i\n", this_node, dir,node_neighbors[dir],node_neighbor_lr[dir],node_neighbor_wrap[dir]);} + ); +#endif + + + return( neighbor_count ); + } void grid_changed_box_l() diff --git a/src/grid.hpp b/src/core/grid.hpp similarity index 65% rename from src/grid.hpp rename to src/core/grid.hpp index 68d7c63fb79..7fb10f7c86f 100644 --- a/src/grid.hpp +++ b/src/core/grid.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _GRID_H #define _GRID_H -/** \file grid.h Domain decomposition for parallel computing. +/** \file grid.hpp Domain decomposition for parallel computing. * * The primary simulation box is divided into orthogonal rectangular * subboxes which are assigned to the different nodes (or processes @@ -28,7 +28,7 @@ * node_grid. Each node has a number \ref this_node and a position * \ref node_pos in that grid. Each node has also 6 nearest neighbors * \ref node_neighbors which are necessary for the communication - * between the nodes (see also \ref ghosts.c and \ref p3m.c for more + * between the nodes (see also \ref ghosts.cpp and \ref p3m.cpp for more * details about the communication. * * For the 6 directions \anchor directions we have the following convention: @@ -40,13 +40,16 @@ * (e.g \ref node_grid, \ref box_l , \ref my_left,...). * * - * For more information on the domain decomposition, see \ref grid.c "grid.c". + * For more information on the domain decomposition, see \ref grid.cpp "grid.c". */ +#include "lees_edwards.hpp" #include "utils.hpp" #include #include "communication.hpp" #include "errorhandling.hpp" +using namespace std; + /** Macro that tests for a coordinate being periodic or not. */ #ifdef PARTIAL_PERIODIC #define PERIODIC(coord) (periodic & (1L << coord)) @@ -62,8 +65,17 @@ extern int node_grid[3]; /** position of node in node grid */ extern int node_pos[3]; +#ifdef LEES_EDWARDS +/** the nearest neighbors of a node in the node grid. */ +extern int *node_neighbors; +extern int *node_neighbor_lr; +extern int *node_neighbor_wrap; +/** the number of nearest neighbors of a node in the node grid. */ +extern int my_neighbor_count; +#else /** the six nearest neighbors of a node in the node grid. */ extern int node_neighbors[6]; +#endif /** where to fold particles that leave local box in direction i. */ extern int boundary[6]; /** Flags for all three dimensions wether pbc are applied (default). @@ -129,11 +141,12 @@ int map_position_node_array(double pos[3]); /** fill neighbor lists of node. * - * Calculates the numbers of the 6 nearest neighbors for a node and - * stors them in \ref node_neighbors. + * Calculates the numbers of the nearest neighbors for a node and + * stores them in \ref node_neighbors. * + * \return the number of neighbors * \param node number of the node. */ -void calc_node_neighbors(int node); +int calc_node_neighbors(int node); /** called from \ref mpi_bcast_parameter . */ void grid_changed_n_nodes(); @@ -169,9 +182,11 @@ int map_3don2d_grid(int g3d[3],int g2d[3], int mult[3]); void rescale_boxl(int dir, double d_new); /** get the minimal distance vector of two vectors in the current bc. - @param a the vector to subtract from - @param b the vector to subtract - @param res where to store the result + * \ref LEES_EDWARDS note: there is no need to add the le_offset here, + * any offset should already have been added when the image particle was prepared. + * @param a the vector to subtract from + * @param b the vector to subtract + * @param res where to store the result */ inline void get_mi_vector(double res[3], double a[3], double b[3]) { @@ -186,6 +201,55 @@ inline void get_mi_vector(double res[3], double a[3], double b[3]) } } + + +#ifdef LEES_EDWARDS +/** fold a coordinate to primary simulation box. + \param pos the position... + \param vel the velocity... + \param image_box and the box + \param dir the coordinate to fold: dir = 0,1,2 for x, y and z coordinate. + + Both pos and image_box are I/O, + i. e. a previously folded position will be folded correctly. +*/ +inline void fold_coordinate(double pos[3], double vel[3], int image_box[3], int dir) +{ + if( dir != 1 ){ + int tmp; + + image_box[dir] += (tmp = (int)floor(pos[dir]*box_l_i[dir])); + pos[dir] = pos[dir] - tmp*box_l[dir]; + if(pos[dir] < 0 || pos[dir] >= box_l[dir]) { + /* slow but safe */ + if (fabs(pos[dir]*box_l_i[dir]) >= INT_MAX/2) { + ostringstream msg; + msg << "particle coordinate out of range, pos = " << pos[dir] << ", image box = " << image_box[dir]; + runtimeError(msg); + image_box[dir] = 0; + pos[dir] = 0; + } + } + }else{ + /* must image y and v_x at same time as x */ + int img_count; + img_count = (int)floor(pos[1]*box_l_i[1]); + pos[0] -= (lees_edwards_offset * img_count); + vel[0] -= (lees_edwards_rate * img_count); + + /* image y */ + image_box[1] += img_count; + pos[1] = pos[1] - img_count*box_l[1]; + + /* (re)-image x */ + img_count = (int)floor(pos[0]*box_l_i[0]); + image_box[0] += img_count; + pos[0] = pos[0] - img_count*box_l[0]; + + } +} +#else + /** fold a coordinate to primary simulation box. \param pos the position... \param image_box and the box @@ -204,15 +268,35 @@ inline void fold_coordinate(double pos[3], int image_box[3], int dir) image_box[dir] += (tmp = (int)floor(pos[dir]*box_l_i[dir])); pos[dir] = pos[dir] - tmp*box_l[dir]; if(pos[dir]*box_l_i[dir] < -ROUND_ERROR_PREC || pos[dir]*box_l_i[dir] >= 1 + ROUND_ERROR_PREC) { - char *errtext = runtime_error(128 + ES_INTEGER_SPACE + ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtext,"{086 particle coordinate out of range, pos = %g, image box = %d} ", pos[dir], image_box[dir]); + ostringstream msg; + msg << "particle coordinate out of range, pos = " << pos[dir] << ", image box = " << image_box[dir]; + runtimeError(msg); image_box[dir] = 0; pos[dir] = 0; return; } } } +#endif + +#ifdef LEES_EDWARDS +/** fold particle coordinates to primary simulation box. + \param pos the position... + \param vel the velocity... + \param image_box and the box + + Pos, vel and image_box are I/O, + i. e. a previously folded position will be folded correctly. +*/ +inline void fold_position(double pos[3], double vel[3], int image_box[3]) +{ + + int i; + for(i=0;i<3;i++) + fold_coordinate(pos, vel, image_box, i); +} +#else /** fold particle coordinates to primary simulation box. \param pos the position... \param image_box and the box @@ -226,7 +310,33 @@ inline void fold_position(double pos[3],int image_box[3]) for(i=0;i<3;i++) fold_coordinate(pos, image_box, i); } +#endif + +#ifdef LEES_EDWARDS +/** unfold coordinates to physical position. + \param pos the position + \param pos the velocity + \param image_box and the box + Both pos and image_box are I/O, i.e. image_box will be (0,0,0) + afterwards. +*/ +inline void unfold_position(double pos[3], double vel[3], int image_box[3]) +{ + int y_img_count; + y_img_count = (int)floor( pos[1]*box_l_i[1] + image_box[1] ); + + pos[0] += image_box[0]*box_l[0] + y_img_count*lees_edwards_offset; + pos[1] += image_box[1]*box_l[1]; + pos[2] += image_box[2]*box_l[2]; + + vel[0] += y_img_count * lees_edwards_rate; + + image_box[0] = image_box[1] = image_box[2] = 0; + + +} +#else /** unfold coordinates to physical position. \param pos the position... \param image_box and the box @@ -242,6 +352,7 @@ inline void unfold_position(double pos[3],int image_box[3]) image_box[i] = 0; } } +#endif /*@}*/ #endif diff --git a/src/halo.cpp b/src/core/halo.cpp similarity index 99% rename from src/halo.cpp rename to src/core/halo.cpp index d207a5f8dde..fa5c7a87665 100644 --- a/src/halo.cpp +++ b/src/core/halo.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file halo.c +/** \file halo.cpp * * Halo scheme for parallelization of lattice algorithms. - * Implementation of file \ref halo.h. + * Implementation of file \ref halo.hpp. * */ diff --git a/src/halo.hpp b/src/core/halo.hpp similarity index 98% rename from src/halo.hpp rename to src/core/halo.hpp index d26cc3befff..3b02048d916 100644 --- a/src/halo.hpp +++ b/src/core/halo.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file halo.h +/** \file halo.hpp * * Halo scheme for parallelization of lattice algorithms. - * Header file for \ref halo.c. + * Header file for \ref halo.cpp. * */ diff --git a/src/harmonic.cpp b/src/core/harmonic.cpp similarity index 91% rename from src/harmonic.cpp rename to src/core/harmonic.cpp index 56a437eb0db..822e319625f 100644 --- a/src/harmonic.cpp +++ b/src/core/harmonic.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file harmonic.c +/** \file harmonic.cpp * - * Implementation of \ref harmonic.h + * Implementation of \ref harmonic.hpp */ #include "harmonic.hpp" #include "communication.hpp" diff --git a/src/harmonic.hpp b/src/core/harmonic.hpp similarity index 92% rename from src/harmonic.hpp rename to src/core/harmonic.hpp index 15e70b459bf..df297ffa8e9 100644 --- a/src/harmonic.hpp +++ b/src/core/harmonic.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef HARMONIC_H -#define HARMONIC_H -/** \file harmonic.h +#ifndef _HARMONIC_HPP +#define _HARMONIC_HPP +/** \file harmonic.hpp * Routines to calculate the HARMONIC Energy or/and HARMONIC force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ /************************************************************/ @@ -37,10 +37,10 @@ int harmonic_set_params(int bond_type, double k, double r,double r_cut); /** Computes the HARMONIC pair force and adds this - force to the particle forces (see \ref interaction_data.c). + force to the particle forces (see \ref interaction_data.cpp). @param p1 Pointer to first particle. @param p2 Pointer to second/middle particle. - @param iaparams bond type number of the angle interaction (see \ref interaction_data.c). + @param iaparams bond type number of the angle interaction (see \ref interaction_data.cpp). @param dx particle distance vector @param force returns force of particle 1 @return 0. diff --git a/src/hat.cpp b/src/core/hat.cpp similarity index 90% rename from src/hat.cpp rename to src/core/hat.cpp index 666b0b60ef8..7815e2200a2 100644 --- a/src/hat.cpp +++ b/src/core/hat.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file soft_sphere.c +/** \file soft_sphere.cpp * - * Implementation of \ref soft_sphere.h + * Implementation of \ref soft_sphere.hpp */ #include "hat.hpp" #include "communication.hpp" diff --git a/src/hat.hpp b/src/core/hat.hpp similarity index 96% rename from src/hat.hpp rename to src/core/hat.hpp index 44090379702..b124b7f7cf2 100644 --- a/src/hat.hpp +++ b/src/core/hat.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef hat_H #define hat_H -/** \file soft_sphere.h +/** \file soft_sphere.hpp * Routines to calculate the soft-sphere energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/hertzian.cpp b/src/core/hertzian.cpp similarity index 90% rename from src/hertzian.cpp rename to src/core/hertzian.cpp index 957d1b66d36..b03bb14802c 100644 --- a/src/hertzian.cpp +++ b/src/core/hertzian.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file hertzian.c +/** \file hertzian.cpp * - * Implementation of \ref hertzian.h + * Implementation of \ref hertzian.hpp */ #include "hertzian.hpp" #include "communication.hpp" diff --git a/src/hertzian.hpp b/src/core/hertzian.hpp similarity index 95% rename from src/hertzian.hpp rename to src/core/hertzian.hpp index 7b051df0e16..b2c7389332a 100644 --- a/src/hertzian.hpp +++ b/src/core/hertzian.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef HERTZIAN_H #define HERTZIAN_H -/** \file hertzian.h +/** \file hertzian.hpp * Routines to calculate the Hertzian energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/iccp3m.cpp b/src/core/iccp3m.cpp similarity index 77% rename from src/iccp3m.cpp rename to src/core/iccp3m.cpp index 1161681e4e8..21f23254100 100644 --- a/src/iccp3m.cpp +++ b/src/core/iccp3m.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,8 +19,8 @@ along with this program. If not, see . */ -/** \file iccp3m.c - Detailed Information about the method is included in the corresponding header file \ref iccp3m.h. +/** \file iccp3m.cpp + Detailed Information about the method is included in the corresponding header file \ref iccp3m.hpp. */ #include @@ -85,6 +85,14 @@ void iccp3m_init(void){ iccp3m_cfg.extx = 0; iccp3m_cfg.exty = 0; iccp3m_cfg.extz = 0; + iccp3m_cfg.first_id = 0; + iccp3m_cfg.num_iteration=30; + iccp3m_cfg.convergence=1e-2; + iccp3m_cfg.relax=0.7; + iccp3m_cfg.eout=1; + iccp3m_cfg.citeration=0; + + } @@ -104,9 +112,11 @@ int bcast_iccp3m_cfg(void){ iccp3m_cfg.nvectorx = (double*) realloc (iccp3m_cfg.nvectorx ,(iccp3m_cfg.n_ic) * sizeof(double)); iccp3m_cfg.nvectory = (double*) realloc (iccp3m_cfg.nvectory ,(iccp3m_cfg.n_ic) * sizeof(double)); iccp3m_cfg.nvectorz = (double*) realloc (iccp3m_cfg.nvectorz ,(iccp3m_cfg.n_ic) * sizeof(double)); + iccp3m_cfg.sigma = (double*) realloc (iccp3m_cfg.sigma ,(iccp3m_cfg.n_ic) * sizeof(double)); } MPI_Bcast((int*)&iccp3m_cfg.num_iteration, 1, MPI_INT, 0, comm_cart); + MPI_Bcast((int*)&iccp3m_cfg.first_id, 1, MPI_INT, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.convergence, 1, MPI_DOUBLE, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.eout, 1, MPI_DOUBLE, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.relax, 1, MPI_DOUBLE, 0, comm_cart); @@ -119,6 +129,7 @@ int bcast_iccp3m_cfg(void){ MPI_Bcast((double*)&iccp3m_cfg.nvectorx[i], 1, MPI_DOUBLE, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.nvectory[i], 1, MPI_DOUBLE, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.nvectorz[i], 1, MPI_DOUBLE, 0, comm_cart); + MPI_Bcast((double*)&iccp3m_cfg.sigma[i], 1, MPI_DOUBLE, 0, comm_cart); } MPI_Bcast((double*)&iccp3m_cfg.extx, 1, MPI_DOUBLE, 0, comm_cart); MPI_Bcast((double*)&iccp3m_cfg.exty, 1, MPI_DOUBLE, 0, comm_cart); @@ -137,7 +148,6 @@ int iccp3m_iteration() { int c,np; Particle *part; int i, j,id; - char* errtxt; double globalmax; double f1, f2 = 0; @@ -145,8 +155,9 @@ int iccp3m_iteration() { l_b = coulomb.bjerrum; if((iccp3m_cfg.eout <= 0)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M: nonpositive dielectric constant is not allowed. Put a decent tcl error here\n"); + ostringstream msg; + msg <<"ICCP3M: nonpositive dielectric constant is not allowed. Put a decent tcl error here\n"; + runtimeError(msg); } @@ -160,8 +171,8 @@ int iccp3m_iteration() { part = cell->part; np = cell->n; for(i=0 ; i < np; i++) { - id = part[i].p.identity ; - if( id < iccp3m_cfg.n_ic ) { + if( part[i].p.identity < iccp3m_cfg.n_ic+iccp3m_cfg.first_id && part[i].p.identity >= iccp3m_cfg.first_id ) { + id = part[i].p.identity - iccp3m_cfg.first_id; /* the dielectric-related prefactor: */ del_eps = (iccp3m_cfg.ein[id]-iccp3m_cfg.eout)/(iccp3m_cfg.ein[id] + iccp3m_cfg.eout)/6.283185307; /* calculate the electric field at the certain position */ @@ -175,8 +186,9 @@ int iccp3m_iteration() { ez += iccp3m_cfg.extz; if (ex == 0 && ey == 0 && ez == 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M found zero electric field on a charge. This must never happen"); + ostringstream msg; + msg <<"ICCP3M found zero electric field on a charge. This must never happen"; + runtimeError(msg); } /* the dot product */ fdot = ex*iccp3m_cfg.nvectorx[id]+ @@ -184,54 +196,54 @@ int iccp3m_iteration() { ez*iccp3m_cfg.nvectorz[id]; /* recalculate the old charge density */ - hold=part[i].p.q/iccp3m_cfg.areas[id]; - /* determine if it is higher than the previously highest charge density */ - if(hold>fabs(hmax))hmax=fabs(hold); - f1 = (+del_eps*fdot/l_b); - // double f2 = (1- 0.5*(iccp3m_cfg.ein[id]-iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] ))*(iccp3m_cfg.sigma[id]); - if (iccp3m_cfg.sigma!=0) { - f2 = (2*iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] )*(iccp3m_cfg.sigma[id]); - } - - hnew=(1.-iccp3m_cfg.relax)*hold + (iccp3m_cfg.relax)*(f1 + f2); - difftemp=fabs( 2.*(hnew - hold)/(hold+hnew) ); /* relative variation: never use - an estimator which can be negative - here */ - if(difftemp > diff && part[i].p.q > 1e-5) - { - // if (fabs(difftemp - 1./(1./iccp3m_cfg.relax - 1.)) > 1e-10) - diff=difftemp; /* Take the largest error to check for convergence */ - } - part[i].p.q = hnew * iccp3m_cfg.areas[id]; - /* check if the charge now is more than 1e6, to determine if ICC still leads to reasonable results */ - /* this is kind a arbitrary measure but, does a good job spotting divergence !*/ - if(fabs(part[i].p.q) > 1e6) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{error occured 990 : too big charge assignment in iccp3m! q >1e6 , \ - assigned charge= %f } \n",part[i].p.q); - diff = 1e90; /* A very high value is used as error code */ - break; - } - } - } /* cell particles */ - // printf("cell %d w %d particles over (node %d)\n",c,np,this_node); fflush(stdout); - } /* local cells */ - iccp3m_cfg.citeration++; - MPI_Allreduce(&diff, &globalmax, 1,MPI_DOUBLE, MPI_MAX, comm_cart); - - if (globalmax < iccp3m_cfg.convergence) - break; - if ( diff > 1e89 ) /* Error happened */ - return iccp3m_cfg.citeration++; - - } /* iteration */ - //on_particle_change(); - - return iccp3m_cfg.citeration++; + hold=part[i].p.q/iccp3m_cfg.areas[id]; + /* determine if it is higher than the previously highest charge density */ + if(fabs(hold)>hmax)hmax=fabs(hold); + f1 = (+del_eps*fdot/l_b); +// double f2 = (1- 0.5*(iccp3m_cfg.ein[id]-iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] ))*(iccp3m_cfg.sigma[id]); + if (iccp3m_cfg.sigma!=0) { + f2 = (2*iccp3m_cfg.eout)/(iccp3m_cfg.eout + iccp3m_cfg.ein[id] )*(iccp3m_cfg.sigma[id]); + } + + hnew=(1.-iccp3m_cfg.relax)*hold + (iccp3m_cfg.relax)*(f1 + f2); + difftemp=fabs( 1*(hnew - hold)/(hmax + fabs(hnew+hold)) ); /* relative variation: never use + an estimator which can be negative + here */ + if(difftemp > diff && part[i].p.q > 1e-5) + { +// if (fabs(difftemp - 1./(1./iccp3m_cfg.relax - 1.)) > 1e-10) + diff=difftemp; /* Take the largest error to check for convergence */ + } + part[i].p.q = hnew * iccp3m_cfg.areas[id]; + /* check if the charge now is more than 1e6, to determine if ICC still leads to reasonable results */ + /* this is kind a arbitrary measure but, does a good job spotting divergence !*/ + if(fabs(part[i].p.q) > 1e6) { + ostringstream msg; + msg <<"too big charge assignment in iccp3m! q >1e6 , assigned charge= " << part[i].p.q << "\n"; + runtimeError(msg); + diff = 1e90; /* A very high value is used as error code */ + break; + } + } + } /* cell particles */ + // printf("cell %d w %d particles over (node %d)\n",c,np,this_node); fflush(stdout); + } /* local cells */ + iccp3m_cfg.citeration++; + MPI_Allreduce(&diff, &globalmax, 1,MPI_DOUBLE, MPI_MAX, comm_cart); + + if (globalmax < iccp3m_cfg.convergence) + break; + if ( diff > 1e89 ) /* Error happened */ + return iccp3m_cfg.citeration++; + + } /* iteration */ + on_particle_change(); + + return iccp3m_cfg.citeration; } void force_calc_iccp3m() { -/* The following ist mostly copied from forces.c */ +/* The following ist mostly copied from forces.cpp */ /* I don´t see the point of this part until there are electrical dipoles in Espresso, BTW, it generates a warning .. JJCP #ifdef DIPOLES @@ -334,7 +346,7 @@ void build_verlet_lists_and_calc_verlet_ia_iccp3m() int estimate, sum=0; fprintf(stderr,"%d: build_verlet_list_and_calc_verlet_ia:\n",this_node); /* estimate number of interactions: (0.5*n_part*ia_volume*density)/n_nodes */ - estimate = 0.5*n_total_particles*(4.0/3.0*PI*pow(max_cut_nonbonded,3.0))*(n_total_particles/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; + estimate = 0.5*n_part*(4.0/3.0*PI*pow(max_cut_nonbonded,3.0))*(n_part/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; if (!dd.use_vList) { fprintf(stderr, "%d: build_verlet_lists, but use_vList == 0\n", this_node); errexit(); } #endif @@ -512,7 +524,7 @@ void nsq_calculate_ia_iccp3m() void init_forces_iccp3m() { - /* copied from forces.c */ + /* copied from forces.cpp */ Cell *cell; Particle *p; int np, c, i; @@ -521,11 +533,11 @@ void init_forces_iccp3m() thermodynamic ensemble */ #ifdef NPT - char* errtxt; /* reset virial part of instantaneous pressure */ if(integ_switch == INTEG_METHOD_NPT_ISO){ - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{ICCP3M cannot be used with pressure coupling} "); + ostringstream msg; + msg << "ICCP3M cannot be used with pressure coupling"; + runtimeError(msg); } #endif @@ -557,40 +569,44 @@ void init_forces_iccp3m() void calc_long_range_forces_iccp3m() { #ifdef ELECTROSTATICS - char* errtxt; - /* calculate k-space part of electrostatic interaction. */ - if (!(coulomb.method == COULOMB_ELC_P3M || - coulomb.method == COULOMB_P3M || - coulomb.method == COULOMB_MMM2D || - coulomb.method == COULOMB_MMM1D) ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{ICCP3M implemented only for MMM1D,MMM2D,ELC or P3M "); - } - switch (coulomb.method) { + /* calculate k-space part of electrostatic interaction. */ + if (!(coulomb.method == COULOMB_ELC_P3M || + coulomb.method == COULOMB_P3M || + coulomb.method == COULOMB_MMM2D || + coulomb.method == COULOMB_MMM1D) ) { + ostringstream msg; + msg <<"ICCP3M implemented only for MMM1D,MMM2D,ELC or P3M "; + runtimeError(msg); + } + switch (coulomb.method) { #ifdef P3M - case COULOMB_ELC_P3M: - if (elc_params.dielectric_contrast_on) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{ICCP3M conflicts with ELC dielectric constrast"); - } - p3m_charge_assign(); - p3m_calc_kspace_forces(1,0); - ELC_add_force(); - break; - - case COULOMB_P3M: - p3m_charge_assign(); - p3m_calc_kspace_forces(1,0); - break; + case COULOMB_ELC_P3M: + if (elc_params.dielectric_contrast_on) { + ostringstream msg; + msg << "ICCP3M conflicts with ELC dielectric constrast"; + runtimeError(msg); + } + p3m_charge_assign(); + p3m_calc_kspace_forces(1,0); + ELC_add_force(); + break; + + case COULOMB_P3M: + p3m_charge_assign(); + p3m_calc_kspace_forces(1,0); + break; #endif - case COULOMB_MMM2D: - MMM2D_add_far_force(); - MMM2D_dielectric_layers_force_contribution(); - } + case COULOMB_MMM2D: + MMM2D_add_far_force(); + MMM2D_dielectric_layers_force_contribution(); + break; + default: break; + } #endif } -/** \name Privat Functions */ + +/** \name Private Functions */ /************************************************************/ /*@{*/ @@ -715,33 +731,39 @@ void iccp3m_store_forces() { int iccp3m_sanity_check() { - switch (coulomb.method) { + switch (coulomb.method) { #ifdef P3M - case COULOMB_ELC_P3M: { - if (elc_params.dielectric_contrast_on) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M conflicts with ELC dielectric constrast"); - return 1; - } - break; - } + case COULOMB_ELC_P3M: { + if (elc_params.dielectric_contrast_on) { + ostringstream msg; + msg << "ICCP3M conflicts with ELC dielectric constrast"; + runtimeError(msg); + return 1; + } + break; + } #endif case COULOMB_DH: { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M does not work with Debye-Hueckel iccp3m.h"); - return 1; - } + ostringstream msg; + msg <<"ICCP3M does not work with Debye-Hueckel iccp3m.h"; + runtimeError(msg); + return 1; + } case COULOMB_RF: { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M does not work with COULOMB_RF iccp3m.h"); - return 1; - } - } + ostringstream msg; + msg <<"ICCP3M does not work with COULOMB_RF iccp3m.h"; + runtimeError(msg); + return 1; + } + default: + break; + } #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "ICCP3M does not work in the NPT ensemble"); + ostringstream msg; + msg <<"ICCP3M does not work in the NPT ensemble"; + runtimeError(msg); return 1; } #endif diff --git a/src/iccp3m.hpp b/src/core/iccp3m.hpp similarity index 96% rename from src/iccp3m.hpp rename to src/core/iccp3m.hpp index eb0c4bd3e4a..c88f0dba4e6 100644 --- a/src/iccp3m.hpp +++ b/src/core/iccp3m.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ // -/** \file iccp3m.h +/** \file iccp3m.hpp ICCP3M is a method that allows to take into account the influence of arbitrarliy shaped dielectric interfaces. The dielectric @@ -90,6 +90,7 @@ typedef struct { double *fx; double *fy; double *fz; + int first_id; } iccp3m_struct; extern iccp3m_struct iccp3m_cfg; /* global variable with ICCP3M configuration */ extern int iccp3m_initialized; @@ -100,32 +101,32 @@ int bcast_iccp3m_cfg(void); /** Calculation of the electrostatic forces between source charges (= real charges) and wall charges. * For each electrostatic method the proper functions for short and long range parts are called. * Long Range Parts are calculated directly, short range parts need helper functions according - * to the particle data organisation. A modified version of \ref force_calc in \ref forces.h. + * to the particle data organisation. A modified version of \ref force_calc in \ref forces.hpp. */ void force_calc_iccp3m(); /** Calculation of short range part of electrostatic interaction in layered systems - * A modified version of \ref layered_calculate_ia in \ref layered.h + * A modified version of \ref layered_calculate_ia in \ref layered.hpp */ void layered_calculate_ia_iccp3m(); /** Calculate the short range part of electrostatic interaction using verlet lists. - * A modified version of \ref build_verlet_lists_and_calc_verlet_ia() in \ref verlet.h + * A modified version of \ref build_verlet_lists_and_calc_verlet_ia() in \ref verlet.hpp */ void build_verlet_lists_and_calc_verlet_ia_iccp3m(); /** Calculate he short range part of electrostatic interaction using verlet lists, if verlet lists - * have already been properly built. A modified version of \ref calculate_verlet_ia() in \ref verlet.h + * have already been properly built. A modified version of \ref calculate_verlet_ia() in \ref verlet.hpp */ void calculate_verlet_ia_iccp3m(); /** Calculate he short range part of electrostatic interaction using for linked cell - * systems. A modified version of \ref calc_link_cell() in \ref domain_decomposition.h + * systems. A modified version of \ref calc_link_cell() in \ref domain_decomposition.hpp */ void calc_link_cell_iccp3m(); /** Calculate he short range part of electrostatic interaction using for n-squared cell - * systems. A modified version of nsq_calculate_ia \ref nsquare.h. + * systems. A modified version of nsq_calculate_ia \ref nsquare.hpp. */ void nsq_calculate_ia_iccp3m(); @@ -174,7 +175,7 @@ inline void add_non_bonded_pair_force_iccp3m(Particle *p1, Particle *p2, case COULOMB_MMM2D: if (q1q2) add_mmm2d_coulomb_pair_force(q1q2,d,dist2,dist,force); break; - case COULOMB_NONE: + default: break; } diff --git a/src/imd.cpp b/src/core/imd.cpp similarity index 98% rename from src/imd.cpp rename to src/core/imd.cpp index 6d105e24e92..4fa74309044 100644 --- a/src/imd.cpp +++ b/src/core/imd.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file imd.c - Implementation of \ref imd.h "imd.h". +/** \file imd.cpp + Implementation of \ref imd.hpp "imd.h". */ #include #include diff --git a/src/imd.hpp b/src/core/imd.hpp similarity index 95% rename from src/imd.hpp rename to src/core/imd.hpp index faa11220513..e5dc06938bc 100644 --- a/src/imd.hpp +++ b/src/core/imd.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _IMD_H #define _IMD_H -/** \file imd.h +/** \file imd.hpp The interface with VMD. This code just provides a wrapper for the IMD interface functions, which allow to send particle positions to VMD. Additionally, VMD can send back a single integer value, called transfer_rate, which is accessible both from c and from Tcl. The IMD force feedback is not implemented. diff --git a/src/initialize.cpp b/src/core/initialize.cpp similarity index 77% rename from src/initialize.cpp rename to src/core/initialize.cpp index 6b334cebbd4..76f5ec08c74 100644 --- a/src/initialize.cpp +++ b/src/core/initialize.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file initialize.c - Implementation of \ref initialize.h "initialize.h" +/** \file initialize.cpp + Implementation of \ref initialize.hpp "initialize.hpp" */ #include "utils.hpp" #include "initialize.hpp" @@ -56,7 +56,6 @@ #include "rattle.hpp" #include "lattice.hpp" #include "iccp3m.hpp" /* -iccp3m- */ -#include "adresso.hpp" #include "metadynamics.hpp" #include "statistics_observable.hpp" #include "statistics_correlation.hpp" @@ -64,6 +63,7 @@ #include "ghmc.hpp" #include "domain_decomposition.hpp" #include "p3m_gpu.hpp" +#include "external_potential.hpp" #include "cuda_init.hpp" #include "cuda_interface.hpp" @@ -75,7 +75,7 @@ static int reinit_magnetostatics = 0; static int lb_reinit_particles_gpu = 1; #endif -#if defined(LB_GPU) || defined(ELECTROSTATICS) +#ifdef CUDA static int reinit_particle_comm_gpu = 1; #endif @@ -99,6 +99,9 @@ void on_program_start() #endif atexit(mpi_stop); } +#ifdef CUDA + cuda_init(); +#endif /* call the initialization of the modules here @@ -107,7 +110,7 @@ void on_program_start() init_bit_random(); init_node_grid(); - /* calculate initial minimimal number of cells (see tclcallback_min_num_cells) */ + /* calculate initial minimal number of cells (see tclcallback_min_num_cells) */ min_num_cells = calc_processor_min_num_cells(); /* initially go for domain decomposition */ @@ -116,20 +119,13 @@ void on_program_start() ghost_init(); /* Initialise force and energy tables */ force_and_energy_tables_init(); -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION - adress_force_and_energy_tables_init(); -#endif - /* #ifdef THERMODYNAMIC_FORCE */ - tf_tables_init(); - /* #endif */ -#endif #ifdef P3M p3m_pre_init(); #endif #ifdef DP3M dp3m_pre_init(); #endif + external_potential_pre_init(); #ifdef LB_GPU if(this_node == 0){ @@ -157,8 +153,6 @@ void on_program_start() void on_integration_start() { - char *errtext; - EVENT_TRACE(fprintf(stderr, "%d: on_integration_start\n", this_node)); INTEG_TRACE(fprintf(stderr,"%d: on_integration_start: reinit_thermo = %d, resort_particles=%d\n", this_node,reinit_thermo,resort_particles)); @@ -167,114 +161,40 @@ void on_integration_start() /* sanity checks */ /********************************************/ - if ( time_step < 0.0 ) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext, "{010 time_step not set} "); - } - if ( skin < 0.0 ) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{011 skin not set} "); - } - if ( temperature < 0.0 ) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{012 thermostat not initialized} "); - } - + integrator_sanity_checks(); #ifdef NPT - if (integ_switch == INTEG_METHOD_NPT_ISO) { - if (nptiso.piston <= 0.0) { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{014 npt on, but piston mass not set} "); - } - -#ifdef ELECTROSTATICS - - switch(coulomb.method) { - case COULOMB_NONE: break; - case COULOMB_DH: break; - case COULOMB_RF: break; -#ifdef P3M - case COULOMB_P3M: break; -#endif /*P3M*/ - default: { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{014 npt only works with P3M, Debye-Huckel or reaction field} "); - } - } -#endif /*ELECTROSTATICS*/ - -#ifdef DIPOLES - - switch (coulomb.Dmethod) { - case DIPOLAR_NONE: break; -#ifdef DP3M - case DIPOLAR_P3M: break; -#endif /* DP3M */ - default: { - char *errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"NpT does not work with your dipolar method, please use P3M."); - } - } -#endif /* ifdef DIPOLES */ - } -#endif /*NPT*/ - - if (!check_obs_calc_initialized()) return; - + integrator_npt_sanity_checks(); +#endif + interactions_sanity_checks(); +#ifdef CATALYTIC_REACTIONS + reactions_sanity_checks(); +#endif #ifdef LB if(lattice_switch & LATTICE_LB) { - if (lbpar.agrid <= 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{098 Lattice Boltzmann agrid not set} "); - } - if (lbpar.tau <= 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{099 Lattice Boltzmann time step not set} "); - } - if (lbpar.rho[0] <= 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{100 Lattice Boltzmann fluid density not set} "); - } - if (lbpar.viscosity[0] <= 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{101 Lattice Boltzmann fluid viscosity not set} "); - } - if (dd.use_vList && skin>=lbpar.agrid/2.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext, "{104 LB requires either no Verlet lists or that the skin of the verlet list to be less than half of lattice-Boltzmann grid spacing.} "); - } + lb_sanity_checks(); } #endif #ifdef LB_GPU -if(this_node == 0){ if(lattice_switch & LATTICE_LB_GPU) { - if (lbpar_gpu.agrid < 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{098 Lattice Boltzmann agrid not set} "); - } - if (lbpar_gpu.tau < 0.0) { - errtext = runtime_error(128); - ERROR_SPRINTF(errtext,"{099 Lattice Boltzmann time step not set} "); - } - for(int i=0;i. */ -/** \file integrate.c Molecular dynamics integrator. +/** \file integrate.cpp Molecular dynamics integrator. * * For more information about the integrator - * see \ref integrate.h "integrate.h". + * see \ref integrate.hpp "integrate.h". */ #include @@ -30,9 +30,11 @@ #include #include #include +#include "lees_edwards.hpp" #include "utils.hpp" #include "integrate.hpp" #include "reaction.hpp" +#include "electrokinetics.hpp" #include "interaction_data.hpp" #include "particle_data.hpp" #include "communication.hpp" @@ -56,7 +58,6 @@ #include "lattice.hpp" #include "lb.hpp" #include "virtual_sites.hpp" -#include "adresso.hpp" #include "statistics_correlation.hpp" #include "ghmc.hpp" @@ -79,8 +80,9 @@ double time_step_squared= -1.0; double time_step_squared_half = -1.0; double sim_time = 0.0; -double skin = -1.0; -double skin2; +double skin = 0.0; +double skin2 = 0.0; +bool skin_set = false; int resort_particles = 1; int recalc_forces = 1; @@ -123,14 +125,62 @@ void finalize_p_inst_npt(); /*@}*/ -/************************************************************/ +void integrator_sanity_checks() +{ + //char *errtext; + if ( time_step < 0.0 ) { + ostringstream msg; + msg <<"time_step not set"; + runtimeError(msg); + } +} -void local_invalidate_system() -{ - resort_particles = 1; - invalidate_obs(); +#ifdef NPT + +void integrator_npt_sanity_checks() +{ + if (integ_switch == INTEG_METHOD_NPT_ISO) { + if (nptiso.piston <= 0.0) { + ostringstream msg; + msg <<"npt on, but piston mass not set"; + runtimeError(msg); + } + +#ifdef ELECTROSTATICS + + switch(coulomb.method) { + case COULOMB_NONE: break; + case COULOMB_DH: break; + case COULOMB_RF: break; +#ifdef P3M + case COULOMB_P3M: break; +#endif /*P3M*/ + default: { + ostringstream msg; + msg <<"npt only works with P3M, Debye-Huckel or reaction field"; + runtimeError(msg); + } + } +#endif /*ELECTROSTATICS*/ + +#ifdef DIPOLES + + switch (coulomb.Dmethod) { + case DIPOLAR_NONE: break; +#ifdef DP3M + case DIPOLAR_P3M: break; +#endif /* DP3M */ + default: { + ostringstream msg; + msg <<"NpT does not work with your dipolar method, please use P3M."; + runtimeError(msg); + } + } +#endif /* ifdef DIPOLES */ + } } +#endif /*NPT*/ /************************************************************/ void integrate_ensemble_init() @@ -158,10 +208,8 @@ void integrate_ensemble_init() /************************************************************/ -void integrate_vv(int n_steps) +void integrate_vv(int n_steps, int reuse_forces) { - int i; - /* Prepare the Integrator */ on_integration_start(); @@ -177,65 +225,38 @@ void integrate_vv(int n_steps) /* Integration Step: Preparation for first integration step: Calculate forces f(t) as function of positions p(t) ( and velocities v(t) ) */ - if (recalc_forces) { + /* reuse_forces logic: + -1: recalculate forces unconditionally, mostly used for timing + 0: recalculate forces if recalc_forces is set, meaning it is probably necessary + 1: do not recalculate forces. Mostly when reading checkpoints with forces + */ + if (reuse_forces == -1 || (recalc_forces && reuse_forces != 1)) { thermo_heat_up(); + #ifdef LB transfer_momentum = 0; + if (lattice_switch & LATTICE_LB && this_node == 0) + if (warnings) fprintf (stderr, "Warning: Recalculating forces, so the LB coupling forces are not included in the particle force the first time step. This only matters if it happens frequently during sampling.\n"); #endif #ifdef LB_GPU transfer_momentum_gpu = 0; -#endif -//VIRTUAL_SITES pos (and vel for DPD) update for security reason !!! -#ifdef VIRTUAL_SITES - update_mol_vel_pos(); - ghost_communicator(&cell_structure.update_ghost_pos_comm); - if (check_runtime_errors()) return; -#ifdef ADRESS - // adress_update_weights(); - if (check_runtime_errors()) return; -#endif -#endif -#ifdef COLLISION_DETECTION - prepare_collision_queue(); -#endif - - force_calc(); - - //VIRTUAL_SITES distribute forces -#ifdef VIRTUAL_SITES - ghost_communicator(&cell_structure.collect_ghost_force_comm); - init_forces_ghosts(); - distribute_mol_force(); - if (check_runtime_errors()) return; + if (lattice_switch & LATTICE_LB_GPU && this_node == 0) + if (warnings) fprintf (stderr, "Warning: Recalculating forces, so the LB coupling forces are not included in the particle force the first time step. This only matters if it happens frequently during sampling.\n"); #endif - ghost_communicator(&cell_structure.collect_ghost_force_comm); + force_calc(); + rescale_forces(); #ifdef ROTATION convert_initial_torques(); #endif - - thermo_cool_down(); - - /* Communication Step: ghost forces */ - - - /*apply trap forces to trapped molecules*/ -#ifdef MOLFORCES - calc_and_apply_mol_constraints(); -#endif - - rescale_forces(); - recalc_forces = 0; -#ifdef COLLISION_DETECTION - handle_collisions(); -#endif + thermo_cool_down(); } #ifdef GHMC - if(thermo_switch & THERMO_GHMC) - ghmc_init(); + if(thermo_switch & THERMO_GHMC) + ghmc_init(); #endif if (check_runtime_errors()) @@ -244,8 +265,8 @@ void integrate_vv(int n_steps) n_verlet_updates = 0; /* Integration loop */ - for(i=0;i skin2 ) resort_particles = 1; +#ifdef LEES_EDWARDS + /* test for crossing of a y-pbc: requires adjustment of velocity.*/ + { + int b1, delta_box; + b1 = (int)floor( p[i].r.p[1]*box_l_i[1]); + if( b1 != 0 ){ + delta_box = b1 - (int)floor(( p[i].r.p[1] - p[i].m.v[1])*box_l_i[1] ); + if( abs(delta_box) > 1 ){ + fprintf(stderr, "Error! Particle moved more than one box length in 1 step\n"); + exit( 8 ); + } + p[i].m.v[0] -= delta_box * lees_edwards_rate; + p[i].r.p[0] -= delta_box * lees_edwards_offset; + p[i].r.p[1] -= delta_box * box_l[1]; + p[i].l.i[1] += delta_box; + while( p[i].r.p[1] > box_l[1] ) {p[i].r.p[1] -= box_l[1]; p[i].l.i[1]++;} + while( p[i].r.p[1] < 0.0 ) {p[i].r.p[1] += box_l[1]; p[i].l.i[1]--;} + resort_particles = 1; + } + /* Branch prediction on most systems should mean there is minimal cost here */ + while( p[i].r.p[0] > box_l[0] ) {p[i].r.p[0] -= box_l[0]; p[i].l.i[0]++;} + while( p[i].r.p[0] < 0.0 ) {p[i].r.p[0] += box_l[0]; p[i].l.i[0]--;} + while( p[i].r.p[2] > box_l[2] ) {p[i].r.p[2] -= box_l[2]; p[i].l.i[2]++;} + while( p[i].r.p[2] < 0.0 ) {p[i].r.p[2] += box_l[2]; p[i].l.i[2]--;} + } +#endif + + /* Verlet criterion check*/ + if(SQR(p[i].r.p[0]-p[i].l.p_old[0]) + +SQR(p[i].r.p[1]-p[i].l.p_old[1]) + +SQR(p[i].r.p[2]-p[i].l.p_old[2]) > skin2) + resort_particles=1; + + } } +#ifdef LEES_EDWARDS /* would be nice to be more refined about this */ + resort_particles = 1; +#endif + announce_resort_particles(); #ifdef ADDITIONAL_CHECKS diff --git a/src/integrate.hpp b/src/core/integrate.hpp similarity index 81% rename from src/integrate.hpp rename to src/core/integrate.hpp index 800cf28e570..38c3a05862f 100644 --- a/src/integrate.hpp +++ b/src/core/integrate.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,9 +21,9 @@ #ifndef INTEGRATE_H #define INTEGRATE_H -/** \file integrate.h Molecular dynamics integrator. +/** \file integrate.hpp Molecular dynamics integrator. * - * For more information see \ref integrate.c "integrate.c". + * For more information see \ref integrate.cpp "integrate.c". */ #define INTEG_METHOD_NPT_ISO 0 @@ -54,6 +54,8 @@ extern double sim_time; extern double max_cut; /** Verlet list skin. */ extern double skin; +/** True iff the user has changed the skin setting. */ +extern bool skin_set; /** If non-zero, the particle data will be resorted before the next integration. */ extern int resort_particles; @@ -69,21 +71,26 @@ extern double verlet_reuse; /************************************************************/ /*@{*/ +/** check sanity of integrator params */ +void integrator_sanity_checks(); + +/** check sanity of npt params */ +void integrator_npt_sanity_checks(); + /** Initialize the used thermodynamic Ensemble (NVT or NPT) */ void integrate_ensemble_init(); /** integrate with velocity verlet integrator. \param n_steps number of steps to integrate. + \param reuse_forces if nonzero, blindly trust + the forces still stored with the particles for the first time step. */ -void integrate_vv(int n_steps); +void integrate_vv(int n_steps, int reuse_forces); /** function that rescales all velocities on one node according to a new time step. */ void rescale_velocities(double scale); -/** local routine of \ref tclcommand_invalidate_system */ -void local_invalidate_system(); - /*@}*/ #endif diff --git a/src/interaction_data.cpp b/src/core/interaction_data.cpp similarity index 88% rename from src/interaction_data.cpp rename to src/core/interaction_data.cpp index c850e5ac7b7..1b7413849ac 100644 --- a/src/interaction_data.cpp +++ b/src/core/interaction_data.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file interaction_data.c - Implementation of interaction_data.h +/** \file interaction_data.cpp + Implementation of interaction_data.hpp */ #include #include @@ -37,6 +37,7 @@ #include "mmm2d.hpp" #include "maggs.hpp" #include "elc.hpp" +#include "actor/EwaldgpuForce.hpp" #include "lj.hpp" #include "ljgen.hpp" #include "ljangle.hpp" @@ -68,12 +69,6 @@ int n_particle_types = 0; int n_interaction_types = 0; IA_parameters *ia_params = NULL; -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -TF_parameters *tf_params = NULL; -/* #endif */ -#endif - #if defined(ELECTROSTATICS) || defined(DIPOLES) Coulomb_parameters coulomb = { #ifdef ELECTROSTATICS @@ -88,6 +83,11 @@ Coulomb_parameters coulomb = { #ifdef ELECTROSTATICS Debye_hueckel_params dh_params = { 0.0, 0.0 }; Reaction_field_params rf_params = { 0.0, 0.0 }; + +/** Induced field (for const. potential feature) **/ +double field_induced; +/** Applied field (for const. potential feature) **/ +double field_applied; #endif int n_bonded_ia = 0; @@ -107,21 +107,6 @@ DoubleList tabulated_forces; /** Corresponding array containing all tabulated energies*/ DoubleList tabulated_energies; -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION -/** Array containing all adress tabulated forces*/ -DoubleList adress_tab_forces; -/** Corresponding array containing all adress tabulated energies*/ -DoubleList adress_tab_energies; -#endif - -/* #ifdef THERMODYNAMIC_FORCE */ -/** Array containing the thermodynamic forces **/ -DoubleList thermodynamic_forces; -DoubleList thermodynamic_f_energies; -/* #endif */ -#endif - /***************************************** * function prototypes *****************************************/ @@ -144,23 +129,6 @@ void force_and_energy_tables_init() { init_doublelist(&tabulated_energies); } -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION -/** Initialize adress force and energy tables */ -void adress_force_and_energy_tables_init() { - init_doublelist(&adress_tab_forces); - init_doublelist(&adress_tab_energies); -} -#endif - -/* #ifdef THERMODYNAMIC_FORCE */ -void tf_tables_init() { - init_doublelist(&thermodynamic_forces); - init_doublelist(&thermodynamic_f_energies); -} -/* #endif */ -#endif - /** Initialize interaction parameters. */ void initialize_ia_params(IA_parameters *params) { @@ -338,16 +306,6 @@ void initialize_ia_params(IA_parameters *params) { params->TUNABLE_SLIP_r_cut = INACTIVE_CUTOFF; #endif -#if defined(ADRESS) && defined(INTERFACE_CORRECTION) - //params->ADRESS_IC_npoints = 0; - params->ADRESS_TAB_npoints = 0; - params->ADRESS_TAB_startindex = 0; - params->ADRESS_TAB_minval = 0.0; - params->ADRESS_TAB_stepsize = 0.0; - strcpy(params->ADRESS_TAB_filename,""); - params->ADRESS_TAB_maxval = INACTIVE_CUTOFF; -#endif - /* things that are not strictly speaking short-ranged interactions, and do not have a cutoff */ #ifdef COMFORCE @@ -386,31 +344,6 @@ IA_parameters *get_ia_param_safe(int i, int j) { return get_ia_param(i, j); } -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -void initialize_tf_params(TF_parameters *params){ - params->TF_TAB_npoints = 0; - params->TF_TAB_startindex = 0; - - params->TF_prefactor = 0.0; - params->TF_TAB_minval = 0.0; - params->TF_TAB_maxval = 0.0; - params->TF_TAB_stepsize = 0.0; - strcpy(params->TF_TAB_filename, ""); -} - -void copy_tf_params(TF_parameters *dst, TF_parameters *src){ - memcpy(dst, src, sizeof(TF_parameters)); -} - -int checkIfTF(TF_parameters *data){ - if (data->TF_TAB_maxval !=0) - return 1; - return 0; -} -/* #endif */ -#endif - static void recalc_maximal_cutoff_bonded() { int i; @@ -517,6 +450,12 @@ static void recalc_global_maximal_nonbonded_cutoff() max_cut_global = r_cut; break; } +#endif +#ifdef EWALD_GPU + case COULOMB_EWALD_GPU: + if (max_cut_global < ewaldgpu_params.rcut) + max_cut_global = ewaldgpu_params.rcut; + break; #endif case COULOMB_DH: if (max_cut_global < dh_params.r_cut) @@ -527,6 +466,8 @@ static void recalc_global_maximal_nonbonded_cutoff() if (max_cut_global < rf_params.r_cut) max_cut_global = rf_params.r_cut; break; + default: + break; } #endif /*ifdef ELECTROSTATICS */ @@ -543,6 +484,8 @@ static void recalc_global_maximal_nonbonded_cutoff() break; } #endif /*ifdef DP3M */ + default: + break; } #endif @@ -670,11 +613,6 @@ static void recalc_maximal_cutoff_nonbonded() max_cut_current = data->TAB_maxval; #endif -#if defined(ADRESS) && defined(INTERFACE_CORRECTION) - if (max_cut_current < data->ADRESS_TAB_maxval) - max_cut_current = data->ADRESS_TAB_maxval; -#endif - #ifdef TUNABLE_SLIP if (max_cut_current < data->TUNABLE_SLIP_r_cut) max_cut_current = data->TUNABLE_SLIP_r_cut; @@ -728,8 +666,8 @@ void recalc_maximal_cutoff() max_cut = max_cut_bonded; } -const char *get_name_of_bonded_ia(int i) { - switch (i) { +const char *get_name_of_bonded_ia(BondedInteraction type) { + switch (type) { case BONDED_IA_FENE: return "FENE"; case BONDED_IA_ANGLE_OLD: @@ -747,7 +685,11 @@ const char *get_name_of_bonded_ia(int i) { case BONDED_IA_ENDANGLEDIST: return "endangledist"; case BONDED_IA_HARMONIC: - return "HARMONIC"; + return "HARMONIC"; + case BONDED_IA_QUARTIC: + return "QUARTIC"; + case BONDED_IA_BONDED_COULOMB: + return "BONDED_COULOMB"; case BONDED_IA_SUBT_LJ: return "SUBT_LJ"; case BONDED_IA_TABULATED: @@ -772,7 +714,7 @@ const char *get_name_of_bonded_ia(int i) { return "STRETCHLIN_FORCE"; default: fprintf(stderr, "%d: INTERNAL ERROR: name of unknown interaction %d requested\n", - this_node, i); + this_node, type); errexit(); } /* just to keep the compiler happy */ @@ -815,40 +757,6 @@ void realloc_ia_params(int nsize) ia_params = new_params; } -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -void realloc_tf_params(int nsize) -{ - int i; - TF_parameters *new_params; - - if (nsize <= n_particle_types) - return; - - new_params = (TF_parameters *) malloc(nsize*sizeof(TF_parameters)); - if (tf_params) { - /* if there is an old field, copy entries and delete */ - for (i = 0; i < nsize; i++) - { - if (i < n_particle_types) - copy_tf_params(&new_params[i], - &tf_params[i]); - else - initialize_tf_params(&new_params[i]); - } - free(tf_params); - } - else { - /* new field, just init */ - for (i = 0; i < nsize; i++) - initialize_tf_params(&new_params[i]); - } - - tf_params = new_params; -} -/* #endif */ -#endif - void make_particle_type_exist(int type) { int ns = type + 1; @@ -889,7 +797,7 @@ void make_bond_type_exist(int type) n_bonded_ia = ns; } -int check_obs_calc_initialized() +int interactions_sanity_checks() { /* set to zero if initialization was not successful. */ int state = 1; @@ -903,6 +811,7 @@ int check_obs_calc_initialized() case COULOMB_P3M_GPU: case COULOMB_P3M: if (p3m_sanity_checks()) state = 0; break; #endif + default: break; } #endif /* ifdef ELECTROSTATICS */ @@ -914,6 +823,8 @@ int check_obs_calc_initialized() #endif case DIPOLAR_MDLC_DS: if (mdlc_sanity_checks()) state = 0; // fall through case DIPOLAR_DS: if (magnetic_dipolar_direct_sum_sanity_checks()) state = 0; break; + default: + break; } #endif /* ifdef DIPOLES */ @@ -955,7 +866,7 @@ int coulomb_set_bjerrum(double bjerrum) rf_params.B = 0.0; case COULOMB_MMM1D: mmm1d_params.maxPWerror = 1e40; - mmm1d_params.bessel_cutoff = 0; + default: break; } mpi_bcast_coulomb_params(); @@ -992,6 +903,8 @@ int dipolar_set_Dbjerrum(double bjerrum) dp3m_set_bjerrum(); break; #endif + default: + break; } mpi_bcast_coulomb_params(); diff --git a/src/interaction_data.hpp b/src/core/interaction_data.hpp similarity index 65% rename from src/interaction_data.hpp rename to src/core/interaction_data.hpp index 7037e6a54ce..f2414ee478d 100644 --- a/src/interaction_data.hpp +++ b/src/core/interaction_data.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _INTERACTION_DATA_H #define _INTERACTION_DATA_H -/** \file interaction_data.h +/** \file interaction_data.hpp Various procedures concerning interactions between particles. */ @@ -33,63 +33,73 @@ /************************************************************/ /*@{*/ -/** This bonded interaction was not set. */ -#define BONDED_IA_NONE -1 -/** Type of bonded interaction is a FENE potential - (to be combined with Lennard Jones). */ -#define BONDED_IA_FENE 0 -/** Type of bonded interaction is a HARMONIC potential. */ -#define BONDED_IA_HARMONIC 1 -/** Type of bonded interaction is a bond angle potential. */ -#define BONDED_IA_ANGLE_OLD 2 -/** Type of bonded interaction is a dihedral potential. */ -#define BONDED_IA_DIHEDRAL 3 -/** Type of tabulated bonded interaction potential, - may be of bond length, of bond angle or of dihedral type. */ -#define BONDED_IA_TABULATED 4 -/** Type of bonded interaction is a (-LJ) potential. */ -#define BONDED_IA_SUBT_LJ 5 -/** Type of a Rigid/Constrained bond*/ -#define BONDED_IA_RIGID_BOND 6 -/** Type of a virtual bond*/ -#define BONDED_IA_VIRTUAL_BOND 7 -/** Type of bonded interaction is a bond angle -- constraint distance potential. */ -#define BONDED_IA_ANGLEDIST 8 -/** Type of bonded interaction is a bond angle -- chain ends have angle with wall constraint */ -#define BONDED_IA_ENDANGLEDIST 9 -/** Type of overlapped bonded interaction potential, - may be of bond length, of bond angle or of dihedral type. */ -#define BONDED_IA_OVERLAPPED 10 -/** Type of bonded interaction is a bond angle cosine potential. */ -#define BONDED_IA_ANGLE_HARMONIC 11 -/** Type of bonded interaction is a bond angle cosine potential. */ -#define BONDED_IA_ANGLE_COSINE 12 -/** Type of bonded interaction is a bond angle cosine potential. */ -#define BONDED_IA_ANGLE_COSSQUARE 13 -/** Type of bonded interaction is a hyperelastic stretching force. */ -#define BONDED_IA_STRETCHING_FORCE 14 -/** Type of bonded interaction is a local area force. */ -#define BONDED_IA_AREA_FORCE_LOCAL 15 -/** Type of bonded interaction is a bending force. */ -#define BONDED_IA_BENDING_FORCE 16 -/** Type of bonded interaction is a bending force. */ -#define BONDED_IA_VOLUME_FORCE 17 -/** Type of bonded interaction is a global area force. */ -#define BONDED_IA_AREA_FORCE_GLOBAL 18 -/** Type of bonded interaction is a linear stretching force. */ -#define BONDED_IA_STRETCHLIN_FORCE 19 +enum BondedInteraction{ + /** This bonded interaction was not set. */ + BONDED_IA_NONE = -1, + /** Type of bonded interaction is a FENE potential + (to be combined with Lennard Jones). */ + BONDED_IA_FENE, + /** Type of bonded interaction is a HARMONIC potential. */ + BONDED_IA_HARMONIC, + /** Type of bonded interaction is a QUARTIC potential. */ + BONDED_IA_QUARTIC, + /** Type of bonded interaction is a BONDED_COULOMB */ + BONDED_IA_BONDED_COULOMB, + /** Type of bonded interaction is a bond angle potential. */ + BONDED_IA_ANGLE_OLD, + /** Type of bonded interaction is a dihedral potential. */ + BONDED_IA_DIHEDRAL, + /** Type of tabulated bonded interaction potential, + may be of bond length, of bond angle or of dihedral type. */ + BONDED_IA_TABULATED, + /** Type of bonded interaction is a (-LJ) potential. */ + BONDED_IA_SUBT_LJ, + /** Type of a Rigid/Constrained bond*/ + BONDED_IA_RIGID_BOND, + /** Type of a virtual bond*/ + BONDED_IA_VIRTUAL_BOND, + /** Type of bonded interaction is a bond angle -- constraint distance potential. */ + BONDED_IA_ANGLEDIST, + /** Type of bonded interaction is a bond angle -- chain ends have angle with wall constraint */ + BONDED_IA_ENDANGLEDIST, + /** Type of overlapped bonded interaction potential, + may be of bond length, of bond angle or of dihedral type. */ + BONDED_IA_OVERLAPPED, + /** Type of bonded interaction is a bond angle cosine potential. */ + BONDED_IA_ANGLE_HARMONIC, + /** Type of bonded interaction is a bond angle cosine potential. */ + BONDED_IA_ANGLE_COSINE, + /** Type of bonded interaction is a bond angle cosine potential. */ + BONDED_IA_ANGLE_COSSQUARE, + /** Type of bonded interaction is a hyperelastic stretching force. */ + BONDED_IA_STRETCHING_FORCE, + /** Type of bonded interaction is a local area force. */ + BONDED_IA_AREA_FORCE_LOCAL, + /** Type of bonded interaction is a bending force. */ + BONDED_IA_BENDING_FORCE, + /** Type of bonded interaction is a bending force. */ + BONDED_IA_VOLUME_FORCE, + /** Type of bonded interaction is a global area force. */ + BONDED_IA_AREA_FORCE_GLOBAL, + /** Type of bonded interaction is a linear stretching force. */ + BONDED_IA_STRETCHLIN_FORCE +}; /** Specify tabulated bonded interactions */ -#define TAB_UNKNOWN 0 -#define TAB_BOND_LENGTH 1 -#define TAB_BOND_ANGLE 2 -#define TAB_BOND_DIHEDRAL 3 +enum TabulatedBondedInteraction{ + TAB_UNKNOWN = 0, + TAB_BOND_LENGTH, + TAB_BOND_ANGLE, + TAB_BOND_DIHEDRAL +}; /** Specify overlapped bonded interactions */ -#define OVERLAP_UNKNOWN 0 -#define OVERLAP_BOND_LENGTH 1 -#define OVERLAP_BOND_ANGLE 2 -#define OVERLAP_BOND_DIHEDRAL 3 +enum OverlappedBondedInteraction{ + OVERLAP_UNKNOWN = 0, + OVERLAP_BOND_LENGTH, + OVERLAP_BOND_ANGLE, + OVERLAP_BOND_DIHEDRAL +}; /** cutoff for deactivated interactions. Below 0, so that even particles on top of each other don't interact by chance. */ @@ -105,28 +115,21 @@ /*@{*/ #ifdef ELECTROSTATICS - /** Coulomb interation switched off (NONE). */ - #define COULOMB_NONE 0 - /** Coulomb method is Debye-Hueckel. */ - #define COULOMB_DH 1 - /** Coulomb method is Debye-Hueckel with parallel separate calculation. */ - #define COULOMB_DH_PW 2 - /** Coulomb method is P3M. */ - #define COULOMB_P3M 3 - /** Coulomb method is one-dimensional MMM */ - #define COULOMB_MMM1D 4 - /** Coulomb method is two-dimensional MMM */ - #define COULOMB_MMM2D 5 - /** Coulomb method is "Maggs" */ - #define COULOMB_MAGGS 6 - /** Coulomb method is P3M plus ELC. */ - #define COULOMB_ELC_P3M 8 - /** Coulomb method is Reaction-Field. */ - #define COULOMB_RF 9 - /** Coulomb method is Reaction-Field BUT as interactions */ - #define COULOMB_INTER_RF 10 - /** Coulomb method is P3M with GPU based long range part calculation */ - #define COULOMB_P3M_GPU 11 + enum CoulombMethod { + COULOMB_NONE, //< Coulomb interaction switched off (NONE) + COULOMB_DH, //< Coulomb method is Debye-Hueckel + COULOMB_P3M, //< Coulomb method is P3M + COULOMB_MMM1D, //< Coulomb method is one-dimensional MMM + COULOMB_MMM2D, //< Coulomb method is two-dimensional MMM + COULOMB_MAGGS, //< Coulomb method is "Maggs" + COULOMB_ELC_P3M, //< Coulomb method is P3M plus ELC + COULOMB_RF, //< Coulomb method is Reaction-Field + COULOMB_INTER_RF, //< Coulomb method is Reaction-Field BUT as interaction + COULOMB_P3M_GPU, //< Coulomb method is P3M with GPU based long range part calculation + COULOMB_MMM1D_GPU, //< Coulomb method is one-dimensional MMM running on GPU + COULOMB_EWALD_GPU, //< Coulomb method is Ewald running on GPU + }; + #endif /*@}*/ @@ -138,20 +141,20 @@ */ /************************************************************/ /*@{*/ - +enum DipolarInteration{ /** dipolar interation switched off (NONE). */ - #define DIPOLAR_NONE 0 + DIPOLAR_NONE = 0, /** dipolar method is P3M. */ - #define DIPOLAR_P3M 1 + DIPOLAR_P3M, /** Dipolar method is P3M plus DLC. */ - #define DIPOLAR_MDLC_P3M 2 + DIPOLAR_MDLC_P3M, /** Dipolar method is all with all and no replicas */ - #define DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA 3 + DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA, /** Dipolar method is magnetic dipolar direct sum */ - #define DIPOLAR_DS 4 + DIPOLAR_DS, /** Dipolar method is direct sum plus DLC. */ - #define DIPOLAR_MDLC_DS 5 - + DIPOLAR_MDLC_DS +}; /*@}*/ #endif @@ -162,33 +165,38 @@ */ /************************************************************/ /*@{*/ - +enum ConstraintApplied{ /** No constraint applied */ -#define CONSTRAINT_NONE 0 + CONSTRAINT_NONE = 0, /** wall constraint applied */ -#define CONSTRAINT_WAL 1 + CONSTRAINT_WAL, /** spherical constraint applied */ -#define CONSTRAINT_SPH 2 + CONSTRAINT_SPH, /** (finite) cylinder shaped constraint applied */ -#define CONSTRAINT_CYL 3 + CONSTRAINT_CYL, /** Rod-like charge. */ -#define CONSTRAINT_ROD 4 + CONSTRAINT_ROD, /** Plate-like charge. */ -#define CONSTRAINT_PLATE 5 + CONSTRAINT_PLATE, /** maze-like constraint applied */ -#define CONSTRAINT_MAZE 6 + CONSTRAINT_MAZE, /** pore constraint applied */ -#define CONSTRAINT_PORE 7 + CONSTRAINT_PORE, //ER /** External magnetic field constraint applied */ -#define CONSTRAINT_EXT_MAGN_FIELD 8 + CONSTRAINT_EXT_MAGN_FIELD, //end ER /** Constraint for tunable-lsip boundary conditions */ -#define CONSTRAINT_PLANE 9 + CONSTRAINT_PLANE, /** Constraint for tunable-lsip boundary conditions */ -#define CONSTRAINT_RHOMBOID 10 + CONSTRAINT_RHOMBOID, /** Constraint for a stomatocyte boundary */ -#define CONSTRAINT_STOMATOCYTE 11 + CONSTRAINT_STOMATOCYTE, +/** slitpore constraint applied */ + CONSTRAINT_SLITPORE, +/** Constraint for a hollow cone boundary */ + CONSTRAINT_HOLLOW_CONE +}; /*@}*/ /* Data Types */ @@ -453,20 +461,6 @@ typedef struct { double mol_cut_cutoff; #endif -#if defined(ADRESS) && defined(INTERFACE_CORRECTION) - /** \name Tabulated potential */ - /*@{*/ - int ADRESS_TAB_npoints; - int ADRESS_TAB_startindex; - double ADRESS_TAB_minval; - double ADRESS_TAB_maxval; - double ADRESS_TAB_stepsize; - /** The maximum allowable filename length for a tabulated potential file*/ -#define MAXLENGTH_ADRESSTABFILE_NAME 256 - char ADRESS_TAB_filename[MAXLENGTH_ADRESSTABFILE_NAME]; - /*@}*/ -#endif - #ifdef TUNABLE_SLIP double TUNABLE_SLIP_temp; double TUNABLE_SLIP_gamma; @@ -481,27 +475,15 @@ typedef struct { double REACTION_range; #endif +#ifdef SHANCHEN + double affinity[LB_COMPONENTS]; + int affinity_on; +#endif + } IA_parameters; /** thermodynamic force parameters */ -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -typedef struct{ - int TF_TAB_npoints; - int TF_TAB_startindex; - - double TF_prefactor; - double TF_TAB_minval; - double TF_TAB_maxval; - double TF_TAB_stepsize; -#define MAXLENGTH_TF_FILENAME 256 - char TF_TAB_filename[MAXLENGTH_TF_FILENAME]; - -} TF_parameters; -/* #endif */ -#endif - /** \name Compounds for Coulomb interactions */ /*@{*/ @@ -515,167 +497,184 @@ typedef struct { /** bjerrum length times temperature. */ double prefactor; - /** Method to treat coulomb interaction. See \ref COULOMB_NONE "Type codes for Coulomb" */ - int method; + /** Method to treat coulomb interaction. */ + CoulombMethod method; #endif #ifdef DIPOLES double Dbjerrum; double Dprefactor; - int Dmethod; + DipolarInteration Dmethod; #endif } Coulomb_parameters; -/*@}*/ +#ifdef ELECTROSTATICS -/** Defines parameters for a bonded interaction. */ +/** Induced field (for const. potential feature). **/ +extern double field_induced; +/** Applied field (for const. potential feature) **/ +extern double field_applied; + +#endif + +/*@}*/ +/** Parameters for FENE bond Potential. +k - spring constant. +drmax - maximal bond streching. +r0 - equilibrium bond length. +drmax2 - square of drmax (internal parameter). +*/ typedef struct { - /** bonded interaction type. See \ref BONDED_IA_FENE "Type code for bonded" */ - int type; - /** (Number of particles - 1) interacting for that type */ - int num; - /** union to store the different bonded interaction parameters. */ - union { - /** Parameters for FENE bond Potential. - k - spring constant. - drmax - maximal bond streching. - r0 - equilibrium bond length. - drmax2 - square of drmax (internal parameter). - */ - struct { double k; double drmax; double r0; double drmax2; double drmax2i; - } fene; - - /** Parameters for hyperelastic stretching_force */ - struct { - double r0; - double ks; - } stretching_force; - /** Parameters for linear stretching_force */ - struct { - double r0; - double kslin; - } stretchlin_force; - /** Parameters for area_force_local */ - struct { - double A0_l; - double ka_l; - } area_force_local; - /** Parameters for area_force_global */ - struct { - double A0_g; - double ka_g; - } area_force_global; - /** Parameters for bending_force */ - struct { - double phi0; - double kb; - } bending_force; - /** Parameters for volume_force */ - struct { - double V0; - double kv; - } volume_force; - - /** Parameters for harmonic bond Potential */ - struct { + } Fene_bond_parameters; + + +/** Parameters for hyperelastic stretching_force */ +typedef struct { + double r0; + double ks; +} Stretching_force_bond_parameters; + + +/** Parameters for linear stretching_force */ +typedef struct { + double r0; + double kslin; +} Stretchlin_force_bond_parameters; + +/** Parameters for area_force_local */ +typedef struct { + double A0_l; + double ka_l; +} Area_force_local_bond_parameters; +/** Parameters for area_force_global */ +typedef struct { + double A0_g; + double ka_g; +} Area_force_global_bond_parameters; + +/** Parameters for bending_force */ +typedef struct { + double phi0; + double kb; +} Bending_force_bond_parameters; + +/** Parameters for volume_force */ +typedef struct { + double V0; + double kv; +} Volume_force_bond_parameters; + + +/** Parameters for harmonic bond Potential */ +typedef struct { double k; double r; double r_cut; - } harmonic; +} Harmonic_bond_parameters; + +/** Parameters for quartic bond Potential */ +typedef struct { + double k0, k1; + double r; + double r_cut; +} Quartic_bond_parameters; + +/** Parameters for coulomb bond Potential */ +typedef struct { + double prefactor; +} Bonded_coulomb_bond_parameters; -#ifdef BOND_ANGLE_OLD - /** Parameters for three body angular potential (bond-angle potentials). +/** Parameters for three body angular potential (bond-angle potentials). ATTENTION: Note that there are different implementations of the bond angle - potential which you may chose with a compiler flag in the file \ref config.h ! + potential which you may chose with a compiler flag in the file \ref config.hpp ! bend - bending constant. phi0 - equilibrium angle (default is 180 degrees / Pi) */ - struct { +typedef struct { double bend; double phi0; -#ifdef BOND_ANGLE_COSINE double cos_phi0; double sin_phi0; -#endif -#ifdef BOND_ANGLE_COSSQUARE - double cos_phi0; -#endif - } angle; -#endif -#ifdef BOND_ANGLE - /** Parameters for three body angular potential (bond_angle_harmonic). - bend - bending constant. - phi0 - equilibrium angle (default is 180 degrees / Pi) */ - struct { - double bend; - double phi0; - } angle_harmonic; +} Angle_bond_parameters; - /** Parameters for three body angular potential (bond_angle_cosine). - bend - bending constant. - phi0 - equilibrium angle (default is 180 degrees / Pi) */ - struct { +/** Parameters for three body angular potential (bond_angle_harmonic). + bend - bending constant. + phi0 - equilibrium angle (default is 180 degrees / Pi) */ +typedef struct { + double bend; + double phi0; +} Angle_harmonic_bond_parameters; + + + + +/** Parameters for three body angular potential (bond_angle_cosine). + bend - bending constant. + phi0 - equilibrium angle (default is 180 degrees / Pi) */ +typedef struct { double bend; double phi0; double cos_phi0; double sin_phi0; - } angle_cosine; +} Angle_cosine_bond_parameters; - /** Parameters for three body angular potential (bond_angle_cossquare). - bend - bending constant. - phi0 - equilibrium angle (default is 180 degrees / Pi) */ - struct { + +/** Parameters for three body angular potential (bond_angle_cossquare). + bend - bending constant. + phi0 - equilibrium angle (default is 180 degrees / Pi) */ +typedef struct { double bend; double phi0; double cos_phi0; - } angle_cossquare; -#endif +} Angle_cossquare_bond_parameters; - /** Parameters for four body angular potential (dihedral-angle potentials). */ - struct { - double mult; - double bend; - double phase; - } dihedral; -#ifdef TABULATED - /** Parameters for n-body tabulated potential (n=2,3,4). */ - struct { +/** Parameters for four body angular potential (dihedral-angle potentials). */ +typedef struct { + double mult; + double bend; + double phase; +} Dihedral_bond_parameters; + +/** Parameters for n-body tabulated potential (n=2,3,4). */ +typedef struct { char *filename; - int type; + TabulatedBondedInteraction type; int npoints; double minval; double maxval; double invstepsize; double *f; double *e; - } tab; -#endif -#ifdef OVERLAPPED - /** Parameters for n-body overlapped potential (n=2,3,4). */ - struct { +} Tabulated_bond_parameters; + +/** Parameters for n-body overlapped potential (n=2,3,4). */ +typedef struct { char *filename; - int type; + OverlappedBondedInteraction type; double maxval; int noverlaps; double *para_a; double *para_b; double *para_c; - } overlap; -#endif - /** Dummy parameters for -LJ Potential */ - struct { +} Overlap_bond_parameters; + + +/** Dummy parameters for -LJ Potential */ +typedef struct { double k; double r; double r2; - } subt_lj; - /**Parameters for the rigid_bond/SHAKE/RATTLE ALGORITHM*/ - struct { +} Subt_lj_bond_parameters; + + +/**Parameters for the rigid_bond/SHAKE/RATTLE ALGORITHM*/ +typedef struct { /**Length of rigid bond/Constrained Bond*/ //double d; /**Square of the length of Constrained Bond*/ @@ -684,42 +683,69 @@ typedef struct { double p_tol; /**Velocity Tolerance/Accuracy for termination of RATTLE/SHAKE iterations during velocity corrections */ double v_tol; - } rigid_bond; +} Rigid_bond_parameters; + -#ifdef BOND_ANGLEDIST - /** Parameters for three body angular potential (bond-angle potentials) that - depends on distance to wall constraint. +/** Parameters for three body angular potential (bond-angle potentials) that + depends on distance to wall constraint. ATTENTION: Note that there are different implementations of the bond angle - potential which you may chose with a compiler flag in the file \ref config.h ! + potential which you may chose with a compiler flag in the file \ref config.hpp ! bend - bending constant. phi0 - equilibrium angle (default is 180 degrees / Pi) dist0 - equilibrium distance (no default) */ - struct { +typedef struct { double bend; double phimin; double distmin; double phimax; double distmax; -#ifdef BOND_ANGLE_COSINE double cos_phi0; double sin_phi0; -#endif -#ifdef BOND_ANGLE_COSSQUARE - double cos_phi0; -#endif - } angledist; -#endif +} Angledist_bond_parameters; -#ifdef BONDED_IA_ENDANGLEDIST - /** Parameters for chainend angular potential with wall */ - struct { + +/** Parameters for chainend angular potential with wall */ +typedef struct { double bend; double phi0; double distmin; double distmax; - } endangledist; -#endif - } p; +} Endangledist_bond_parameters; + +/** Union in which to store the parameters of an individual bonded interaction */ +typedef union { + Fene_bond_parameters fene; + Stretchlin_force_bond_parameters stretchlin_force; + Stretching_force_bond_parameters stretching_force; + Area_force_local_bond_parameters area_force_local; + Area_force_global_bond_parameters area_force_global; + Bending_force_bond_parameters bending_force; + Volume_force_bond_parameters volume_force; + Harmonic_bond_parameters harmonic; + Quartic_bond_parameters quartic; + Bonded_coulomb_bond_parameters bonded_coulomb; + Angle_bond_parameters angle; + Angle_harmonic_bond_parameters angle_harmonic; + Angle_cosine_bond_parameters angle_cosine; + Angle_cossquare_bond_parameters angle_cossquare; + Dihedral_bond_parameters dihedral; + Tabulated_bond_parameters tab; + Overlap_bond_parameters overlap; + Subt_lj_bond_parameters subt_lj; + Rigid_bond_parameters rigid_bond; + Angledist_bond_parameters angledist; + Endangledist_bond_parameters endangledist; + + } Bond_parameters; + +/** Defines parameters for a bonded interaction. */ +typedef struct { + /** bonded interaction type. See \ref BONDED_IA_FENE "Type code for bonded" */ + BondedInteraction type; + /** (Number of particles - 1) interacting for that type */ + int num; + /** union to store the different bonded interaction parameters. */ + Bond_parameters p; } Bonded_ia_parameters; #ifdef CONSTRAINTS @@ -735,6 +761,7 @@ typedef struct { /** whether the constraint is penetrable 1 or not 0*/ int penetrable; int reflecting; + int only_positive; } Constraint_wall; /** Parameters for a SPHERE constraint. */ @@ -795,8 +822,25 @@ typedef struct { /** cylinder length. (!!!NOTE this is only the half length of the cylinder.)*/ double length; int reflecting; + double outer_rad_left; + double outer_rad_right; } Constraint_pore; + +/** Parameters for a SLITPORE constraint. */ +typedef struct { + /** center of the cylinder. */ + double pore_mouth; + /** Axis of the cylinder .*/ + double upper_smoothing_radius; + double lower_smoothing_radius; + /** cylinder length. (!!!NOTE this is only the half length of the cylinder.)*/ + double channel_width; + double pore_width; + double pore_length; + int reflecting; +} Constraint_slitpore; + /** Parameters for a ROD constraint. */ typedef struct { /** center of the cylinder in the x-y plane. */ @@ -838,7 +882,7 @@ typedef struct { double position_y; double position_z; - /** Stomatocyte position. */ + /** Stomatocyte orientation. */ double orientation_x; double orientation_y; @@ -861,6 +905,44 @@ typedef struct { } Constraint_stomatocyte; +/** Parameters for a HOLLOW_CONE constraint. */ +typedef struct { + + /** Hollow cone position. */ + + double position_x; + double position_y; + double position_z; + + /** Hollow cone orientation. */ + + double orientation_x; + double orientation_y; + double orientation_z; + + /** Hollow cone dimensions. */ + + double inner_radius; + double outer_radius; + double width; + double opening_angle; + + /** Inside/Outside (+1 outside -1 inside interaction direction)*/ + + double direction; + + /** whether the constraint is penetrable 1 or not 0*/ + + int penetrable; + int reflecting; + +} Constraint_hollow_cone; + +/** Parameters for a BOX constraint. */ +typedef struct { + int value; +} Constraint_box; + //ER /** Parameters for a EXTERNAL MAGNETIC FIELD constraint */ typedef struct{ @@ -875,10 +957,15 @@ typedef struct { double pos[3]; } Constraint_plane; +typedef struct { + double omega; + double Prefactor; +} SinusoidalField; + /** Structure to specify a constraint. */ typedef struct { /** type of the constraint. */ - int type; + ConstraintApplied type; union { Constraint_wall wal; @@ -889,7 +976,9 @@ typedef struct { Constraint_plate plate; Constraint_maze maze; Constraint_pore pore; + Constraint_slitpore slitpore; Constraint_stomatocyte stomatocyte; + Constraint_hollow_cone hollow_cone; //ER Constraint_ext_magn_field emfield; //end ER @@ -926,20 +1015,6 @@ extern DoubleList tabulated_forces; /** Array containing all tabulated energies*/ extern DoubleList tabulated_energies; -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION -/** Array containing all adress tabulated forces*/ -extern DoubleList adress_tab_forces; -/** Array containing all adress tabulated energies*/ -extern DoubleList adress_tab_energies; -#endif -/* #ifdef THERMODYNAMIC_FORCE */ -extern DoubleList thermodynamic_forces; - -extern DoubleList thermodynamic_f_energies; -/* #endif */ -#endif - /** Maximal interaction cutoff (real space/short range interactions). */ extern double max_cut; /** Maximal interaction cutoff (real space/short range non-bonded interactions). */ @@ -968,17 +1043,6 @@ int coulomb_set_bjerrum(double bjerrum); int dipolar_set_Dbjerrum(double bjerrum); #endif -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION -/** Function for initializing adress force and energy tables */ -void adress_force_and_energy_tables_init(); -#endif -/* #ifdef THERMODYNAMIC_FORCE */ -void tf_tables_init(); -/* #endif */ - -#endif - /** copy a set of interaction parameters. */ void copy_ia_params(IA_parameters *dst, IA_parameters *src); @@ -994,13 +1058,6 @@ inline IA_parameters *get_ia_param(int i, int j) { yet present particle types*/ IA_parameters *get_ia_param_safe(int i, int j); -#ifdef ADRESS -inline TF_parameters *get_tf_param(int i) { - extern TF_parameters *tf_params; - return &tf_params[i]; -} -#endif - /** Makes sure that ia_params is large enough to cover interactions for this particle type. The interactions are initialized with values such that no physical interaction occurs. */ @@ -1018,24 +1075,20 @@ void make_bond_type_exist(int type); the other nodes. */ void realloc_ia_params(int nsize); -#ifdef ADRESS -void realloc_tf_params(int nsize); -#endif - /** calculates the maximal cutoff of all real space interactions. these are: bonded, non bonded + real space electrostatics. The result is stored in the global variable max_cut. The maximal cutoff of the non-bonded + real space electrostatic interactions is stored in max_cut_non_bonded. This value is used in the verlet pair list algorithm (see \ref - verlet.h). */ + verlet.hpp). */ void recalc_maximal_cutoff(); /** call when the temperature changes, for Bjerrum length adjusting. */ void recalc_coulomb_prefactor(); /** check whether all force calculation routines are properly initialized. */ -int check_obs_calc_initialized(); +int interactions_sanity_checks(); /** check if a non bonded interaction is defined */ inline int checkIfInteraction(IA_parameters *data) { @@ -1049,11 +1102,7 @@ inline int checkIfParticlesInteract(int i, int j) { } /// -const char *get_name_of_bonded_ia(int i); - -#ifdef ADRESS -int checkIfTF(TF_parameters *data); -#endif +const char *get_name_of_bonded_ia(BondedInteraction type); #ifdef BOND_VIRTUAL int virtual_set_params(int bond_type); diff --git a/src/core/lattice.cpp b/src/core/lattice.cpp new file mode 100644 index 00000000000..b68cbcb95d4 --- /dev/null +++ b/src/core/lattice.cpp @@ -0,0 +1,454 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lattice.cpp + * + * Lattice class definition + * + */ + +#include "lattice_inline.hpp" + +int lattice_switch = LATTICE_OFF ; + +//int Lattice::init(double *agrid, double* offset, int halo_size, size_t dim) { +int Lattice::init(double *agrid, double* offset, int halo_size, size_t dim) { + this->dim=dim; + + /* determine the number of local lattice nodes */ + for (int d=0; d<3; d++) { + this->agrid[d] = agrid[d]; + this->global_grid[d] = (int)dround(box_l[d]/agrid[d]); + this->offset[d]=offset[d]; + this->local_index_offset[d]=(int) ceil((my_left[d]-this->offset[d])/this->agrid[d]); + this->local_offset[d] = this->offset[d] + + this->local_index_offset[d]*this->agrid[d]; + this->grid[d] = (int) ceil ( ( my_right[d] - this->local_offset[d]-ROUND_ERROR_PREC ) + / this->agrid[d]); + } + + // sanity checks + for (int dir=0;dir<3;dir++) { + // check if local_box_l is compatible with lattice spacing + if (fabs(local_box_l[dir]-this->grid[dir]*agrid[dir]) > ROUND_ERROR_PREC*box_l[dir]) { + ostringstream msg; + msg << "Lattice spacing agrid["<< dir << "]=" << agrid[dir] \ + << " is incompatible with local_box_l["<< dir << "]=" << local_box_l[dir]\ + << " ( box_l["<< dir << "]=" << box_l[dir] \ + << " node_grid["<< dir << "]=" << node_grid[dir] <<" )"; + runtimeError(msg); + } + } + + this->element_size = this->dim*sizeof(double); + + LATTICE_TRACE(fprintf(stderr,"%d: box_l (%.3f,%.3f,%.3f) grid (%d,%d,%d) node_neighbors (%d,%d,%d,%d,%d,%d)\n",this_node,local_box_l[0],local_box_l[1],local_box_l[2],this->grid[0],this->grid[1],this->grid[2],node_neighbors[0],node_neighbors[1],node_neighbors[2],node_neighbors[3],node_neighbors[4],node_neighbors[5])); + + this->halo_size = halo_size; + /* determine the number of total nodes including halo */ + this->halo_grid[0] = this->grid[0] + 2*halo_size ; + this->halo_grid[1] = this->grid[1] + 2*halo_size ; + this->halo_grid[2] = this->grid[2] + 2*halo_size ; + + this->grid_volume = this->grid[0]*this->grid[1]*this->grid[2] ; + this->halo_grid_volume = this->halo_grid[0]*this->halo_grid[1]*this->halo_grid[2] ; + this->halo_grid_surface = this->halo_grid_volume - this->grid_volume ; + this->halo_offset = get_linear_index(halo_size,halo_size,halo_size,this->halo_grid) ; + + this->interpolation_type = INTERPOLATION_LINEAR; + + allocate_memory(); + return ES_OK; + +} + +void Lattice::allocate_memory() { + + this->_data = malloc(this->element_size*this->halo_grid_volume); + memset(this->_data, (unsigned int)(-1), this->element_size*this->halo_grid_volume); + +} + +void Lattice::interpolate(double* pos, double* value) { + if (this->interpolation_type == INTERPOLATION_LINEAR) { + interpolate_linear(pos, value); + } else { + ostringstream msg; + msg <<"Unknown interpolation type"; + runtimeError(msg); + } +} + +void Lattice::interpolate_linear(double* pos, double* value) { + int left_halo_index[3]; + double d[3]; + if (this->halo_size <= 0) { + ostringstream msg; + msg <<"Error in interpolate_linear: halo size is 0"; + runtimeError(msg); + return; + } + for (int dim = 0; dim<3; dim++) { + left_halo_index[dim]=(int) floor((pos[dim]-this->local_offset[dim])/this->agrid[dim]) + this->halo_size; + d[dim]=((pos[dim]-this->local_offset[dim])/this->agrid[dim] - floor((pos[dim]-this->local_offset[dim])/this->agrid[dim])); + if (left_halo_index[dim] < 0 || left_halo_index[dim] >= this->halo_grid[dim]) { + ostringstream msg; + msg <<"Error in interpolate_linear: Particle out of range"; + runtimeError(msg); + return; + } + } + double w[8]; + index_t index[8]; + w[0] = (1-d[0])*(1-d[1])*(1-d[2]); + index[0]=get_linear_index( left_halo_index[0], left_halo_index[1], left_halo_index[2], this->halo_grid); + w[1] = ( +d[0])*(1-d[1])*(1-d[2]); + index[1]=get_linear_index( left_halo_index[0]+1, left_halo_index[1], left_halo_index[2], this->halo_grid); + w[2] = (1-d[0])*( +d[1])*(1-d[2]); + index[2]=get_linear_index( left_halo_index[0], left_halo_index[1]+1, left_halo_index[2], this->halo_grid); + w[3] = ( +d[0])*( +d[1])*(1-d[2]); + index[3]=get_linear_index( left_halo_index[0]+1, left_halo_index[1]+1, left_halo_index[2], this->halo_grid); + + w[4] = (1-d[0])*(1-d[1])*( +d[2]); + index[4]=get_linear_index( left_halo_index[0], left_halo_index[1], left_halo_index[2]+1, this->halo_grid); + w[5] = ( +d[0])*(1-d[1])*( +d[2]); + index[5]=get_linear_index( left_halo_index[0]+1, left_halo_index[1], left_halo_index[2]+1, this->halo_grid); + w[6] = (1-d[0])*( +d[1])*( +d[2]); + index[6]=get_linear_index( left_halo_index[0], left_halo_index[1]+1, left_halo_index[2]+1, this->halo_grid); + w[7] = ( +d[0])*( +d[1])*( +d[2]); + index[7]=get_linear_index( left_halo_index[0]+1, left_halo_index[1]+1, left_halo_index[2]+1, this->halo_grid); + + for (unsigned int i = 0; idim; i++) { + value[i] = 0; + } + + double* local_value; + for (unsigned int i=0; i<8; i++) { + get_data_for_linear_index(index[i], (void**) &local_value); + for (unsigned int j = 0; jdim; j++) { + value[j]+=w[i]*local_value[j]; + } + } +} + +void Lattice::interpolate_gradient(double* pos, double* value) { + if (this->interpolation_type == INTERPOLATION_LINEAR) { + interpolate_linear_gradient(pos, value); + } else { + ostringstream msg; + msg <<"Unknown interpolation type"; + runtimeError(msg); + } +} + +void Lattice::interpolate_linear_gradient(double* pos, double* value) { + int left_halo_index[3]; + double d[3]; + if (this->halo_size <= 0) { + ostringstream msg; + msg << "Error in interpolate_linear: halo size is 0"; + runtimeError(msg); + return; + } + for (int dim = 0; dim<3; dim++) { + left_halo_index[dim]=(int) floor((pos[dim]-this->local_offset[dim])/this->agrid[dim]) + this->halo_size; + d[dim]=((pos[dim]-this->local_offset[dim])/this->agrid[dim] - floor((pos[dim]-this->local_offset[dim])/this->agrid[dim])); + if (left_halo_index[dim] < 0 || left_halo_index[dim] >= this->halo_grid[dim]) { + ostringstream msg; + msg <<"Error in interpolate_linear: Particle out of range"; + runtimeError(msg); + return; + } + } + + index_t index; + double* local_value; + + for (unsigned int i = 0; i<3*this->dim; i++) { + value[i] = 0; + } + + index=get_linear_index( left_halo_index[0], left_halo_index[1], left_halo_index[2], this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( -1 )*(1-d[1])*(1-d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= (1-d[0])*( -1 )*(1-d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= (1-d[0])*(1-d[1])*( -1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0]+1, left_halo_index[1], left_halo_index[2], this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( +1 )*(1-d[1])*(1-d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= ( +d[0])*( -1 )*(1-d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= ( +d[0])*(1-d[1])*( -1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0], left_halo_index[1]+1, left_halo_index[2], this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( -1 )*( +d[1])*(1-d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= (1-d[0])*( +1 )*(1-d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= (1-d[0])*( +d[1])*( -1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0]+1, left_halo_index[1]+1, left_halo_index[2], this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( +1 )*( +d[1])*(1-d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= ( +d[0])*( +1 )*(1-d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= ( +d[0])*( +d[1])*( -1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0] , left_halo_index[1] , left_halo_index[2] + 1, this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( -1 )*(1-d[1])*( +d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= (1-d[0])*( -1 )*( +d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= (1-d[0])*(1-d[1])*( +1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0]+1, left_halo_index[1], left_halo_index[2]+1, this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( +1 )*(1-d[1])*( +d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= ( +d[0])*( -1 )*( +d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= ( +d[0])*(1-d[1])*( +1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0], left_halo_index[1]+1, left_halo_index[2]+1, this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( -1 )*( +d[1])*( +d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= (1-d[0])*( +1 )*( +d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= (1-d[0])*( +d[1])*( +1 ) * local_value[i] / this->agrid[2]; + } + index=get_linear_index( left_halo_index[0]+1, left_halo_index[1]+1, left_halo_index[2]+1, this->halo_grid); + for (unsigned int i = 0; idim; i++) { + get_data_for_linear_index(index, (void**) &local_value); + value[3*i ]+= ( +1 )*( +d[1])*( +d[2]) * local_value[i] / this->agrid[0]; + value[3*i+1]+= ( +d[0])*( +1 )*( +d[2]) * local_value[i] / this->agrid[1]; + value[3*i+2]+= ( +d[0])*( +d[1])*( +1 ) * local_value[i] / this->agrid[2]; + } + +} + +void Lattice::set_data_for_global_position_with_periodic_image(double* pos, void* data) { + + index_t replica[3]; + index_t global_index[3]; + index_t halo_index[3]; + + + for (int i = 0; i<3; i++) { + global_index[i] = (int)dround((pos[i]-this->offset[i])/this->agrid[i]); + } + + for (int i=-this->halo_size; i<=this->halo_size; i++) { + for (int j=-this->halo_size; j<=this->halo_size; j++) { + for (int k=-this->halo_size; k<=this->halo_size; k++) { + replica[0]=global_index[0]+i*this->global_grid[0]; + replica[1]=global_index[1]+j*this->global_grid[1]; + replica[2]=global_index[2]+k*this->global_grid[2]; + if (map_global_index_to_halo_index(replica, halo_index)) { + set_data_for_local_halo_grid_index(halo_index, data); + } + + } + } + } +} + +int global_pos_in_local_box(double pos[3]) { + if (!(pos[0]>my_left[0] && pos[0]my_left[1] && pos[1]my_left[2] && pos[2]dim; i++) { + if (!(pos[i]>this->local_offset[i]-this->halo_size*this->agrid[i] && + pos[i]local_offset[i]+this->halo_grid[i]*this->agrid[i] )) + return 0; + } + return 1; +} + +int Lattice::global_pos_to_lattice_index_checked(double pos[3], int* index) { + int i; + for (i=0; i<3; i++) + if (abs(fmod(pos[i]-this->offset[i],this->agrid[i])) > ROUND_ERROR_PREC) + return ES_ERROR; + int ind[3]; + for (i=0; i<3; i++) + ind[i] = (int) round((pos[i]-this->offset[i])/this->agrid[i]); + *index = get_linear_index(this->halo_size + ind[0], this->halo_size + ind[1], this->halo_size + ind[2], this->halo_grid); + return ES_OK; +} + +/* @TODO: Implement! */ +int Lattice::map_lattice_to_position(int *ind, int *grid) { + return 0; +} + +void Lattice::map_linear_index_to_global_pos(index_t ind, double* pos) { + int index_in_halogrid[3]; + get_grid_pos(ind, &index_in_halogrid[0], &index_in_halogrid[1], &index_in_halogrid[2], this->halo_grid); + pos[0] = this->local_offset[0] + (index_in_halogrid[0] - this->halo_size)*this->agrid[0]; + pos[1] = this->local_offset[1] + (index_in_halogrid[1] - this->halo_size)*this->agrid[1]; + pos[2] = this->local_offset[2] + (index_in_halogrid[2] - this->halo_size)*this->agrid[2]; +} + +void Lattice::map_local_index_to_pos(index_t* index, double* pos) { + pos[0] = this->local_offset[0] + (index[0])*this->agrid[0]; + pos[1] = this->local_offset[1] + (index[1])*this->agrid[1]; + pos[2] = this->local_offset[2] + (index[2])*this->agrid[2]; +} + +int Lattice::map_global_index_to_halo_index(index_t* global_index, index_t* halo_index) { + int out=0; + for (int d=0; d<3; d++) { + halo_index[d] = global_index[d]-this->local_index_offset[d] +this->halo_size; + if (halo_index[d] < 0 || halo_index[d] >= this->halo_grid[d]) + out=1; + } + + if (out) { + return 0; + } + return 1; + +} + +void Lattice::map_halo_index_to_pos(index_t* index_in_halogrid, double* pos) { + pos[0] = this->local_offset[0] + (index_in_halogrid[0] - this->halo_size)*this->agrid[0]; + pos[1] = this->local_offset[1] + (index_in_halogrid[1] - this->halo_size)*this->agrid[1]; + pos[2] = this->local_offset[2] + (index_in_halogrid[2] - this->halo_size)*this->agrid[2]; +} + +void Lattice::map_position_to_lattice(const double pos[3], index_t node_index[8], double delta[6]) { + + int dir,ind[3] ; + double lpos, rel; + + /* determine the elementary lattice cell containing the particle + and the relative position of the particle in this cell */ + for (dir=0;dir<3;dir++) { + lpos = pos[dir] - my_left[dir]; + rel = lpos/this->agrid[dir] + 0.5; // +1 for halo offset + ind[dir] = (int)floor(rel); + + /* surrounding elementary cell is not completely inside this box, + adjust if this is due to round off errors */ + if (ind[dir] < 0) { + if (abs(rel) < ROUND_ERROR_PREC) { + ind[dir] = 0; // TODO + } else { + fprintf(stderr,"%d: map_position_to_lattice: position (%f,%f,%f) not inside a local plaquette in dir %d ind[dir]=%d rel=%f lpos=%f.\n",this_node,pos[0],pos[1],pos[2],dir,ind[dir],rel,lpos); + } + } + else if (ind[dir] > this->grid[dir]) { + if (lpos - local_box_l[dir] < ROUND_ERROR_PREC*local_box_l[dir]) + ind[dir] = this->grid[dir]; + else + fprintf(stderr,"%d: map_position_to_lattice: position (%f,%f,%f) not inside a local plaquette in dir %d ind[dir]=%d rel=%f lpos=%f.\n",this_node,pos[0],pos[1],pos[2],dir,ind[dir],rel,lpos); + } + + delta[3+dir] = rel - ind[dir]; // delta_x/a + delta[dir] = 1.0 - delta[3+dir]; + } + + node_index[0] = get_linear_index(ind[0],ind[1],ind[2],this->halo_grid); + node_index[1] = node_index[0] + 1; + node_index[2] = node_index[0] + this->halo_grid[0]; + node_index[3] = node_index[0] + this->halo_grid[0] + 1; + node_index[4] = node_index[0] + this->halo_grid[0]*this->halo_grid[1]; + node_index[5] = node_index[4] + 1; + node_index[6] = node_index[4] + this->halo_grid[0]; + node_index[7] = node_index[4] + this->halo_grid[0] + 1; +} + +void Lattice::get_data_for_halo_index(index_t* ind, void** data) { + (*data) = ((char*)this->_data) + get_linear_index(ind[0], ind[1], ind[2], this->halo_grid)*this->element_size; +} + +void Lattice::get_data_for_linear_index(index_t ind, void** data) { + (*data) = ((char*)this->_data) + ind*this->element_size; +} + +void Lattice::get_data_for_local_index(index_t* ind, void** data) { + index_t index_in_halogrid[3]; + index_in_halogrid[0] = ind[0]+this->halo_size; + index_in_halogrid[1] = ind[1]+this->halo_size; + index_in_halogrid[2] = ind[2]+this->halo_size; + (*data) = ((char*)this->_data) + get_linear_index(index_in_halogrid[0], index_in_halogrid[1], index_in_halogrid[2], this->halo_grid)*this->element_size; +} + +void Lattice::set_data_for_local_halo_grid_index(index_t* ind, void* data) { + memcpy(((char*)this->_data) + get_linear_index(ind[0], ind[1], ind[2], this->halo_grid)*this->element_size, data, this->element_size); + +} + +void Lattice::set_data_for_local_grid_index(index_t* ind, void* data) { + memcpy(((char*)this->_data) + get_linear_index(ind[0]+this->halo_size, ind[1]+this->halo_size, ind[2]+this->halo_size, this->halo_grid)*this->element_size, data, this->element_size); +} + +int Lattice::global_pos_to_lattice_halo_index(double* pos, index_t* ind) { + for (int i = 0; i<3; i++) { + ind[i] = (int)dround((pos[i]-this->local_offset[i])/this->agrid[i])+this->halo_size; + if (ind[i] < 0 || ind[i] >= this->halo_grid[i]) + return 0; + } + return 1; +} + +/********************** static Functions **********************/ + +void Lattice::map_position_to_lattice_global (double pos[3], int ind[3], double delta[6], double tmp_agrid) { + //not sure why I don't have access to agrid here so I make a temp var and pass it to this function + int i; + double rel[3]; + // fold the position onto the local box, note here ind is used as a dummy variable + for (i=0;i<3;i++) { + pos[i] = pos[i]-0.5*tmp_agrid; + } + +#ifdef LEES_EDWARDS + double tmp[3]; + fold_position (pos,tmp,ind); +#else + fold_position (pos,ind); +#endif + + // convert the position into lower left grid point + for (i=0;i<3;i++) { + rel[i] = (pos[i])/tmp_agrid; + } + + // calculate the index of the position + for (i=0;i<3;i++) { + ind[i] = floor(rel[i]); + } + + // calculate the linear interpolation weighting + for (i=0;i<3;i++) { + delta[3+i] = rel[i] - ind[i]; + delta[i] = 1 - delta[3+i]; + } + +} diff --git a/src/core/lattice.hpp b/src/core/lattice.hpp new file mode 100644 index 00000000000..62fe6bc2c03 --- /dev/null +++ b/src/core/lattice.hpp @@ -0,0 +1,206 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lattice.hpp + * + * Lattice class definition + * Contains the lattice layout and pointers to the data fields. + * For parallelization purposes, it is assumed that a halo region + * surrounds the local lattice sites. + */ + +#ifndef _LATTICE_HPP +#define _LATTICE_HPP + +#include "grid.hpp" +#include "particle_data.hpp" + +/** Switch determining the type of lattice dynamics. A value of zero + * means that there is no lattice dynamics. Different types can be + * combined by or'ing the respective flags. + * So far, only \ref LATTICE_OFF and \ref LATTICE_LB exist. + */ +extern int lattice_switch; + +#define LATTICE_LB 1 /** Lattice Boltzmann */ +#define LATTICE_LB_GPU 2 /** Lattice Boltzmann */ +#define INTERPOLATION_LINEAR 1 +#define index_t long +#define LATTICE_OFF 0 /** Lattice off */ + +enum { LATTICE_ANISOTROPIC = 1, + LATTICE_X_NOTEXT = 2, LATTICE_Y_NOTEXT = 4, LATTICE_Z_NOTEXT = 8 }; + +class Lattice { +public: + int grid[3] ;/** number of local lattice sites in each direction (excluding halo) */ + int global_grid[3]; + unsigned int dim; + double agrid[3];/** lattice constant */ + + int halo_grid[3] ;/** number of lattice sites in each direction including halo */ + int halo_size;/** halo size in all directions */ + + double offset[3];/** global offset */ + double local_offset[3]; + int local_index_offset[3]; + + unsigned int interpolation_type; + char flags; + size_t element_size;/** Size of each element in size units (=bytes) */ + size_t lattice_dim;/** Dimension of the field, assuming entries are arrays */ + + index_t grid_volume;/** total number (volume) of local lattice sites (excluding halo) */ + index_t halo_grid_volume;/** total number (volume) of lattice sites (including halo) */ + index_t halo_grid_surface;/** number of lattice sites in the halo region */ + index_t halo_offset;/** offset for number of halo sites stored in front of the local lattice sites */ + + void *_data;/** pointer to the actual lattice data. This can be a contiguous field of arbitrary data. */ + + /** particle representation of this lattice. This is needed to + * specify interactions between particles and the lattice. + * Actually used are only the identity and the type. */ + Particle part_rep; + + /* Constructor */ + Lattice() {} + + /** Initialize lattice. + * + * This function initializes the variables describing the lattice + * layout. Important: The lattice data is not allocated here! + * + * \param lattice pointer to the lattice + * \param agrid lattice spacing + */ + int init(double* agrid, double* offset, int halo_size, size_t dim); + + /** lattice memory allocation. + * \param lattice pointer to the lattice + */ + void allocate_memory(); + void allocate_memory(size_t element_size); + + void interpolate(double* pos, double* value); + + void interpolate_linear(double* pos, double* value); + + void interpolate_gradient(double* pos, double* value); + + void interpolate_linear_gradient(double* pos, double* value); + + void set_data_for_global_position_with_periodic_image(double* pos, void* data); + + int global_pos_in_local_box(double pos[3]); + + int global_pos_in_local_halobox(double pos[3]); + + int global_pos_to_lattice_index_checked(double pos[3], int* index); + + /** Map a local lattice site to the global position. + * + * This function determines the processor responsible for + * the specified lattice site. The coordinates of the site are + * taken as global coordinates andcoordinates of the site are + * taken as global coordinates and are returned as local coordinates. + * + * \param lattice pointer to the lattice + * \param ind global coordinates of the lattice site (Input) + * \param grid local coordinates of the lattice site (Output) + * \return index of the node for the lattice site + */ + /* @TODO: Implement! */ + int map_lattice_to_position(int *ind, int *grid); + + void map_linear_index_to_global_pos(index_t ind, double* pos); + + void map_local_index_to_pos(index_t* index, double* pos); + + int map_global_index_to_halo_index(index_t* global_index, index_t* halo_index); + + void map_halo_index_to_pos(index_t* index_in_halogrid, double* pos); + + /** Map a spatial position to the surrounding lattice sites. + * + * This function takes a global spatial position and determines the + * surrounding elementary cell of the lattice for this position. + * The distance fraction in each direction is also calculated. + *
    Remarks: + *
      + *
    • The spatial position has to be in the local domain.
    • + *
    • The lattice sites of the elementary cell are returned as local indices
    • + *
    + * \param lattice pointer to the lattice (Input) + * \param pos spatial position (Input) + * \param node_index local indices of the surrounding lattice sites (Output) + * \param delta distance fraction of pos from the surrounding + * elementary cell, 6 directions (Output) + */ + void map_position_to_lattice(const double pos[3], index_t node_index[8], double delta[6]); + + void get_data_for_halo_index(index_t* ind, void** data); + + void get_data_for_linear_index(index_t ind, void** data); + + void get_data_for_local_index(index_t* ind, void** data); + + void set_data_for_local_halo_grid_index(index_t* ind, void* data); + + void set_data_for_local_grid_index(index_t* ind, void* data); + + int global_pos_to_lattice_halo_index(double* pos, index_t* ind); + + /********************** Inline Functions **********************/ + + /** Map a global lattice site to the node grid. + * + * This function determines the processor responsible for + * the specified lattice site. The coordinates of the site are + * taken as global coordinates and are returned as local coordinates. + * + * \param lattice pointer to the lattice + * \param ind global coordinates of the lattice site (Input) + * \param grid local coordinates of the lattice site (Output) + * \return index of the node for the lattice site + */ + int map_lattice_to_node(int *ind, int *grid); + + /********************** static Functions **********************/ + + /** Map a spatial position to the surrounding lattice sites. + * + * This function takes a global spatial position and determines the + * surrounding elementary cell of the lattice for this position. + * The distance fraction in each direction is also calculated. + *
    Remarks: + *
      + *
    • The spatial position is given in global coordinates.
    • + *
    • The lattice sites of the elementary cell are returned as local indices
    • + *
    + * \param pos spatial position (Input) + * \param ind global index of the lower left lattice site (Output) + * \param delta distance fraction of pos from the surrounding + * elementary cell, 6 directions (Output) + * \param tmp_agrid lattice mesh distance + */ + static void map_position_to_lattice_global (double pos[3], int ind[3], double delta[6], double tmp_agrid); +}; + +#endif /* LATTICE_HPP */ diff --git a/src/core/lattice_inline.hpp b/src/core/lattice_inline.hpp new file mode 100644 index 00000000000..3b0fc6e2e72 --- /dev/null +++ b/src/core/lattice_inline.hpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lattice_inline.hpp */ + +#ifndef LATTICE_INLINE_HPP +#define LATTICE_INLINE_HPP + +#include "lattice.hpp" + +inline int Lattice::map_lattice_to_node(int *ind, int *grid) { + + /* determine coordinates in node_grid */ + grid[0] = (int)floor(ind[0]*this->agrid[0]*box_l_i[0]*node_grid[0]); + grid[1] = (int)floor(ind[1]*this->agrid[1]*box_l_i[1]*node_grid[1]); + grid[2] = (int)floor(ind[2]*this->agrid[2]*box_l_i[2]*node_grid[2]); + + //fprintf(stderr,"%d: (%d,%d,%d)\n",this_node,grid[0],grid[1],grid[2]); + + /* change from global to local lattice coordinates */ + ind[0] = ind[0] - grid[0]*this->grid[0] + this->halo_size; + ind[1] = ind[1] - grid[1]*this->grid[1] + this->halo_size; + ind[2] = ind[2] - grid[2]*this->grid[2] + this->halo_size; + + /* return linear index into node array */ + return map_array_node(grid); +} + +#endif // LATTICE_INLINE_HPP diff --git a/src/layered.cpp b/src/core/layered.cpp similarity index 94% rename from src/layered.cpp rename to src/core/layered.cpp index c20bb88e78a..7fa59c7ec59 100644 --- a/src/layered.cpp +++ b/src/core/layered.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file layered.c - Implementation of \ref layered.h "layered.h". +/** \file layered.cpp + Implementation of \ref layered.hpp "layered.h". */ #include #include @@ -32,7 +32,7 @@ #include "ghosts.hpp" #include "forces.hpp" #include "pressure.hpp" -#include "energy.hpp" +#include "energy_inline.hpp" #include "constraint.hpp" #include "domain_decomposition.hpp" @@ -320,8 +320,9 @@ void layered_topology_init(CellPList *old) /* check node grid. All we can do is 1x1xn. */ if (node_grid[0] != 1 || node_grid[1] != 1) { - char *errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{016 selected node grid is not suitable for layered cell structure (needs 1x1x%d grid)} ", n_nodes); + ostringstream msg; + msg <<"selected node grid is not suitable for layered cell structure (needs 1x1x"<< n_nodes << " grid"; + runtimeError(msg); node_grid[0] = node_grid[1] = 1; node_grid[2] = n_nodes; } @@ -330,8 +331,9 @@ void layered_topology_init(CellPList *old) if (max_range > 0) { n_layers = (int)floor(local_box_l[2]/max_range); if (n_layers < 1) { - char *errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt, "{017 layered: maximal interaction range %g larger than local box length %g} ", max_range, local_box_l[2]); + ostringstream msg; + msg <<"layered: maximal interaction range " << max_range << " larger than local box length " << local_box_l[2]; + runtimeError(msg); n_layers = 1; } if (n_layers > max_num_cells - 2) @@ -353,8 +355,9 @@ void layered_topology_init(CellPList *old) layer_h_i = 1/layer_h; if (layer_h < max_range) { - char *errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt, "{018 layered: maximal interaction range %g larger than layer height %g} ", max_range, layer_h); + ostringstream msg; + msg <<"layered: maximal interaction range " << max_range << " larger than layer height " << layer_h; + runtimeError(msg); } /* check wether node is top and/or bottom */ @@ -409,7 +412,11 @@ static void layered_append_particles(ParticleList *pl, ParticleList *up, Particl CELL_TRACE(fprintf(stderr, "%d: sorting in %d\n", this_node, pl->n)); for(p = 0; p < pl->n; p++) { +#ifdef LEES_EDWARDS + fold_position(pl->part[p].r.p, pl->part[p].m.v, pl->part[p].l.i); +#else fold_position(pl->part[p].r.p, pl->part[p].l.i); +#endif if (LAYERED_BTM_NEIGHBOR && pl->part[p].r.p[2] < my_left[2]) { CELL_TRACE(fprintf(stderr, "%d: leaving part %d for node below\n", this_node, pl->part[p].p.identity)); move_indexed_particle(dn, pl, p); @@ -460,7 +467,11 @@ void layered_exchange_and_sort_particles(int global_flag) } else { /* particle stays here. Fold anyways to get x,y correct */ - fold_position(part->r.p, part->l.i); +#ifdef LEES_EDWARDS + fold_position(part->r.p, part->m.v, part->l.i); +#else + fold_position(part->r.p, part->l.i); +#endif nc = layered_position_to_cell(part->r.p); if (nc != oc) { move_indexed_particle(nc, oc, p); @@ -512,7 +523,6 @@ void layered_exchange_and_sort_particles(int global_flag) } } } -#ifdef ADDITIONAL_CHECKS else { if (recv_buf.n != 0 || send_buf_dn.n != 0 || send_buf_up.n != 0) { fprintf(stderr, "1 node but transfer buffers are not empty. send up %d, down %d, recv %d\n", @@ -520,7 +530,6 @@ void layered_exchange_and_sort_particles(int global_flag) errexit(); } } -#endif layered_append_particles(&recv_buf, &send_buf_up, &send_buf_dn); /* handshake redo */ @@ -536,8 +545,9 @@ void layered_exchange_and_sort_particles(int global_flag) } else { if (flag) { - char *errtxt = runtime_error(128 + ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{019 layered_exchange_and_sort_particles: particle moved more than one cell} "); + ostringstream msg; + msg <<"layered_exchange_and_sort_particles: particle moved more than one cell"; + runtimeError(msg); /* sort left over particles into border cells */ CELL_TRACE(fprintf(stderr, "%d: emergency sort\n", this_node)); @@ -583,6 +593,7 @@ void layered_calculate_ia() #ifdef CONSTRAINTS add_constraints_forces(p1); #endif + add_external_potential_forces(p1); /* cell itself and bonded / constraints */ for(j = i+1; j < npl; j++) { @@ -639,6 +650,7 @@ void layered_calculate_energies() #ifdef CONSTRAINTS add_constraints_energy(p1); #endif + add_external_potential_energy(p1); /* cell itself and bonded / constraints */ for(j = i+1; j < npl; j++) { diff --git a/src/layered.hpp b/src/core/layered.hpp similarity index 93% rename from src/layered.hpp rename to src/core/layered.hpp index a0a360bc689..5e63a742a4b 100644 --- a/src/layered.hpp +++ b/src/core/layered.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file layered.h +/** \file layered.hpp The layered cellsystem. This cellsystem is a combination of a single processor n-squared method along x and y, and a multiprocessor domain decomposition along z. Therefore only \f$1\times 1\times N\f$ processors grids are allowed for this cellsystem. The implementation is pretty similar to - \ref domain_decomposition.h "domain_decomposition.h". + \ref domain_decomposition.hpp "domain_decomposition.h". */ #ifndef LAYERED_H #define LAYERED_H diff --git a/src/lb-boundaries.cpp b/src/core/lb-boundaries.cpp similarity index 51% rename from src/lb-boundaries.cpp rename to src/core/lb-boundaries.cpp index a107f6ed2ff..180519bc9c1 100644 --- a/src/lb-boundaries.cpp +++ b/src/core/lb-boundaries.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group, @@ -18,17 +18,20 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb-boundaries.c +/** \file lb-boundaries.cpp * * Boundary conditions for Lattice Boltzmann fluid dynamics. - * Header file for \ref lb-boundaries.h. + * Header file for \ref lb-boundaries.hpp. * */ + #include "utils.hpp" #include "constraint.hpp" #include "lb-boundaries.hpp" #include "lbgpu.hpp" #include "lb.hpp" +#include "electrokinetics.hpp" +#include "electrokinetics_pdb_parse.hpp" #include "interaction_data.hpp" #include "communication.hpp" @@ -47,29 +50,33 @@ void lbboundary_mindist_position(double pos[3], double* mindist, double distvec[ for(n=0;n dist_tmp || n == 0) { dist = dist_tmp; boundary_number = n; } +#ifdef EK_BOUNDARIES + if (ek_initialized) + { + if(dist_tmp <= 0 && lb_boundaries[n].charge_density != 0.0f) { + node_charged = 1; + node_wallcharge += lb_boundaries[n].charge_density * ek_parameters.agrid*ek_parameters.agrid*ek_parameters.agrid; + } + } +#endif } - - if (dist <= 0 && boundary_number >= 0 && n_lb_boundaries > 0) { + +#ifdef EK_BOUNDARIES + if(pdb_boundary_lattice && + pdb_boundary_lattice[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x]) { + dist = -1; + boundary_number = n_lb_boundaries; // Makes sure that boundary_number is not used by a constraint + } +#endif + if (dist <= 0 && boundary_number >= 0 && (n_lb_boundaries > 0 || pdb_boundary_lattice)) { size_of_index = (number_of_boundnodes+1)*sizeof(int); host_boundary_node_list = (int *) realloc(host_boundary_node_list, size_of_index); host_boundary_index_list = (int *) realloc(host_boundary_index_list, size_of_index); host_boundary_node_list[number_of_boundnodes] = x + lbpar_gpu.dim_x*y + lbpar_gpu.dim_x*lbpar_gpu.dim_y*z; host_boundary_index_list[number_of_boundnodes] = boundary_number + 1; number_of_boundnodes++; - // printf("boundindex %i: \n", number_of_boundnodes); + //printf("boundindex %i: \n", number_of_boundnodes); } + +#ifdef EK_BOUNDARIES + if (ek_initialized) + { + if(wallcharge_species != -1) { + if(pdb_charge_lattice && + pdb_charge_lattice[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x] != 0.0f) { + node_charged = 1; + node_wallcharge += pdb_charge_lattice[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x]; + } + if(node_charged) + host_wallcharge_species_density[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x] = node_wallcharge / ek_parameters.valency[wallcharge_species]; + else if(dist <= 0) + host_wallcharge_species_density[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x] = 0.0f; + else + host_wallcharge_species_density[ek_parameters.dim_y*ek_parameters.dim_x*z + ek_parameters.dim_x*y + x] = ek_parameters.density[wallcharge_species] * ek_parameters.agrid*ek_parameters.agrid*ek_parameters.agrid; + } + } +#endif } } } /**call of cuda fkt*/ - float* boundary_velocity = (float *) malloc(3*n_lb_boundaries*sizeof(float)); + float* boundary_velocity = (float *) malloc(3*(n_lb_boundaries+1)*sizeof(float)); for (n=0; n 0 && x -lbmodel.c[i][0] < lblattice.grid[0]+1 && + y-lbmodel.c[i][1] > 0 && y -lbmodel.c[i][1] < lblattice.grid[1]+1 && + z-lbmodel.c[i][2] > 0 && z -lbmodel.c[i][2] < lblattice.grid[2]+1) { + if ( !lbfields[k-next[i]].boundary ) { + for (l=0; l<3; l++) { + lb_boundaries[lbfields[k].boundary-1].force[l]+=(2*lbfluid[1][i][k]+population_shift)*lbmodel.c[i][l]; + } + lbfluid[1][reverse[i]][k-next[i]] = lbfluid[1][i][k] + population_shift; + } + else + lbfluid[1][reverse[i]][k-next[i]] = lbfluid[1][i][k]; + } + } + } + } + } + } +#else +#error Bounce back boundary conditions are only implemented for PUSH scheme! +#endif +#else +#error Bounce back boundary conditions are only implemented for D3Q19! +#endif +} + +#endif diff --git a/src/lb-boundaries.hpp b/src/core/lb-boundaries.hpp similarity index 50% rename from src/lb-boundaries.hpp rename to src/core/lb-boundaries.hpp index 2b16e987d31..8b2d548af74 100644 --- a/src/lb-boundaries.hpp +++ b/src/core/lb-boundaries.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb-boundaries.h +/** \file lb-boundaries.hpp * * Boundary conditions for Lattice Boltzmann fluid dynamics. - * Header file for \ref lb-boundaries.c. + * Header file for \ref lb-boundaries.cpp. * * In the current version only simple bounce back walls are implemented. Thus * after the streaming step, in all wall nodes all populations are bounced @@ -36,12 +36,9 @@ #ifndef LB_BOUNDARIES_H #define LB_BOUNDARIES_H + #include "utils.hpp" -#include "halo.hpp" #include "constraint.hpp" -#include "config.hpp" -#include "lb.hpp" - #if defined (LB_BOUNDARIES) || defined (LB_BOUNDARIES_GPU) @@ -57,6 +54,10 @@ #define LB_BOUNDARY_RHOMBOID 5 /** stomatocyte shaped constraint applied */ #define LB_BOUNDARY_STOMATOCYTE 6 +/** box shaped constraint (for electrokinetics reaction code) */ +#define LB_BOUNDARY_BOX 7 +/** hollow cone shaped constraint (for electrokinetics reaction code) */ +#define LB_BOUNDARY_HOLLOW_CONE 8 // If we have several possible types of boundary treatment #define LB_BOUNDARY_BOUNCE_BACK 1 @@ -74,9 +75,14 @@ typedef struct { Constraint_rhomboid rhomboid; Constraint_pore pore; Constraint_stomatocyte stomatocyte; + Constraint_box box; + Constraint_hollow_cone hollow_cone; } c; double force[3]; double velocity[3]; +#ifdef EK_BOUNDARIES + float charge_density; +#endif } LB_Boundary; extern int n_lb_boundaries; @@ -96,10 +102,6 @@ int lbboundary_get_force(int no, double* f); #endif // (LB_BOUNDARIES) || (LB_BOUNDARIES_GPU) #ifdef LB_BOUNDARIES - -void lb_init_boundaries(); - - /** Bounce back boundary conditions. * The populations that have propagated into a boundary node * are bounced back to the node they came from. This results @@ -107,80 +109,7 @@ void lb_init_boundaries(); * * [cf. Ladd and Verberg, J. Stat. Phys. 104(5/6):1191-1251, 2001] */ -inline void lb_bounce_back() { - -#ifdef D3Q19 -#ifndef PULL - int k,i,l; - int yperiod = lblattice.halo_grid[0]; - int zperiod = lblattice.halo_grid[0]*lblattice.halo_grid[1]; - int next[19]; - int x,y,z; - double population_shift; - double modes[19]; - next[0] = 0; // ( 0, 0, 0) = - next[1] = 1; // ( 1, 0, 0) + - next[2] = - 1; // (-1, 0, 0) - next[3] = yperiod; // ( 0, 1, 0) + - next[4] = - yperiod; // ( 0,-1, 0) - next[5] = zperiod; // ( 0, 0, 1) + - next[6] = - zperiod; // ( 0, 0,-1) - next[7] = (1+yperiod); // ( 1, 1, 0) + - next[8] = - (1+yperiod); // (-1,-1, 0) - next[9] = (1-yperiod); // ( 1,-1, 0) - next[10] = - (1-yperiod); // (-1, 1, 0) + - next[11] = (1+zperiod); // ( 1, 0, 1) + - next[12] = - (1+zperiod); // (-1, 0,-1) - next[13] = (1-zperiod); // ( 1, 0,-1) - next[14] = - (1-zperiod); // (-1, 0, 1) + - next[15] = (yperiod+zperiod); // ( 0, 1, 1) + - next[16] = - (yperiod+zperiod); // ( 0,-1,-1) - next[17] = (yperiod-zperiod); // ( 0, 1,-1) - next[18] = - (yperiod-zperiod); // ( 0,-1, 1) + - int reverse[] = { 0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15, 18, 17 }; - - /* bottom-up sweep */ -// for (k=lblattice.halo_offset;k 0 && x -lbmodel.c[i][0] < lblattice.grid[0]+1 && - y-lbmodel.c[i][1] > 0 && y -lbmodel.c[i][1] < lblattice.grid[1]+1 && - z-lbmodel.c[i][2] > 0 && z -lbmodel.c[i][2] < lblattice.grid[2]+1) { - if ( !lbfields[k-next[i]].boundary ) { - for (l=0; l<3; l++) { - lb_boundaries[lbfields[k].boundary-1].force[l]+=(2*lbfluid[1][i][k]+population_shift)*lbmodel.c[i][l]; - } - lbfluid[1][reverse[i]][k-next[i]] = lbfluid[1][i][k] + population_shift; - } - else - lbfluid[1][reverse[i]][k-next[i]] = lbfluid[1][i][k]; - } - } - } - } - } - } -#else -#error Bounce back boundary conditions are only implemented for PUSH scheme! -#endif -#else -#error Bounce back boundary conditions are only implemented for D3Q19! -#endif -} - - - +void lb_bounce_back(); #endif /* LB_BOUNDARIES */ #endif /* LB_BOUNDARIES_H */ diff --git a/src/lb-d3q18.hpp b/src/core/lb-d3q18.hpp similarity index 97% rename from src/lb-d3q18.hpp rename to src/core/lb-d3q18.hpp index dd8624ccc99..0980af1f928 100644 --- a/src/lb-d3q18.hpp +++ b/src/core/lb-d3q18.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb-d3q18.h +/** \file lb-d3q18.hpp * Header file for the lattice Boltzmann D3Q18 model. * * This header file contains the definition of the D3Q18 model. diff --git a/src/lb-d3q19.hpp b/src/core/lb-d3q19.hpp similarity index 98% rename from src/lb-d3q19.hpp rename to src/core/lb-d3q19.hpp index 09f5da509c1..d11eea83a53 100644 --- a/src/lb-d3q19.hpp +++ b/src/core/lb-d3q19.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb-d3q19.h +/** \file lb-d3q19.hpp * Header file for the lattice Boltzmann D3Q19 model. * * This header file contains the definition of the D3Q19 model. diff --git a/src/core/lb.cpp b/src/core/lb.cpp new file mode 100644 index 00000000000..58232f547b7 --- /dev/null +++ b/src/core/lb.cpp @@ -0,0 +1,3728 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lb.cpp + * + * Lattice Boltzmann algorithm for hydrodynamic degrees of freedom. + * + * Includes fluctuating LB and coupling to MD particles via frictional + * momentum transfer. + * + */ + +#include +#include +#include "utils.hpp" +#include "communication.hpp" +#include "grid.hpp" +#include "domain_decomposition.hpp" +#include "interaction_data.hpp" +#include "thermostat.hpp" +#include "halo.hpp" +#include "lb-d3q19.hpp" +#include "lb-boundaries.hpp" +#include "lb.hpp" + +#include "cuda_interface.hpp" + +// global variable holding the number of fluid components (see global.cpp) +int lb_components = LB_COMPONENTS; + +#ifdef LB + +#ifdef ADDITIONAL_CHECKS +static void lb_check_halo_regions(); +#endif // ADDITIONAL_CHECKS + +/** Flag indicating momentum exchange between particles and fluid */ +int transfer_momentum = 0; + +/** Struct holding the Lattice Boltzmann parameters */ +// LB_Parameters lbpar = { .rho={0.0}, .viscosity={0.0}, .bulk_viscosity={-1.0}, .agrid=-1.0, .tau=-1.0, .friction={0.0}, .ext_force={ 0.0, 0.0, 0.0},.rho_lb_units={0.},.gamma_odd={0.}, .gamma_even={0.} }; +LB_Parameters lbpar = { + // rho + {0.0}, + // viscosity + {0.0}, + // bulk_viscosity + {-1.0}, + // agrid + -1.0, + // tau + -1.0, + // friction + {0.0}, + // ext_force + { 0.0, 0.0, 0.0}, + // rho_lb_units + {0.}, + // gamma_odd + {0.}, + // gamma_even + {0.}, + // resend_halo + 0 +}; + +/** The DnQm model to be used. */ +LB_Model lbmodel = { 19, d3q19_lattice, d3q19_coefficients, d3q19_w, NULL, 1./3. }; +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * ! MAKE SURE THAT D3Q19 is #undefined WHEN USING OTHER MODELS ! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* doesn't work yet */ +#ifndef D3Q19 +#error The implementation only works for D3Q19 so far! +#endif // D3Q19 + +#if (!defined(FLATNOISE) && !defined(GAUSSRANDOMCUT) && !defined(GAUSSRANDOM)) +#define FLATNOISE +#endif // (!defined(FLATNOISE) && !defined(GAUSSRANDOMCUT) && !defined(GAUSSRANDOM)) + +/** The underlying lattice structure */ +Lattice lblattice; + +/** Pointer to the velocity populations of the fluid nodes */ +double **lbfluid[2] = { NULL, NULL }; + +/** Pointer to the hydrodynamic fields of the fluid nodes */ +LB_FluidNode *lbfields = NULL; + +/** Communicator for halo exchange between processors */ +HaloCommunicator update_halo_comm = { 0, NULL }; + +/** \name Derived parameters */ +/*@{*/ +/** Flag indicating whether fluctuations are present. */ +static int fluct; + +/** relaxation rate of shear modes */ +double gamma_shear = 0.0; +/** relaxation rate of bulk modes */ +double gamma_bulk = 0.0; +/** relaxation of the odd kinetic modes */ +static double gamma_odd = 0.0; +/** relaxation of the even kinetic modes */ +static double gamma_even = 0.0; +/** amplitudes of the fluctuations of the modes */ +static double lb_phi[19]; +/** amplitude of the fluctuations in the viscous coupling */ +static double lb_coupl_pref = 0.0; +/** amplitude of the fluctuations in the viscous coupling with gaussian random numbers */ +static double lb_coupl_pref2 = 0.0; +/*@}*/ + +/** measures the MD time since the last fluid update */ +static double fluidstep=0.0; + +#ifdef ADDITIONAL_CHECKS +/** counts the random numbers drawn for fluctuating LB and the coupling */ +static int rancounter=0; +/** counts the occurences of negative populations due to fluctuations */ +static int failcounter=0; +#endif // ADDITIONAL_CHECKS + +/***********************************************************************/ +#endif // LB + +#if defined (LB) || defined (LB_GPU) + +/* *********************** C Interface part *************************************/ +/* ******************************************************************************/ + +#ifdef SHANCHEN +int lb_lbfluid_set_shanchen_coupling(double *p_coupling) { +#ifdef LB_GPU + int ii,jj,n=0; + switch(LB_COMPONENTS){ + case 1: + lbpar_gpu.coupling[0] = (float)p_coupling[0]; + lbpar_gpu.coupling[1] = (float)p_coupling[1]; + break; + default: + for(ii=0;iiaffinity_on=0; + if (!data) return ES_ERROR; + for(int ii=0;ii1) { return ES_ERROR; } + data->affinity[ii]= affinity[ii]; + if (data->affinity[ii]>0) data->affinity_on=1; + } + + /* broadcast interaction parameters */ + mpi_bcast_ia_params(part_type_a, part_type_b); + + return ES_OK; +} + +#endif // SHANCHEN + +int lb_lbfluid_set_density(double *p_dens) { + for (int ii=0;ii 1 ) + return -1; + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + lbpar_gpu.gamma_odd[ii] = (float)p_gamma_odd[ii]; + on_lb_params_change_gpu(0); +#endif // LB_GPU + } else { +#ifdef LB + lbpar.gamma_odd[ii] = gamma_odd = p_gamma_odd[ii]; + mpi_bcast_lb_params(0); +#endif // LB + } + } + return 0; +} + +int lb_lbfluid_set_gamma_even(double *p_gamma_even) +{ + for (int ii=0;ii 1 ) + return -1; + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + lbpar_gpu.gamma_even[ii] = (float)p_gamma_even[ii]; + on_lb_params_change_gpu(0); +#endif // LB_GPU + } else { +#ifdef LB + lbpar.gamma_even[ii] = gamma_even = p_gamma_even[ii]; + mpi_bcast_lb_params(0); +#endif // LB + } + } + return 0; +} + + +int lb_lbfluid_set_friction(double * p_friction) +{ + for (int ii=0;ii ROUND_ERROR_PREC) { + ostringstream msg; + msg <<"Lattice spacing p_agrid= " << p_agrid << " is incompatible with box_l[" << dir << "]=" + << box_l[dir] << ", factor=" << tmp[dir] << " err= " << fabs(box_l[dir]-tmp[dir]*p_agrid); + runtimeError(msg); + } + } + lbpar_gpu.number_of_nodes = lbpar_gpu.dim_x * lbpar_gpu.dim_y * lbpar_gpu.dim_z; + on_lb_params_change_gpu(LBPAR_AGRID); +#endif // LB_GPU + } else { +#ifdef LB + lbpar.agrid = p_agrid; + mpi_bcast_lb_params(LBPAR_AGRID); +#endif // LB + } + return 0; +} + + +int lb_lbfluid_set_tau(double p_tau){ + if ( p_tau <= 0 ) + return -1; + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + lbpar_gpu.tau = (float)p_tau; + on_lb_params_change_gpu(0); +#endif // LB_GPU + } else { +#ifdef LB + lbpar.tau = p_tau; + mpi_bcast_lb_params(0); +#endif // LB + } + return 0; +} + + +#ifdef SHANCHEN +int lb_lbfluid_set_remove_momentum(void){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + lbpar_gpu.remove_momentum = 1; + on_lb_params_change_gpu(0); +#endif // LB_GPU + } else { +#ifdef LB + return -1; +#endif // LB + } + return 0; +} +#endif // SHANCHEN + + +int lb_lbfluid_set_ext_force(int component, double p_fx, double p_fy, double p_fz) { + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + /* external force density is stored in MD units */ + lbpar_gpu.ext_force[3*component+0] = (float)p_fx; + lbpar_gpu.ext_force[3*component+1] = (float)p_fy; + lbpar_gpu.ext_force[3*component+2] = (float)p_fz; + lbpar_gpu.external_force = 1; + lb_reinit_extern_nodeforce_GPU(&lbpar_gpu); +#endif // LB_GPU + } else { +#ifdef LB + lbpar.ext_force[0] = p_fx; + lbpar.ext_force[1] = p_fy; + lbpar.ext_force[2] = p_fz; + mpi_bcast_lb_params(LBPAR_EXTFORCE); +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_density(double* p_dens){ +// TODO: implement all lb_lbfluid_get_*() correctly for all components!! + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_dens = lbpar_gpu.rho[0]; +#endif // LB_GPU + } else { +#ifdef LB + *p_dens = lbpar.rho[0]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_visc(double* p_visc){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_visc = lbpar_gpu.viscosity[0]; +#endif // LB_GPU + } else { +#ifdef LB + *p_visc = lbpar.viscosity[0]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_bulk_visc(double* p_bulk_visc){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_bulk_visc = lbpar_gpu.bulk_viscosity[0]; +#endif // LB_GPU + } else { +#ifdef LB + *p_bulk_visc = lbpar.bulk_viscosity[0]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_gamma_odd(double* p_gamma_odd){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_gamma_odd = lbpar_gpu.gamma_odd[0]; +#endif // LB_GPU + } else { +#ifdef LB + *p_gamma_odd = lbpar.gamma_odd[0]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_gamma_even(double* p_gamma_even){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_gamma_even = lbpar_gpu.gamma_even[0]; +#endif // LB_GPU + } else { +#ifdef LB + *p_gamma_even = lbpar.gamma_even[0]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_agrid(double* p_agrid){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_agrid = lbpar_gpu.agrid; +#endif // LB_GPU + } else { +#ifdef LB + *p_agrid = lbpar.agrid; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_get_ext_force(double* p_fx, double* p_fy, double* p_fz){ +#ifdef SHANCHEN + exit(printf("Not implemented yet (%s:%d) ",__FILE__,__LINE__)); +#endif // SHANCHEN + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + *p_fx = lbpar_gpu.ext_force[0]; + *p_fy = lbpar_gpu.ext_force[1]; + *p_fz = lbpar_gpu.ext_force[2]; +#endif // LB_GPU + } else { +#ifdef LB + *p_fx = lbpar.ext_force[0]; + *p_fy = lbpar.ext_force[1]; + *p_fz = lbpar.ext_force[2]; +#endif // LB + } + return 0; +} + + +int lb_lbfluid_print_vtk_boundary(char* filename) { + FILE* fp = fopen(filename, "w"); + + if(fp == NULL) + { + return 1; + } + + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + unsigned int* bound_array; + bound_array = (unsigned int*) malloc(lbpar_gpu.number_of_nodes*sizeof(unsigned int)); + lb_get_boundary_flags_GPU(bound_array); + + int j; + /** print of the calculated phys values */ + fprintf(fp, "# vtk DataFile Version 2.0\nlbboundaries\n" + "ASCII\nDATASET STRUCTURED_POINTS\nDIMENSIONS %u %u %u\n" + "ORIGIN %f %f %f\nSPACING %f %f %f\nPOINT_DATA %u\n" + "SCALARS boundary float 1\nLOOKUP_TABLE default\n", + lbpar_gpu.dim_x, lbpar_gpu.dim_y, lbpar_gpu.dim_z, + lbpar_gpu.agrid*0.5, lbpar_gpu.agrid*0.5, lbpar_gpu.agrid*0.5, + lbpar_gpu.agrid, lbpar_gpu.agrid, lbpar_gpu.agrid, + lbpar_gpu.number_of_nodes); + for(j=0; jrho[ii]); + } +#endif // LB_GPU + } else { +#ifdef LB + index_t index; + int node, grid[3], ind_shifted[3]; + double rho; double j[3]; double pi[6]; + + ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; + node = lblattice.map_lattice_to_node(ind_shifted,grid); + index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); + + mpi_recv_fluid(node,index,&rho,j,pi); + // unit conversion + rho *= 1/lbpar.agrid/lbpar.agrid/lbpar.agrid; + *p_rho = rho; +#endif // LB + } + return 0; +} + + +int lb_lbnode_get_u(int* ind, double* p_u) { + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + static LB_rho_v_pi_gpu *host_print_values=NULL; + if(host_print_values==NULL) host_print_values= (LB_rho_v_pi_gpu *) malloc(sizeof(LB_rho_v_pi_gpu)); + + int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; + lb_print_node_GPU(single_nodeindex, host_print_values); + + p_u[0] = (double)(host_print_values[0].v[0]); + p_u[1] = (double)(host_print_values[0].v[1]); + p_u[2] = (double)(host_print_values[0].v[2]); +#endif // LB_GPU + } else { +#ifdef LB + index_t index; + int node, grid[3], ind_shifted[3]; + double rho; double j[3]; double pi[6]; + + ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; + node = lblattice.map_lattice_to_node(ind_shifted,grid); + index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); + + mpi_recv_fluid(node,index,&rho,j,pi); + // unit conversion + p_u[0] = j[0]/rho/lbpar.tau/lbpar.agrid; + p_u[1] = j[1]/rho/lbpar.tau/lbpar.agrid; + p_u[2] = j[2]/rho/lbpar.tau/lbpar.agrid; +#endif // LB + } + return 0; +} + + +/** calculates the fluid velocity at a given position of the + * lattice. Note that it can lead to undefined behavior if the + * position is not within the local lattice. This version of the function + * can be called without the position needing to be on the local processor. + * Note that this gives a slightly different version than the values used to + * couple to MD beads when near a wall, see lb_lbfluid_get_interpolated_velocity. + */ +int lb_lbfluid_get_interpolated_velocity_global (double* p, double* v) { + double local_v[3] = {0, 0, 0}, delta[6]; //velocity field, relative positions to surrounding nodes + int ind[3] = {0,0,0}, tmpind[3]; //node indices + int x, y, z; //counters + + // convert the position into lower left grid point + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + Lattice::map_position_to_lattice_global(p, ind, delta, lbpar_gpu.agrid); +#endif // LB_GPU + } else { +#ifdef LB + Lattice::map_position_to_lattice_global(p, ind, delta, lbpar.agrid); +#endif // LB + } + + //set the initial velocity to zero in all directions + v[0] = 0; + v[1] = 0; + v[2] = 0; + for (z=0;z<2;z++) { + for (y=0;y<2;y++) { + for (x=0;x<2;x++) { + //give the index of the neighbouring nodes + tmpind[0] = ind[0]+x; + tmpind[1] = ind[1]+y; + tmpind[2] = ind[2]+z; + + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + if (tmpind[0] == int(lbpar_gpu.dim_x)) tmpind[0] = 0; + if (tmpind[1] == int(lbpar_gpu.dim_y)) tmpind[1] = 0; + if (tmpind[2] == int(lbpar_gpu.dim_z)) tmpind[2] = 0; +#endif // LB_GPU + } else { +#ifdef LB + if (tmpind[0] == box_l[0]/lbpar.agrid) tmpind[0] = 0; + if (tmpind[1] == box_l[1]/lbpar.agrid) tmpind[1] = 0; + if (tmpind[2] == box_l[2]/lbpar.agrid) tmpind[2] = 0; +#endif // LB + } +#ifdef SHANCHEN + //printf (" %d %d %d %f %f %f\n", tmpind[0], tmpind[1],tmpind[2],v[0], v[1], v[2]); + printf("TODO:adapt for SHANCHEN (%s:%d)\n",__FILE__,__LINE__); + exit(1); +#endif // SHANCHEN + lb_lbnode_get_u(tmpind, local_v); + + v[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[0]; + v[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[1]; + v[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[2]; + } + } + } + + return 0; +} + + +int lb_lbnode_get_pi(int* ind, double* p_pi) { + double p0 = 0; + + lb_lbnode_get_pi_neq(ind, p_pi); + + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + for(int ii=0;iipi[i]; + } + return 0; +#endif // LB_GPU + } else { +#ifdef LB + index_t index; + int node, grid[3], ind_shifted[3]; + double rho; double j[3]; double pi[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; + node = lblattice.map_lattice_to_node(ind_shifted,grid); + index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); + + mpi_recv_fluid(node,index,&rho,j,pi); + // unit conversion // TODO: Check Unit Conversion! + p_pi[0] = pi[0]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; + p_pi[1] = pi[1]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; + p_pi[2] = pi[2]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; + p_pi[3] = pi[3]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; + p_pi[4] = pi[4]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; + p_pi[5] = pi[5]/lbpar.tau/lbpar.tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; +#endif // LB + } + return 0; +} + + +int lb_lbnode_get_boundary(int* ind, int* p_boundary) { + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + unsigned int host_flag; + int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; + lb_get_boundary_flag_GPU(single_nodeindex, &host_flag); + p_boundary[0] = host_flag; +#endif // LB_GPU + } else { +#ifdef LB + index_t index; + int node, grid[3], ind_shifted[3]; + + ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; + node = lblattice.map_lattice_to_node(ind_shifted,grid); + index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); + + mpi_recv_fluid_boundary_flag(node,index,p_boundary); +#endif // LB + } + return 0; +} +#endif //defined (LB) || defined (LB_GPU) + + +int lb_lbnode_get_pop(int* ind, double* p_pop) { + if (lattice_switch & LATTICE_LB_GPU) { + fprintf(stderr, "Not implemented for GPU\n"); + } else { +#ifdef LB + index_t index; + int node, grid[3], ind_shifted[3]; + + ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; + node = lblattice.map_lattice_to_node(ind_shifted,grid); + index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); + mpi_recv_fluid_populations(node, index, p_pop); +#endif // LB + } + return 0; +} + + +int lb_lbnode_set_rho(int* ind, double *p_rho){ + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + float host_rho[LB_COMPONENTS]; + int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; + int i; + for(i=0;i 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(1,0,0,lblattice.halo_grid); + for (z=0; z 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(lblattice.grid[0],0,0,lblattice.halo_grid); + for (z=0; z 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(0,1,0,lblattice.halo_grid); + for (z=0; z 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(0,lblattice.grid[1],0,lblattice.halo_grid); + for (z=0; z 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(0,0,1,lblattice.halo_grid); + for (y=0; y 1) { + MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, + rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, + comm_cart, &status); + } else { + memcpy(rbuf,sbuf,count*sizeof(double)); + } + + buffer = rbuf; + index = get_linear_index(0,0,lblattice.grid[2],lblattice.halo_grid); + for (y=0; y=lbpar.agrid/2.0) { + ostringstream msg; + msg <<"LB requires either no Verlet lists or that the skin of the verlet list to be less than half of lattice-Boltzmann grid spacing"; + runtimeError(msg); + ret = -1; + } + if (thermo_switch & ~THERMO_LB) { + ostringstream msg; + msg <<"LB must not be used with other thermostats"; + runtimeError(msg); + ret = 1; + } + return ret; +} + +/***********************************************************************/ + +/** (Pre-)allocate memory for data structures */ +void lb_pre_init() { + lbfluid[0] = (double**) malloc(2*lbmodel.n_veloc*sizeof(double *)); + lbfluid[0][0] = (double*) malloc(2*lblattice.halo_grid_volume*lbmodel.n_veloc*sizeof(double)); +} + + +/** (Re-)allocate memory for the fluid and initialize pointers. */ +static void lb_realloc_fluid() { + int i; + + LB_TRACE(printf("reallocating fluid\n")); + + lbfluid[0] = (double**) realloc(*lbfluid,2*lbmodel.n_veloc*sizeof(double *)); + lbfluid[0][0] = (double*) realloc(**lbfluid,2*lblattice.halo_grid_volume*lbmodel.n_veloc*sizeof(double)); + lbfluid[1] = (double **)lbfluid[0] + lbmodel.n_veloc; + lbfluid[1][0] = (double *)lbfluid[0][0] + lblattice.halo_grid_volume*lbmodel.n_veloc; + + for (i=0; isource_node = comm.halo_info[i].source_node; + hinfo->dest_node = comm.halo_info[i].dest_node; + hinfo->s_offset = comm.halo_info[i].s_offset; + hinfo->r_offset = comm.halo_info[i].r_offset; + hinfo->type = comm.halo_info[i].type; + + /* generate the vector datatype for the structure of lattices we + * have to use hvector here because the extent of the subtypes + * does not span the full lattice and hence we cannot get the + * correct vskip out of them */ + + MPI_Aint lower; + MPI_Aint extent; + MPI_Type_get_extent(MPI_DOUBLE, &lower, &extent); + MPI_Type_create_hvector(lbmodel.n_veloc, 1, + lblattice.halo_grid_volume*extent, + comm.halo_info[i].datatype, &hinfo->datatype); + MPI_Type_commit(&hinfo->datatype); + + halo_create_field_hvector(lbmodel.n_veloc,1, + lblattice.halo_grid_volume*sizeof(double), + comm.halo_info[i].fieldtype,&hinfo->fieldtype); + } + + release_halo_communication(&comm); +} + + +/** (Re-)initializes the fluid. */ +void lb_reinit_parameters() { + int i; + + if (lbpar.viscosity[0] > 0.0) { + /* Eq. (80) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). */ + // unit conversion: viscosity + gamma_shear = 1. - 2./(6.*lbpar.viscosity[0]*lbpar.tau/(lbpar.agrid*lbpar.agrid)+1.); + } + + if (lbpar.bulk_viscosity[0] > 0.0) { + /* Eq. (81) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). */ + // unit conversion: viscosity + gamma_bulk = 1. - 2./(9.*lbpar.bulk_viscosity[0]*lbpar.tau/(lbpar.agrid*lbpar.agrid)+1.); + } + + gamma_odd = lbpar.gamma_odd[0]; + gamma_even = lbpar.gamma_even[0]; + + double mu = 0.0; + + if (temperature > 0.0) + { + /* fluctuating hydrodynamics ? */ + fluct = 1; + + /* Eq. (51) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). + * Note that the modes are not normalized as in the paper here! */ + mu = temperature/lbmodel.c_sound_sq*lbpar.tau*lbpar.tau/(lbpar.agrid*lbpar.agrid); + //mu *= agrid*agrid*agrid; // Marcello's conjecture +#ifdef D3Q19 + double (*e)[19] = d3q19_modebase; +#else // D3Q19 + double **e = lbmodel.e; +#endif // D3Q19 + for (i = 0; i < 3; i++) lb_phi[i] = 0.0; + lb_phi[4] = sqrt(mu*e[19][4]*(1.-SQR(gamma_bulk))); // SQR(x) == x*x + for (i = 5; i < 10; i++) lb_phi[i] = sqrt(mu*e[19][i]*(1.-SQR(gamma_shear))); + for (i = 10; i < lbmodel.n_veloc; i++) lb_phi[i] = sqrt(mu*e[19][i]); + + /* lb_coupl_pref is stored in MD units (force) + * Eq. (16) Ahlrichs and Duenweg, JCP 111(17):8225 (1999). + * The factor 12 comes from the fact that we use random numbers + * from -0.5 to 0.5 (equally distributed) which have variance 1/12. + * time_step comes from the discretization. + */ + lb_coupl_pref = sqrt(12.*2.*lbpar.friction[0]*temperature/time_step); + lb_coupl_pref2 = sqrt(2.*lbpar.friction[0]*temperature/time_step); + } else { + /* no fluctuations at zero temperature */ + fluct = 0; + for (i = 0; i < lbmodel.n_veloc; i++) lb_phi[i] = 0.0; + lb_coupl_pref = 0.0; + lb_coupl_pref2 = 0.0; + } + LB_TRACE(fprintf(stderr,"%d: gamma_shear=%lf gamma_bulk=%lf shear_fluct=%lf " \ + "bulk_fluct=%lf mu=%lf, bulkvisc=%lf, visc=%lf\n", \ + this_node, gamma_shear, gamma_bulk, lb_phi[9], lb_phi[4], mu, \ + lbpar.bulk_viscosity[0], lbpar.viscosity[0])); +} + + +/** Resets the forces on the fluid nodes */ +void lb_reinit_forces() { + for (index_t index=0; index < lblattice.halo_grid_volume; index++) { +#ifdef EXTERNAL_FORCES + // unit conversion: force density + lbfields[index].force[0] = lbpar.ext_force[0]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; + lbfields[index].force[1] = lbpar.ext_force[1]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; + lbfields[index].force[2] = lbpar.ext_force[2]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; +#else // EXTERNAL_FORCES + lbfields[index].force[0] = 0.0; + lbfields[index].force[1] = 0.0; + lbfields[index].force[2] = 0.0; + lbfields[index].has_force = 0; +#endif // EXTERNAL_FORCES + } +#ifdef LB_BOUNDARIES + for (int i = 0; i < n_lb_boundaries; i++) { + lb_boundaries[i].force[0]=0.; + lb_boundaries[i].force[1]=0.; + lb_boundaries[i].force[2]=0.; + } +#endif // LB_BOUNDARIES +} + + +/** (Re-)initializes the fluid according to the given value of rho. */ +void lb_reinit_fluid() { + /* default values for fields in lattice units */ + /* here the conversion to lb units is performed */ + double rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; + double j[3] = { 0., 0., 0. }; +// double pi[6] = { rho*lbmodel.c_sound_sq, 0., rho*lbmodel.c_sound_sq, 0., 0., rho*lbmodel.c_sound_sq }; + double pi[6] = { 0., 0., 0., 0., 0., 0. }; + + LB_TRACE(fprintf(stderr, "Initialising the fluid with equilibrium populations\n");); + + for (index_t index = 0; index < lblattice.halo_grid_volume; index++) { + // calculate equilibrium distribution + lb_calc_n_from_rho_j_pi(index,rho,j,pi); + + lbfields[index].recalc_fields = 1; +#ifdef LB_BOUNDARIES + lbfields[index].boundary = 0; +#endif // LB_BOUNDARIES + } + + lbpar.resend_halo = 0; +#ifdef LB_BOUNDARIES + lb_init_boundaries(); +#endif // LB_BOUNDARIES +} + + +/** Performs a full initialization of + * the Lattice Boltzmann system. All derived parameters + * and the fluid are reset to their default values. */ +void lb_init() { + LB_TRACE(printf("Begin initialzing fluid on CPU\n")); + + if (lbpar.agrid <= 0.0) { + ostringstream msg; + msg <<"Lattice Boltzmann agrid not set when initializing fluid"; + runtimeError(msg); + } + + if (check_runtime_errors()) return; + + double temp_agrid[3]; + double temp_offset[3]; + for (int i =0; i<3; i++) { + temp_agrid[i]=lbpar.agrid; + temp_offset[i]=0.5; + } + + /* initialize the local lattice domain */ + lblattice.init(temp_agrid, temp_offset, 1, 0); + + if (check_runtime_errors()) return; + + /* allocate memory for data structures */ + lb_realloc_fluid(); + + /* prepare the halo communication */ + lb_prepare_communication(); + + /* initialize derived parameters */ + lb_reinit_parameters(); + + /* setup the initial particle velocity distribution */ + lb_reinit_fluid(); + + /* setup the external forces */ + lb_reinit_forces(); + + LB_TRACE(printf("Initialzing fluid on CPU successful\n")); +} + + +/** Release the fluid. */ +void lb_release_fluid() { + free(lbfluid[0][0]); + free(lbfluid[0]); + free(lbfields); +} + + +/** Release fluid and communication. */ +void lb_release() { + lb_release_fluid(); + release_halo_communication(&update_halo_comm); +} + +/***********************************************************************/ +/** \name Mapping between hydrodynamic fields and particle populations */ +/***********************************************************************/ +/*@{*/ +void lb_calc_n_from_rho_j_pi(const index_t index, + const double rho, + const double *j, + double *pi) +{ + int i; + double local_rho, local_j[3], local_pi[6], trace; + const double avg_rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; + + local_rho = rho; + + local_j[0] = j[0]; + local_j[1] = j[1]; + local_j[2] = j[2]; + + for (i = 0; i < 6; i++) local_pi[i] = pi[i]; + + trace = local_pi[0] + local_pi[2] + local_pi[5]; + +#ifdef D3Q19 + double rho_times_coeff; + double tmp1,tmp2; + + /* update the q=0 sublattice */ + lbfluid[0][0][index] = 1./3. * (local_rho-avg_rho) - 1./2. * trace; + + /* update the q=1 sublattice */ + rho_times_coeff = 1./18. * (local_rho-avg_rho); + + lbfluid[0][1][index] = rho_times_coeff + 1./6.*local_j[0] + 1./4. * local_pi[0] - 1./12.*trace; + lbfluid[0][2][index] = rho_times_coeff - 1./6.*local_j[0] + 1./4. * local_pi[0] - 1./12.*trace; + lbfluid[0][3][index] = rho_times_coeff + 1./6.*local_j[1] + 1./4. * local_pi[2] - 1./12.*trace; + lbfluid[0][4][index] = rho_times_coeff - 1./6.*local_j[1] + 1./4. * local_pi[2] - 1./12.*trace; + lbfluid[0][5][index] = rho_times_coeff + 1./6.*local_j[2] + 1./4. * local_pi[5] - 1./12.*trace; + lbfluid[0][6][index] = rho_times_coeff - 1./6.*local_j[2] + 1./4. * local_pi[5] - 1./12.*trace; + + /* update the q=2 sublattice */ + rho_times_coeff = 1./36. * (local_rho-avg_rho); + + tmp1 = local_pi[0] + local_pi[2]; + tmp2 = 2.0*local_pi[1]; + + lbfluid[0][7][index] = rho_times_coeff + 1./12.*(local_j[0]+local_j[1]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][8][index] = rho_times_coeff - 1./12.*(local_j[0]+local_j[1]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][9][index] = rho_times_coeff + 1./12.*(local_j[0]-local_j[1]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + lbfluid[0][10][index] = rho_times_coeff - 1./12.*(local_j[0]-local_j[1]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + + tmp1 = local_pi[0] + local_pi[5]; + tmp2 = 2.0*local_pi[3]; + + lbfluid[0][11][index] = rho_times_coeff + 1./12.*(local_j[0]+local_j[2]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][12][index] = rho_times_coeff - 1./12.*(local_j[0]+local_j[2]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][13][index] = rho_times_coeff + 1./12.*(local_j[0]-local_j[2]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + lbfluid[0][14][index] = rho_times_coeff - 1./12.*(local_j[0]-local_j[2]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + + tmp1 = local_pi[2] + local_pi[5]; + tmp2 = 2.0*local_pi[4]; + + lbfluid[0][15][index] = rho_times_coeff + 1./12.*(local_j[1]+local_j[2]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][16][index] = rho_times_coeff - 1./12.*(local_j[1]+local_j[2]) + 1./8.*(tmp1+tmp2) - 1./24.*trace; + lbfluid[0][17][index] = rho_times_coeff + 1./12.*(local_j[1]-local_j[2]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + lbfluid[0][18][index] = rho_times_coeff - 1./12.*(local_j[1]-local_j[2]) + 1./8.*(tmp1-tmp2) - 1./24.*trace; + +#else // D3Q19 + + int i; + double tmp=0.0; + double (*c)[3] = lbmodel.c; + double (*coeff)[4] = lbmodel.coeff; + + for (i = 0; i < lbmodel.n_veloc; i++) { + tmp = local_pi[0] * SQR(c[i][0]) + + (2.0 * local_pi[1] * c[i][0] + local_pi[2] * c[i][1])*c[i][1] + + (2.0 * (local_pi[3]*c[i][0] + local_pi[4] * c[i][1]) + local_pi[5] * c[i][2]) * c[i][2]; + + lbfluid[0][i][index] = coeff[i][0] * (local_rho-avg_rho); + lbfluid[0][i][index] += coeff[i][1] * scalar(local_j,c[i]); + lbfluid[0][i][index] += coeff[i][2] * tmp; + lbfluid[0][i][index] += coeff[i][3] * trace; + } +#endif // D3Q19 +} + +/*@}*/ + + +/** Calculation of hydrodynamic modes */ +void lb_calc_modes(index_t index, double *mode) +{ +#ifdef D3Q19 + double n0, n1p, n1m, n2p, n2m, n3p, n3m, n4p, n4m, n5p, n5m, n6p, n6m, n7p, n7m, n8p, n8m, n9p, n9m; + + n0 = lbfluid[0][0][index]; + n1p = lbfluid[0][1][index] + lbfluid[0][2][index]; + n1m = lbfluid[0][1][index] - lbfluid[0][2][index]; + n2p = lbfluid[0][3][index] + lbfluid[0][4][index]; + n2m = lbfluid[0][3][index] - lbfluid[0][4][index]; + n3p = lbfluid[0][5][index] + lbfluid[0][6][index]; + n3m = lbfluid[0][5][index] - lbfluid[0][6][index]; + n4p = lbfluid[0][7][index] + lbfluid[0][8][index]; + n4m = lbfluid[0][7][index] - lbfluid[0][8][index]; + n5p = lbfluid[0][9][index] + lbfluid[0][10][index]; + n5m = lbfluid[0][9][index] - lbfluid[0][10][index]; + n6p = lbfluid[0][11][index] + lbfluid[0][12][index]; + n6m = lbfluid[0][11][index] - lbfluid[0][12][index]; + n7p = lbfluid[0][13][index] + lbfluid[0][14][index]; + n7m = lbfluid[0][13][index] - lbfluid[0][14][index]; + n8p = lbfluid[0][15][index] + lbfluid[0][16][index]; + n8m = lbfluid[0][15][index] - lbfluid[0][16][index]; + n9p = lbfluid[0][17][index] + lbfluid[0][18][index]; + n9m = lbfluid[0][17][index] - lbfluid[0][18][index]; +// printf("n: "); +// for (i=0; i<19; i++) +// printf("%f ", lbfluid[1][i][index]); +// printf("\n"); + + /* mass mode */ + mode[0] = n0 + n1p + n2p + n3p + n4p + n5p + n6p + n7p + n8p + n9p; + + /* momentum modes */ + mode[1] = n1m + n4m + n5m + n6m + n7m; + mode[2] = n2m + n4m - n5m + n8m + n9m; + mode[3] = n3m + n6m - n7m + n8m - n9m; + + /* stress modes */ + mode[4] = -n0 + n4p + n5p + n6p + n7p + n8p + n9p; + mode[5] = n1p - n2p + n6p + n7p - n8p - n9p; + mode[6] = n1p + n2p - n6p - n7p - n8p - n9p - 2.*(n3p - n4p - n5p); + mode[7] = n4p - n5p; + mode[8] = n6p - n7p; + mode[9] = n8p - n9p; + +#ifndef OLD_FLUCT + /* kinetic modes */ + mode[10] = -2.*n1m + n4m + n5m + n6m + n7m; + mode[11] = -2.*n2m + n4m - n5m + n8m + n9m; + mode[12] = -2.*n3m + n6m - n7m + n8m - n9m; + mode[13] = n4m + n5m - n6m - n7m; + mode[14] = n4m - n5m - n8m - n9m; + mode[15] = n6m - n7m - n8m + n9m; + mode[16] = n0 + n4p + n5p + n6p + n7p + n8p + n9p + - 2.*(n1p + n2p + n3p); + mode[17] = - n1p + n2p + n6p + n7p - n8p - n9p; + mode[18] = - n1p - n2p -n6p - n7p - n8p - n9p + + 2.*(n3p + n4p + n5p); +#endif // !OLD_FLUCT + +#else // D3Q19 + int i, j; + for (i = 0; i < lbmodel.n_veloc; i++) { + mode[i] = 0.0; + for (j = 0; j < lbmodel.n_veloc; j++) { + mode[i] += lbmodel.e[i][j] * lbfluid[0][i][index]; + } + } +#endif // D3Q19 +} + + +/** Streaming and calculation of modes (pull scheme) */ +inline void lb_pull_calc_modes(index_t index, double *mode) { + + int yperiod = lblattice.halo_grid[0]; + int zperiod = lblattice.halo_grid[0]*lblattice.halo_grid[1]; + + double n[19]; + n[0] = lbfluid[0][0][index]; + n[1] = lbfluid[0][1][index-1]; + n[2] = lbfluid[0][2][index+1]; + n[3] = lbfluid[0][3][index-yperiod]; + n[4] = lbfluid[0][4][index+yperiod]; + n[5] = lbfluid[0][5][index-zperiod]; + n[6] = lbfluid[0][6][index+zperiod]; + n[7] = lbfluid[0][7][index-(1+yperiod)]; + n[8] = lbfluid[0][8][index+(1+yperiod)]; + n[9] = lbfluid[0][9][index-(1-yperiod)]; + n[10] = lbfluid[0][10][index+(1-yperiod)]; + n[11] = lbfluid[0][11][index-(1+zperiod)]; + n[12] = lbfluid[0][12][index+(1+zperiod)]; + n[13] = lbfluid[0][13][index-(1-zperiod)]; + n[14] = lbfluid[0][14][index+(1-zperiod)]; + n[15] = lbfluid[0][15][index-(yperiod+zperiod)]; + n[16] = lbfluid[0][16][index+(yperiod+zperiod)]; + n[17] = lbfluid[0][17][index-(yperiod-zperiod)]; + n[18] = lbfluid[0][18][index+(yperiod-zperiod)]; + +#ifdef D3Q19 + /* mass mode */ + mode[ 0] = n[ 0] + n[ 1] + n[ 2] + n[ 3] + n[4] + n[5] + n[6] + + n[ 7] + n[ 8] + n[ 9] + n[10] + + n[11] + n[12] + n[13] + n[14] + + n[15] + n[16] + n[17] + n[18]; + + /* momentum modes */ + mode[ 1] = n[ 1] - n[ 2] + + n[ 7] - n[ 8] + n[ 9] - n[10] + n[11] - n[12] + n[13] - n[14]; + mode[ 2] = n[ 3] - n[ 4] + + n[ 7] - n[ 8] - n[ 9] + n[10] + n[15] - n[16] + n[17] - n[18]; + mode[ 3] = n[ 5] - n[ 6] + + n[11] - n[12] - n[13] + n[14] + n[15] - n[16] - n[17] + n[18]; + + /* stress modes */ + mode[ 4] = - n[ 0] + + n[ 7] + n[ 8] + n[ 9] + n[10] + + n[11] + n[12] + n[13] + n[14] + + n[15] + n[16] + n[17] + n[18]; + mode[ 5] = n[ 1] + n[ 2] - n[ 3] - n[4] + + n[11] + n[12] + n[13] + n[14] - n[15] - n[16] - n[17] - n[18]; + mode[ 6] = n[ 1] + n[ 2] + n[ 3] + n[ 4] + - n[11] - n[12] - n[13] - n[14] - n[15] - n[16] - n[17] - n[18] + - 2.*(n[5] + n[6] - n[7] - n[8] - n[9] - n[10]); + mode[ 7] = n[ 7] + n[ 8] - n[ 9] - n[10]; + mode[ 8] = n[11] + n[12] - n[13] - n[14]; + mode[ 9] = n[15] + n[16] - n[17] - n[18]; + + /* kinetic modes */ + mode[10] = 2.*(n[2] - n[1]) + + n[7] - n[8] + n[9] - n[10] + n[11] - n[12] + n[13] - n[14]; + mode[11] = 2.*(n[4] - n[3]) + + n[7] - n[8] - n[9] + n[10] + n[15] - n[16] + n[17] - n[18]; + mode[12] = 2.*(n[6] - n[5]) + + n[11] - n[12] - n[13] + n[14] + n[15] - n[16] - n[17] + n[18]; + mode[13] = n[ 7] - n[ 8] + n[ 9] - n[10] - n[11] + n[12] - n[13] + n[14]; + mode[14] = n[ 7] - n[ 8] - n[ 9] + n[10] - n[15] + n[16] - n[17] + n[18]; + mode[15] = n[11] - n[12] - n[13] + n[14] - n[15] + n[16] + n[17] - n[18]; + mode[16] = n[ 0] + + n[ 7] + n[ 8] + n[ 9] + n[10] + + n[11] + n[12] + n[13] + n[14] + + n[15] + n[16] + n[17] + n[18] + - 2.*(n[1] + n[2] + n[3] + n[4] + n[5] + n[6]); + mode[17] = n[ 3] + n[ 4] - n[ 1] - n[ 2] + + n[11] + n[12] + n[13] + n[14] + - n[15] - n[16] - n[17] - n[18]; + mode[18] = - n[ 1] - n[ 2] - n[ 3] - n[ 4] + - n[11] - n[12] - n[13] - n[14] - n[15] - n[16] - n[17] - n[18] + + 2.*(n[5] + n[6] + n[7] + n[8] + n[9] + n[10]); +#else // D3Q19 + int i, j; + double **e = lbmodel.e; + for (i = 0; i < lbmodel.n_veloc; i++) + { + mode[i] = 0.0; + for (j = 0; j < lbmodel.n_veloc; j++) + { + mode[i] += e[i][j]*n[j]; + } + } +#endif // D3Q19 +} + + +inline void lb_relax_modes(index_t index, double *mode) +{ + double rho, j[3], pi_eq[6]; + + /* re-construct the real density + * remember that the populations are stored as differences to their + * equilibrium value */ + rho = mode[0] + lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; + + j[0] = mode[1]; + j[1] = mode[2]; + j[2] = mode[3]; + + /* if forces are present, the momentum density is redefined to + * include one half-step of the force action. See the + * Chapman-Enskog expansion in [Ladd & Verberg]. */ +#ifndef EXTERNAL_FORCES + if (lbfields[index].has_force) +#endif // !EXTERNAL_FORCES + { + j[0] += 0.5 * lbfields[index].force[0]; + j[1] += 0.5 * lbfields[index].force[1]; + j[2] += 0.5 * lbfields[index].force[2]; + } + + /* equilibrium part of the stress modes */ + pi_eq[0] = scalar(j,j) / rho; + pi_eq[1] = (SQR(j[0])-SQR(j[1])) / rho; + pi_eq[2] = (scalar(j,j) - 3.0 * SQR(j[2])) / rho; + pi_eq[3] = j[0] * j[1] / rho; + pi_eq[4] = j[0] * j[2] / rho; + pi_eq[5] = j[1] * j[2] / rho; + + /* relax the stress modes */ + mode[4] = pi_eq[0] + gamma_bulk * (mode[4] - pi_eq[0]); + mode[5] = pi_eq[1] + gamma_shear * (mode[5] - pi_eq[1]); + mode[6] = pi_eq[2] + gamma_shear * (mode[6] - pi_eq[2]); + mode[7] = pi_eq[3] + gamma_shear * (mode[7] - pi_eq[3]); + mode[8] = pi_eq[4] + gamma_shear * (mode[8] - pi_eq[4]); + mode[9] = pi_eq[5] + gamma_shear * (mode[9] - pi_eq[5]); + +#ifndef OLD_FLUCT + /* relax the ghost modes (project them out) */ + /* ghost modes have no equilibrium part due to orthogonality */ + mode[10] = gamma_odd*mode[10]; + mode[11] = gamma_odd*mode[11]; + mode[12] = gamma_odd*mode[12]; + mode[13] = gamma_odd*mode[13]; + mode[14] = gamma_odd*mode[14]; + mode[15] = gamma_odd*mode[15]; + mode[16] = gamma_even*mode[16]; + mode[17] = gamma_even*mode[17]; + mode[18] = gamma_even*mode[18]; +#endif // !OLD_FLUCT +} + + +inline void lb_thermalize_modes(index_t index, double *mode) { + double fluct[6]; +#ifdef GAUSSRANDOM + double rootrho_gauss = sqrt(fabs(mode[0]+lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid)); + + /* stress modes */ + mode[4] += (fluct[0] = rootrho_gauss*lb_phi[4]*gaussian_random()); + mode[5] += (fluct[1] = rootrho_gauss*lb_phi[5]*gaussian_random()); + mode[6] += (fluct[2] = rootrho_gauss*lb_phi[6]*gaussian_random()); + mode[7] += (fluct[3] = rootrho_gauss*lb_phi[7]*gaussian_random()); + mode[8] += (fluct[4] = rootrho_gauss*lb_phi[8]*gaussian_random()); + mode[9] += (fluct[5] = rootrho_gauss*lb_phi[9]*gaussian_random()); + +#ifndef OLD_FLUCT + /* ghost modes */ + mode[10] += rootrho_gauss*lb_phi[10]*gaussian_random(); + mode[11] += rootrho_gauss*lb_phi[11]*gaussian_random(); + mode[12] += rootrho_gauss*lb_phi[12]*gaussian_random(); + mode[13] += rootrho_gauss*lb_phi[13]*gaussian_random(); + mode[14] += rootrho_gauss*lb_phi[14]*gaussian_random(); + mode[15] += rootrho_gauss*lb_phi[15]*gaussian_random(); + mode[16] += rootrho_gauss*lb_phi[16]*gaussian_random(); + mode[17] += rootrho_gauss*lb_phi[17]*gaussian_random(); + mode[18] += rootrho_gauss*lb_phi[18]*gaussian_random(); +#endif // !OLD_FLUCT + +#elif defined (GAUSSRANDOMCUT) + double rootrho_gauss = sqrt(fabs(mode[0]+lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid)); + + /* stress modes */ + mode[4] += (fluct[0] = rootrho_gauss*lb_phi[4]*gaussian_random_cut()); + mode[5] += (fluct[1] = rootrho_gauss*lb_phi[5]*gaussian_random_cut()); + mode[6] += (fluct[2] = rootrho_gauss*lb_phi[6]*gaussian_random_cut()); + mode[7] += (fluct[3] = rootrho_gauss*lb_phi[7]*gaussian_random_cut()); + mode[8] += (fluct[4] = rootrho_gauss*lb_phi[8]*gaussian_random_cut()); + mode[9] += (fluct[5] = rootrho_gauss*lb_phi[9]*gaussian_random_cut()); + +#ifndef OLD_FLUCT + /* ghost modes */ + mode[10] += rootrho_gauss*lb_phi[10]*gaussian_random_cut(); + mode[11] += rootrho_gauss*lb_phi[11]*gaussian_random_cut(); + mode[12] += rootrho_gauss*lb_phi[12]*gaussian_random_cut(); + mode[13] += rootrho_gauss*lb_phi[13]*gaussian_random_cut(); + mode[14] += rootrho_gauss*lb_phi[14]*gaussian_random_cut(); + mode[15] += rootrho_gauss*lb_phi[15]*gaussian_random_cut(); + mode[16] += rootrho_gauss*lb_phi[16]*gaussian_random_cut(); + mode[17] += rootrho_gauss*lb_phi[17]*gaussian_random_cut(); + mode[18] += rootrho_gauss*lb_phi[18]*gaussian_random_cut(); +#endif // OLD_FLUCT + +#elif defined (FLATNOISE) + double rootrho = sqrt(fabs(12.0*(mode[0]+lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid))); + + /* stress modes */ + mode[4] += (fluct[0] = rootrho*lb_phi[4]*(d_random()-0.5)); + mode[5] += (fluct[1] = rootrho*lb_phi[5]*(d_random()-0.5)); + mode[6] += (fluct[2] = rootrho*lb_phi[6]*(d_random()-0.5)); + mode[7] += (fluct[3] = rootrho*lb_phi[7]*(d_random()-0.5)); + mode[8] += (fluct[4] = rootrho*lb_phi[8]*(d_random()-0.5)); + mode[9] += (fluct[5] = rootrho*lb_phi[9]*(d_random()-0.5)); + +#ifndef OLD_FLUCT + /* ghost modes */ + mode[10] += rootrho*lb_phi[10]*(d_random()-0.5); + mode[11] += rootrho*lb_phi[11]*(d_random()-0.5); + mode[12] += rootrho*lb_phi[12]*(d_random()-0.5); + mode[13] += rootrho*lb_phi[13]*(d_random()-0.5); + mode[14] += rootrho*lb_phi[14]*(d_random()-0.5); + mode[15] += rootrho*lb_phi[15]*(d_random()-0.5); + mode[16] += rootrho*lb_phi[16]*(d_random()-0.5); + mode[17] += rootrho*lb_phi[17]*(d_random()-0.5); + mode[18] += rootrho*lb_phi[18]*(d_random()-0.5); +#endif // !OLD_FLUCT +#else // GAUSSRANDOM +#error No noise type defined for the CPU LB +#endif //GAUSSRANDOM + +#ifdef ADDITIONAL_CHECKS + rancounter += 15; +#endif // ADDITIONAL_CHECKS +} + + +inline void lb_apply_forces(index_t index, double* mode) { + + double rho, *f, u[3], C[6]; + + f = lbfields[index].force; + + rho = mode[0] + lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; + + /* hydrodynamic momentum density is redefined when external forces present */ + u[0] = (mode[1] + 0.5 * f[0])/rho; + u[1] = (mode[2] + 0.5 * f[1])/rho; + u[2] = (mode[3] + 0.5 * f[2])/rho; + + C[0] = (1.+gamma_bulk)*u[0]*f[0] + 1./3.*(gamma_bulk-gamma_shear)*scalar(u,f); + C[2] = (1.+gamma_bulk)*u[1]*f[1] + 1./3.*(gamma_bulk-gamma_shear)*scalar(u,f); + C[5] = (1.+gamma_bulk)*u[2]*f[2] + 1./3.*(gamma_bulk-gamma_shear)*scalar(u,f); + C[1] = 1./2. * (1.+gamma_shear)*(u[0]*f[1]+u[1]*f[0]); + C[3] = 1./2. * (1.+gamma_shear)*(u[0]*f[2]+u[2]*f[0]); + C[4] = 1./2. * (1.+gamma_shear)*(u[1]*f[2]+u[2]*f[1]); + + /* update momentum modes */ + mode[1] += f[0]; + mode[2] += f[1]; + mode[3] += f[2]; + + /* update stress modes */ + mode[4] += C[0] + C[2] + C[5]; + mode[5] += C[0] - C[2]; + mode[6] += C[0] + C[2] - 2. * C[5]; + mode[7] += C[1]; + mode[8] += C[3]; + mode[9] += C[4]; + + /* reset force */ +#ifdef EXTERNAL_FORCES + // unit conversion: force density + lbfields[index].force[0] = lbpar.ext_force[0]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; + lbfields[index].force[1] = lbpar.ext_force[1]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; + lbfields[index].force[2] = lbpar.ext_force[2]*pow(lbpar.agrid,4)*lbpar.tau*lbpar.tau; +#else // EXTERNAL_FORCES + lbfields[index].force[0] = 0.0; + lbfields[index].force[1] = 0.0; + lbfields[index].force[2] = 0.0; + lbfields[index].has_force = 0; +#endif // EXTERNAL_FORCES +} + + +inline void lb_calc_n_from_modes(index_t index, double *mode) +{ + + double *w = lbmodel.w; + +#ifdef D3Q19 + double (*e)[19] = d3q19_modebase; + double m[19]; + + /* normalization factors enter in the back transformation */ + for (int i = 0; i < lbmodel.n_veloc; i++) + m[i] = (1./e[19][i])*mode[i]; + + lbfluid[0][ 0][index] = m[0] - m[4] + m[16]; + lbfluid[0][ 1][index] = m[0] + m[1] + m[5] + m[6] - m[17] - m[18] - 2.*(m[10] + m[16]); + lbfluid[0][ 2][index] = m[0] - m[1] + m[5] + m[6] - m[17] - m[18] + 2.*(m[10] - m[16]); + lbfluid[0][ 3][index] = m[0] + m[2] - m[5] + m[6] + m[17] - m[18] - 2.*(m[11] + m[16]); + lbfluid[0][ 4][index] = m[0] - m[2] - m[5] + m[6] + m[17] - m[18] + 2.*(m[11] - m[16]); + lbfluid[0][ 5][index] = m[0] + m[3] - 2.*(m[6] + m[12] + m[16] - m[18]); + lbfluid[0][ 6][index] = m[0] - m[3] - 2.*(m[6] - m[12] + m[16] - m[18]); + lbfluid[0][ 7][index] = m[0] + m[ 1] + m[ 2] + m[ 4] + 2.*m[6] + + m[7] + m[10] + m[11] + m[13] + m[14] + m[16] + 2.*m[18]; + lbfluid[0][ 8][index] = m[0] - m[ 1] - m[ 2] + m[ 4] + 2.*m[6] + + m[7] - m[10] - m[11] - m[13] - m[14] + m[16] + 2.*m[18]; + lbfluid[0][ 9][index] = m[0] + m[ 1] - m[ 2] + m[ 4] + 2.*m[6] + - m[7] + m[10] - m[11] + m[13] - m[14] + m[16] + 2.*m[18]; + lbfluid[0][10][index] = m[0] - m[ 1] + m[ 2] + m[ 4] + 2.*m[6] + - m[7] - m[10] + m[11] - m[13] + m[14] + m[16] + 2.*m[18]; + lbfluid[0][11][index] = m[0] + m[ 1] + m[ 3] + m[ 4] + m[ 5] - m[ 6] + + m[8] + m[10] + m[12] - m[13] + m[15] + m[16] + m[17] - m[18]; + lbfluid[0][12][index] = m[0] - m[ 1] - m[ 3] + m[ 4] + m[ 5] - m[ 6] + + m[8] - m[10] - m[12] + m[13] - m[15] + m[16] + m[17] - m[18]; + lbfluid[0][13][index] = m[0] + m[ 1] - m[ 3] + m[ 4] + m[ 5] - m[ 6] + - m[8] + m[10] - m[12] - m[13] - m[15] + m[16] + m[17] - m[18]; + lbfluid[0][14][index] = m[0] - m[ 1] + m[ 3] + m[ 4] + m[ 5] - m[ 6] + - m[8] - m[10] + m[12] + m[13] + m[15] + m[16] + m[17] - m[18]; + lbfluid[0][15][index] = m[0] + m[ 2] + m[ 3] + m[ 4] - m[ 5] - m[ 6] + + m[9] + m[11] + m[12] - m[14] - m[15] + m[16] - m[17] - m[18]; + lbfluid[0][16][index] = m[0] - m[ 2] - m[ 3] + m[ 4] - m[ 5] - m[ 6] + + m[9] - m[11] - m[12] + m[14] + m[15] + m[16] - m[17] - m[18]; + lbfluid[0][17][index] = m[0] + m[ 2] - m[ 3] + m[ 4] - m[ 5] - m[ 6] + - m[9] + m[11] - m[12] - m[14] + m[15] + m[16] - m[17] - m[18]; + lbfluid[0][18][index] = m[0] - m[ 2] + m[ 3] + m[ 4] - m[ 5] - m[ 6] + - m[9] - m[11] + m[12] + m[14] - m[15] + m[16] - m[17] - m[18]; + + /* weights enter in the back transformation */ + for (int i = 0; i < lbmodel.n_veloc; i++) + lbfluid[0][i][index] *= w[i]; + +#else // D3Q19 + double **e = lbmodel.e; + for (int i = 0; i < lbmodel.n_veloc; i++) { + lbfluid[0][i][index] = 0.0; + for (int j = 0; j < lbmodel.n_veloc; j++) + lbfluid[0][i][index] += mode[j] * e[j][i] / e[19][j]; + + lbfluid[0][i][index] *= w[i]; + } +#endif // D3Q19 +} + + +inline void lb_calc_n_from_modes_push(index_t index, double *m) { +#ifdef D3Q19 + int yperiod = lblattice.halo_grid[0]; + int zperiod = lblattice.halo_grid[0]*lblattice.halo_grid[1]; + index_t next[19]; + next[0] = index; + next[1] = index + 1; + next[2] = index - 1; + next[3] = index + yperiod; + next[4] = index - yperiod; + next[5] = index + zperiod; + next[6] = index - zperiod; + next[7] = index + (1 + yperiod); + next[8] = index - (1 + yperiod); + next[9] = index + (1 - yperiod); + next[10] = index - (1 - yperiod); + next[11] = index + (1 + zperiod); + next[12] = index - (1 + zperiod); + next[13] = index + (1 - zperiod); + next[14] = index - (1 - zperiod); + next[15] = index + (yperiod + zperiod); + next[16] = index - (yperiod + zperiod); + next[17] = index + (yperiod - zperiod); + next[18] = index - (yperiod - zperiod); + + /* normalization factors enter in the back transformation */ + for (int i = 0; i < lbmodel.n_veloc; i++) + m[i] = (1./d3q19_modebase[19][i])*m[i]; + +#ifndef OLD_FLUCT + lbfluid[1][ 0][next[0]] = m[0] - m[4] + m[16]; + lbfluid[1][ 1][next[1]] = m[0] + m[1] + m[5] + m[6] - m[17] - m[18] - 2.*(m[10] + m[16]); + lbfluid[1][ 2][next[2]] = m[0] - m[1] + m[5] + m[6] - m[17] - m[18] + 2.*(m[10] - m[16]); + lbfluid[1][ 3][next[3]] = m[0] + m[2] - m[5] + m[6] + m[17] - m[18] - 2.*(m[11] + m[16]); + lbfluid[1][ 4][next[4]] = m[0] - m[2] - m[5] + m[6] + m[17] - m[18] + 2.*(m[11] - m[16]); + lbfluid[1][ 5][next[5]] = m[0] + m[3] - 2.*(m[6] + m[12] + m[16] - m[18]); + lbfluid[1][ 6][next[6]] = m[0] - m[3] - 2.*(m[6] - m[12] + m[16] - m[18]); + lbfluid[1][ 7][next[7]] = m[0] + m[1] + m[2] + m[4] + 2.*m[6] + m[7] + m[10] + m[11] + m[13] + m[14] + m[16] + 2.*m[18]; + lbfluid[1][ 8][next[8]] = m[0] - m[1] - m[2] + m[4] + 2.*m[6] + m[7] - m[10] - m[11] - m[13] - m[14] + m[16] + 2.*m[18]; + lbfluid[1][ 9][next[9]] = m[0] + m[1] - m[2] + m[4] + 2.*m[6] - m[7] + m[10] - m[11] + m[13] - m[14] + m[16] + 2.*m[18]; + lbfluid[1][10][next[10]] = m[0] - m[1] + m[2] + m[4] + 2.*m[6] - m[7] - m[10] + m[11] - m[13] + m[14] + m[16] + 2.*m[18]; + lbfluid[1][11][next[11]] = m[0] + m[1] + m[3] + m[4] + m[5] - m[6] + m[8] + m[10] + m[12] - m[13] + m[15] + m[16] + m[17] - m[18]; + lbfluid[1][12][next[12]] = m[0] - m[1] - m[3] + m[4] + m[5] - m[6] + m[8] - m[10] - m[12] + m[13] - m[15] + m[16] + m[17] - m[18]; + lbfluid[1][13][next[13]] = m[0] + m[1] - m[3] + m[4] + m[5] - m[6] - m[8] + m[10] - m[12] - m[13] - m[15] + m[16] + m[17] - m[18]; + lbfluid[1][14][next[14]] = m[0] - m[1] + m[3] + m[4] + m[5] - m[6] - m[8] - m[10] + m[12] + m[13] + m[15] + m[16] + m[17] - m[18]; + lbfluid[1][15][next[15]] = m[0] + m[2] + m[3] + m[4] - m[5] - m[6] + m[9] + m[11] + m[12] - m[14] - m[15] + m[16] - m[17] - m[18]; + lbfluid[1][16][next[16]] = m[0] - m[2] - m[3] + m[4] - m[5] - m[6] + m[9] - m[11] - m[12] + m[14] + m[15] + m[16] - m[17] - m[18]; + lbfluid[1][17][next[17]] = m[0] + m[2] - m[3] + m[4] - m[5] - m[6] - m[9] + m[11] - m[12] - m[14] + m[15] + m[16] - m[17] - m[18]; + lbfluid[1][18][next[18]] = m[0] - m[2] + m[3] + m[4] - m[5] - m[6] - m[9] - m[11] + m[12] + m[14] - m[15] + m[16] - m[17] - m[18]; +#else // !OLD_FLUCT + lbfluid[1][ 0][next[0]] = m[0] - m[4]; + lbfluid[1][ 1][next[1]] = m[0] + m[1] + m[5] + m[6]; + lbfluid[1][ 2][next[2]] = m[0] - m[1] + m[5] + m[6]; + lbfluid[1][ 3][next[3]] = m[0] + m[2] - m[5] + m[6]; + lbfluid[1][ 4][next[4]] = m[0] - m[2] - m[5] + m[6]; + lbfluid[1][ 5][next[5]] = m[0] + m[3] - 2.*m[6]; + lbfluid[1][ 6][next[6]] = m[0] - m[3] - 2.*m[6]; + lbfluid[1][ 7][next[7]] = m[0] + m[1] + m[2] + m[4] + 2.*m[6] + m[7]; + lbfluid[1][ 8][next[8]] = m[0] - m[1] - m[2] + m[4] + 2.*m[6] + m[7]; + lbfluid[1][ 9][next[9]] = m[0] + m[1] - m[2] + m[4] + 2.*m[6] - m[7]; + lbfluid[1][10][next[10]] = m[0] - m[1] + m[2] + m[4] + 2.*m[6] - m[7]; + lbfluid[1][11][next[11]] = m[0] + m[1] + m[3] + m[4] + m[5] - m[6] + m[8]; + lbfluid[1][12][next[12]] = m[0] - m[1] - m[3] + m[4] + m[5] - m[6] + m[8]; + lbfluid[1][13][next[13]] = m[0] + m[1] - m[3] + m[4] + m[5] - m[6] - m[8]; + lbfluid[1][14][next[14]] = m[0] - m[1] + m[3] + m[4] + m[5] - m[6] - m[8]; + lbfluid[1][15][next[15]] = m[0] + m[2] + m[3] + m[4] - m[5] - m[6] + m[9]; + lbfluid[1][16][next[16]] = m[0] - m[2] - m[3] + m[4] - m[5] - m[6] + m[9]; + lbfluid[1][17][next[17]] = m[0] + m[2] - m[3] + m[4] - m[5] - m[6] - m[9]; + lbfluid[1][18][next[18]] = m[0] - m[2] + m[3] + m[4] - m[5] - m[6] - m[9]; +#endif // !OLD_FLUCT + + /* weights enter in the back transformation */ + for (int i = 0; i < lbmodel.n_veloc; i++) + lbfluid[1][i][next[i]] *= lbmodel.w[i]; +#else // D3Q19 + double **e = lbmodel.e; + index_t next[lbmodel.n_veloc]; + for (int i = 0; i < lbmodel.n_veloc; i++) { + next[i] = get_linear_index(c[i][0],c[i][1],c[i][2],lblattic.halo_grid); + lbfluid[1][i][next[i]] = 0.0; + for (int j = 0; j < lbmodel.n_veloc; j++) + lbfluid[1][i][next[i]] += mode[j]*e[j][i]/e[19][j]; + lbfluid[1][i][index] *= w[i]; + } +#endif // D3Q19 +} + + +/* Collisions and streaming (push scheme) */ +inline void lb_collide_stream() { + index_t index; + int x, y, z; + double modes[19]; + + /* loop over all lattice cells (halo excluded) */ +#ifdef LB_BOUNDARIES + for (int i = 0; i < n_lb_boundaries; i++) { + lb_boundaries[i].force[0]=0.; + lb_boundaries[i].force[1]=0.; + lb_boundaries[i].force[2]=0.; + } +#endif // LB_BOUNDARIES + + index = lblattice.halo_offset; + for (z = 1; z <= lblattice.grid[2]; z++) { + for (y = 1; y<=lblattice.grid[1]; y++) { + for (x = 1; x<=lblattice.grid[0]; x++) { + // as we only want to apply this to non-boundary nodes we can throw out the if-clause + // if we have a non-bounded domain +#ifdef LB_BOUNDARIES + if (!lbfields[index].boundary) +#endif // LB_BOUNDARIES + { + + /* calculate modes locally */ + lb_calc_modes(index, modes); + + /* deterministic collisions */ + lb_relax_modes(index, modes); + + /* fluctuating hydrodynamics */ + if (fluct) lb_thermalize_modes(index, modes); + + /* apply forces */ +#ifdef EXTERNAL_FORCES + lb_apply_forces(index, modes); +#else // EXTERNAL_FORCES + if (lbfields[index].has_force) lb_apply_forces(index, modes); +#endif // EXTERNAL_FORCES + + /* transform back to populations and streaming */ + lb_calc_n_from_modes_push(index, modes); + + } +// #ifdef LB_BOUNDARIES +// else { +// // Here collision in the boundary nodes +// // can be included, if this is necessary +// // lb_boundary_collisions(index, modes); +// } +// #endif // LB_BOUNDARIES + ++index; /* next node */ + } + index += 2; /* skip halo region */ + } + index += 2*lblattice.halo_grid[0]; /* skip halo region */ + } + + /* exchange halo regions */ + halo_push_communication(); + +#ifdef LB_BOUNDARIES + /* boundary conditions for links */ + lb_bounce_back(); +#endif // LB_BOUNDARIES + + /* swap the pointers for old and new population fields */ + double **tmp; + tmp = lbfluid[0]; + lbfluid[0] = lbfluid[1]; + lbfluid[1] = tmp; + + /* halo region is invalid after update */ + lbpar.resend_halo = 1; +} + + +/** Streaming and collisions (pull scheme) */ +inline void lb_stream_collide() { + index_t index; + int x, y, z; + double modes[19]; + + /* exchange halo regions */ + halo_communication(&update_halo_comm,(char*)**lbfluid); + +#ifdef ADDITIONAL_CHECKS + lb_check_halo_regions(); +#endif // ADDITIONAL_CHECKS + + /* loop over all lattice cells (halo excluded) */ + index = lblattice.halo_offset; + for (z = 1; z <= lblattice.grid[2]; z++) { + for (y = 1; y <= lblattice.grid[1]; y++) { + for (x = 1; x <= lblattice.grid[0]; x++) { + // as we only want to apply this to non-boundary nodes we can throw out the if-clause + // if we have a non-bounded domain +#ifdef LB_BOUNDARIES + if (!lbfields[index].boundary) +#endif // LB_BOUNDARIES + { + + /* stream (pull) and calculate modes */ + lb_pull_calc_modes(index, modes); + + /* deterministic collisions */ + lb_relax_modes(index, modes); + + /* fluctuating hydrodynamics */ + if (fluct) lb_thermalize_modes(index, modes); + + /* apply forces */ + if (lbfields[index].has_force) lb_apply_forces(index, modes); + + /* calculate new particle populations */ + lb_calc_n_from_modes(index, modes); + } + // Here collision in the boundary nodes + // can be included, if this is necessary +// #ifdef LB_BOUNDARIES +// else { +// lb_boundary_collisions(index, modes); +// } +// #endif // LB_BOUNDARIES + ++index; /* next node */ + } + index += 2; /* skip halo region */ + } + index += 2*lblattice.halo_grid[0]; /* skip halo region */ + } + + /* swap the pointers for old and new population fields */ + //fprintf(stderr,"swapping pointers\n"); + double **tmp = lbfluid[0]; + lbfluid[0] = lbfluid[1]; + lbfluid[1] = tmp; + + /* halo region is invalid after update */ + lbpar.resend_halo = 1; +} + + +/***********************************************************************/ +/** \name Update step for the lattice Boltzmann fluid */ +/***********************************************************************/ +/*@{*/ +/*@}*/ + +/** Update the lattice Boltzmann fluid. + * + * This function is called from the integrator. Since the time step + * for the lattice dynamics can be coarser than the MD time step, we + * monitor the time since the last lattice update. + */ +void lattice_boltzmann_update() { + int factor = (int)round(lbpar.tau/time_step); + + fluidstep += 1; + if (fluidstep>=factor) { + fluidstep=0; +#ifdef PULL + lb_stream_collide(); +#else // PULL + lb_collide_stream(); +#endif // PULL + } +} + +/***********************************************************************/ +/** \name Coupling part */ +/***********************************************************************/ +/*@{*/ + +/** Coupling of a single particle to viscous fluid with Stokesian friction. + * + * Section II.C. Ahlrichs and Duenweg, JCP 111(17):8225 (1999) + * + * @param p The coupled particle (Input). + * @param force Coupling force between particle and fluid (Output). + */ +inline void lb_viscous_coupling(Particle *p, double force[3]) { + int x,y,z; + index_t node_index[8]; + double delta[6]; + double *local_f, interpolated_u[3],delta_j[3]; + +#ifdef EXTERNAL_FORCES + if (!(p->l.ext_flag & COORD_FIXED(0)) + && !(p->l.ext_flag & COORD_FIXED(1)) && !(p->l.ext_flag & COORD_FIXED(2))) + { + ONEPART_TRACE( + if(p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: f = (%.3e,%.3e,%.3e)\n", + this_node, p->f.f[0], p->f.f[1], p->f.f[2]); + } + ); + } +#endif + + /* determine elementary lattice cell surrounding the particle + and the relative position of the particle in this cell */ + lblattice.map_position_to_lattice(p->r.p,node_index,delta); + + ONEPART_TRACE( + if(p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB delta=(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f) pos=(%.3f,%.3f,%.3f)\n", + this_node, delta[0], delta[1], delta[2], delta[3], + delta[4], delta[5], p->r.p[0], p->r.p[1], p->r.p[2]); + } + ); + + /* calculate fluid velocity at particle's position + this is done by linear interpolation + (Eq. (11) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ + lb_lbfluid_get_interpolated_velocity(p->r.p, interpolated_u); + + ONEPART_TRACE( + if (p->p.identity==check_id) + { + fprintf(stderr, + "%d: OPT: LB u = (%.16e,%.3e,%.3e) v = (%.16e,%.3e,%.3e)\n", + this_node, interpolated_u[0], interpolated_u[1], interpolated_u[2], + p->m.v[0], p->m.v[1], p->m.v[2]); + } + ); + + /* calculate viscous force + * take care to rescale velocities with time_step and transform to MD units + * (Eq. (9) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ +#ifdef LB_ELECTROHYDRODYNAMICS + force[0] = - lbpar.friction[0] * (p->m.v[0]/time_step - interpolated_u[0] - p->p.mu_E[0]); + force[1] = - lbpar.friction[0] * (p->m.v[1]/time_step - interpolated_u[1] - p->p.mu_E[1]); + force[2] = - lbpar.friction[0] * (p->m.v[2]/time_step - interpolated_u[2] - p->p.mu_E[2]); +#else // LB_ELECTROHYDRODYNAMICS + force[0] = - lbpar.friction[0] * (p->m.v[0]/time_step - interpolated_u[0]); + force[1] = - lbpar.friction[0] * (p->m.v[1]/time_step - interpolated_u[1]); + force[2] = - lbpar.friction[0] * (p->m.v[2]/time_step - interpolated_u[2]); +#endif // LB_ELECTROHYDRODYNAMICS + + ONEPART_TRACE( + if (p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB f_drag = (%.6e,%.3e,%.3e)\n", + this_node, force[0], force[1], force[2]); + } + ); + + ONEPART_TRACE( + if (p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB f_random = (%.6e,%.3e,%.3e)\n", + this_node, p->lc.f_random[0], p->lc.f_random[1], p->lc.f_random[2]); + } + ); + + force[0] = force[0] + p->lc.f_random[0]; + force[1] = force[1] + p->lc.f_random[1]; + force[2] = force[2] + p->lc.f_random[2]; + + ONEPART_TRACE( + if (p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB f_tot = (%.6e,%.3e,%.3e)\n", + this_node, force[0], force[1], force[2]); + } + ); + + /* transform momentum transfer to lattice units + (Eq. (12) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ + delta_j[0] = - force[0]*time_step*lbpar.tau/lbpar.agrid; + delta_j[1] = - force[1]*time_step*lbpar.tau/lbpar.agrid; + delta_j[2] = - force[2]*time_step*lbpar.tau/lbpar.agrid; + + for (z = 0; z < 2; z++) { + for (y = 0; y < 2; y++) { + for (x = 0; x < 2; x++) { + local_f = lbfields[node_index[(z*2+y)*2+x]].force; + + local_f[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[0]; + local_f[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[1]; + local_f[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[2]; + } + } + } +} + + +int lb_lbfluid_get_interpolated_velocity(double* p, double* v) { + index_t node_index[8], index; + double delta[6]; + double local_rho, local_j[3], interpolated_u[3]; + double modes[19]; + int x,y,z; + double pos[3]; + +#ifdef LB_BOUNDARIES + double lbboundary_mindist, distvec[3]; + int boundary_no; + int boundary_flag=-1; // 0 if more than agrid/2 away from the boundary, 1 if 0 0.5 * lbpar.agrid) { + boundary_flag=0; + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; + } else if (lbboundary_mindist > 0 ) { + boundary_flag=1; + pos[0] = p[0] - distvec[0] + distvec[0]/lbboundary_mindist * lbpar.agrid/2.; + pos[1] = p[1] - distvec[1] + distvec[1]/lbboundary_mindist * lbpar.agrid/2.; + pos[2] = p[2] - distvec[2] + distvec[2]/lbboundary_mindist * lbpar.agrid/2.; + } else { + boundary_flag=2; + v[0]= lb_boundaries[boundary_no].velocity[0]*lbpar.agrid/lbpar.tau; + v[1]= lb_boundaries[boundary_no].velocity[1]*lbpar.agrid/lbpar.tau; + v[2]= lb_boundaries[boundary_no].velocity[2]*lbpar.agrid/lbpar.tau; + return 0; // we can return without interpolating + } +#else // LB_BOUNDARIES + pos[0]=p[0]; + pos[1]=p[1]; + pos[2]=p[2]; +#endif // LB_BOUNDARIES + + /* determine elementary lattice cell surrounding the particle + and the relative position of the particle in this cell */ + lblattice.map_position_to_lattice(pos,node_index,delta); + + /* calculate fluid velocity at particle's position + this is done by linear interpolation + (Eq. (11) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ + interpolated_u[0] = interpolated_u[1] = interpolated_u[2] = 0.0 ; + + for (z=0;z<2;z++) { + for (y=0;y<2;y++) { + for (x=0;x<2;x++) { + index = node_index[(z*2+y)*2+x]; + +#ifdef LB_BOUNDARIES + if (lbfields[index].boundary) { + local_rho=lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; + local_j[0] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[0]; + local_j[1] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[1]; + local_j[2] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[2]; + } else { + lb_calc_modes(index, modes); + local_rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid + modes[0]; + local_j[0] = modes[1]; + local_j[1] = modes[2]; + local_j[2] = modes[3]; + } +#else // LB_BOUNDARIES + lb_calc_modes(index, modes); + local_rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid + modes[0]; + local_j[0] = modes[1]; + local_j[1] = modes[2]; + local_j[2] = modes[3]; +#endif // LB_BOUNDARIES + interpolated_u[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[0]/(local_rho); + interpolated_u[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[1]/(local_rho); + interpolated_u[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[2]/(local_rho) ; + } + } + } +#ifdef LB_BOUNDARIES + if (boundary_flag==1) { + v[0] = lbboundary_mindist / (0.5 * lbpar.agrid) * interpolated_u[0] + + (1 - lbboundary_mindist/(0.5 * lbpar.agrid)) * lb_boundaries[boundary_no].velocity[0]; + v[1] = lbboundary_mindist / (0.5 * lbpar.agrid) * interpolated_u[1] + + (1 - lbboundary_mindist/(0.5 * lbpar.agrid)) * lb_boundaries[boundary_no].velocity[1]; + v[2] = lbboundary_mindist / (0.5 * lbpar.agrid) * interpolated_u[2] + + (1 - lbboundary_mindist/(0.5 * lbpar.agrid)) * lb_boundaries[boundary_no].velocity[2]; + } else { + v[0] = interpolated_u[0]; + v[1] = interpolated_u[1]; + v[2] = interpolated_u[2]; + } +#else // LB_BOUNDARIES + v[0] = interpolated_u[0]; + v[1] = interpolated_u[1]; + v[2] = interpolated_u[2]; +#endif // LB_BOUNDARIES + v[0] *= lbpar.agrid/lbpar.tau; + v[1] *= lbpar.agrid/lbpar.tau; + v[2] *= lbpar.agrid/lbpar.tau; + return 0; +} + + +/** Calculate particle lattice interactions. + * So far, only viscous coupling with Stokesian friction is + * implemented. + * Include all particle-lattice forces in this function. + * The function is called from \ref force_calc. + * + * Parallelizing the fluid particle coupling is not straightforward + * because drawing of random numbers makes the whole thing nonlocal. + * One way to do it is to treat every particle only on one node, i.e. + * the random numbers need not be communicated. The particles that are + * not fully inside the local lattice are taken into account via their + * ghost images on the neighbouring nodes. But this requires that the + * correct values of the surrounding lattice nodes are available on + * the respective node, which means that we have to communicate the + * halo regions before treating the ghost particles. Moreover, after + * determining the ghost couplings, we have to communicate back the + * halo region such that all local lattice nodes have the correct values. + * Thus two communication phases are involved which will most likely be + * the bottleneck of the computation. + * + * Another way of dealing with the particle lattice coupling is to + * treat a particle and all of it's images explicitly. This requires the + * communication of the random numbers used in the calculation of the + * coupling force. The problem is now that, if random numbers have to + * be redrawn, we cannot efficiently determine which particles and which + * images have to be re-calculated. We therefore go back to the outset + * and go through the whole system again until no failure occurs during + * such a sweep. In the worst case, this is very inefficient because + * many things are recalculated although they actually don't need. + * But we can assume that this happens extremely rarely and then we have + * on average only one communication phase for the random numbers, which + * probably makes this method preferable compared to the above one. + */ +void calc_particle_lattice_ia() { + int np; + Cell *cell ; + Particle *p ; + double force[3]; + + if (transfer_momentum) { + + if (lbpar.resend_halo) { /* first MD step after last LB update */ + + /* exchange halo regions (for fluid-particle coupling) */ + halo_communication(&update_halo_comm, (char*)**lbfluid); +#ifdef ADDITIONAL_CHECKS + lb_check_halo_regions(); +#endif // ADDITIONAL_CHECKS + + /* halo is valid now */ + lbpar.resend_halo = 0; + + /* all fields have to be recalculated */ + for (int i = 0; i < lblattice.halo_grid_volume; ++i) + lbfields[i].recalc_fields = 1; + } + + /* draw random numbers for local particles */ + for (int c = 0; c < local_cells.n; c++) + { + cell = local_cells.cell[c] ; + p = cell->part ; + np = cell->n ; + for (int i = 0; i < np; i++) + { +#ifdef GAUSSRANDOM + p[i].lc.f_random[0] = lb_coupl_pref2 * gaussian_random(); + p[i].lc.f_random[1] = lb_coupl_pref2 * gaussian_random(); + p[i].lc.f_random[2] = lb_coupl_pref2 * gaussian_random(); +#elif defined (GAUSSRANDOMCUT) + p[i].lc.f_random[0] = lb_coupl_pref2 * gaussian_random_cut(); + p[i].lc.f_random[1] = lb_coupl_pref2 * gaussian_random_cut(); + p[i].lc.f_random[2] = lb_coupl_pref2 * gaussian_random_cut(); +#elif defined (FLATNOISE) + p[i].lc.f_random[0] = lb_coupl_pref * (d_random()-0.5); + p[i].lc.f_random[1] = lb_coupl_pref * (d_random()-0.5); + p[i].lc.f_random[2] = lb_coupl_pref * (d_random()-0.5); +#else // GAUSSRANDOM +#error No noise type defined for the CPU LB +#endif // GAUSSRANDOM + +#ifdef ADDITIONAL_CHECKS + rancounter += 3; +#endif // ADDITIONAL_CHECKS + } + } + + /* communicate the random numbers */ + ghost_communicator(&cell_structure.ghost_lbcoupling_comm) ; + + /* local cells */ + for (int c = 0; c < local_cells.n; c++) { + cell = local_cells.cell[c] ; + p = cell->part ; + np = cell->n ; + + for (int i = 0; i < np; i++) { + lb_viscous_coupling(&p[i],force); + + /* add force to the particle */ + p[i].f.f[0] += force[0]; + p[i].f.f[1] += force[1]; + p[i].f.f[2] += force[2]; + + ONEPART_TRACE( + if (p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB f = (%.6e,%.3e,%.3e)\n", + this_node, p->f.f[0], p->f.f[1], p->f.f[2]); + } + ); + } + } + + /* ghost cells */ + for (int c = 0; c < ghost_cells.n ;c++) { + cell = ghost_cells.cell[c] ; + p = cell->part ; + np = cell->n ; + + for (int i = 0; i < np; i++) { + /* for ghost particles we have to check if they lie + * in the range of the local lattice nodes */ + if (p[i].r.p[0] >= my_left[0]-0.5*lblattice.agrid[0] + && p[i].r.p[0] < my_right[0]+0.5*lblattice.agrid[0] + && p[i].r.p[1] >= my_left[1]-0.5*lblattice.agrid[1] + && p[i].r.p[1] < my_right[1]+0.5*lblattice.agrid[1] + && p[i].r.p[2] >= my_left[2]-0.5*lblattice.agrid[2] + && p[i].r.p[2] < my_right[2]+0.5*lblattice.agrid[2]) + { + ONEPART_TRACE( + if (p[i].p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB coupling of ghost particle:\n", + this_node); + } + ); + + lb_viscous_coupling(&p[i],force); + + /* ghosts must not have the force added! */ + ONEPART_TRACE( + if (p->p.identity == check_id) + { + fprintf(stderr, + "%d: OPT: LB f = (%.6e,%.3e,%.3e)\n", + this_node, p->f.f[0], p->f.f[1], p->f.f[2]); + } + ); + } + } + } + } +} + +/***********************************************************************/ + +/** Calculate the average density of the fluid in the system. + * This function has to be called after changing the density of + * a local lattice site in order to set lbpar.rho consistently. */ +void lb_calc_average_rho() { + index_t index; + int x, y, z; + double rho, local_rho, sum_rho; + + rho = 0.0; + local_rho = 0.0; + index = 0; + for (z = 1; z <= lblattice.grid[2]; z++) { + for (y = 1; y <= lblattice.grid[1]; y++) { + for (x = 1; x<=lblattice.grid[0]; x++) { + lb_calc_local_rho(index, &rho); + local_rho += rho; + + index++; + } + // skip halo region + index += 2; + } + // skip halo region + index += 2*lblattice.halo_grid[0]; + } + MPI_Allreduce(&rho, &sum_rho, 1, MPI_DOUBLE, MPI_SUM, comm_cart); + + /* calculate average density in MD units */ + // TODO!!! + lbpar.rho[0] = sum_rho / (box_l[0]*box_l[1]*box_l[2]); +} + +/*@}*/ + +#ifdef ADDITIONAL_CHECKS +static int compare_buffers(double *buf1, double *buf2, int size) { + int ret; + if (memcmp(buf1,buf2,size)) { + ostringstream msg; + msg <<"Halo buffers are not identical"; + runtimeError(msg); + ret = 1; + } else { + ret = 0; + } + return ret; +} + + +/** Checks consistency of the halo regions (ADDITIONAL_CHECKS) + This function can be used as an additional check. It test whether the + halo regions have been exchanged correctly. +*/ +static void lb_check_halo_regions() { + index_t index; + int i,x,y,z, s_node, r_node, count=lbmodel.n_veloc; + double *s_buffer, *r_buffer; + MPI_Status status[2]; + + r_buffer = (double*) malloc(count*sizeof(double)); + s_buffer = (double*) malloc(count*sizeof(double)); + + if (PERIODIC(0)) { + for (z = 0; z < lblattice.halo_grid[2]; ++z) { + for (y = 0; y < lblattice.halo_grid[1]; ++y) { + index = get_linear_index(0,y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[1]; + r_node = node_neighbors[0]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(lblattice.grid[0],y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(lblattice.grid[0],y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) + { + s_buffer[i] = lbfluid[0][i][index]; + } + if (compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld y=%d z=%d\n",0,index,y,z); + } + } + + index = get_linear_index(lblattice.grid[0]+1,y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[0]; + r_node = node_neighbors[1]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(1,y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(1,y,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) r_buffer[i] = lbfluid[0][i][index]; + if (compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld y=%d z=%d\n",0,index,y,z); + } + } + + } + } + } + + if (PERIODIC(1)) { + for (z = 0; z < lblattice.halo_grid[2]; ++z) { + for (x = 0; x < lblattice.halo_grid[0]; ++x) { + index = get_linear_index(x,0,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[3]; + r_node = node_neighbors[2]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(x,lblattice.grid[1],z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(x,lblattice.grid[1],z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) r_buffer[i] = lbfluid[0][i][index]; + if (compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld x=%d z=%d\n",1,index,x,z); + } + } + + } + for (x = 0; x < lblattice.halo_grid[0]; ++x) { + index = get_linear_index(x,lblattice.grid[1]+1,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[2]; + r_node = node_neighbors[3]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(x,1,z,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(x,1,z,lblattice.halo_grid); + for (i = 0;i < lbmodel.n_veloc; i++) r_buffer[i] = lbfluid[0][i][index]; + if (compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld x=%d z=%d\n",1,index,x,z); + } + } + + } + } + } + + if (PERIODIC(2)) { + for (y = 0; y < lblattice.halo_grid[1]; ++y) { + for (x = 0; x < lblattice.halo_grid[0]; ++x) { + index = get_linear_index(x,y,0,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[5]; + r_node = node_neighbors[4]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(x,y,lblattice.grid[2],lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(x,y,lblattice.grid[2],lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) r_buffer[i] = lbfluid[0][i][index]; + if (compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld x=%d y=%d z=%d\n",2,index,x,y,lblattice.grid[2]); + } + } + + } + } + for (y = 0; y < lblattice.halo_grid[1]; ++y) { + for (x = 0; x < lblattice.halo_grid[0]; ++x) { + index = get_linear_index(x,y,lblattice.grid[2]+1,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + + s_node = node_neighbors[4]; + r_node = node_neighbors[5]; + if (n_nodes > 1) { + MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, + r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, + comm_cart, status); + index = get_linear_index(x,y,1,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) s_buffer[i] = lbfluid[0][i][index]; + compare_buffers(s_buffer,r_buffer,count*sizeof(double)); + } else { + index = get_linear_index(x,y,1,lblattice.halo_grid); + for (i = 0; i < lbmodel.n_veloc; i++) r_buffer[i] = lbfluid[0][i][index]; + if(compare_buffers(s_buffer,r_buffer,count*sizeof(double))) { + fprintf(stderr,"buffers differ in dir=%d at index=%ld x=%d y=%d\n",2,index,x,y); + } + } + + } + } + } + + free(r_buffer); + free(s_buffer); + + //if (check_runtime_errors()); + //else fprintf(stderr,"halo check successful\n"); +} +#endif /* ADDITIONAL_CHECKS */ + + +#if 0 /* These debug functions are used nowhere. If you need it, here they are. + Remove this comment line and the matching #endif. + The functions in question are: + lb_lattice_sum + lb_check_mode_transformation + lb_init_mode_transformation + lb_check_negative_n + */ +#ifdef ADDITIONAL_CHECKS +static void lb_lattice_sum() { + + double *w = lbmodel.w; + double (*v)[3] = lbmodel.c; + + //int n_veloc = 14; + //double w[14] = { 7./18., + // 1./12., 1./12., 1./12., 1./12., 1./18., + // 1./36., 1./36., 1./36., 1./36., + // 1./36., 1./36., 1./36., 1./36. }; + //double v[14][3] = { { 0., 0., 0. }, + // { 1., 0., 0. }, + // {-1., 0., 0. }, + // { 0., 1., 0. }, + // { 0.,-1., 0. }, + // { 0., 0., 1. }, + // { 1., 1., 0. }, + // {-1.,-1., 0. }, + // { 1.,-1., 0. }, + // {-1., 1., 0. }, + // { 1., 0., 1. }, + // {-1., 0., 1. }, + // { 0., 1., 1. }, + // { 0.,-1., 1. } }; + + int i,a,b,c,d,e; + double sum1,sum2,sum3,sum4,sum5; + int count=0; + + for (a = 0; a < 3; a++) + { + sum1 = 0.0; + for (i = 0; i < lbmodel.n_veloc; ++i) { + if (v[i][2] < 0) sum1 += w[i]*v[i][a]; + } + if (fabs(sum1) > ROUND_ERROR_PREC) { + count++; fprintf(stderr,"(%d) %f\n",a,sum1); + } + } + + for (a=0; a<3; a++) + for (b=0; b<3; b++) + { + sum2 = 0.0; + for (i=0; i ROUND_ERROR_PREC) { + count++; fprintf(stderr,"(%d,%d,%d,%d) %f\n",a,b,c,d,sum4); + } + } + + for (a=0; a<3; a++) + for (b=0; b<3; b++) + for (c=0; c<3; c++) + for (d=0; d<3; d++) + for (e=0; e<3; e++) + { + sum5 = 0.0; + for (i=0; i ROUND_ERROR_PREC) { + count++; fprintf(stderr,"(%d,%d,%d,%d,%d) %f\n",a,b,c,d,e,sum5); + } + } + + fprintf(stderr,"%d non-null entries\n",count); + +} +#endif /* #ifdef ADDITIONAL_CHECKS */ + +#ifdef ADDITIONAL_CHECKS +static void lb_check_mode_transformation(index_t index, double *mode) { + /* check if what I think is right */ + int i; + double *w = lbmodel.w; + double (*e)[19] = d3q19_modebase; + double sum_n=0.0, sum_m=0.0; + double n_eq[19]; + double m_eq[19]; + // unit conversion: mass density + double avg_rho = lbpar.rho*lbpar.agrid*lbpar.agrid*lbpar.agrid; + double (*c)[3] = lbmodel.c; + + m_eq[0] = mode[0]; + m_eq[1] = mode[1]; + m_eq[2] = mode[2]; + m_eq[3] = mode[3]; + + double rho = mode[0] + avg_rho; + double *j = mode+1; + + /* equilibrium part of the stress modes */ + /* remember that the modes have (\todo not?) been normalized! */ + m_eq[4] = /*1./6.*/scalar(j,j)/rho; + m_eq[5] = /*1./4.*/(SQR(j[0])-SQR(j[1]))/rho; + m_eq[6] = /*1./12.*/(scalar(j,j) - 3.0*SQR(j[2]))/rho; + m_eq[7] = j[0]*j[1]/rho; + m_eq[8] = j[0]*j[2]/rho; + m_eq[9] = j[1]*j[2]/rho; + + for (i=10;iROUND_ERROR_PREC) { + fprintf(stderr,"Attention: sum_n=%f sum_m=%f %e\n",sum_n,sum_m,fabs(sum_n-sum_m)); + } +} + +static void lb_init_mode_transformation() { +#ifdef D3Q19 + int i, j, k, l; + int n_veloc = 14; + double w[14] = { 7./18., + 1./12., 1./12., 1./12., 1./12., 1./18., + 1./36., 1./36., 1./36., 1./36., + 1./36., 1./36., 1./36., 1./36. }; + double c[14][3] = { { 0., 0., 0. }, + { 1., 0., 0. }, + {-1., 0., 0. }, + { 0., 1., 0. }, + { 0.,-1., 0. }, + { 0., 0., 1. }, + { 1., 1., 0. }, + {-1.,-1., 0. }, + { 1.,-1., 0. }, + {-1., 1., 0. }, + { 1., 0., 1. }, + {-1., 0., 1. }, + { 0., 1., 1. }, + { 0.,-1., 1. } }; + + double b[19][14]; + double e[14][14]; + double proj, norm[14]; + + /* construct polynomials from the discrete velocity vectors */ + for (i=0;i. */ -/** \file lb.h - * Header file for lb.c +/** \file lb.hpp + * Header file for lb.cpp * - * This is the header file for the Lattice Boltzmann implementation in lb.c + * This is the header file for the Lattice Boltzmann implementation in lb.cpp */ #ifndef LB_H #define LB_H #include "utils.hpp" -#include "lattice.hpp" +#include "lattice_inline.hpp" extern int lb_components ; // global variable holding the number of fluid components @@ -53,6 +53,11 @@ extern int lb_components ; // global variable holding the number of fluid compon #define LBPAR_EXTFORCE 5 /**< external force acting on the fluid */ #define LBPAR_BULKVISC 6 /**< fluid bulk viscosity */ +/** Note these are used for binary logic so should be powers of 2 */ +#define LB_COUPLE_NULL 1 +#define LB_COUPLE_TWO_POINT 2 +#define LB_COUPLE_THREE_POINT 4 + /*@}*/ /** Some general remarks: * This file implements the LB D3Q19 method to Espresso. The LB_Model @@ -126,7 +131,7 @@ typedef struct { /** normal vector of the boundary surface */ double *nvec; //doesn't work like that any more, I think (georg, 17.08.10) -#endif +#endif // LB_BOUNDARIES } LB_FluidNode; @@ -251,7 +256,7 @@ void lb_get_local_fields(LB_FluidNode *node, double *rho, double *j, double *pi) @param j local fluid speed @param pi local fluid pressure */ -void lb_calc_n_equilibrium(const index_t index, const double rho, const double *j, double *pi); +void lb_calc_n_from_rho_j_pi(const index_t index, const double rho, const double *j, double *pi); /** Propagates the Lattice Boltzmann system for one time step. * This function performs the collision step and the streaming step. @@ -296,8 +301,9 @@ inline void lb_calc_local_rho(index_t index, double *rho) { // unit conversion: mass density if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_calc_local_rho in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_calc_local_rho in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); *rho =0; return; } @@ -310,11 +316,11 @@ inline void lb_calc_local_rho(index_t index, double *rho) { + lbfluid[0][3][index] + lbfluid[0][4][index] + lbfluid[0][5][index] + lbfluid[0][6][index] + lbfluid[0][7][index] + lbfluid[0][8][index] - + lbfluid[0][9][index] + lbfluid[0][10][index] + + lbfluid[0][9][index] + lbfluid[0][10][index] + lbfluid[0][11][index] + lbfluid[0][12][index] - + lbfluid[0][13][index] + lbfluid[0][14][index] + + lbfluid[0][13][index] + lbfluid[0][14][index] + lbfluid[0][15][index] + lbfluid[0][16][index] - + lbfluid[0][17][index] + lbfluid[0][18][index]; + + lbfluid[0][17][index] + lbfluid[0][18][index]; } @@ -329,8 +335,9 @@ inline void lb_calc_local_j(index_t index, double *j) { #error Only D3Q19 is implemened! #endif if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_calc_local_j in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_calc_local_j in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); j[0]=j[1]=j[2]=0; return; } @@ -364,8 +371,9 @@ inline void lb_calc_local_pi(index_t index, double *pi) { double j[3]; if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_calc_local_pi in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_calc_local_pi in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); j[0] = j[1] = j[2] = 0; return; } @@ -382,10 +390,11 @@ inline void lb_calc_local_pi(index_t index, double *pi) { * @param pi local fluid pressure */ inline void lb_calc_local_fields(index_t index, double *rho, double *j, double *pi) { - + if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_calc_local_fields in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_calc_local_fields in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); *rho=0; j[0]=j[1]=j[2]=0; pi[0]=pi[1]=pi[2]=pi[3]=pi[4]=pi[5]=0; return; } @@ -395,8 +404,9 @@ inline void lb_calc_local_fields(index_t index, double *rho, double *j, double * #endif if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_calc_local_pi in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_calc_local_pi in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); j[0] = j[1] = j[2] = 0; return; } @@ -410,7 +420,7 @@ inline void lb_calc_local_fields(index_t index, double *rho, double *j, double * } #endif double mode[19]; - double pi_eq[6]; + double modes_from_pi_eq[6]; lb_calc_modes(index, mode); *rho = mode[0] + lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; @@ -431,30 +441,34 @@ inline void lb_calc_local_fields(index_t index, double *rho, double *j, double * return; /* equilibrium part of the stress modes */ - pi_eq[0] = scalar(j,j)/ *rho; - pi_eq[1] = (SQR(j[0])-SQR(j[1]))/ *rho; - pi_eq[2] = (scalar(j,j) - 3.0*SQR(j[2]))/ *rho; - pi_eq[3] = j[0]*j[1]/ *rho; - pi_eq[4] = j[0]*j[2]/ *rho; - pi_eq[5] = j[1]*j[2]/ *rho; + modes_from_pi_eq[0] = scalar(j,j)/ *rho; + modes_from_pi_eq[1] = (SQR(j[0])-SQR(j[1]))/ *rho; + modes_from_pi_eq[2] = (scalar(j,j) - 3.0*SQR(j[2]))/ *rho; + modes_from_pi_eq[3] = j[0]*j[1]/ *rho; + modes_from_pi_eq[4] = j[0]*j[2]/ *rho; + modes_from_pi_eq[5] = j[1]*j[2]/ *rho; /* Now we must predict the outcome of the next collision */ /* We immediately average pre- and post-collision. */ - mode[4] = pi_eq[0] + (0.5+0.5*gamma_bulk )*(mode[4] - pi_eq[0]); - mode[5] = pi_eq[1] + (0.5+0.5*gamma_shear)*(mode[5] - pi_eq[1]); - mode[6] = pi_eq[2] + (0.5+0.5*gamma_shear)*(mode[6] - pi_eq[2]); - mode[7] = pi_eq[3] + (0.5+0.5*gamma_shear)*(mode[7] - pi_eq[3]); - mode[8] = pi_eq[4] + (0.5+0.5*gamma_shear)*(mode[8] - pi_eq[4]); - mode[9] = pi_eq[5] + (0.5+0.5*gamma_shear)*(mode[9] - pi_eq[5]); - - /* Now we have to transform to the "usual" stress tensor components */ - /* We use eq. 116ff in Duenweg Ladd for that. */ - pi[0]=(mode[0]+mode[4]+mode[5])/3.; - pi[2]=(2*mode[0]+2*mode[4]-mode[5]+3*mode[6])/6.; - pi[5]=(2*mode[0]+2*mode[4]-mode[5]+3*mode[6])/6.; - pi[1]=mode[7]; - pi[3]=mode[8]; - pi[4]=mode[9]; + mode[4] = modes_from_pi_eq[0] + (0.5+0.5*gamma_bulk )*(mode[4] - modes_from_pi_eq[0]); + mode[5] = modes_from_pi_eq[1] + (0.5+0.5*gamma_shear)*(mode[5] - modes_from_pi_eq[1]); + mode[6] = modes_from_pi_eq[2] + (0.5+0.5*gamma_shear)*(mode[6] - modes_from_pi_eq[2]); + mode[7] = modes_from_pi_eq[3] + (0.5+0.5*gamma_shear)*(mode[7] - modes_from_pi_eq[3]); + mode[8] = modes_from_pi_eq[4] + (0.5+0.5*gamma_shear)*(mode[8] - modes_from_pi_eq[4]); + mode[9] = modes_from_pi_eq[5] + (0.5+0.5*gamma_shear)*(mode[9] - modes_from_pi_eq[5]); + + // Transform the stress tensor components according to the modes that + // correspond to those used by U. Schiller. In terms of populations this + // expression then corresponds exactly to those in Eqs. 116 - 121 in the + // Duenweg and Ladd paper, when these are written out in populations. + // But to ensure this, the expression in Schiller's modes has to be different! + + pi[0] = ( 2.0*(mode[0] + mode[4]) + mode[6] + 3.0*mode[5] )/6.0; // xx + pi[1] = mode[7]; // xy + pi[2] = ( 2.0*(mode[0] + mode[4]) + mode[6] - 3.0*mode[5] )/6.0; // yy + pi[3] = mode[8]; // xz + pi[4] = mode[9]; // yz + pi[5] = ( mode[0] + mode[4] - mode[6] )/3.0; // zz } @@ -462,8 +476,9 @@ inline void lb_calc_local_fields(index_t index, double *rho, double *j, double * inline void lb_local_fields_get_boundary_flag(index_t index, int *boundary) { if (!(lattice_switch & LATTICE_LB)) { - ERROR_SPRINTF(runtime_error(128), - "{ Error in lb_local_fields_get_boundary_flag in %s %d: CPU LB not switched on. } ", __FILE__, __LINE__); + ostringstream msg; + msg <<"Error in lb_local_fields_get_boundary_flag in " << __FILE__ << __LINE__ << ": CPU LB not switched on."; + runtimeError(msg); *boundary = 0; return; } @@ -502,9 +517,11 @@ int lb_lbfluid_set_bulk_visc(double * p_bulk_visc); int lb_lbfluid_set_gamma_odd(double * p_gamma_odd); int lb_lbfluid_set_gamma_even(double * p_gamma_even); int lb_lbfluid_set_friction(double * p_friction); +int lb_lbfluid_set_couple_flag(int couple_flag); int lb_lbfluid_set_agrid(double p_agrid); -int lb_lbfluid_set_ext_force(double p_fx, double p_fy, double p_fz); +int lb_lbfluid_set_ext_force(int component, double p_fx, double p_fy, double p_fz); int lb_lbfluid_set_tau(double p_tau); +int lb_lbfluid_set_remove_momentum(void); #ifdef SHANCHEN int lb_lbfluid_set_shanchen_coupling(double * p_coupling); int lb_lbfluid_set_mobility(double * p_mobility); diff --git a/src/lbgpu.cpp b/src/core/lbgpu.cpp similarity index 76% rename from src/lbgpu.cpp rename to src/core/lbgpu.cpp index 67cfc747782..b9b02aa9baf 100644 --- a/src/lbgpu.cpp +++ b/src/core/lbgpu.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/** \file lbgpu_cfile.c +/** \file lbgpu.cpp * * C file for the Lattice Boltzmann implementation on GPUs. - * Header file for \ref lbgpu.h. + * Header file for \ref lbgpu.hpp. */ //#include #include @@ -88,6 +88,8 @@ LB_parameters_gpu lbpar_gpu = { SC0, // friction SC0, + // lb_couple_switch + LB_COUPLE_TWO_POINT, // lb_coupl_pref SC0, // lb_coupl_pref2 @@ -128,10 +130,13 @@ LB_parameters_gpu lbpar_gpu = { // mobility SC1, // coupling - SC20 + SC20, + // remove_momentum + 0 #endif // SHANCHEN }; + /** this is the array that stores the hydrodynamic fields for the output */ LB_rho_v_pi_gpu *host_values = NULL; @@ -150,7 +155,7 @@ static int max_ran = 1000000; static int fluidstep = 0; /** c_sound_square in LB units*/ -static float c_sound_sq = 1.f/3.f; +static float c_sound_sq = 1.0f/3.0f; //clock_t start, end; int i; @@ -158,12 +163,13 @@ int i; int n_extern_nodeforces = 0; LB_extern_nodeforce_gpu *host_extern_nodeforces = NULL; +int ek_initialized = 0; /*-----------------------------------------------------------*/ /** main of lb_gpu_programm */ /*-----------------------------------------------------------*/ #ifdef SHANCHEN -/* called from forces.c. This is at the beginning of the force +/* called from forces.cpp. This is at the beginning of the force calculation loop, so we increment the fluidstep counter here, and we reset it only when the last call to a LB function [lattice_boltzmann_update_gpu()] is performed within integrate_vv() @@ -177,7 +183,7 @@ void lattice_boltzmann_calc_shanchen_gpu(void){ } #endif //SHANCHEN -/** lattice boltzmann update gpu called from integrate.c +/** lattice boltzmann update gpu called from integrate.cpp */ void lattice_boltzmann_update_gpu() { @@ -190,17 +196,19 @@ void lattice_boltzmann_update_gpu() { fluidstep=0; lb_integrate_GPU(); +#ifdef SHANCHEN + if(lbpar_gpu.remove_momentum) lb_remove_fluid_momentum_GPU(); +#endif LB_TRACE (fprintf(stderr,"lb_integrate_GPU \n")); } } - - -/** (re-) allocation of the memory need for the particles (cpu part)*/ +/** (re-) allocation of the memory needed for the particles (cpu part) +*/ void lb_realloc_particles_gpu(){ - lbpar_gpu.number_of_particles = n_total_particles; + lbpar_gpu.number_of_particles = n_part; LB_TRACE (printf("#particles realloc\t %u \n", lbpar_gpu.number_of_particles)); //fprintf(stderr, "%u \t \n", lbpar_gpu.number_of_particles); /**-----------------------------------------------------*/ @@ -210,13 +218,18 @@ void lb_realloc_particles_gpu(){ LB_TRACE (fprintf(stderr,"test your_seed %u \n", lbpar_gpu.your_seed)); - lb_realloc_particle_GPU_leftovers(&lbpar_gpu); + lb_realloc_particles_GPU_leftovers(&lbpar_gpu); } + /** (Re-)initializes the fluid according to the given value of rho. */ void lb_reinit_fluid_gpu() { //lbpar_gpu.your_seed = (unsigned int)i_random(max_ran); lb_reinit_parameters_gpu(); +//#ifdef SHANCHEN +// lb_calc_particle_lattice_ia_gpu(); +// copy_forces_from_GPU(); +//#endif if(lbpar_gpu.number_of_nodes != 0){ lb_reinit_GPU(&lbpar_gpu); lbpar_gpu.reinit = 1; @@ -264,8 +277,7 @@ void lb_reinit_parameters_gpu() { LB_TRACE (fprintf(stderr, "fluct on \n")); /* Eq. (51) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007).*/ /* Note that the modes are not normalized as in the paper here! */ - - lbpar_gpu.mu[ii] = (float)temperature/c_sound_sq*lbpar_gpu.tau*lbpar_gpu.tau/(lbpar_gpu.agrid*lbpar_gpu.agrid); // TODO: check how to change mu + lbpar_gpu.mu[ii] = (float)temperature*lbpar_gpu.tau*lbpar_gpu.tau/c_sound_sq/(lbpar_gpu.agrid*lbpar_gpu.agrid); /* lb_coupl_pref is stored in MD units (force) * Eq. (16) Ahlrichs and Duenweg, JCP 111(17):8225 (1999). @@ -285,6 +297,39 @@ void lb_reinit_parameters_gpu() { } LB_TRACE (fprintf(stderr,"lb_reinit_prarameters_gpu \n")); } + + +#ifdef ELECTROKINETICS + if (ek_initialized) { + lbpar_gpu.dim_x = (unsigned int) round(box_l[0] / lbpar_gpu.agrid); //TODO code duplication with lb.c start + lbpar_gpu.dim_y = (unsigned int) round(box_l[1] / lbpar_gpu.agrid); + lbpar_gpu.dim_z = (unsigned int) round(box_l[2] / lbpar_gpu.agrid); + + unsigned int tmp[3]; + + tmp[0] = lbpar_gpu.dim_x; + tmp[1] = lbpar_gpu.dim_y; + tmp[2] = lbpar_gpu.dim_z; + + /* sanity checks */ + int dir; + + for (dir=0;dir<3;dir++) { + /* check if box_l is compatible with lattice spacing */ + if (fabs(box_l[dir] - tmp[dir] * lbpar_gpu.agrid) > 1.0e-3) { + ostringstream msg; + msg <<"Lattice spacing lbpar_gpu.agrid= "<< lbpar_gpu.agrid << " is incompatible with box_l[" << dir << "]=" << box_l[dir]; + runtimeError(msg); + } + } + + lbpar_gpu.number_of_nodes = lbpar_gpu.dim_x * lbpar_gpu.dim_y * lbpar_gpu.dim_z; + lbpar_gpu.tau = (float) time_step; //TODO code duplication with lb.c end + } +#endif + + LB_TRACE (fprintf(stderr,"lb_reinit_prarameters_gpu \n")); + reinit_parameters_GPU(&lbpar_gpu); } @@ -294,7 +339,6 @@ void lb_reinit_parameters_gpu() { void lb_init_gpu() { LB_TRACE(printf("Begin initialzing fluid on GPU\n")); - /** set parameters for transfer to gpu */ lb_reinit_parameters_gpu(); @@ -312,9 +356,9 @@ void lb_init_gpu() { int lb_lbnode_set_extforce_GPU(int ind[3], double f[3]) { - if ( ind[0] < 0 || ind[0] >= lbpar_gpu.dim_x || - ind[1] < 0 || ind[1] >= lbpar_gpu.dim_y || - ind[2] < 0 || ind[2] >= lbpar_gpu.dim_z ) + if ( ind[0] < 0 || ind[0] >= int(lbpar_gpu.dim_x) || + ind[1] < 0 || ind[1] >= int(lbpar_gpu.dim_y) || + ind[2] < 0 || ind[2] >= int(lbpar_gpu.dim_z) ) return ES_ERROR; unsigned int index = @@ -337,4 +381,32 @@ int lb_lbnode_set_extforce_GPU(int ind[3], double f[3]) return ES_OK; } +void lb_GPU_sanity_checks() +{ + if(this_node == 0){ + if (lbpar_gpu.agrid < 0.0) { + ostringstream msg; + msg <<"Lattice Boltzmann agrid not set"; + runtimeError(msg); + } + if (lbpar_gpu.tau < 0.0) { + ostringstream msg; + msg <<"Lattice Boltzmann time step not set"; + runtimeError(msg); + } + for(int i=0;i. */ -/** \file lbgpu.h - * Header file for lbgpu.c +/** \file lbgpu.hpp + * Header file for lbgpu.cpp * - * This is the header file for the Lattice Boltzmann implementation in lbgpu_cfile.c + * This is the header file for the Lattice Boltzmann implementation in lbgpu_cfile.cpp */ #ifndef LB_GPU_H @@ -28,7 +28,7 @@ #include "utils.hpp" #include "config.hpp" - +#include "statistics_observable.hpp" #ifdef LB_GPU /* For the D3Q19 model most functions have a separate implementation @@ -38,6 +38,11 @@ #define D3Q19 #define LBQ 19 +/** Note these are usef for binary logic so should be powers of 2 */ +#define LB_COUPLE_NULL 1 +#define LB_COUPLE_TWO_POINT 2 +#define LB_COUPLE_THREE_POINT 4 + /** \name Parameter fields for Lattice Boltzmann * The numbers are referenced in \ref mpi_bcast_lb_params * to determine what actions have to take place upon change @@ -80,6 +85,10 @@ typedef struct { * lead to numerical artifacts with low order integrators */ float friction[LB_COMPONENTS]; /** amplitude of the fluctuations in the viscous coupling */ + /** Switch indicating what type of coupling is used, can either + use nearest neighbors or next nearest neighbors. */ + int lb_couple_switch; + float lb_coupl_pref[LB_COMPONENTS]; float lb_coupl_pref2[LB_COMPONENTS]; float bulk_viscosity[LB_COMPONENTS]; @@ -107,7 +116,7 @@ typedef struct { int external_force; - float ext_force[3]; + float ext_force[3*LB_COMPONENTS]; unsigned int your_seed; @@ -118,6 +127,7 @@ typedef struct { float gamma_mobility[LB_COMPONENTS]; float mobility[LB_COMPONENTS]; float coupling[LB_COMPONENTS*LB_COMPONENTS]; + int remove_momentum; #endif // SHANCHEN } LB_parameters_gpu; @@ -128,6 +138,7 @@ typedef struct { /** density of the node */ float rho[LB_COMPONENTS]; /** veolcity of the node */ + float v[3]; } LB_rho_v_gpu; @@ -167,6 +178,7 @@ typedef struct { typedef struct { float *force; + float *scforce; } LB_node_force_gpu; @@ -195,7 +207,10 @@ extern LB_rho_v_pi_gpu *host_values; extern int transfer_momentum_gpu; extern LB_extern_nodeforce_gpu *extern_nodeforces_gpu; extern int n_lb_boundaries; - +#ifdef ELECTROKINETICS +extern LB_node_force_gpu node_f; +extern int ek_initialized; +#endif /*@}*/ @@ -205,10 +220,12 @@ extern int n_lb_boundaries; /************************************************************/ /*@{*/ +void lb_GPU_sanity_checks(); +void lb_get_device_values_pointer(LB_rho_v_gpu** pointeradress); +void lb_get_boundary_force_pointer(float** pointeradress); void lb_get_lbpar_pointer(LB_parameters_gpu** pointeradress); void lb_get_para_pointer(LB_parameters_gpu** pointeradress); - void lattice_boltzmann_update_gpu(); /** (Pre-)initializes data structures. */ @@ -232,7 +249,7 @@ void lb_reinit_fluid_gpu(); /** (Re-)initializes the particle array*/ void lb_realloc_particles_gpu(); -void lb_realloc_particle_GPU_leftovers(LB_parameters_gpu *lbpar_gpu); +void lb_realloc_particles_GPU_leftovers(LB_parameters_gpu *lbpar_gpu); void lb_init_GPU(LB_parameters_gpu *lbpar_gpu); void lb_integrate_GPU(); @@ -252,6 +269,7 @@ void lb_calc_particle_lattice_ia_gpu(); void lb_calc_fluid_mass_GPU(double* mass); void lb_calc_fluid_momentum_GPU(double* host_mom); +void lb_remove_fluid_momentum_GPU(void); void lb_calc_fluid_temperature_GPU(double* host_temp); void lb_get_boundary_flag_GPU(int single_nodeindex, unsigned int* host_flag); void lb_get_boundary_flags_GPU(unsigned int* host_bound_array); @@ -267,6 +285,7 @@ void lb_gpu_get_boundary_forces(double* forces); void lb_save_checkpoint_GPU(float *host_checkpoint_vd, unsigned int *host_checkpoint_seed, unsigned int *host_checkpoint_boundary, float *host_checkpoint_force); void lb_load_checkpoint_GPU(float *host_checkpoint_vd, unsigned int *host_checkpoint_seed, unsigned int *host_checkpoint_boundary, float *host_checkpoint_force); +int statistics_observable_lbgpu_radial_velocity_profile(radial_profile_data* pdata, double* A, unsigned int n_A); /*@{*/ diff --git a/src/core/lbgpu_cuda.cu b/src/core/lbgpu_cuda.cu new file mode 100644 index 00000000000..4ffe1b0000c --- /dev/null +++ b/src/core/lbgpu_cuda.cu @@ -0,0 +1,3721 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** \file lbgpu_cuda.cu + * + * Cuda (.cu) file for the Lattice Boltzmann implementation on GPUs. + * Header file for \ref lbgpu.hpp. + */ + +#include "config.hpp" + +#ifdef LB_GPU +#include +#include +#include + +#include "electrokinetics.hpp" +#include "electrokinetics_pdb_parse.hpp" +#include "lbgpu.hpp" +#include "cuda_interface.hpp" +#include "cuda_utils.hpp" + +#if (!defined(FLATNOISE) && !defined(GAUSSRANDOMCUT) && !defined(GAUSSRANDOM)) +#define FLATNOISE +#endif + +int extended_values_flag=0; /* TODO: this has to be set to one by + appropriate functions if there is + the need to compute pi at every + step (e.g. moving boundaries)*/ + +/**defining structures residing in global memory */ + +/** device_rho_v: struct for hydrodynamic fields: this is for internal use + (i.e. stores values in LB units) and should not used for + printing values */ +static LB_rho_v_gpu *device_rho_v= NULL; + +/** device_rho_v_pi: extended struct for hydrodynamic fields: this is the interface + to tcl, and stores values in MD units. It should not be used + as an input for any LB calculations. TODO: This structure is not yet + used, and it is here to allow access to the stress tensor at any + timestep, e.g. for future implementations of moving boundary codes */ +static LB_rho_v_pi_gpu *device_rho_v_pi= NULL; + +/** print_rho_v_pi: struct for hydrodynamic fields: this is the interface + to tcl, and stores values in MD units. It should not used + as an input for any LB calculations. TODO: in the future, + one might want to have several structures for printing + separately rho, v, pi without having to compute/store + the complete set. */ +static LB_rho_v_pi_gpu *print_rho_v_pi= NULL; + +/** structs for velocity densities */ +static LB_nodes_gpu nodes_a = {.vd=NULL,.seed=NULL,.boundary=NULL}; +static LB_nodes_gpu nodes_b = {.vd=NULL,.seed=NULL,.boundary=NULL};; +/** struct for node force */ + +LB_node_force_gpu node_f = {.force=NULL,.scforce=NULL} ; + +static LB_extern_nodeforce_gpu *extern_nodeforces = NULL; + +#ifdef LB_BOUNDARIES_GPU +static float* lb_boundary_force = NULL; +static float* lb_boundary_velocity = NULL; +/** pointer for bound index array*/ +static int *boundary_node_list; +static int *boundary_index_list; +static __device__ __constant__ int n_lb_boundaries_gpu = 0; +static size_t size_of_boundindex; +#endif + +#if defined(ELECTROKINETICS) +static __device__ __constant__ int ek_initialized_gpu = 0; +#endif + +EK_parameters* lb_ek_parameters_gpu; + +/** pointers for additional cuda check flag*/ +static int *gpu_check = NULL; +static int *h_gpu_check = NULL; + +static unsigned int intflag = 1; +LB_nodes_gpu *current_nodes = NULL; +/**defining size values for allocating global memory */ +static size_t size_of_rho_v; +static size_t size_of_rho_v_pi; +static size_t size_of_extern_nodeforces; + +/**parameters residing in constant memory */ +static __device__ __constant__ LB_parameters_gpu para; +static const float c_sound_sq = 1.0f/3.0f; + +/*-------------------------------------------------------*/ +/*********************************************************/ +/** \name device functions called by kernel functions */ +/*********************************************************/ +/*-------------------------------------------------------*/ + +/*-------------------------------------------------------*/ + +/** atomic add function for sveral cuda architectures +*/ +__device__ inline void atomicadd(float* address, float value){ +#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 // for Fermi, atomicAdd supports floats + atomicAdd(address, value); +#elif __CUDA_ARCH__ >= 110 +#warning Using slower atomicAdd emulation +// float-atomic-add from +// [url="http://forums.nvidia.com/index.php?showtopic=158039&view=findpost&p=991561"] + float old = value; + while ((old = atomicExch(address, atomicExch(address, 0.0f)+old))!=0.0f); +#else +#error I need at least compute capability 1.1 +#endif +} + +/**randomgenerator which generates numbers [0,1] + * @param *rn Pointer to randomnumber array of the local node or particle +*/ +__device__ void random_01(LB_randomnr_gpu *rn){ + + const float mxi = 1.0f/(float)(1ul<<31); + unsigned int curr = rn->seed; + + curr = 1103515245 * curr + 12345; + rn->randomnr[0] = (float)(curr & ((1ul<<31)-1))*mxi; + curr = 1103515245 * curr + 12345; + rn->randomnr[1] = (float)(curr & ((1ul<<31)-1))*mxi; + rn->seed = curr; + +} + +/**randomgenerator which generates numbers between -2 sigma and 2 sigma in the form of a Gaussian with standard deviation sigma=1.118591404 resulting in + * an actual standard deviation of 1. + * @param *rn Pointer to randomnumber array of the local node or particle +*/ +__device__ void gaussian_random_cut(LB_randomnr_gpu *rn){ + + float x1, x2; + float r2, fac; + /** On every second call two gaussian random numbers are calculated + via the Box-Muller transformation.*/ + /** draw two uniform random numbers in the unit circle */ + do { + random_01(rn); + x1 = 2.0f*rn->randomnr[0] - 1.0f; + x2 = 2.0f*rn->randomnr[1] - 1.0f; + r2 = x1*x1 + x2*x2; + } while (r2 >= 1.0f || r2 == 0.0f); + + /** perform Box-Muller transformation and cutoff the ends and replace with flat noise */ + /* + fac = sqrtf(-2.0f*__logf(r2)/r2)*1.118591404f; + rn->randomnr[0] = x2*fac; + rn->randomnr[1] = x1*fac; + random_01(rn); + if ( fabs(rn->randomnr[0]) > 2.0f*1.118591404f) { + rn->randomnr[0] = (2.0f*rn->randomnr[0]-1.0f)*2.0f*1.118591404f; + } + if ( fabs(rn->randomnr[1]) > 2.0f*1.118591404f ) { + rn->randomnr[0] = (2.0f*rn->randomnr[1]-1.0f)*2.0f*1.118591404f; + } + */ + + fac = sqrtf(-2.0f*__logf(r2)/r2)*1.042267973f; + rn->randomnr[0] = x2*fac; + rn->randomnr[1] = x1*fac; + if ( fabs(rn->randomnr[0]) > 2.0f*1.042267973f) { + if ( rn->randomnr[0] > 0 ) rn->randomnr[0] = 2.0f*1.042267973f; + else rn->randomnr[0] = -2.0f*1.042267973f; + } + if ( fabs(rn->randomnr[1]) > 2.0f*1.042267973f ) { + if ( rn->randomnr[1] > 0 ) rn->randomnr[1] = 2.0f*1.042267973f; + else rn->randomnr[1] = -2.0f*1.042267973f; + } +} + +/** gaussian random nummber generator for thermalisation + * @param *rn Pointer to randomnumber array of the local node node or particle +*/ +__device__ void gaussian_random(LB_randomnr_gpu *rn){ + + float x1, x2; + float r2, fac; + /** On every second call two gaussian random numbers are calculated + via the Box-Muller transformation.*/ + /** draw two uniform random numbers in the unit circle */ + do { + random_01(rn); + x1 = 2.0f*rn->randomnr[0]-1.0f; + x2 = 2.0f*rn->randomnr[1]-1.0f; + r2 = x1*x1 + x2*x2; + } while (r2 >= 1.0f || r2 == 0.0f); + + /** perform Box-Muller transformation */ + fac = sqrtf(-2.0f*__logf(r2)/r2); + rn->randomnr[0] = x2*fac; + rn->randomnr[1] = x1*fac; + +} +/* wrapper */ +__device__ void random_wrapper(LB_randomnr_gpu *rn) { + +#if defined(FLATNOISE) +#define sqrt12 3.46410161514f + random_01(rn); + rn->randomnr[0]-=0.5f; + rn->randomnr[0]*=sqrt12; + rn->randomnr[1]-=0.5f; + rn->randomnr[1]*=sqrt12; +#elif defined(GAUSSRANDOMCUT) + gaussian_random_cut(rn); +#elif defined(GAUSSRANDOM) + gaussian_random(rn); +#else +#error No noise type defined for the GPU LB +#endif + +} + + +/**tranformation from 1d array-index to xyz + * @param index node index / thread index (Input) + * @param xyz Pointer to calculated xyz array (Output) + */ +__device__ void index_to_xyz(unsigned int index, unsigned int *xyz){ + + xyz[0] = index%para.dim_x; + index /= para.dim_x; + xyz[1] = index%para.dim_y; + index /= para.dim_y; + xyz[2] = index; +} + +/**calculation of the modes from the velocity densities (space-transform.) + * @param n_a Pointer to local node residing in array a (Input) + * @param index Node index / thread index (Input) + * @param mode Pointer to the local register values mode (Output) +*/ +__device__ void calc_m_from_n(LB_nodes_gpu n_a, unsigned int index, float *mode){ + + #pragma unroll + for(int ii=0;iirandomnr[0]; + mode[2 + ii * LBQ] += sqrt(c*(1-c)*Rho_tot*(para.mu[ii]*(2.0f/3.0f)*(1.0f-(para.gamma_mobility[0]*para.gamma_mobility[0])))) * (2*ii-1) * rn->randomnr[1]; + } + random_wrapper(rn); + for(int ii=0;iirandomnr[0]; +#endif + + + for(int ii=0;iirandomnr[0]; + mode[5 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.0f/9.0f)*(1.0f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[6 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.0f/3.0f)*(1.0f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[0]; + mode[7 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.0f/9.0f)*(1.0f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[8 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.0f/9.0f)*(1.0f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[0]; + mode[9 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.0f/9.0f)*(1.0f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; + + /** ghost modes */ + random_wrapper(rn); + mode[10 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/3.0f))) * rn->randomnr[0]; + mode[11 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/3.0f))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[12 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/3.0f))) * rn->randomnr[0]; + mode[13 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/9.0f))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[14 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/9.0f))) * rn->randomnr[0]; + mode[15 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f/9.0f))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[16 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.0f))) * rn->randomnr[0]; + mode[17 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.0f/9.0f))) * rn->randomnr[1]; + + random_wrapper(rn); + mode[18 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.0f/3.0f))) * rn->randomnr[0]; + } +} + + +/*-------------------------------------------------------*/ +/**normalization of the modes need befor backtransformation into velocity space + * @param mode Pointer to the local register values mode (Input/Output) +*/ +__device__ void normalize_modes(float* mode){ + #pragma unroll + for(int ii=0;iirho[ii]; + rho_out[ii] = Rho; + + // note that d_v_single->v[] already includes the 1/2 f term, + // accounting for the pre- and post-collisional average + + j[0] = Rho * d_v_single->v[0]; + j[1] = Rho * d_v_single->v[1]; + j[2] = Rho * d_v_single->v[2]; + + j_out[3*ii + 0] = j[0]; + j_out[3*ii + 1] = j[1]; + j_out[3*ii + 2] = j[2]; + + // equilibrium part of the stress modes, which comes from + // the equality between modes and stress tensor components + + modes_from_pi_eq[0] = ( j[0]*j[0] + j[1]*j[1] + j[2]*j[2] ) / Rho; + modes_from_pi_eq[1] = ( j[0]*j[0] - j[1]*j[1] ) / Rho; + modes_from_pi_eq[2] = ( j[0]*j[0] + j[1]*j[1] + j[2]*j[2] - 3.0*j[2]*j[2] ) / Rho; + modes_from_pi_eq[3] = j[0]*j[1] / Rho; + modes_from_pi_eq[4] = j[0]*j[2] / Rho; + modes_from_pi_eq[5] = j[1]*j[2] / Rho; + + // Now we must predict the outcome of the next collision + // We immediately average pre- and post-collision. + + mode_single[4 + ii * LBQ ] = modes_from_pi_eq[0] + (0.5 + 0.5* para.gamma_bulk[ii]) * (mode_single[4 + ii * LBQ] - modes_from_pi_eq[0]); + mode_single[5 + ii * LBQ ] = modes_from_pi_eq[1] + (0.5 + 0.5*para.gamma_shear[ii]) * (mode_single[5 + ii * LBQ] - modes_from_pi_eq[1]); + mode_single[6 + ii * LBQ ] = modes_from_pi_eq[2] + (0.5 + 0.5*para.gamma_shear[ii]) * (mode_single[6 + ii * LBQ] - modes_from_pi_eq[2]); + mode_single[7 + ii * LBQ ] = modes_from_pi_eq[3] + (0.5 + 0.5*para.gamma_shear[ii]) * (mode_single[7 + ii * LBQ] - modes_from_pi_eq[3]); + mode_single[8 + ii * LBQ ] = modes_from_pi_eq[4] + (0.5 + 0.5*para.gamma_shear[ii]) * (mode_single[8 + ii * LBQ] - modes_from_pi_eq[4]); + mode_single[9 + ii * LBQ ] = modes_from_pi_eq[5] + (0.5 + 0.5*para.gamma_shear[ii]) * (mode_single[9 + ii * LBQ] - modes_from_pi_eq[5]); + + // Transform the stress tensor components according to the mode_singles. + + pi_out[6*ii + 0] = ( 2.0f*(mode_single[0 + ii * LBQ] + mode_single[4 + ii * LBQ]) + + mode_single[6 + ii * LBQ] + 3.0f*mode_single[5 + ii * LBQ] )/6.0f; // xx + pi_out[6*ii + 1] = mode_single[7 + ii * LBQ]; // xy + pi_out[6*ii + 2] = ( 2.0f*(mode_single[0 + ii * LBQ] + mode_single[4 + ii * LBQ]) + + mode_single[6 + ii * LBQ] - 3.0f*mode_single[5 + ii * LBQ] )/6.0f; // yy + pi_out[6*ii + 3] = mode_single[8 + ii * LBQ]; // xz + pi_out[6*ii + 4] = mode_single[9 + ii * LBQ]; // yz + pi_out[6*ii + 5] = ( mode_single[0 + ii * LBQ] + mode_single[4 + ii * LBQ] + - mode_single[6 + ii * LBQ] )/3.0f; // zz + } +} + +/**function used to calc physical values of every node + * @param n_a Pointer to local node residing in array a for boundary flag(Input) + * @param mode Pointer to the local register values mode (Input) + * @param d_v Pointer to local device values (Input/Output) + * @param node_f Pointer to local node force (Input) + * @param index node index / thread index (Input) +*/ + +/* FIXME this function is basically un-used, think about removing/replacing it */ +__device__ void calc_values(LB_nodes_gpu n_a, float *mode, LB_rho_v_gpu *d_v, LB_node_force_gpu node_f, unsigned int index){ + + float Rho_tot=0.0f; + float u_tot[3]={0.0f,0.0f,0.0f}; + + if(n_a.boundary[index] != 1){ + #pragma unroll + for(int ii=0;iirandomnr[0]-0.5f); + viscforce[1+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[1]-0.5f); + random_01(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[0]-0.5f); +#elif defined(GAUSSRANDOMCUT) + gaussian_random_cut(rn_part); + viscforce[0+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; + viscforce[1+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[1]; + gaussian_random_cut(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; +#elif defined(GAUSSRANDOM) + gaussian_random(rn_part); + viscforce[0+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; + viscforce[1+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[1]; + gaussian_random(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; +#else +#error No noise type defined for the GPU LB +#endif + /** delta_j for transform momentum transfer to lattice units which is done in calc_node_force + (Eq. (12) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ + + particle_force[part_index].f[0] += viscforce[0+ii*3]; + particle_force[part_index].f[1] += viscforce[1+ii*3]; + particle_force[part_index].f[2] += viscforce[2+ii*3]; + + /* note that scforce is zero if SHANCHEN is not #defined */ + delta_j[0+3*ii] -= (viscforce[0+ii*3])*para.time_step*para.tau/para.agrid; + delta_j[1+3*ii] -= (viscforce[1+ii*3])*para.time_step*para.tau/para.agrid; + delta_j[2+3*ii] -= (viscforce[2+ii*3])*para.time_step*para.tau/para.agrid; + } +} + +/**calcutlation of the node force caused by the particles, with atomicadd due to avoiding race conditions + (Eq. (14) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) + * @param *delta Pointer for the weighting of particle position (Input) + * @param *delta_j Pointer for the weighting of particle momentum (Input) + * @param node_index node index around (8) particle (Input) + * @param node_f Pointer to the node force (Output). +*/ +__device__ void calc_node_force_three_point_couple(float *delta, float *delta_j, unsigned int *node_index, LB_node_force_gpu node_f){ +/* TODO: should the drag depend on the density?? */ + + for (int i=-1; i<=1; i++) { + for (int j=-1; j<=1; j++) { + for (int k=-1; k<=1; k++) { + atomicadd(&(node_f.force[0*para.number_of_nodes + node_index[i+3*j+9*k+13]]), (delta[i+3*j+9*k+13]*delta_j[0])); + atomicadd(&(node_f.force[1*para.number_of_nodes + node_index[i+3*j+9*k+13]]), (delta[i+3*j+9*k+13]*delta_j[1])); + atomicadd(&(node_f.force[2*para.number_of_nodes + node_index[i+3*j+9*k+13]]), (delta[i+3*j+9*k+13]*delta_j[2])); + } + } + } +} + + +/**calculate temperature of the fluid kernel + * @param *cpu_jsquared Pointer to result storage value (Output) + * @param n_a Pointer to local node residing in array a (Input) +*/ +__global__ void temperature(LB_nodes_gpu n_a, float *cpu_jsquared, int *number_of_non_boundary_nodes ) { + float mode[4]; + float jsquared = 0.0f; + unsigned int index = blockIdx.y * gridDim.x * blockDim.x + blockDim.x * blockIdx.x + threadIdx.x; + + if(indexrandomnr[0]-0.5f); + viscforce[1+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[1]-0.5f); + random_01(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[0]-0.5f); +#elif defined(GAUSSRANDOMCUT) + gaussian_random_cut(rn_part); + viscforce[0+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; + viscforce[1+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[1]; + gaussian_random_cut(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; +#elif defined(GAUSSRANDOM) + gaussian_random(rn_part); + viscforce[0+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; + viscforce[1+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[1]; + gaussian_random(rn_part); + viscforce[2+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; +#else +#error No noise type defined for the GPU LB +#endif + + /** delta_j for transform momentum transfer to lattice units which is done in calc_node_force + (Eq. (12) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ + + particle_force[part_index].f[0] += viscforce[0+ii*3]; + particle_force[part_index].f[1] += viscforce[1+ii*3]; + particle_force[part_index].f[2] += viscforce[2+ii*3]; + + /* the average force from the particle to surrounding nodes is transmitted back to preserve momentum */ + for(int node=0 ; node < 8 ; node++ ) { + particle_force[part_index].f[0] -= partgrad1[node+ii*8]/8.0f; + particle_force[part_index].f[1] -= partgrad2[node+ii*8]/8.0f; + particle_force[part_index].f[2] -= partgrad3[node+ii*8]/8.0f; + } + + /* note that scforce is zero if SHANCHEN is not #defined */ + delta_j[0+3*ii] -= (scforce[0+ii*3]+viscforce[0+ii*3])*para.time_step*para.tau/para.agrid; + delta_j[1+3*ii] -= (scforce[1+ii*3]+viscforce[1+ii*3])*para.time_step*para.tau/para.agrid; + delta_j[2+3*ii] -= (scforce[2+ii*3]+viscforce[2+ii*3])*para.time_step*para.tau/para.agrid; + } +#ifdef SHANCHEN + for(int node=0 ; node < 8 ; node++ ) { + for(int ii=0 ; ii < LB_COMPONENTS ; ii++ ) { + partgrad1[node+ii*8]*=(para.time_step*para.tau/para.agrid); + partgrad2[node+ii*8]*=(para.time_step*para.tau/para.agrid); + partgrad3[node+ii*8]*=(para.time_step*para.tau/para.agrid); + } + } +#endif +} + +/**calculation of the node force caused by the particles, with atomicadd due to avoiding race conditions + (Eq. (14) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) + * @param *delta Pointer for the weighting of particle position (Input) + * @param partgrad1 particle gradient for the Shan-Chen + * @param partgrad2 particle gradient for the Shan-Chen + * @param partgrad3 particle gradient for the Shan-Chen + * @param *delta_j Pointer for the weighting of particle momentum (Input) + * @param node_index node index around (8) particle (Input) + * @param node_f Pointer to the node force (Output). +*/ +__device__ void calc_node_force(float *delta, float *delta_j, float * partgrad1, float * partgrad2, float * partgrad3, unsigned int *node_index, LB_node_force_gpu node_f){ +/* TODO: should the drag depend on the density?? */ +/* NOTE: partgrad is not zero only if SHANCHEN is defined. It is initialized in calc_node_force. Alternatively one could + specialize this function to the single component LB */ + for(int ii=0; ii < LB_COMPONENTS; ++ii) + { + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[0+ii*3] + partgrad1[ii*8+0])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[1+ii*3] + partgrad2[ii*8+0])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[2+ii*3] + partgrad3[ii*8+0])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[0+ii*3] + partgrad1[ii*8+1])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[1+ii*3] + partgrad2[ii*8+1])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[2+ii*3] + partgrad3[ii*8+1])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[0+ii*3] + partgrad1[ii*8+2])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[1+ii*3] + partgrad2[ii*8+2])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[2+ii*3] + partgrad3[ii*8+2])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[0+ii*3] + partgrad1[ii*8+3])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[1+ii*3] + partgrad2[ii*8+3])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[2+ii*3] + partgrad3[ii*8+3])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[0+ii*3] + partgrad1[ii*8+4])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[1+ii*3] + partgrad2[ii*8+4])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[2+ii*3] + partgrad3[ii*8+4])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[0+ii*3] + partgrad1[ii*8+5])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[1+ii*3] + partgrad2[ii*8+5])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[2+ii*3] + partgrad3[ii*8+5])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[0+ii*3] + partgrad1[ii*8+6])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[1+ii*3] + partgrad2[ii*8+6])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[2+ii*3] + partgrad3[ii*8+6])); + + atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[0+ii*3] + partgrad1[ii*8+7])); + atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[1+ii*3] + partgrad2[ii*8+7])); + atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[2+ii*3] + partgrad3[ii*8+7])); + } +} + +/*********************************************************/ +/** \name System setup and Kernel functions */ +/*********************************************************/ + +/**kernel to calculate local populations from hydrodynamic fields given by the tcl values. + * The mapping is given in terms of the equilibrium distribution. + * + * Eq. (2.15) Ladd, J. Fluid Mech. 271, 295-309 (1994) + * Eq. (4) in Berk Usta, Ladd and Butler, JCP 122, 094902 (2005) + * + * @param n_a Pointer to the lattice site (Input). + * @param *gpu_check additional check if gpu kernel are executed(Input). + * @param *d_v Pointer to local device values + * @param *node_f Pointer to node forces +*/ +__global__ void calc_n_from_rho_j_pi(LB_nodes_gpu n_a, LB_rho_v_gpu *d_v, LB_node_force_gpu node_f, int *gpu_check) { + /* TODO: this can handle only a uniform density, something similar, but local, + has to be called every time the fields are set by the user ! */ + unsigned int index = blockIdx.y * gridDim.x * blockDim.x + blockDim.x * blockIdx.x + threadIdx.x; + if(index0) + for(int ii=0;iinumber_of_nodes * sizeof(LB_rho_v_gpu); + size_of_rho_v_pi = lbpar_gpu->number_of_nodes * sizeof(LB_rho_v_pi_gpu); + + + /** Allocate structs in device memory*/ + /* see the notes to the stucture device_rho_v_pi above...*/ + if(extended_values_flag==0) + { + free_and_realloc(device_rho_v, size_of_rho_v); + } + else + { + free_and_realloc(device_rho_v_pi, size_of_rho_v_pi); + } + + /* TODO: this is a almost a copy copy of device_rho_v think about eliminating it, and maybe pi can be added to device_rho_v in this case*/ + free_and_realloc(print_rho_v_pi , size_of_rho_v_pi); + free_and_realloc(nodes_a.vd , lbpar_gpu->number_of_nodes * 19 * LB_COMPONENTS * sizeof(float)); + free_and_realloc(nodes_b.vd , lbpar_gpu->number_of_nodes * 19 * LB_COMPONENTS * sizeof(float)); + free_and_realloc(node_f.force , lbpar_gpu->number_of_nodes * 3 * LB_COMPONENTS * sizeof(float)); +#ifdef SHANCHEN + free_and_realloc(node_f.scforce , lbpar_gpu->number_of_nodes * 3 * LB_COMPONENTS * sizeof(float)); +#endif + + free_and_realloc(nodes_a.seed , lbpar_gpu->number_of_nodes * sizeof( unsigned int)); + free_and_realloc(nodes_a.boundary, lbpar_gpu->number_of_nodes * sizeof( unsigned int)); + free_and_realloc(nodes_b.seed , lbpar_gpu->number_of_nodes * sizeof( unsigned int)); + free_and_realloc(nodes_b.boundary, lbpar_gpu->number_of_nodes * sizeof( unsigned int)); + + /**write parameters in const memory*/ + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); + + /**check flag if lb gpu init works*/ + free_and_realloc(gpu_check, sizeof(int)); + + if(h_gpu_check!=NULL) + free(h_gpu_check); + + h_gpu_check = (int*)malloc(sizeof(int)); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(reset_boundaries, dim_grid, threads_per_block, (nodes_a, nodes_b)); + + #ifdef SHANCHEN + // TODO FIXME: + /* We must add shan-chen forces, which are zero only if the densities are uniform*/ + #endif + +#if defined(ELECTROKINETICS) + // We need to know if the electrokinetics is being used or not + cuda_safe_mem(cudaMemcpyToSymbol(ek_initialized_gpu, &ek_initialized, sizeof(int))); +#endif + + + /** calc of velocitydensities from given parameters and initialize the Node_Force array with zero */ + KERNELCALL(reinit_node_force, dim_grid, threads_per_block, (node_f)); + KERNELCALL(calc_n_from_rho_j_pi, dim_grid, threads_per_block, (nodes_a, device_rho_v, node_f, gpu_check)); + + intflag = 1; + current_nodes = &nodes_a; + h_gpu_check[0] = 0; + cuda_safe_mem(cudaMemcpy(h_gpu_check, gpu_check, sizeof(int), cudaMemcpyDeviceToHost)); +//fprintf(stderr, "initialization of lb gpu code %i\n", lbpar_gpu->number_of_nodes); + cudaThreadSynchronize(); + +#if __CUDA_ARCH__ >= 200 + if(!h_gpu_check[0]) + { + fprintf(stderr, "initialization of lb gpu code failed! \n"); + errexit(); + } +#endif +} + +/** reinitialization for the lb gpu fluid called from host + * @param *lbpar_gpu Pointer to parameters to setup the lb field +*/ +void lb_reinit_GPU(LB_parameters_gpu *lbpar_gpu){ + + /**write parameters in const memory*/ + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + /** calc of velocity densities from given parameters and initialize the Node_Force array with zero */ + KERNELCALL(calc_n_from_rho_j_pi, dim_grid, threads_per_block, (nodes_a, device_rho_v, node_f, gpu_check)); +} + +void lb_realloc_particles_GPU_leftovers(LB_parameters_gpu *lbpar_gpu){ + + //copy parameters, especially number of parts to gpu mem + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); +} + +#ifdef LB_BOUNDARIES_GPU +/** setup and call boundaries from the host + * @param host_n_lb_boundaries number of LB boundaries + * @param number_of_boundnodes number of boundnodes + * @param host_boundary_node_list The indices of the boundary nodes + * @param host_boundary_index_list The flag representing the corresponding boundary + * @param host_lb_boundary_velocity The constant velocity at the boundary, set by the user (Input) +*/ +void lb_init_boundaries_GPU(int host_n_lb_boundaries, int number_of_boundnodes, int *host_boundary_node_list, int* host_boundary_index_list, float* host_lb_boundary_velocity){ + int temp = host_n_lb_boundaries; + + size_of_boundindex = number_of_boundnodes*sizeof(int); + cuda_safe_mem(cudaMalloc((void**)&boundary_node_list, size_of_boundindex)); + cuda_safe_mem(cudaMalloc((void**)&boundary_index_list, size_of_boundindex)); + cuda_safe_mem(cudaMemcpy(boundary_index_list, host_boundary_index_list, size_of_boundindex, cudaMemcpyHostToDevice)); + cuda_safe_mem(cudaMemcpy(boundary_node_list, host_boundary_node_list, size_of_boundindex, cudaMemcpyHostToDevice)); + cuda_safe_mem(cudaMalloc((void**)&lb_boundary_force , 3*host_n_lb_boundaries*sizeof(float))); + cuda_safe_mem(cudaMalloc((void**)&lb_boundary_velocity, 3*host_n_lb_boundaries*sizeof(float))); + cuda_safe_mem(cudaMemcpy(lb_boundary_velocity, host_lb_boundary_velocity, 3*n_lb_boundaries*sizeof(float), cudaMemcpyHostToDevice)); + cuda_safe_mem(cudaMemcpyToSymbol(n_lb_boundaries_gpu, &temp, sizeof(int))); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(reset_boundaries, dim_grid, threads_per_block, (nodes_a, nodes_b)); + + if (n_lb_boundaries == 0 && !pdb_boundary_lattice) + { + cudaThreadSynchronize(); + return; + } + + if(number_of_boundnodes == 0) + { + fprintf(stderr, "WARNING: boundary cmd executed but no boundary node found!\n"); + } + else + { + int threads_per_block_bound = 64; + int blocks_per_grid_bound_y = 4; + int blocks_per_grid_bound_x = (number_of_boundnodes + threads_per_block_bound * blocks_per_grid_bound_y - 1) /(threads_per_block_bound * blocks_per_grid_bound_y); + dim3 dim_grid_bound = make_uint3(blocks_per_grid_bound_x, blocks_per_grid_bound_y, 1); + + KERNELCALL(init_boundaries, dim_grid_bound, threads_per_block_bound, (boundary_node_list, boundary_index_list, number_of_boundnodes, nodes_a, nodes_b)); + } + + cudaThreadSynchronize(); +} +#endif +/**setup and call extern single node force initialization from the host + * @param *lbpar_gpu Pointer to host parameter struct +*/ +void lb_reinit_extern_nodeforce_GPU(LB_parameters_gpu *lbpar_gpu){ + + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(reinit_node_force, dim_grid, threads_per_block, (node_f)); + +} +/**setup and call extern single node force initialization from the host + * @param n_extern_nodeforces number of nodes on which the external force has to be applied + * @param *host_extern_nodeforces Pointer to the host extern node forces + * @param *lbpar_gpu Pointer to host parameter struct +*/ +void lb_init_extern_nodeforces_GPU(int n_extern_nodeforces, LB_extern_nodeforce_gpu *host_extern_nodeforces, LB_parameters_gpu *lbpar_gpu){ + + size_of_extern_nodeforces = n_extern_nodeforces*sizeof(LB_extern_nodeforce_gpu); + cuda_safe_mem(cudaMalloc((void**)&extern_nodeforces, size_of_extern_nodeforces)); + cuda_safe_mem(cudaMemcpy(extern_nodeforces, host_extern_nodeforces, size_of_extern_nodeforces, cudaMemcpyHostToDevice)); + + if(lbpar_gpu->external_force == 0) + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); + + int threads_per_block_exf = 64; + int blocks_per_grid_exf_y = 4; + int blocks_per_grid_exf_x = (n_extern_nodeforces + threads_per_block_exf * blocks_per_grid_exf_y - 1) / + (threads_per_block_exf * blocks_per_grid_exf_y); + dim3 dim_grid_exf = make_uint3(blocks_per_grid_exf_x, blocks_per_grid_exf_y, 1); + + KERNELCALL(init_extern_nodeforces, dim_grid_exf, threads_per_block_exf, (n_extern_nodeforces, extern_nodeforces, node_f)); + cudaFree(extern_nodeforces); +} + +/**setup and call particle kernel from the host +*/ +void lb_calc_particle_lattice_ia_gpu(){ + if (lbpar_gpu.number_of_particles) + { + /** call of the particle kernel */ + /** values for the particle kernel */ + int threads_per_block_particles = 64; + int blocks_per_grid_particles_y = 4; + int blocks_per_grid_particles_x = (lbpar_gpu.number_of_particles + threads_per_block_particles * blocks_per_grid_particles_y - 1) / + (threads_per_block_particles * blocks_per_grid_particles_y); + dim3 dim_grid_particles = make_uint3(blocks_per_grid_particles_x, blocks_per_grid_particles_y, 1); + + if ( lbpar_gpu.lb_couple_switch & LB_COUPLE_TWO_POINT ) + { + KERNELCALL( calc_fluid_particle_ia, dim_grid_particles, threads_per_block_particles, + ( *current_nodes, gpu_get_particle_pointer(), + gpu_get_particle_force_pointer(), gpu_get_fluid_composition_pointer(), + node_f, gpu_get_particle_seed_pointer(), device_rho_v ) + ); + } + else { /** only other option is the three point coupling scheme */ +#ifdef SHANCHEN +#if __CUDA_ARCH__ >= 200 + fprintf (stderr, "The three point particle coupling is not currently compatible with the Shan-Chen implementation of the LB\n"); + errexit(); +#endif +#endif + KERNELCALL( calc_fluid_particle_ia_three_point_couple, dim_grid_particles, threads_per_block_particles, + ( *current_nodes, gpu_get_particle_pointer(), + gpu_get_particle_force_pointer(), node_f, + gpu_get_particle_seed_pointer(), device_rho_v ) + ); + } + } +} + +/** setup and call kernel for getting macroscopic fluid values of all nodes + * @param *host_values struct to save the gpu values +*/ +void lb_get_values_GPU(LB_rho_v_pi_gpu *host_values){ + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) / + (threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL( get_mesoscopic_values_in_MD_units, dim_grid, threads_per_block, + ( *current_nodes, print_rho_v_pi, device_rho_v, node_f ) ); + cuda_safe_mem( cudaMemcpy( host_values, print_rho_v_pi, size_of_rho_v_pi, cudaMemcpyDeviceToHost ) ); + +} + +/** get all the boundary flags for all nodes + * @param host_bound_array here go the values of the boundary flag + */ +void lb_get_boundary_flags_GPU(unsigned int* host_bound_array){ + + unsigned int* device_bound_array; + cuda_safe_mem(cudaMalloc((void**)&device_bound_array, lbpar_gpu.number_of_nodes*sizeof(unsigned int))); + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) / (threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(lb_get_boundaries, dim_grid, threads_per_block, (*current_nodes, device_bound_array)); + + cuda_safe_mem(cudaMemcpy(host_bound_array, device_bound_array, lbpar_gpu.number_of_nodes*sizeof(unsigned int), cudaMemcpyDeviceToHost)); + + cudaFree(device_bound_array); + +} + +/** setup and call kernel for getting macroscopic fluid values of a single node*/ +void lb_print_node_GPU(int single_nodeindex, LB_rho_v_pi_gpu *host_print_values){ + + LB_rho_v_pi_gpu *device_print_values; + cuda_safe_mem(cudaMalloc((void**)&device_print_values, sizeof(LB_rho_v_pi_gpu))); + int threads_per_block_print = 1; + int blocks_per_grid_print_y = 1; + int blocks_per_grid_print_x = 1; + dim3 dim_grid_print = make_uint3(blocks_per_grid_print_x, blocks_per_grid_print_y, 1); + + KERNELCALL(lb_print_node, dim_grid_print, threads_per_block_print, (single_nodeindex, device_print_values, *current_nodes, device_rho_v, node_f)); + + cuda_safe_mem(cudaMemcpy(host_print_values, device_print_values, sizeof(LB_rho_v_pi_gpu), cudaMemcpyDeviceToHost)); + cudaFree(device_print_values); + +} + +/** setup and call kernel to calculate the total momentum of the hole fluid + * @param *mass value of the mass calcutated on the GPU +*/ +void lb_calc_fluid_mass_GPU(double* mass){ + + float* tot_mass; + float cpu_mass = 0.0f ; + cuda_safe_mem(cudaMalloc((void**)&tot_mass, sizeof(float))); + cuda_safe_mem(cudaMemcpy(tot_mass, &cpu_mass, sizeof(float), cudaMemcpyHostToDevice)); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(calc_mass, dim_grid, threads_per_block,(*current_nodes, tot_mass)); + + cuda_safe_mem(cudaMemcpy(&cpu_mass, tot_mass, sizeof(float), cudaMemcpyDeviceToHost)); + + cudaFree(tot_mass); + mass[0] = (double)(cpu_mass); +} + +/** setup and call kernel to calculate the total momentum of the whole fluid + * @param host_mom value of the momentum calcutated on the GPU + */ +void lb_calc_fluid_momentum_GPU(double* host_mom){ + + float* tot_momentum; + float host_momentum[3] = { 0.0f, 0.0f, 0.0f}; + cuda_safe_mem(cudaMalloc((void**)&tot_momentum, 3*sizeof(float))); + cuda_safe_mem(cudaMemcpy(tot_momentum, host_momentum, 3*sizeof(float), cudaMemcpyHostToDevice)); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(momentum, dim_grid, threads_per_block,(*current_nodes, device_rho_v, node_f, tot_momentum)); + + cuda_safe_mem(cudaMemcpy(host_momentum, tot_momentum, 3*sizeof(float), cudaMemcpyDeviceToHost)); + + cudaFree(tot_momentum); + host_mom[0] = (double)(host_momentum[0]* lbpar_gpu.agrid/lbpar_gpu.tau); + host_mom[1] = (double)(host_momentum[1]* lbpar_gpu.agrid/lbpar_gpu.tau); + host_mom[2] = (double)(host_momentum[2]* lbpar_gpu.agrid/lbpar_gpu.tau); +} + +/** setup and call kernel to remove the net momentum of the whole fluid + */ +void lb_remove_fluid_momentum_GPU(void){ + float* tot_momentum; + float host_momentum[3] = { 0.0f, 0.0f, 0.0f}; + cuda_safe_mem(cudaMalloc((void**)&tot_momentum, 3*sizeof(float))); + cuda_safe_mem(cudaMemcpy(tot_momentum, host_momentum, 3*sizeof(float), cudaMemcpyHostToDevice)); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(momentum, dim_grid, threads_per_block,(*current_nodes, device_rho_v, node_f, tot_momentum)); + + cuda_safe_mem(cudaMemcpy(host_momentum, tot_momentum, 3*sizeof(float), cudaMemcpyDeviceToHost)); + + KERNELCALL(remove_momentum, dim_grid, threads_per_block,(*current_nodes, device_rho_v, node_f, tot_momentum)); + + cudaFree(tot_momentum); +} + + +/** setup and call kernel to calculate the temperature of the hole fluid + * @param host_temp value of the temperatur calcutated on the GPU +*/ +void lb_calc_fluid_temperature_GPU(double* host_temp){ + + int host_number_of_non_boundary_nodes = 0; + int *device_number_of_non_boundary_nodes; + cuda_safe_mem(cudaMalloc((void**)&device_number_of_non_boundary_nodes, sizeof(int))); + cuda_safe_mem(cudaMemcpy(device_number_of_non_boundary_nodes, &host_number_of_non_boundary_nodes, sizeof(int), cudaMemcpyHostToDevice)); + + float host_jsquared = 0.0f; + float* device_jsquared; + cuda_safe_mem(cudaMalloc((void**)&device_jsquared, sizeof(float))); + cuda_safe_mem(cudaMemcpy(device_jsquared, &host_jsquared, sizeof(float), cudaMemcpyHostToDevice)); + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + + KERNELCALL(temperature, dim_grid, threads_per_block,(*current_nodes, device_jsquared, device_number_of_non_boundary_nodes)); + + cuda_safe_mem(cudaMemcpy(&host_number_of_non_boundary_nodes, device_number_of_non_boundary_nodes, sizeof(int), cudaMemcpyDeviceToHost)); + cuda_safe_mem(cudaMemcpy(&host_jsquared, device_jsquared, sizeof(float), cudaMemcpyDeviceToHost)); + + // TODO: check that temperature calculation is properly implemented for shanchen + *host_temp=0; + + #pragma unroll + for(int ii=0;iivd, lbpar_gpu.number_of_nodes * 19 * sizeof(float), cudaMemcpyDeviceToHost)); + cuda_safe_mem(cudaMemcpy(host_checkpoint_seed, current_nodes->seed, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyDeviceToHost)); + cuda_safe_mem(cudaMemcpy(host_checkpoint_boundary, current_nodes->boundary, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyDeviceToHost)); + cuda_safe_mem(cudaMemcpy(host_checkpoint_force, node_f.force, lbpar_gpu.number_of_nodes * 3 * sizeof(float), cudaMemcpyDeviceToHost)); + +} + +/** setup and call kernel for setting macroscopic fluid values of all nodes + * @param *host_checkpoint_vd struct to save the gpu populations + * @param *host_checkpoint_seed struct to save the nodes' seeds for the lb on the gpu + * @param *host_checkpoint_boundary struct to save the boundary nodes + * @param *host_checkpoint_force struct to save the forces on the nodes +*/ +void lb_load_checkpoint_GPU(float *host_checkpoint_vd, unsigned int *host_checkpoint_seed, unsigned int *host_checkpoint_boundary, float *host_checkpoint_force){ + + current_nodes = &nodes_a; + intflag = 1; + + cuda_safe_mem(cudaMemcpy(current_nodes->vd, host_checkpoint_vd, lbpar_gpu.number_of_nodes * 19 * sizeof(float), cudaMemcpyHostToDevice)); + + cuda_safe_mem(cudaMemcpy(current_nodes->seed, host_checkpoint_seed, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyHostToDevice)); + cuda_safe_mem(cudaMemcpy(current_nodes->boundary, host_checkpoint_boundary, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyHostToDevice)); + cuda_safe_mem(cudaMemcpy(node_f.force, host_checkpoint_force, lbpar_gpu.number_of_nodes * 3 * sizeof(float), cudaMemcpyHostToDevice)); +} + +/** setup and call kernel to get the boundary flag of a single node + * @param single_nodeindex number of the node to get the flag for + * @param host_flag her goes the value of the boundary flag + */ +void lb_get_boundary_flag_GPU(int single_nodeindex, unsigned int* host_flag){ + + unsigned int* device_flag; + cuda_safe_mem(cudaMalloc((void**)&device_flag, sizeof(unsigned int))); + int threads_per_block_flag = 1; + int blocks_per_grid_flag_y = 1; + int blocks_per_grid_flag_x = 1; + dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); + + KERNELCALL(lb_get_boundary_flag, dim_grid_flag, threads_per_block_flag, (single_nodeindex, device_flag, *current_nodes)); + + cuda_safe_mem(cudaMemcpy(host_flag, device_flag, sizeof(unsigned int), cudaMemcpyDeviceToHost)); + + cudaFree(device_flag); +} + +/** set the density at a single node + * @param single_nodeindex the node to set the velocity for + * @param *host_rho the density to set + */ +void lb_set_node_rho_GPU(int single_nodeindex, float* host_rho){ + + float* device_rho; + cuda_safe_mem(cudaMalloc((void**)&device_rho, LB_COMPONENTS*sizeof(float))); + cuda_safe_mem(cudaMemcpy(device_rho, host_rho, LB_COMPONENTS*sizeof(float), cudaMemcpyHostToDevice)); + int threads_per_block_flag = 1; + int blocks_per_grid_flag_y = 1; + int blocks_per_grid_flag_x = 1; + dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); + KERNELCALL(set_rho, dim_grid_flag, threads_per_block_flag, (*current_nodes, device_rho_v, single_nodeindex, device_rho)); + cudaFree(device_rho); +} + +/** set the net velocity at a single node + * @param single_nodeindex the node to set the velocity for + * @param host_velocity the velocity to set + */ +void lb_set_node_velocity_GPU(int single_nodeindex, float* host_velocity){ + + float* device_velocity; + cuda_safe_mem(cudaMalloc((void**)&device_velocity, 3*sizeof(float))); + cuda_safe_mem(cudaMemcpy(device_velocity, host_velocity, 3*sizeof(float), cudaMemcpyHostToDevice)); + int threads_per_block_flag = 1; + int blocks_per_grid_flag_y = 1; + int blocks_per_grid_flag_x = 1; + dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); + + KERNELCALL(set_u_from_rho_v_pi, dim_grid_flag, threads_per_block_flag, (*current_nodes, single_nodeindex, device_velocity, device_rho_v, node_f)); + + cudaFree(device_velocity); +} + +/** reinit of params + * @param *lbpar_gpu struct containing the paramters of the fluid +*/ +void reinit_parameters_GPU(LB_parameters_gpu *lbpar_gpu){ + /**write parameters in const memory*/ + cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); +} + +/**integration kernel for the lb gpu fluid update called from host */ +void lb_integrate_GPU() { + + /** values for the kernel call */ + int threads_per_block = 64; + int blocks_per_grid_y = 4; + int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); + dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); + +#ifdef LB_BOUNDARIES_GPU + if (n_lb_boundaries > 0) + { + cuda_safe_mem(cudaMemset( lb_boundary_force, 0, 3*n_lb_boundaries*sizeof(float))); + } +#endif + + /**call of fluid step*/ + /* NOTE: if pi is needed at every integration step, one should call an extended version + of the integrate kernel, or pass also device_rho_v_pi and make sure that either + it or device_rho_v are NULL depending on extended_values_flag */ + if (intflag == 1) + { + KERNELCALL(integrate, dim_grid, threads_per_block, (nodes_a, nodes_b, device_rho_v, node_f, lb_ek_parameters_gpu)); + current_nodes = &nodes_b; + intflag = 0; + } + else + { + KERNELCALL(integrate, dim_grid, threads_per_block, (nodes_b, nodes_a, device_rho_v, node_f, lb_ek_parameters_gpu)); + current_nodes = &nodes_a; + intflag = 1; + } + +#ifdef LB_BOUNDARIES_GPU + if (n_lb_boundaries > 0) + { + KERNELCALL(apply_boundaries, dim_grid, threads_per_block, (*current_nodes, lb_boundary_velocity, lb_boundary_force)); + } +#endif +} + +void lb_gpu_get_boundary_forces(double* forces) { +#ifdef LB_BOUNDARIES_GPU + float* temp = (float*) malloc(3*n_lb_boundaries*sizeof(float)); + cuda_safe_mem(cudaMemcpy(temp, lb_boundary_force, 3*n_lb_boundaries*sizeof(float), cudaMemcpyDeviceToHost)); + + for (int i =0; i<3*n_lb_boundaries; i++) + { + forces[i]=(double)temp[i]; + } + free(temp); +#endif +} + +__device__ void get_interpolated_velocity(LB_nodes_gpu n_a, float* r, float* u, LB_node_force_gpu node_f, int asdf) { + + /** see ahlrichs + duenweg page 8227 equ (10) and (11) */ + float temp_delta[6]; + float delta[8]; + int my_left[3]; + int node_index[8]; + float mode[4]; + u[0]=u[1]=u[2]=0; + #pragma unroll + for(int i=0; i<3; ++i){ + float scaledpos = r[i]/para.agrid - 0.5f; + my_left[i] = (int)(floorf(scaledpos)); + temp_delta[3+i] = scaledpos - my_left[i]; + temp_delta[i] = 1.f - temp_delta[3+i]; + } + + delta[0] = temp_delta[0] * temp_delta[1] * temp_delta[2]; + delta[1] = temp_delta[3] * temp_delta[1] * temp_delta[2]; + delta[2] = temp_delta[0] * temp_delta[4] * temp_delta[2]; + delta[3] = temp_delta[3] * temp_delta[4] * temp_delta[2]; + delta[4] = temp_delta[0] * temp_delta[1] * temp_delta[5]; + delta[5] = temp_delta[3] * temp_delta[1] * temp_delta[5]; + delta[6] = temp_delta[0] * temp_delta[4] * temp_delta[5]; + delta[7] = temp_delta[3] * temp_delta[4] * temp_delta[5]; + + // modulo for negative numbers is strange at best, shift to make sure we are positive + int x = my_left[0] + para.dim_x; + int y = my_left[1] + para.dim_y; + int z = my_left[2] + para.dim_z; + + node_index[0] = x%para.dim_x + para.dim_x*(y%para.dim_y) + para.dim_x*para.dim_y*(z%para.dim_z); + node_index[1] = (x+1)%para.dim_x + para.dim_x*(y%para.dim_y) + para.dim_x*para.dim_y*(z%para.dim_z); + node_index[2] = x%para.dim_x + para.dim_x*((y+1)%para.dim_y) + para.dim_x*para.dim_y*(z%para.dim_z); + node_index[3] = (x+1)%para.dim_x + para.dim_x*((y+1)%para.dim_y) + para.dim_x*para.dim_y*(z%para.dim_z); + node_index[4] = x%para.dim_x + para.dim_x*(y%para.dim_y) + para.dim_x*para.dim_y*((z+1)%para.dim_z); + node_index[5] = (x+1)%para.dim_x + para.dim_x*(y%para.dim_y) + para.dim_x*para.dim_y*((z+1)%para.dim_z); + node_index[6] = x%para.dim_x + para.dim_x*((y+1)%para.dim_y) + para.dim_x*para.dim_y*((z+1)%para.dim_z); + node_index[7] = (x+1)%para.dim_x + para.dim_x*((y+1)%para.dim_y) + para.dim_x*para.dim_y*((z+1)%para.dim_z); + + for(int i=0; i<8; ++i) + { + float totmass=0.0f; + + if(n_a.boundary[node_index[i]]) + continue; + + + calc_m_from_n(n_a,node_index[i],mode); + + #pragma unroll + for(int ii=0;iiminr; + float r_incr=(pdata->maxr-pdata->minr)/(pdata->rbins-1); + + float r = roffset + rbin*r_incr; + + unsigned int maxj; + float phioffset, phi_incr; + if ( pdata->phibins == 1 ) { + maxj = (int)floor( 2*3.1415*pdata->maxr/para.agrid ) ; + phioffset=0; + phi_incr=2*3.1415/maxj; + } else { + maxj = pdata->phibins; + phioffset=pdata->minphi; + phi_incr=(pdata->maxphi-pdata->minphi)/(pdata->phibins); + } + float phi = phioffset + phibin*phi_incr; + + unsigned int maxk; + float zoffset, z_incr; + if ( pdata->zbins == 1 ) { + maxk = (int) para.dim_z; + zoffset=-pdata->center[2]; + z_incr=para.agrid; + } else { + maxk = (int) pdata->zbins; + zoffset=pdata->minz; + z_incr=(pdata->maxz-pdata->minz)/(pdata->zbins-1); + } + + float z = zoffset + zbin*z_incr; + + float p[3]; + p[0]=r*cos(phi)+pdata->center[0]; + p[1]=r*sin(phi)+pdata->center[1]; + p[2]=z+pdata->center[2]; + + float v[3]; + get_interpolated_velocity(n_a, p, v, node_f, 0); + unsigned int linear_index = rbin*maxj*maxk + phibin*maxk + zbin; + + float v_r,v_phi; + + if (r==0) { + v_r=0; + v_phi=0; + } else { + v_r = 1/r*((p[0]-pdata->center[0])*v[0] + (p[1]-pdata->center[1])*v[1]); + v_phi = 1/r/r*((p[0]-pdata->center[0])*v[1]-(p[1]-pdata->center[1])*v[0]); + } + data[3*linear_index+0]=v_r; + data[3*linear_index+1]=v_phi; + data[3*linear_index+2]=v[2]; + +} + + +int statistics_observable_lbgpu_radial_velocity_profile(radial_profile_data* pdata, double* A, unsigned int n_A){ + + unsigned int maxj, maxk; + float normalization_factor=1; + + if ( pdata->rbins == 1 ) { + return 1; + } + + unsigned int maxi=pdata->rbins; + + if ( pdata->phibins == 1 ) { + maxj = (int)floor( 2*3.1415*pdata->maxr/lbpar_gpu.agrid ) ; + normalization_factor/=maxj; + } else { + maxj = pdata->phibins; + } + if ( pdata->zbins == 1 ) { + maxk = (int) lbpar_gpu.dim_z; + normalization_factor/=maxk; + } else { + maxk = pdata->zbins; + } + + for (int i = 0; irbins > 1) + linear_index += i*pdata->phibins*pdata->zbins; + if (pdata->phibins > 1) + linear_index += j*pdata->zbins; + if (pdata->zbins > 1) + linear_index +=k; + A[3*linear_index+0]+=host_data[3*(i*maxj*maxk + j*maxk + k)+0]*normalization_factor; + A[3*linear_index+1]+=host_data[3*(i*maxj*maxk + j*maxk + k)+1]*normalization_factor; + A[3*linear_index+2]+=host_data[3*(i*maxj*maxk + j*maxk + k)+2]*normalization_factor; + } + + // free device data + cudaFree(pdata_device); + cudaFree(data_device); + + // free host data + free(host_data); + + return 0; +} + +#endif /* LB_GPU */ diff --git a/src/core/lees_edwards.cpp b/src/core/lees_edwards.cpp new file mode 100644 index 00000000000..12a9c2aa980 --- /dev/null +++ b/src/core/lees_edwards.cpp @@ -0,0 +1,73 @@ +/* + Copyright (C) 2010,2011,2012 The ESPResSo project + Copyright (C) 2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "lees_edwards.hpp" +#include "domain_decomposition.hpp" +#include "lees_edwards_domain_decomposition.hpp" +#include "grid.hpp" + +/* global state variables */ +double lees_edwards_offset = 0.0; +double lees_edwards_rate = 0.0; + +#ifdef LEES_EDWARDS +int lees_edwards_count = 0; + +/* local state variables */ +double lees_edwards_prev_set_at = 0.0; +double lees_edwards_prev_offset = 0.0; + + +/** React to news of a broadcast change in the \ref lees_edwards_offset */ +void lees_edwards_step_boundaries(){ + + double delta; + + delta = lees_edwards_offset - lees_edwards_prev_offset; + while( delta > 0.5 * box_l[0] ) delta -= box_l[0]; + while( delta < -0.5 * box_l[0] ) delta += box_l[0]; + + while( lees_edwards_offset > 0.5*box_l[0]) { lees_edwards_count++; lees_edwards_offset -= box_l[0];} + while( lees_edwards_offset < -0.5*box_l[0]) { lees_edwards_count--; lees_edwards_offset += box_l[0];} + + /* update the apparent shear rate */ + if( sim_time - lees_edwards_prev_set_at > 0.0 ) + lees_edwards_rate = delta * time_step / (sim_time - lees_edwards_prev_set_at); + else + lees_edwards_rate = 0.0; + + /* save some state */ + lees_edwards_prev_set_at = sim_time; + lees_edwards_prev_offset = lees_edwards_offset; + + /* request a new verlet list */ + rebuild_verletlist = 1; + + /* request a redo of particle-cell assignment */ + resort_particles = 1; + + /* Only part of the comms system needs to be rebuilt, + but it is still very slow. */ + cells_on_geometry_change( CELL_FLAG_LEES_EDWARDS ); + + return; +} + +#endif diff --git a/src/core/lees_edwards.hpp b/src/core/lees_edwards.hpp new file mode 100644 index 00000000000..a95d482693b --- /dev/null +++ b/src/core/lees_edwards.hpp @@ -0,0 +1,37 @@ +/* + Copyright (C) 2010,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards.h + Data and methods for Lees-Edwards periodic boundary conditions. The gist of LE-PBCs is to impose shear flow + by constantly moving the PBC wrap such that: $x_{unfolded} == x_{folded} + x_{img} \times L + (y_{img} * \gamma * t)$, + and $vx_{unfolded} = vx_{folded} + (y_{img} * \gamma)$. +*/ +#ifndef LEES_EDWARDS_H +#define LEES_EDWARDS_H +#define _ADDITIONAL_CHECKS +#define _GHOST_DEBUG +extern double lees_edwards_offset, lees_edwards_rate; +extern int lees_edwards_count; + +#ifdef LEES_EDWARDS +void lees_edwards_step_boundaries(); +#endif //LEES_EDWARDS + +#endif //LEES_EDWARDS_H diff --git a/src/core/lees_edwards_comms_manager.cpp b/src/core/lees_edwards_comms_manager.cpp new file mode 100644 index 00000000000..c8d157c42be --- /dev/null +++ b/src/core/lees_edwards_comms_manager.cpp @@ -0,0 +1,202 @@ +/* + Copyright (C) 2010,2011,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards_comms_manager.cpp + * + * This file defined methods for a class to hold some + * state for Lees-Edwards Comms updates. Comms structures + * need to be partly rebuilt whenever the Lees-Edwards offset + * changes. + * See also \ref lees_edwards_domain_decomposition.hpp , + * \ref lees_edwards_comms_manager.hpp and \ref domain_decomposition.hpp + */ + + +#include "domain_decomposition.hpp" +#include "lees_edwards_domain_decomposition.hpp" +#include "lees_edwards_comms_manager.hpp" +#include "errorhandling.hpp" +#include "initialize.hpp" +#include "lees_edwards.hpp" +#include "grid.hpp" + + +#ifdef LEES_EDWARDS + +/** Allocate and fill a short int array with the order of comms. + The neighbor index is into \ref node_neighbors is stored, + not the actual node id (a comms system with one node only + will have 6 entries in \ref node_neighbours, all pointing to itself).*/ +void le_dd_comms_manager :: init(int neighbor_count){ + + int i, cnt; + + comms_order = new unsigned short int [neighbor_count]; + + i = 0; + comms_order[i++] = 2; /* regular y neighbors come first */ + comms_order[i++] = 3; + + /* extra LE y-neighbors */ + for( cnt = 6; cnt < neighbor_count; cnt++ ) + comms_order[i++] = cnt; + + /* z and then x neighbors */ + comms_order[i++] = 4; + comms_order[i++] = 5; + comms_order[i++] = 0; + comms_order[i++] = 1; + + le_offset_cells_up = -1; + le_offset_cells_down = -1; + + update_on_le_offset_change(); + +} + +/** Change some state based on a new lees-edwards offset, + variables saved are \ref total_xcells, + \ref le_offset_cells_down, \ref le_offset_cells_up*/ +int le_dd_comms_manager :: update_on_le_offset_change(){ + + double le_dx; + int old_off_up, old_off_down; + + old_off_up = le_offset_cells_up; + old_off_down = le_offset_cells_down; + + total_xcells = dd.cell_grid[0] * node_grid[0]; + + le_dx = lees_edwards_offset; + while( le_dx < 0.0 ) {le_dx += box_l[0]; } + while( le_dx >= box_l[0] ){le_dx -= box_l[0]; } + + /* round to the right (up) on transfer from lower to upper + because the extra neighbor cell is provided to the right. */ + le_offset_cells_up = int(le_dx * dd.inv_cell_size[0]); + if( le_dx * dd.inv_cell_size[0] > (float)le_offset_cells_up ) + le_offset_cells_up++; + + /* round to the right (down) on transfer from upper to lower as well + because the extra neighbor cell is also provided to the right. */ + le_offset_cells_down = -1 * int(le_dx * dd.inv_cell_size[0]); + while(le_offset_cells_down < 0) le_offset_cells_down += total_xcells; + + if( le_offset_cells_down == old_off_down + && le_offset_cells_up == old_off_up ){ + cells_shifted = LE_CELLS_SAME; + return( LE_CELLS_SAME ); + }else{ + cells_shifted = LE_CELLS_SHIFTED; + return( LE_CELLS_SHIFTED ); + } +} + + +/**Sending or receiving cells in Y direction with LE wrap means looking at the + * existing cell list with an offset. This function fills the comm list + * using cells with an offset or no cells at all, depending on what is required.*/ +int le_dd_comms_manager :: wrap_fill_comm_cell_lists(Cell **part_lists, + int lc[3], + int hc[3], + int lower_xIndex, + int upper_xIndex, + int amUpper, + int amSender) +{ + + int i,m,n,o,c=0; + int imaged_o, lower_base_o, lower_top_o; + int upper_base_o, upper_top_o; + int doIt; + + lower_base_o = lower_xIndex * dd.cell_grid[0]; + lower_top_o = lower_base_o + dd.cell_grid[0]; + upper_base_o = upper_xIndex * dd.cell_grid[0]; + upper_top_o = upper_base_o + dd.cell_grid[0]; + + /* actually copy a different cell to o (or no cells), + * based on Lees-Edwards imaging*/ + doIt = 0; + for(o=lc[0]; o<=hc[0]; o++){ + + if( amUpper == 1 ){ + + /* find cell pos in the global list of cells */ + if( amSender ) + imaged_o = (upper_base_o + (o-1) + le_offset_cells_down) % total_xcells; + else + imaged_o = (lower_base_o + (o-1) + le_offset_cells_up) % total_xcells; + + + /* test if the received cell is in the range of the receiving node */ + if( ( amSender && ( imaged_o < lower_base_o || imaged_o >= lower_top_o ) ) + ||(!amSender && ( imaged_o < upper_base_o || imaged_o >= upper_top_o ) ) ){ + doIt = 0; + } + else { + doIt = 1; + if( !amSender ) { + imaged_o = imaged_o - upper_base_o + 1; + } + } + }else{ + /* find cell pos in the global list of cells */ + if( amSender ) + imaged_o = (lower_base_o + (o-1) + le_offset_cells_up) % total_xcells; + else + imaged_o = (upper_base_o + (o-1) + le_offset_cells_down) % total_xcells; + + /* test if the received cell is in the range of the receiving node */ + if( ( amSender && ( imaged_o < upper_base_o || imaged_o >= upper_top_o ) ) + ||(!amSender && ( imaged_o < lower_base_o || imaged_o >= lower_top_o ) ) ){ + doIt = 0; + } + else{ + doIt = 1; + if( !amSender ) { + imaged_o = imaged_o - lower_base_o + 1; + } + } + } + + + CELL_TRACE(fprintf(stderr,"%i: linking cell with range %f -- %f %+f to cell with x range: %f -- %f\n", + this_node, (o-1)*dd.cell_size[0],(o)*dd.cell_size[0],lees_edwards_offset, + (imaged_o-1)*dd.cell_size[0],(imaged_o)*dd.cell_size[0]);) + + for(n=lc[1]; n<=hc[1]; n++) { + for(m=lc[2]; m<=hc[2]; m++) { + + if( amSender ) + i = get_linear_index(o,n,m,dd.ghost_cell_grid); + else + i = get_linear_index(imaged_o,n,m,dd.ghost_cell_grid); + + if( doIt ){ + part_lists[c] = &cells[i]; + c++; + } + } + } + } + return c; +} +#endif \ No newline at end of file diff --git a/src/core/lees_edwards_comms_manager.hpp b/src/core/lees_edwards_comms_manager.hpp new file mode 100644 index 00000000000..3667d8dfff4 --- /dev/null +++ b/src/core/lees_edwards_comms_manager.hpp @@ -0,0 +1,91 @@ +/* + Copyright (C) 2010,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards_comms_manager.hpp + Class definition and a few macros for Lees Edwards comms rebuild manager. +*/ +#ifndef LEES_EDWARDS_CM_H +#define LEES_EDWARDS_CM_H + +#include "utils.hpp" +#include "cells.hpp" +#include "integrate.hpp" +#include "verlet.hpp" +#include "thermostat.hpp" + +/** \name Switches and state flags for Lees Edwards */ +/************************************************************/ +/*@{*/ +typedef enum{ + LE_COMM_FORWARDS = 0, + LE_COMM_BACKWARDS +} LE_COMM_REVERSED_T; + +typedef enum{ + LE_CELLS_SAME = 0, + LE_CELLS_SHIFTED +} LE_CELLS_SHIFTED_T; + +/*@}*/ + + +/************************************************************/ +/** \name Class Definitions */ +/************************************************************/ +/*@{*/ +/** Class to manage rebuilds + * of the communicators after a Lees-Edwards offset + * change + */ +class le_dd_comms_manager { + public: + /** Setup the comms order.*/ + void init(int neighbor_count); + + /** change some state based on a new lees-edwards offset */ + int update_on_le_offset_change(); + + /** Update a y-direction comm after a Lees-Edwards offset change.*/ + int wrap_fill_comm_cell_lists(Cell **part_lists, + int lc[3], + int hc[3], + int lower_xIndex, + int upper_xIndex, + int amUpper, + int amSender); + + /** Array of neighbour indexes in order to carry out the comms.*/ + unsigned short int *comms_order; + + /** destructor for the comms manager */ + ~le_dd_comms_manager(){ + delete [] comms_order; + } + + private: + /** Handy to have the number of cells in x for the system.*/ + int total_xcells; + /** Positive integer number of cells which the current LE offset implies.*/ + int le_offset_cells_up, le_offset_cells_down; + /** Has there been a shift in the cell wrap lately?*/ + int cells_shifted; +}; +/*@}*/ +#endif //LEES_EDWARDS_CM_H diff --git a/src/core/lees_edwards_domain_decomposition.cpp b/src/core/lees_edwards_domain_decomposition.cpp new file mode 100644 index 00000000000..be573861c10 --- /dev/null +++ b/src/core/lees_edwards_domain_decomposition.cpp @@ -0,0 +1,902 @@ +/* + Copyright (C) 2010,2011,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards_domain_decomposition.cpp + * + * This file contains modifications to the domain decomposition functions + * which are specific to Lees-Edwards boundary conditions. + * See also \ref lees_edwards_domain_decomposition.hpp , + * \ref lees_edwards_comms_manager.hpp and \ref domain_decomposition.hpp + */ + + + +#include "domain_decomposition.hpp" +#include "lees_edwards_domain_decomposition.hpp" +#include "lees_edwards_comms_manager.hpp" +#include "errorhandling.hpp" +#include "initialize.hpp" +#include "lees_edwards.hpp" +#include "grid.hpp" + + +#ifdef LEES_EDWARDS + +#define LE_TRACE(x) +#ifdef LE_DEBUG +FILE *comms_log = NULL; +int comms_count = 0; +#endif + +/** Init cell interactions for the Lees-Edwards cell system. + * initializes the interacting neighbor cell list of a cell. The + * created list of interacting neighbor cells is used by the verlet + * algorithm (see verlet.cpp) to build the verlet lists. + */ +void le_dd_init_cell_interactions() +{ + int m,n,o,p,q,r,ind1,ind2,c_cnt=0,n_cnt=0; + int extra_cells = 0; + + /* initialize cell neighbor structures */ + dd.cell_inter = (IA_Neighbor_List *) realloc(dd.cell_inter,local_cells.n*sizeof(IA_Neighbor_List)); + for(m=0; m= ind1) { + dd.cell_inter[c_cnt].nList[n_cnt].cell_ind = ind2; + dd.cell_inter[c_cnt].nList[n_cnt].pList = &cells[ind2]; + init_pairList(&dd.cell_inter[c_cnt].nList[n_cnt].vList); +#ifdef LE_DEBUG + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[0] = my_left[0] + r * dd.cell_size[0]; + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[1] = my_left[1] + q * dd.cell_size[1]; + dd.cell_inter[c_cnt].nList[n_cnt].my_pos[2] = my_left[2] + p * dd.cell_size[2]; +#endif + n_cnt++; + } + } + } + } + dd.cell_inter[c_cnt].n_neighbors = n_cnt; + c_cnt++; + } + } + } + +#ifdef LE_DEBUG + FILE *cells_fp; + char cLogName[64]; + int c,nn,this_n; + double myPos[3]; + sprintf(cLogName, "cells_map%i.dat", this_node); + cells_fp = fopen(cLogName,"w"); + + /* print out line segments showing the vector from each cell to each neighbour cell*/ + for(c=0;ccomms_order[i]; + + /* find some geometry about this comm, comms order is y-x-z */ + dir = 1; + if( neighbor_index / 2 == 0 ) { dir = 0;} + else if ( neighbor_index / 2 == 2 ){ dir = 2;} + + neighbor_rank = node_neighbors[neighbor_index]; + + if( neighbor_rank == this_node ) { + /* prepare folding of ghost positions */ + if(node_neighbor_wrap[neighbor_index] != 0) { + cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + if( dir == 1 ){ + cell_structure.exchange_ghosts_comm.comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + } + cnt++; + } + else { + /* send/recv loop: easiest to just set the shift for both of them, only sends will actually be shifted. */ + for(int send_rec=0; send_rec<2; send_rec++) { + + /* prepare folding of ghost positions */ + if(node_neighbor_wrap[neighbor_index] != 0) { + cell_structure.exchange_ghosts_comm.comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + if( dir == 1 ){ + cell_structure.exchange_ghosts_comm.comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + cell_structure.update_ghost_pos_comm.comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + } + cnt++; + + } + } + } + + +} + +#ifdef LE_DEBUG +void printAllComms(FILE *ofile, GhostCommunicator *comm, int backwards){ + + int i,j,cnt,ccnt, num; + int neighbor_index; + char ***comGrid; + int l1, l2; + + l1 = dd.cell_grid[0]+3; + l2 = dd.cell_grid[1]+2; + comGrid = new char**[l1]; + + for( i = 0; i < l1;i++){ + comGrid[i] = new char*[l2]; + for( j = 0; j < l2;j++){ + comGrid[i][j]=new char[8]; + sprintf(&comGrid[i][j][0],"......."); + comGrid[i][j][3]='\0'; + comGrid[i][j][7]='\0'; + } + } + + /* prepare communicator... need 2 comms for node-node, 1 comm for intranode exchange */ + num = my_neighbor_count * 2; + for(i = 0; i < my_neighbor_count; i++) { + if( node_neighbors[i] == this_node ) num--; + } + + fprintf(ofile,"printing comms for node %i dimensions %i-%i-%i\n",this_node,dd.cell_grid[0],dd.cell_grid[1],dd.cell_grid[2]); + fprintf(ofile,"list of partners and sizes:\n"); + for(ccnt = 0; ccnt < num; ccnt++){ + if( backwards ) cnt = num - 1 - ccnt; + else cnt = ccnt; + fprintf(ofile," %i %i\n",comm->comm[cnt].node,comm->comm[cnt].n_part_lists); + } + fprintf(ofile,"\n"); + + /*loop over comms */ + for(ccnt = 0; ccnt < num; ccnt++) { + + int neighbor_coords[3]; + + if( backwards == LE_COMM_BACKWARDS ) cnt = num - 1 - ccnt; + else cnt = ccnt; + + neighbor_index = comm->comm[cnt].node; + map_node_array(neighbor_index, neighbor_coords); + + if( ( comm->comm[cnt].type == GHOST_SEND + || comm->comm[cnt].type == GHOST_RECV ) + && comm->comm[cnt].node == this_node ){ + fprintf(ofile,"serious comms error\n"); + fprintf(stderr,"serious comms error\n"); + exit(8); + } + + /* clear the representation of this comm */ + for( i = 0; i < l1;i++){ + for( j = 0; j < l2;j++){ + sprintf(&comGrid[i][j][0],"......."); + comGrid[i][j][3]='\0'; + comGrid[i][j][7]='\0'; + } + } + + if( comm->comm[cnt].type == GHOST_LOCL ){ + for( i = 0; i < comm->comm[cnt].n_part_lists/2; i++){ + if( comm->comm[cnt].part_lists[i]->myIndex[2] > 1 + && comm->comm[cnt].part_lists[i]->myIndex[2] < 10){ + //fprintf(stderr,"%i: local send %i %i\n",this_node,comm->comm[cnt].part_lists[i]->myIndex[0],comm->comm[cnt].part_lists[i]->myIndex[1]); + sprintf( comGrid[comm->comm[cnt].part_lists[i]->myIndex[0]] + [comm->comm[cnt].part_lists[i]->myIndex[1]], + "%is%i",this_node,comm->comm[cnt].part_lists[i]->myIndex[2]); + } + } + for( i = comm->comm[cnt].n_part_lists/2; i < comm->comm[cnt].n_part_lists; i++){ + if( comm->comm[cnt].part_lists[i]->myIndex[2] > 1 + && comm->comm[cnt].part_lists[i]->myIndex[2] < 10){ + //fprintf(stderr,"%i: local rec %i %i\n",this_node,comm->comm[cnt].part_lists[i]->myIndex[0],comm->comm[cnt].part_lists[i]->myIndex[1]); + sprintf(&comGrid[comm->comm[cnt].part_lists[i]->myIndex[0]] + [comm->comm[cnt].part_lists[i]->myIndex[1]][4], + "%ir%i",this_node,comm->comm[cnt].part_lists[i]->myIndex[2]); + } + } + }else if (comm->comm[cnt].type == GHOST_SEND){ + for( i = 0; i < comm->comm[cnt].n_part_lists; i++){ + if( comm->comm[cnt].part_lists[i]->myIndex[2] > 1 + && comm->comm[cnt].part_lists[i]->myIndex[2] < 10){ + //fprintf(stderr,"%i: ghost send %i %i\n",this_node,comm->comm[cnt].part_lists[i]->myIndex[0],comm->comm[cnt].part_lists[i]->myIndex[1]); + sprintf( comGrid[comm->comm[cnt].part_lists[i]->myIndex[0]] + [comm->comm[cnt].part_lists[i]->myIndex[1]], + "%iS%i",neighbor_index,comm->comm[cnt].part_lists[i]->myIndex[2]); + } + } + }else if (comm->comm[cnt].type == GHOST_RECV){ + for( i = 0; i < comm->comm[cnt].n_part_lists; i++){ + if( comm->comm[cnt].part_lists[i]->myIndex[2] > 1 + && comm->comm[cnt].part_lists[i]->myIndex[2] < 10){ + //fprintf(stderr,"%i: ghost rec %i %i\n",this_node,comm->comm[cnt].part_lists[i]->myIndex[0],comm->comm[cnt].part_lists[i]->myIndex[1]); + sprintf(&comGrid[comm->comm[cnt].part_lists[i]->myIndex[0]] + [comm->comm[cnt].part_lists[i]->myIndex[1]][4], + "%iR%i",neighbor_index,comm->comm[cnt].part_lists[i]->myIndex[2]); + } + } + } + /* print a diagram of this comm, only if it is in a particular z-slice */ + + if( comm->comm[cnt].type == GHOST_LOCL + || comm->comm[cnt].type == GHOST_SEND + || comm->comm[cnt].type == GHOST_RECV ){ + fprintf(ofile,"COMM TYPE: %i partner %i, size %i \n", + comm->comm[cnt].type,comm->comm[cnt].node,comm->comm[cnt].n_part_lists); + for( j = dd.cell_grid[1]+1; j >=0; j--){ + for( i = 0; i < dd.cell_grid[0]+3;i++){ + fprintf(ofile,"|%s%s",comGrid[i][j],&comGrid[i][j][4]); + } + fprintf(ofile,"|\n"); + } + fprintf(ofile,"\n*****************\n"); + + if( comm->comm[cnt].type == GHOST_LOCL ){ + fprintf(ofile,"COMM TYPE: %i\n",comm->comm[cnt].type); + for( j = dd.cell_grid[1]+1; j >=0; j--){ + fprintf(ofile,".\n"); + } + fprintf(ofile,"\n*****************\n"); + + } + } + } + + for( i = 0; i < dd.cell_grid[0]+3;i++){ + for( j = 0; j < dd.cell_grid[1]+2;j++){ + delete [] comGrid[i][j]; + } + delete [] comGrid[i]; + } + delete [] comGrid; +} +#endif + +/** Create communicators for cell structure domain decomposition. (see \ref GhostCommunicator) */ +void le_dd_prepare_comm(le_dd_comms_manager *mgr, GhostCommunicator *comm, int data_parts) +{ + static int le_cells_state_physical = 1; + int dir,lr,i,cnt, num, n_comm_cells[3], send_rec, thisCommCount; + int lc[3],hc[3], neighbor_index; + +#ifdef LE_DEBUG + if( comms_log != NULL ){ fclose(comms_log);comms_log=NULL;} + char vLogName[64]; + sprintf(vLogName, "%i_comms_%i.dat", comms_count++,this_node); + comms_log = fopen(vLogName, "w"); +#endif + + CELL_TRACE(fprintf(stderr,"%d: neighbours:", this_node)); + CELL_TRACE(for(i = 0; i < my_neighbor_count; i++)fprintf(stderr," %d",node_neighbors[i]);) + CELL_TRACE(fprintf(stderr,"\n")); + + /* prepare communicator... need 2 comms for node-node, 1 comm for intranode exchange */ + num = my_neighbor_count * 2; + for(i = 0; i < my_neighbor_count; i++) { + if( node_neighbors[i] == this_node ) num--; + } + + /* flag data_parts is global to all individual sub-comms prepared in the communicator.*/ + CELL_TRACE(fprintf(stderr,"%d: Create Communicator: Aprep_comm ghost flags %d num_neighbor_comms: %d\n",this_node,data_parts,num)); + prepare_comm(comm, data_parts, num); + + /* number of cells owned by this node to communicate in each direction: + the sequence of comms decides the size of the surface to share, because ghost cells are acquired at each comm. */ + n_comm_cells[1] = dd.cell_grid[0] * dd.cell_grid[2]; /* order of comms is y-z-x */ + n_comm_cells[2] = dd.cell_grid[0] * (dd.cell_grid[1] + 2); /*x-dir has one extra ghost layer (not all used).*/ + n_comm_cells[0] = 2 * (dd.cell_grid[1]+2) * (dd.cell_grid[2] + 2); /*x-dir has one extra ghost layer (not all used).*/ + + + /* loop over neighbours */ + cnt=0; + for(i = 0; i < my_neighbor_count; i++) { + + int neighbor_coords[3], neighbor_rank; + neighbor_index = mgr->comms_order[i]; + + /* must loop on order y-x-z for Lees Edwards: each imaging must carry ghost cells already genned in the + plane perpendicular to it. */ + if( neighbor_index == 2 || neighbor_index == 3 || neighbor_index >= 6 ) { + dir = 1; /* sharing a y-plane of the cube */ + lc[0] = 1; + lc[2] = 1; + hc[0] = dd.cell_grid[0]; + hc[2] = dd.cell_grid[2]; + } + else if( neighbor_index == 0 || neighbor_index == 1 ){ + dir = 0; /* sharing an x-plane of the cube */ + /* set lc and hc at the specific comm... not here.*/ + } + else { /*if(neighbor_index == 4 || neighbor_index == 5){*/ + dir = 2; /* sharing a z-plane of the cube */ + lc[0] = 1; + hc[0] = dd.cell_grid[0]; + lc[1] = 0; + hc[1] = dd.cell_grid[1]+1; + } + lr = node_neighbor_lr[neighbor_index]; + + /* find out where this neighbor is */ + neighbor_rank = node_neighbors[neighbor_index]; + map_node_array(neighbor_rank, neighbor_coords); + + /* transfers along a given axis have lc[axis] == hc[axis] == fixed: you are sending/receiving + * a layer of cells defined by that value of x,y or z. + * + * For example, a receive from the cell above you in y would the range: + * (??, dd.cell_grid[1] + 1, ??) for both lc and hc + * while a send to the cell above you would be the range: + * (??, dd.cell_grid[1], ??) + * because the arriving cells go into the "ghost" plane, while the sent ones are 'real'. + * + * For example, a (send to /receive from) the cell below in y would be: + * send: (??, 1, ??) + * recv: (??, 0, ??) + */ + + if( neighbor_rank == this_node ) { /* if copying cells on a single node, then comms are a bit simpler... */ + + comm->comm[cnt].type = GHOST_LOCL; + comm->comm[cnt].node = this_node; + + /* prepare folding of ghost positions */ + if( data_parts & GHOSTTRANS_POSSHFTD ) + comm->comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + + /*if top plane */ + if( lr == 1 ) { + lc[dir] = dd.cell_grid[dir]; + hc[dir] = dd.cell_grid[dir]; + } + /*bottom plane*/ + else { + lc[dir] = 1; + hc[dir] = 1; + } + + /* Buffer has to contain both Send and Recv cells -> factor 2 */ + comm->comm[cnt].part_lists = (ParticleList **)malloc(2*n_comm_cells[dir]*sizeof(ParticleList *)); + + switch( dir ){ + //send the single-thickness x-ghost layer, and then parts of the double-thickness + //layer only when needed. + case 0: + lc[1] = 0; + hc[1] = dd.cell_grid[1] + 1; + lc[2] = 0; + hc[2] = dd.cell_grid[2] + 1; + + /* double-thickness send */ + if( lr == 0 ) hc[0] = 2; + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + + case 1: + if( data_parts & GHOSTTRANS_POSSHFTD ){ + comm->comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + /* Wrap on send */ + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + node_pos[0], + node_pos[0], + lr == 1, + 1); + break; + case 2: + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + } + comm->comm[cnt].n_part_lists = thisCommCount; + + //if( dir == 1 || dir == 0 ) + CELL_TRACE(fprintf(stderr,"%d: Yprep_comm %d send %d dir %i grid-range (%d,%d,%d)-(%d,%d,%d) shift: %f %f %f\n", + this_node,cnt,thisCommCount,dir, + lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + /* fill recv comm cells */ + if( lr == 1 ) { + lc[dir] = 0; + hc[dir] = 0; + } + else { + lc[dir] = dd.cell_grid[dir] + 1; + hc[dir] = dd.cell_grid[dir] + 1; + } + + + switch( dir ){ + case 0: + lc[1] = 0; + hc[1] = dd.cell_grid[1] + 1; + lc[2] = 0; + hc[2] = dd.cell_grid[2] + 1; + + if( lr == 0 ) hc[0] = dd.cell_grid[0] + 2; + + thisCommCount = dd_fill_comm_cell_lists(&comm->comm[cnt].part_lists[thisCommCount],lc,hc); + break; + + case 1: + thisCommCount = mgr->wrap_fill_comm_cell_lists(&comm->comm[cnt].part_lists[thisCommCount], + lc, + hc, + node_pos[0], + node_pos[0], + lr != 1, + 0); + break; + case 2: + thisCommCount = dd_fill_comm_cell_lists(&comm->comm[cnt].part_lists[thisCommCount],lc,hc); + break; + } + comm->comm[cnt].n_part_lists += thisCommCount; + + + LE_TRACE(fprintf(comms_log,"%d send/rcv %d lists within node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + cnt++; + + }else{ + /* send/recv loop: sends and receives must synchronise, or at worst be in the correct order to avoid deadlocks. */ + for(send_rec=0; send_rec<2; send_rec++) { + + comm->comm[cnt].node = neighbor_rank; + + if( (send_rec == 0 && neighbor_rank > this_node) + ||(send_rec == 1 && neighbor_rank < this_node)){ + comm->comm[cnt].type = GHOST_SEND; + /* prepare fold-on-send of ghost positions */ + if(node_neighbor_wrap[neighbor_index] != 0 ){ + if( data_parts & GHOSTTRANS_POSSHFTD ){ + comm->comm[cnt].shift[dir] = node_neighbor_wrap[neighbor_index]*box_l[dir]; + if( dir == 1 ) + comm->comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + } + + /*choose the plane to send*/ + if( lr == 1 ) { + lc[dir] = dd.cell_grid[dir]; + hc[dir] = dd.cell_grid[dir]; + }else { + lc[dir] = 1; + hc[dir] = 1; + } + comm->comm[cnt].part_lists = (ParticleList **)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); + + + switch( dir ){ + case 0: + lc[1] = 0; + hc[1] = dd.cell_grid[1] + 1; + lc[2] = 0; + hc[2] = dd.cell_grid[2] + 1; + + if( 2 > dd.cell_grid[0] ){ + if( le_cells_state_physical ){ + fprintf(stderr,"%i: WARNING: Cells per node is currently too small (%d of %d) for Lees-Edwards Simulation.\n", + this_node,hc[dir],dd.cell_grid[dir]); + fprintf(stderr,"%i: WARNING: This may fix itself during setup, so will continue and notify if it does.\n",this_node); + le_cells_state_physical = 0; + } + }else if( le_cells_state_physical == 0 ){ + fprintf(stderr,"%i: UN-WARNING: Cell system is now large enough for LE simulation.\n",this_node); + le_cells_state_physical = 1; + } + + + /* just send and receive an entire extra layer */ + if( lr == 0 ) hc[0] = 2; + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + + case 1: + if( node_neighbor_wrap[neighbor_index] != 0 ) + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + lr != 1 ? node_pos[0] : neighbor_coords[0], + lr == 1 ? node_pos[0] : neighbor_coords[0], + lr == 1, + 1); + else + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + case 2: + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + } + comm->comm[cnt].n_part_lists = thisCommCount; + + LE_TRACE(fprintf(comms_log,"%d send %d lists to node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + cnt++; + }else { + comm->comm[cnt].type = GHOST_RECV; + + if( lr == 1 ) { + /* if top plane */ + lc[dir] = dd.cell_grid[dir] + 1; + hc[dir] = dd.cell_grid[dir] + 1; + } + else { + /* bottom plane */ + lc[dir] = 0; + hc[dir] = 0; + } + comm->comm[cnt].part_lists = (ParticleList **)malloc(n_comm_cells[dir]*sizeof(ParticleList *)); + + switch( dir ){ + case 0: + lc[1] = 0; + lc[2] = 0; + hc[1] = dd.cell_grid[1] + 1; + hc[2] = dd.cell_grid[2] + 1; + + if( 2 > dd.cell_grid[0] ){ + if( le_cells_state_physical ){ + fprintf(stderr,"%i: WARNING: Cells per node is currently too small (%d of %d) for Lees-Edwards Simulation.\n", + this_node,hc[dir],dd.cell_grid[dir]); + fprintf(stderr,"%i: WARNING: This may fix itself during setup, so will continue and notify if it does.\n",this_node); + le_cells_state_physical = 0; + } + }else if( le_cells_state_physical == 0 ){ + fprintf(stderr,"%i: UN-WARNING: Cell system is now large enough for LE simulation.\n",this_node); + le_cells_state_physical = 1; + } + + + /* just send and receive an entire extra layer */ + if( lr == 1 ) hc[0] = dd.cell_grid[0] + 2; + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + + case 1: + if( node_neighbor_wrap[neighbor_index] != 0) + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + lr != 1 ? node_pos[0] : neighbor_coords[0], + lr == 1 ? node_pos[0] : neighbor_coords[0], + lr == 1, + 0); + else + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + case 2: + thisCommCount = dd_fill_comm_cell_lists(comm->comm[cnt].part_lists,lc,hc); + break; + } + comm->comm[cnt].n_part_lists = thisCommCount; + + LE_TRACE(fprintf(comms_log,"%i recv %d lists from node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + cnt++; + } + } + } + } + +#ifdef LE_DEBUG + printAllComms(comms_log, comm, 0); + if( comms_log != NULL ){ fclose(comms_log);comms_log=NULL;} +#endif + +} + +/** Dynamic update of communicators for cell structure domain decomposition. (see \ref GhostCommunicator) */ +void le_dd_dynamic_update_comm(le_dd_comms_manager *mgr, GhostCommunicator *comm, int data_parts, int backwards) +{ + int lr,i,cnt, num, send_rec, thisCommCount; + int lc[3],hc[3], neighbor_index; + +#ifdef LE_DEBUG + if( comms_log != NULL ){ fclose(comms_log);comms_log=NULL;} + char vLogName[64]; + sprintf(vLogName, "%i_recomm_%i.dat", comms_count++, this_node); + comms_log = fopen(vLogName, "w"); +#endif + + LE_TRACE(fprintf(stderr,"%d: neighbours:", this_node);) + LE_TRACE(for(i = 0; i < my_neighbor_count; i++)fprintf(stderr," %d",node_neighbors[i]);) + LE_TRACE(fprintf(stderr,"\n");) + + /* calculate the total number of communicators */ + num = my_neighbor_count * 2; + for(i = 0; i < my_neighbor_count; i++) { + if( node_neighbors[i] == this_node ) num--; + } + + /* loop over neighbours */ + cnt = 0; + if(backwards == LE_COMM_BACKWARDS) cnt = num - 1; + + for(i = 0; i < my_neighbor_count; i++) { + + int neighbor_coords[3], neighbor_rank; + neighbor_index = mgr->comms_order[i]; + neighbor_rank = node_neighbors[neighbor_index]; + + /* non-imaged comms or comms in x or z directions do not need to be updated */ + if( (neighbor_rank != this_node && node_neighbor_wrap[neighbor_index] == 0) + || neighbor_index == 0 + || neighbor_index == 1 + || neighbor_index == 4 + || neighbor_index == 5 ) { + /* skip one comm if this node is talking to itself, otherwise two comms (send+recv)*/ + if( neighbor_rank == this_node ) + backwards == LE_COMM_BACKWARDS ? cnt-- : cnt++; + else + backwards == LE_COMM_BACKWARDS ? cnt-=2 : cnt+=2; + continue; + } + + LE_TRACE(fprintf(stderr,"%d: Not Skipping comm: %d %d dir 1 shift: %f %f %f\n\n", + this_node,cnt,thisCommCount, + comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + /* sharing a y-plane of the cube */ + lc[0] = 1; + lc[2] = 1; + hc[0] = dd.cell_grid[0]; + hc[2] = dd.cell_grid[2]; + + lr = node_neighbor_lr[neighbor_index]; + + /* find out where this neighbor is */ + map_node_array(neighbor_rank, neighbor_coords); + + if( neighbor_rank == this_node ) { /* if copying cells on a single node, then comms are a bit simpler... */ + + /*if top plane */ + if( lr == 1 ) { + lc[1] = dd.cell_grid[1]; + hc[1] = dd.cell_grid[1]; + } + /*bottom plane*/ + else { + lc[1] = 1; + hc[1] = 1; + } + + /* sending or receiving coords or coords+vels through a y-wrap */ + if( data_parts & GHOSTTRANS_POSSHFTD ){ + comm->comm[cnt].shift[1] = node_neighbor_wrap[neighbor_index]*box_l[1]; + comm->comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + /* Wrap on send */ + LE_TRACE(fprintf(stderr,"%d: Comm to reinit: %d send %d dir %i grid-range (%d,%d,%d)-(%d,%d,%d) shift: %f %f %f\n", + this_node,cnt,thisCommCount,dir, + lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + node_pos[0], + node_pos[0], + lr == 1, + 1); + comm->comm[cnt].n_part_lists = thisCommCount; + + LE_TRACE(fprintf(stderr,"%d: Reinitted comm %d send %d dir %i grid-range (%d,%d,%d)-(%d,%d,%d) shift: %f %f %f\n\n", + this_node,cnt,thisCommCount,dir, + lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + + /* fill recv comm cells */ + if( lr == 1 ) { + lc[1] = 0; + hc[1] = 0; + } + else { + lc[1] = dd.cell_grid[1] + 1; + hc[1] = dd.cell_grid[1] + 1; + } + + LE_TRACE(fprintf(stderr,"%d: Comm to reinit: %d receive %d grid-range (%d,%d,%d)-(%d,%d,%d) shift: %f %f %f\n", + this_node,cnt,thisCommCount, + lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + thisCommCount = mgr->wrap_fill_comm_cell_lists(&comm->comm[cnt].part_lists[thisCommCount], + lc, + hc, + node_pos[0], + node_pos[0], + lr != 1, + 0); + comm->comm[cnt].n_part_lists += thisCommCount; + + + + LE_TRACE(fprintf(comms_log,"%i send/rec %d lists within node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + if( backwards == LE_COMM_BACKWARDS ){ + /* exchange the send and receive parts of the comm */ + int nlist2=comm->comm[cnt].n_part_lists/2; + for(int j=0;jcomm[cnt].part_lists[j]; + comm->comm[cnt].part_lists[j] = comm->comm[cnt].part_lists[j+nlist2]; + comm->comm[cnt].part_lists[j+nlist2] = tmplist; + } + cnt--; + }else{ + cnt++; + } + }else{ + /* send/recv loop: sends and receives must synchronise, or at worst be in the correct order to avoid deadlocks. */ + for(send_rec=0; send_rec<2; send_rec++) { + + /* prepare fold-on-send/fold-on-rec of ghost positions (or pos+vels)*/ + if(node_neighbor_wrap[neighbor_index] != 0 ){ + if( data_parts & GHOSTTRANS_POSSHFTD ){ + comm->comm[cnt].shift[1] = node_neighbor_wrap[neighbor_index]*box_l[1]; + comm->comm[cnt].shift[0] = node_neighbor_wrap[neighbor_index]*lees_edwards_offset; + } + } + + if( (send_rec == 0 && neighbor_rank > this_node) + ||(send_rec == 1 && neighbor_rank < this_node)){ + + + /*choose the plane to send*/ + if( lr == 1 ) { + lc[1] = dd.cell_grid[1]; + hc[1] = dd.cell_grid[1]; + }else { + lc[1] = 1; + hc[1] = 1; + } + + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + lr != 1 ? node_pos[0] : neighbor_coords[0], + lr == 1 ? node_pos[0] : neighbor_coords[0], + lr == 1, + 1); + comm->comm[cnt].n_part_lists = thisCommCount; + + + LE_TRACE(fprintf(comms_log,"%i send %d lists to node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + + backwards == LE_COMM_BACKWARDS ? cnt-- : cnt++; + }else { + if( lr == 1 ) { + /* if top plane */ + lc[1] = dd.cell_grid[1] + 1; + hc[1] = dd.cell_grid[1] + 1; + } + else { + /* bottom plane */ + lc[1] = 0; + hc[1] = 0; + } + + thisCommCount = mgr->wrap_fill_comm_cell_lists(comm->comm[cnt].part_lists, + lc, + hc, + lr != 1 ? node_pos[0] : neighbor_coords[0], + lr == 1 ? node_pos[0] : neighbor_coords[0], + lr == 1, + 0); + comm->comm[cnt].n_part_lists = thisCommCount; + + LE_TRACE(fprintf(comms_log,"%i recv %d lists from node %d grid (%d,%d,%d)-(%d,%d,%d) dir %d shift (%f,%f,%f)\n", + cnt,comm->comm[cnt].n_part_lists,comm->comm[cnt].node,lc[0],lc[1],lc[2],hc[0],hc[1],hc[2], + dir,comm->comm[cnt].shift[0],comm->comm[cnt].shift[1],comm->comm[cnt].shift[2]);) + + backwards == LE_COMM_BACKWARDS ? cnt-- : cnt++; + } + } + } + } +#ifdef LE_DEBUG + printAllComms(comms_log, comm, backwards); + if( comms_log != NULL ){ fclose(comms_log);comms_log=NULL;} +#endif +} + + + +#endif //LEES_EDWARDS diff --git a/src/core/lees_edwards_domain_decomposition.hpp b/src/core/lees_edwards_domain_decomposition.hpp new file mode 100644 index 00000000000..c9044818f03 --- /dev/null +++ b/src/core/lees_edwards_domain_decomposition.hpp @@ -0,0 +1,70 @@ +/* + Copyright (C) 2010,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards_domain_decomposition.hpp + Data and methods for Lees-Edwards periodic boundary conditions. Most of the domain decomposition is handled + as normal, (see \ref domain_decomposition.hpp ) however imaging over + the Y-axis is neccessarily a little different. +*/ +#ifndef LEES_EDWARDS_DD_H +#define LEES_EDWARDS_DD_H + +#include "utils.hpp" +#include "cells.hpp" +#include "integrate.hpp" +#include "verlet.hpp" +#include "thermostat.hpp" +#include "lees_edwards_comms_manager.hpp" + + +#ifdef LEES_EDWARDS + +/************************************************************/ +/** \name Exported Functions */ +/************************************************************/ +/*@{*/ + +/** Create communicators for cell structure domain decomposition. (see \ref GhostCommunicator and also \ref dd_prepare_comm) */ +void le_dd_prepare_comm(le_dd_comms_manager *mgr, GhostCommunicator *comm, int data_parts); + +/** Update communicators based on a new LE offset. (see \ref GhostCommunicator and also \ref le_dd_prepare_comm) */ +void le_dd_dynamic_update_comm(le_dd_comms_manager *mgr, GhostCommunicator *comm, int data_parts, int backwards); + +/** update the 'shift' member of those GhostCommunicators, which use + that value to speed up the folding process of its ghost members + (see \ref dd_prepare_comm for the original), i.e. all which have + GHOSTTRANS_POSSHFTD or'd into 'data_parts' upon execution of \ref + dd_prepare_comm. */ +void le_dd_update_communicators_w_boxl(le_dd_comms_manager *mgr); + +/** Init cell interactions for the Lees-Edwards cell system. + * initializes the interacting neighbor cell list of a cell. The + * created list of interacting neighbor cells is used by the verlet + * algorithm (see verlet.c) to build the verlet lists. + */ +void le_dd_init_cell_interactions(); +/*@}*/ + + + + + +#endif //LEES_EDWARDS +#endif //LEES_EDWARDS_DD_H diff --git a/src/lj.cpp b/src/core/lj.cpp similarity index 98% rename from src/lj.cpp rename to src/core/lj.cpp index de50e9503e6..717caa947f2 100644 --- a/src/lj.cpp +++ b/src/core/lj.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -56,7 +56,6 @@ int lennard_jones_set_params(int part_type_a, int part_type_b, if (min > 0) { data->LJ_min = min; } - /* broadcast interaction parameters */ mpi_bcast_ia_params(part_type_a, part_type_b); diff --git a/src/lj.hpp b/src/core/lj.hpp similarity index 83% rename from src/lj.hpp rename to src/core/lj.hpp index d8b8b548422..d85bba7b3f8 100644 --- a/src/lj.hpp +++ b/src/core/lj.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef _LJ_H #define _LJ_H -/** \file lj.h +/** \file lj.hpp * Routines to calculate the lennard jones energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -46,7 +46,11 @@ inline void add_lj_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_para double d[3], double dist, double force[3]) { int j; - double r_off, frac2, frac6, fac=0.0; + double r_off, frac2, frac6, fac=0.0 ; +#ifdef SHANCHEN + double order; + double SixtRootOfTwo=1.12246204830937; +#endif if (CUTOFF_CHECK(dist < ia_params->LJ_cut+ia_params->LJ_offset) && CUTOFF_CHECK(dist > ia_params->LJ_min+ia_params->LJ_offset)) { @@ -56,7 +60,19 @@ inline void add_lj_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_para frac2 = SQR(ia_params->LJ_sig/r_off); frac6 = frac2*frac2*frac2; fac = 48.0 * ia_params->LJ_eps * frac6*(frac6 - 0.5) / (r_off * dist); - +#ifdef SHANCHEN + if(ia_params->affinity_on==1){ + if(LB_COMPONENTS==2){ + if (dist > SixtRootOfTwo * ia_params->LJ_sig && + p1->r.composition[0] * p1->r.composition[1] * p2->r.composition[0] * p2->r.composition[1] > 0 ) { + order = 2 * ( (p1->r.composition[0] - p1->r.composition[1])/(p1->r.composition[0] + p1->r.composition[1]) + + (p2->r.composition[0] - p2->r.composition[1])/(p2->r.composition[0] + p2->r.composition[1])); +/* TODO: order should be rescaled properly by the lattice spacing */ + fac *= ( (1-ia_params->affinity[1]) * 0.5 * (1+tanh(-order)) + (1-ia_params->affinity[0]) * 0.5 * (1+tanh(order)) ) ; + } + } + } +#endif for(j=0;j<3;j++) force[j] += fac * d[j]; diff --git a/src/ljangle.cpp b/src/core/ljangle.cpp similarity index 97% rename from src/ljangle.cpp rename to src/core/ljangle.cpp index 9dc84934ab7..c0c81524060 100644 --- a/src/ljangle.cpp +++ b/src/core/ljangle.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file ljangle.h +/** \file ljangle.hpp * Routines to calculate the lennard-jones 12-10 with angular dependance. * The potential is a product of a 12-10 LJ potential with two cos^2. * The potential actually relies on 6 particles: the 2 primary beads @@ -34,7 +34,7 @@ * interaction strength in this medium. The interaction strengh of the second * environment must be *stronger* than of the first one. * - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/ljangle.hpp b/src/core/ljangle.hpp similarity index 96% rename from src/ljangle.hpp rename to src/core/ljangle.hpp index 4b9b6046be1..e9bca564b11 100644 --- a/src/ljangle.hpp +++ b/src/core/ljangle.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _LJANGLE_H #define _LJANGLE_H -/** \file ljangle.h +/** \file ljangle.hpp * Routines to calculate the lennard-jones 12-10 with angular dependance. * The potential is a product of a 12-10 LJ potential with two cos^2. * The potential actually relies on 6 particles: the 2 primary beads @@ -36,7 +36,7 @@ * interaction strength in this medium. The interaction strengh of the second * environment must be *stronger* than of the first one. * - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -98,10 +98,10 @@ inline void add_ljangle_pair_force(Particle *p1, Particle *p2, IA_parameters *ia part2n = p2->p.identity + ia_params->LJANGLE_bonded1neg; } - if (part1p >= 0 && part1p < n_total_particles && - part1n >= 0 && part1n < n_total_particles && - part2p >= 0 && part2p < n_total_particles && - part2n >= 0 && part2n < n_total_particles ) { + if (part1p >= 0 && part1p < n_part && + part1n >= 0 && part1n < n_part && + part2p >= 0 && part2p < n_part && + part2n >= 0 && part2n < n_part ) { p3 = local_particles[part1p]; p4 = local_particles[part1n]; @@ -206,7 +206,7 @@ inline void add_ljangle_pair_force(Particle *p1, Particle *p2, IA_parameters *ia } /* Regroup the last two cases in one */ - /* Propagate all forces in this function rather than in the forces.h file */ + /* Propagate all forces in this function rather than in the forces.hpp file */ if (dist > 0.0){ for(j=0;j<3;++j){ p1->f.f[j] += angular_jik * angular_ikn * rik[j]/l_rik *radprime @@ -295,10 +295,10 @@ inline double ljangle_pair_energy(Particle *p1, Particle *p2, IA_parameters *ia_ part2n = p2->p.identity + ia_params->LJANGLE_bonded1neg; } - if (part1p >= 0 && part1p < n_total_particles && - part1n >= 0 && part1n < n_total_particles && - part2p >= 0 && part2p < n_total_particles && - part2n >= 0 && part2n < n_total_particles ) { + if (part1p >= 0 && part1p < n_part && + part1n >= 0 && part1n < n_part && + part2p >= 0 && part2p < n_part && + part2n >= 0 && part2n < n_part ) { p3 = local_particles[part1p]; p4 = local_particles[part1n]; diff --git a/src/ljcos.cpp b/src/core/ljcos.cpp similarity index 96% rename from src/ljcos.cpp rename to src/core/ljcos.cpp index a4d36e568f9..532cc8142e1 100644 --- a/src/ljcos.cpp +++ b/src/core/ljcos.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/ljcos.hpp b/src/core/ljcos.hpp similarity index 97% rename from src/ljcos.hpp rename to src/core/ljcos.hpp index c7aa4212c54..b59c1c2a69e 100644 --- a/src/ljcos.hpp +++ b/src/core/ljcos.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef _LJCOS_H #define _LJCOS_H -/** \file ljcos.h +/** \file ljcos.hpp * Routines to calculate the lennard jones+cosine energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/ljcos2.cpp b/src/core/ljcos2.cpp similarity index 96% rename from src/ljcos2.cpp rename to src/core/ljcos2.cpp index 3a7a470d927..9a39e2f9fd3 100644 --- a/src/ljcos2.cpp +++ b/src/core/ljcos2.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,12 +19,12 @@ along with this program. If not, see . */ -/** \file ljcos2.h +/** \file ljcos2.hpp * * Routines to calculate the lennard-jones with cosine tail energy and/or force - * for a particle pair. Cosine tail is different from that in ljcos.h + * for a particle pair. Cosine tail is different from that in ljcos.hpp * Used for attractive tail/tail interactions in lipid bilayer calculations - * \ref forces.c + * \ref forces.cpp */ #include "ljcos2.hpp" diff --git a/src/ljcos2.hpp b/src/core/ljcos2.hpp similarity index 98% rename from src/ljcos2.hpp rename to src/core/ljcos2.hpp index f62a7b2fde5..ffb290e30f5 100644 --- a/src/ljcos2.hpp +++ b/src/core/ljcos2.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,11 +21,11 @@ #ifndef _LJCOS2_H #define _LJCOS2_H -/** \file ljcos2.h +/** \file ljcos2.hpp * Routines to calculate the lennard-jones with cosine tail energy and/or force - * for a particle pair. Cosine tail is different from that in ljcos.h + * for a particle pair. Cosine tail is different from that in ljcos.hpp * Used for attractive tail/tail interactions in lipid bilayer calculations - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/ljgen.cpp b/src/core/ljgen.cpp similarity index 95% rename from src/ljgen.cpp rename to src/core/ljgen.cpp index f69c2da82b6..1f8beb1ff7c 100644 --- a/src/ljgen.cpp +++ b/src/core/ljgen.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,13 +19,13 @@ along with this program. If not, see . */ -/** \file ljgen.c Routines to calculate the generalized lennard jones +/** \file ljgen.cpp Routines to calculate the generalized lennard jones * energy and/or force for a particle pair. "Generalized" here means * that the LJ energy is of the form * * eps * [ b1 * (sigma/(r-r_offset))^a1 - b2 * (sigma/(r-r_offset))^a2 + shift] * - * \ref forces.c + * \ref forces.cpp */ #include "config.hpp" diff --git a/src/ljgen.hpp b/src/core/ljgen.hpp similarity index 96% rename from src/ljgen.hpp rename to src/core/ljgen.hpp index d4239c03271..cd7f12ffcd2 100644 --- a/src/ljgen.hpp +++ b/src/core/ljgen.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,13 +21,13 @@ #ifndef _LJGEN_H #define _LJGEN_H -/** \file ljgen.h Routines to calculate the generalized lennard jones +/** \file ljgen.hpp Routines to calculate the generalized lennard jones * energy and/or force for a particle pair. "Generalized" here means * that the LJ energy is of the form * * eps * [ b1 * (sigma/(r-r_offset))^a1 - b2 * (sigma/(r-r_offset))^a2 + shift] * - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -55,6 +55,7 @@ inline void add_ljgen_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_p int j; double r_off, frac, fac=0.0; r_off = dist - ia_params->LJGEN_offset; + #ifdef LJGEN_SOFTCORE r_off *= r_off; r_off += pow(ia_params->LJGEN_sig,2) * (1.0-ia_params->LJGEN_lambda) @@ -64,7 +65,7 @@ inline void add_ljgen_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_p r_off = sqrt(r_off); #endif /* normal case: resulting force/energy smaller than capping. */ - if(r_off > ia_params->LJGEN_capradius) { + if((ia_params->LJGEN_capradius == 0) || (r_off > ia_params->LJGEN_capradius)) { frac = ia_params->LJGEN_sig/r_off; fac = ia_params->LJGEN_eps #ifdef LJGEN_SOFTCORE diff --git a/src/maggs.cpp b/src/core/maggs.cpp similarity index 98% rename from src/maggs.cpp rename to src/core/maggs.cpp index 4f7b62b457c..2b34cc09374 100644 --- a/src/maggs.cpp +++ b/src/core/maggs.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2010,2011 Florian Fahrenberger Copyright (C) 2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ along with this program. If not, see . */ -/** \file maggs.c +/** \file maggs.cpp * Maxwell Equations Molecular Dynamics (MEMD) method for electrostatic * interactions. * @@ -402,7 +402,6 @@ void maggs_update_plaquette(int mue, int nue, int* Neighbor, int index, double d */ int maggs_sanity_checks() { - char *errtxt; int ret = 0; int d; int max_node_grid = 1; @@ -410,51 +409,60 @@ int maggs_sanity_checks() FOR3D(d) if(node_grid[d] > max_node_grid) max_node_grid = node_grid[d]; if (maggs.bjerrum == 0.) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{301 MEMD: bjerrum length is zero.} "); + ostringstream msg; + msg <<"MEMD: bjerrum length is zero."; + runtimeError(msg); ret = -1; } else if ( (box_l[0] != box_l[1]) || (box_l[1] != box_l[2]) ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{302 MEMD needs cubic box.} "); + ostringstream msg; + msg <<"MEMD needs cubic box"; + runtimeError(msg); ret = -1; } if (!PERIODIC(0) || !PERIODIC(1) || !PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{303 MEMD requires periodicity 1 1 1} "); + ostringstream msg; + msg <<"MEMD requires periodicity 1 1 1"; + runtimeError(msg); ret = 1; } else if ( maggs.mesh%max_node_grid != 0 ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{304 MEMD: meshsize is incompatible with number of processes.} "); + ostringstream msg; + msg <<"MEMD: meshsize is incompatible with number of processes"; + runtimeError(msg); ret = -1; } /* else if ( maggs_count_charged_particles() == 0 ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{30? MEMD: No charges in the system.} "); + ostringstream msg; + msg <<"MEMD: No charges in the system."; + runtimeError(msg); ret = -1; } */ else if (cell_structure.type != CELL_STRUCTURE_DOMDEC) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{305 MEMD requires domain-decomposition cellsystem.} "); + ostringstream msg; + msg <<"MEMD requires domain-decomposition cellsystem."; + runtimeError(msg); ret = -1; } else if (dd.use_vList) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{306 MEMD requires no Verlet Lists.} "); + ostringstream msg; + msg <<"MEMD requires no Verlet Lists."; + runtimeError(msg); ret = -1; } /** check if speed of light parameter makes sense */ else if (maggs.f_mass < ( 2. * time_step * time_step / maggs.a / maggs.a ) ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{307 MEMD: Speed of light is set too high. Increase f_mass.} "); + ostringstream msg; + msg <<"MEMD: Speed of light is set too high. Increase f_mass."; + runtimeError(msg); ret = -1; } else if (maggs.a < skin) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{308 MEMD: Skin should be smaller than MEMD mesh size.} "); + ostringstream msg; + msg <<"MEMD: Skin should be smaller than MEMD mesh size."; + runtimeError(msg); ret = -1; } #ifdef EXTERNAL_FORCES @@ -465,8 +473,9 @@ int maggs_sanity_checks() int np = cell->n; for(int i = 0; i < np; i++) { if ( (p[i].p.q != 0.0) & p[i].l.ext_flag & COORDS_FIX_MASK) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{309 MEMD does not work with fixed particles.} "); + ostringstream msg; + msg <<"MEMD does not work with fixed particles."; + runtimeError(msg); ret = -1; } } @@ -2055,6 +2064,10 @@ void maggs_interpolate_part_charge_from_grad(double *rel, double *grad, double * */ void maggs_calc_interpolated_self_force(Particle *p) { +// TODO : FIX WARNING ABOUT UNUSED VARIABLES +// FUCTION CURRENTLY NOT USED IN CODE. +/* + int ix,iy,iz,k,index,globalindex; int xmax=2, ymax=2, zmax=2; double self_force[SPACE_DIM]; @@ -2067,7 +2080,7 @@ void maggs_calc_interpolated_self_force(Particle *p) double local_D_field[12]; double *force = p->f.f; - /* calculate position in cell, normalized to lattice size: */ + // calculate position in cell, normalized to lattice size: FOR3D(k) { position[k] = (p->r.p[k] - lparams.left_down_position[k]) * maggs.inva; left_down_position[k] = floor(position[k]); @@ -2076,7 +2089,7 @@ void maggs_calc_interpolated_self_force(Particle *p) local_D_field[k] = 0.0; } - /* Copy permittivity values to the mini-lattice: */ + // Copy permittivity values to the mini-lattice: for (iz=0;iz. */ -/** \file maggs.h +/** \file maggs.hpp * Maxwell Equations Molecular Dynamics (MEMD) method for electrostatic * interactions. * @@ -90,9 +90,9 @@ extern MAGGS_struct maggs; /*@{*/ /** initialization function, parse command and set parameters. - Called from \ref initialize.c + Called from \ref initialize.cpp */ -void maggs_init(); /** called from: initialize.c */ +void maggs_init(); /** called from: initialize.cpp */ /** set the main parameters for the algorithm. @param bjerrum Bjerrum length for the system @@ -118,7 +118,7 @@ int maggs_get_mesh_1D(); double maggs_set_permittivity(int node_x, int node_y, int node_z, int direction, double relative_epsilon); /** Propagate the B-field in the system. - Called TWICE from \ref integrate.c with timestep dt/2 to ensure time-reversibility of the integrator. + Called TWICE from \ref integrate.cpp with timestep dt/2 to ensure time-reversibility of the integrator. @param dt Timestep for which to propagate the field. */ void maggs_propagate_B_field(double dt); diff --git a/src/magnetic_non_p3m_methods.cpp b/src/core/magnetic_non_p3m_methods.cpp similarity index 93% rename from src/magnetic_non_p3m_methods.cpp rename to src/core/magnetic_non_p3m_methods.cpp index dd85d08182b..525349368ce 100644 --- a/src/magnetic_non_p3m_methods.cpp +++ b/src/core/magnetic_non_p3m_methods.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file magnetic_non_p3m_methods.c All 3d non P3M methods to deal with the magnetic dipoles +/** \file magnetic_non_p3m_methods.cpp All 3d non P3M methods to deal with the magnetic dipoles * * DAWAANR => DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA * Handling of a system of dipoles where no replicas @@ -218,23 +218,23 @@ double magnetic_dipolar_direct_sum_calculations(int force_flag, int energy_flag if(n_nodes!=1) {fprintf(stderr,"error: magnetic Direct Sum is just for one cpu .... \n"); exit(1);} if(!(force_flag) && !(energy_flag) ) {fprintf(stderr," I don't know why you call dawaanr_caclulations with all flags zero \n"); return 0;} - x = (double *) malloc(sizeof(double)*n_total_particles); - y = (double *) malloc(sizeof(double)*n_total_particles); - z = (double *) malloc(sizeof(double)*n_total_particles); + x = (double *) malloc(sizeof(double)*n_part); + y = (double *) malloc(sizeof(double)*n_part); + z = (double *) malloc(sizeof(double)*n_part); - mx = (double *) malloc(sizeof(double)*n_total_particles); - my = (double *) malloc(sizeof(double)*n_total_particles); - mz = (double *) malloc(sizeof(double)*n_total_particles); + mx = (double *) malloc(sizeof(double)*n_part); + my = (double *) malloc(sizeof(double)*n_part); + mz = (double *) malloc(sizeof(double)*n_part); if(force_flag) { - fx = (double *) malloc(sizeof(double)*n_total_particles); - fy = (double *) malloc(sizeof(double)*n_total_particles); - fz = (double *) malloc(sizeof(double)*n_total_particles); + fx = (double *) malloc(sizeof(double)*n_part); + fy = (double *) malloc(sizeof(double)*n_part); + fz = (double *) malloc(sizeof(double)*n_part); #ifdef ROTATION - tx = (double *) malloc(sizeof(double)*n_total_particles); - ty = (double *) malloc(sizeof(double)*n_total_particles); - tz = (double *) malloc(sizeof(double)*n_total_particles); + tx = (double *) malloc(sizeof(double)*n_part); + ty = (double *) malloc(sizeof(double)*n_part); + tz = (double *) malloc(sizeof(double)*n_part); #endif } diff --git a/src/magnetic_non_p3m_methods.hpp b/src/core/magnetic_non_p3m_methods.hpp similarity index 93% rename from src/magnetic_non_p3m_methods.hpp rename to src/core/magnetic_non_p3m_methods.hpp index bc9df3446a7..cfe8010c2b6 100644 --- a/src/magnetic_non_p3m_methods.hpp +++ b/src/core/magnetic_non_p3m_methods.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef MAG_NON_P3M_H #define MAG_NON_P3M_H -/** \file magnetic_non_p3m_methods.h Header of all 3d non P3M methods to deal with the magnetic dipoles +/** \file magnetic_non_p3m_methods.hpp Header of all 3d non P3M methods to deal with the magnetic dipoles * * DAWAANR => DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA * Handling of a system of dipoles where no replicas exist diff --git a/src/mdlc_correction.cpp b/src/core/mdlc_correction.cpp similarity index 96% rename from src/mdlc_correction.cpp rename to src/core/mdlc_correction.cpp index 99703544baf..9776bc30001 100644 --- a/src/mdlc_correction.cpp +++ b/src/core/mdlc_correction.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file p3m.h code for calculating the MDLC (magnetic dipolar layer correction). +/** \file p3m.hpp code for calculating the MDLC (magnetic dipolar layer correction). * Purpose: get the corrections for dipolar 3D algorithms * when applied to a slab geometry and dipolar * particles. DLC & co @@ -479,13 +479,13 @@ void add_mdlc_force_corrections(){ // --- Create arrays that should contain the corrections to // the forces and torques, and set them to zero. - dip_DLC_f_x = (double *) malloc(sizeof(double)*n_total_particles); - dip_DLC_f_y = (double *) malloc(sizeof(double)*n_total_particles); - dip_DLC_f_z = (double *) malloc(sizeof(double)*n_total_particles); + dip_DLC_f_x = (double *) malloc(sizeof(double)*n_part); + dip_DLC_f_y = (double *) malloc(sizeof(double)*n_part); + dip_DLC_f_z = (double *) malloc(sizeof(double)*n_part); - dip_DLC_t_x = (double *) malloc(sizeof(double)*n_total_particles); - dip_DLC_t_y = (double *) malloc(sizeof(double)*n_total_particles); - dip_DLC_t_z = (double *) malloc(sizeof(double)*n_total_particles); + dip_DLC_t_x = (double *) malloc(sizeof(double)*n_part); + dip_DLC_t_y = (double *) malloc(sizeof(double)*n_part); + dip_DLC_t_z = (double *) malloc(sizeof(double)*n_part); for(i=0;i. */ -/** \file p3m.h main header-file for MDLC (magnetic dipolar layer correction). +/** \file p3m.hpp main header-file for MDLC (magnetic dipolar layer correction). * * Developer: Joan J. Cerda. * Purpose: get the corrections for dipolar 3D algorithms diff --git a/src/metadynamics.cpp b/src/core/metadynamics.cpp similarity index 90% rename from src/metadynamics.cpp rename to src/core/metadynamics.cpp index c0c695320e1..2677320cc70 100644 --- a/src/metadynamics.cpp +++ b/src/core/metadynamics.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2010,2012,2013 The ESPResSo project +Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -24,7 +24,7 @@ along with this program. If not, see . #include "grid.hpp" #include "cells.hpp" -/** \file metadynamics.h +/** \file metadynamics.hpp * * This file contains routines to perform metadynamics. Right now, the * reaction coordinate is defined between two particles (either distance @@ -88,8 +88,9 @@ void meta_init(){ /* Check that the simulation uses onle a single processor. Otherwise exit. * MPI interface *not* implemented. */ if (n_nodes != 1) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"Can't use metadynamics on more than one processor.\n"); + ostringstream msg; + msg <<"Can't use metadynamics on more than one processor.\n"; + runtimeError(msg); return; } @@ -121,7 +122,15 @@ void meta_perform() p1 = &p[i]; memcpy(ppos1, p[i].r.p, 3*sizeof(double)); memcpy(img1, p[i].l.i, 3*sizeof(int)); +#ifdef LEES_EDWARDS + { + double pv[3]; + memcpy(pv, part[i].m.v, 3*sizeof(double)); + unfold_position(ppos1, pv, img1); + } +#else unfold_position(ppos1, img1); +#endif if (flag1 && flag2) { /* vector r2-r1 - Not a minimal image! Unfolded position */ vector_subt(meta_cur_xi,ppos2,ppos1); @@ -133,7 +142,15 @@ void meta_perform() p2 = &p[i]; memcpy(ppos2, p[i].r.p, 3*sizeof(double)); memcpy(img2, p[i].l.i, 3*sizeof(int)); +#ifdef LEES_EDWARDS + { + double pv[3]; + memcpy(pv, part[i].m.v, 3*sizeof(double)); + unfold_position(ppos2, pv, img2); + } +#else unfold_position(ppos2, img2); +#endif if (flag1 && flag2) { /* vector r2-r1 - Not a minimal image! Unfolded position */ vector_subt(meta_cur_xi,ppos2,ppos1); @@ -144,8 +161,9 @@ void meta_perform() } if (flag1 == 0 || flag2 == 0) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"Metadynamics: can't find pid1 or pid2.\n"); + ostringstream msg; + msg <<"Metadynamics: can't find pid1 or pid2.\n"; + runtimeError(msg); return; } @@ -175,8 +193,9 @@ void meta_perform() meta_apply_direction[0] = meta_apply_direction[1] = 0.; meta_apply_direction[2] = -1.; } else { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"Undefined metadynamics scheme.\n"); + ostringstream msg; + msg <<"Undefined metadynamics scheme.\n"; + runtimeError(msg); return; } } diff --git a/src/metadynamics.hpp b/src/core/metadynamics.hpp similarity index 97% rename from src/metadynamics.hpp rename to src/core/metadynamics.hpp index 4283427efd4..83cbadc3aa9 100644 --- a/src/metadynamics.hpp +++ b/src/core/metadynamics.hpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2010,2012,2013 The ESPResSo project +Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -27,7 +27,7 @@ along with this program. If not, see . #include "particle_data.hpp" #include "utils.hpp" -/** \file metadynamics.h +/** \file metadynamics.hpp * * This file contains routines to perform metadynamics. Right now, the * reaction coordinate is defined between two particles. Note that these diff --git a/src/mmm-common.cpp b/src/core/mmm-common.cpp similarity index 97% rename from src/mmm-common.cpp rename to src/core/mmm-common.cpp index b8735da33e4..0304291a03e 100644 --- a/src/mmm-common.cpp +++ b/src/core/mmm-common.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm-common.c +/** \file mmm-common.cpp Common parts of the MMM family of methods for the electrostatic interaction, MMM1D, MMM2D and ELC. This file contains the code for the polygamma expansions used for the near formulas of MMM1D and MMM2D. diff --git a/src/mmm-common.hpp b/src/core/mmm-common.hpp similarity index 95% rename from src/mmm-common.hpp rename to src/core/mmm-common.hpp index e23b7897f6f..a40d51a8211 100644 --- a/src/mmm-common.hpp +++ b/src/core/mmm-common.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm-common.h +/** \file mmm-common.hpp modified polygamma functions. See Arnold,Holm 2002 */ #ifndef MMM_COMMON_H diff --git a/src/mmm1d.cpp b/src/core/mmm1d.cpp similarity index 68% rename from src/mmm1d.cpp rename to src/core/mmm1d.cpp index 55872ddab3d..a5ddeb0f94d 100644 --- a/src/mmm1d.cpp +++ b/src/core/mmm1d.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm1d.c MMM1D algorithm for long range coulomb interaction. +/** \file mmm1d.cpp MMM1D algorithm for long range coulomb interaction. * - * For more information about MMM1D, see \ref mmm1d.h "mmm1d.h". + * For more information about MMM1D, see \ref mmm1d.hpp "mmm1d.h". */ #include "utils.hpp" @@ -40,11 +40,12 @@ /** How many trial calculations */ #define TEST_INTEGRATIONS 1000 -/** Largest reasonable cutoff for Bessel function */ +/** Largest numerically stable cutoff for Bessel function. Don't + change without improving the formulas. */ #define MAXIMAL_B_CUT 30 -/** Granularity of the radius scan in multiples of box_l[2] */ -#define RAD_STEPPING 0.1 +/** minimal radius for the far formula in multiples of box_l[2] */ +#define MIN_RAD 0.01 /** if you define this, the Besselfunctions are calculated up to machine precision, otherwise 10^-14, which should be @@ -61,62 +62,65 @@ static double uz, L2, uz2, prefuz2, prefL3_i; /*@}*/ -MMM1D_struct mmm1d_params = { 0.05, 5, 1, 1e-5 }; - +MMM1D_struct mmm1d_params = { 0.05, 1e-5 }; +/** From which distance a certain bessel cutoff is valid. Can't be part of the + params since these get broadcasted. */ +static double *bessel_radii; + -static void MMM1D_setup_constants() +static double far_error(int P, double minrad) { - uz = 1/box_l[2]; - L2 = box_l[2]*box_l[2]; - uz2 = uz*uz; - prefuz2 = coulomb.prefactor*uz2; - prefL3_i = prefuz2*uz; + // this uses an upper bound to all force components and the potential + double rhores = 2*M_PI*uz*minrad; + double pref = 4*uz*dmax(1, 2*M_PI*uz); + + return pref*K1(rhores*P)*exp(rhores)/rhores*(P - 1 + 1/rhores); } -double determine_bessel_cutoff(double switch_rad, double maxPWerror, int maxP) +static double determine_minrad(double maxPWerror, int P) { - /* this calculates an upper bound to all force components and the potential */ - - // fprintf(stderr, "determ: %f %f %d\n", switch_rad, maxPWerror, maxP); + // bisection to search for where the error is maxPWerror + double rgranularity = MIN_RAD*box_l[2]; + double rmin = rgranularity; + double rmax = dmin(box_l[0], box_l[1]); + double errmin = far_error(P, rmin); + double errmax = far_error(P, rmax); + if (errmin < maxPWerror) { + // we can do almost all radii with this P + return rmin; + } + if (errmax > maxPWerror) { + // make sure that this switching radius cannot be reached + return 2*dmax(box_l[0], box_l[1]); + } - double err; - double rhores = 2*M_PI*uz*switch_rad; - double pref = 4*uz*dmax(1, 2*M_PI*uz); - int P = 1; - do { - err = pref*K1(rhores*P)*exp(rhores)/rhores*(P - 1 + 1/rhores); - // fprintf(stderr, "%d %e\n", P, err); */ - P++; - } while (err > maxPWerror && P <= maxP); - P--; - return P; + while (rmax - rmin > rgranularity) { + double c = 0.5*(rmin + rmax); + double errc = far_error(P, c); + if (errc > maxPWerror) { + rmin = c; + } else { + rmax = c; + } + } + return 0.5*(rmin + rmax); } -int MMM1D_set_params(double switch_rad, int bessel_cutoff, double maxPWerror) +static void determine_bessel_radii(double maxPWerror, int maxP) { - MMM1D_setup_constants(); - - mmm1d_params.far_switch_radius_2 = (switch_rad > 0) ? SQR(switch_rad) : -1; - mmm1d_params.bessel_cutoff = bessel_cutoff; - /* if parameters come from here they are never calculated that is - only the case if you call mmm1d_tune, which then - changes this flag */ - mmm1d_params.bessel_calculated = 0; - - mmm1d_params.maxPWerror = maxPWerror; - coulomb.method = COULOMB_MMM1D; - - mpi_bcast_coulomb_params(); - - return 0; + bessel_radii = (double *)realloc(bessel_radii, sizeof(double)*maxP); + for (int P = 1; P <= maxP; ++P) { + bessel_radii[P-1] = determine_minrad(maxPWerror, P); + //printf("cutoff %d %f\n", P, bessel_radii[P-1]); + } } -void MMM1D_recalcTables() +static void prepare_polygamma_series(double maxPWerror, double maxrad2) { /* polygamma, determine order */ int n; double err; - double rhomax2nm2, rhomax2 = uz2*mmm1d_params.far_switch_radius_2; + double rhomax2nm2, rhomax2 = uz2*maxrad2; /* rhomax2 < 1, so rhomax2m2 falls monotonously */ n = 1; @@ -130,21 +134,34 @@ void MMM1D_recalcTables() n++; // fprintf(stderr, "%f\n", err); } - while (err > 0.1*mmm1d_params.maxPWerror); + while (err > 0.1*maxPWerror); +} + +int MMM1D_set_params(double switch_rad, double maxPWerror) +{ + mmm1d_params.far_switch_radius_2 = (switch_rad > 0) ? SQR(switch_rad) : -1; + mmm1d_params.maxPWerror = maxPWerror; + coulomb.method = COULOMB_MMM1D; + + mpi_bcast_coulomb_params(); + + return 0; } int MMM1D_sanity_checks() { - char *errtxt; + //char *errtxt; if (PERIODIC(0) || PERIODIC(1) || !PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{022 MMM1D requires periodicity 0 0 1} "); + ostringstream msg; + msg <<"MMM1D requires periodicity 0 0 1"; + runtimeError(msg); return 1; } if (cell_structure.type != CELL_STRUCTURE_NSQUARE) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{023 MMM1D requires n-square cellsystem} "); + ostringstream msg; + msg <<"MMM1D requires n-square cellsystem"; + runtimeError(msg); return 1; } return 0; @@ -157,12 +174,14 @@ void MMM1D_init() if (mmm1d_params.far_switch_radius_2 >= SQR(box_l[2])) mmm1d_params.far_switch_radius_2 = 0.8*SQR(box_l[2]); - MMM1D_setup_constants(); + uz = 1/box_l[2]; + L2 = box_l[2]*box_l[2]; + uz2 = uz*uz; + prefuz2 = coulomb.prefactor*uz2; + prefL3_i = prefuz2*uz; - if (mmm1d_params.bessel_calculated) { - mmm1d_params.bessel_cutoff = determine_bessel_cutoff(sqrt(mmm1d_params.far_switch_radius_2), mmm1d_params.maxPWerror, MAXIMAL_B_CUT); - } - MMM1D_recalcTables(); + determine_bessel_radii(mmm1d_params.maxPWerror, MAXIMAL_B_CUT); + prepare_polygamma_series(mmm1d_params.maxPWerror, mmm1d_params.far_switch_radius_2); } void add_mmm1d_coulomb_pair_force(double chpref, double d[3], double r2, double r, double force[3]) @@ -242,7 +261,10 @@ void add_mmm1d_coulomb_pair_force(double chpref, double d[3], double r2, double double sr = 0, sz = 0; int bp; - for (bp = 1; bp < mmm1d_params.bessel_cutoff; bp++) { + for (bp = 1; bp < MAXIMAL_B_CUT; bp++) { + if (bessel_radii[bp-1] < rxy) + break; + double fq = C_2PI*bp, k0, k1; #ifdef BESSEL_MACHINE_PREC k0 = K0(fq*rxy_d); @@ -320,7 +342,10 @@ double mmm1d_coulomb_pair_energy(Particle *p1, Particle *p2, double d[3], double /* The first Bessel term will compensate a little bit the log term, so add them close together */ E = -0.25*log(rxy2_d) + 0.5*(M_LN2 - C_GAMMA); - for (bp = 1; bp < mmm1d_params.bessel_cutoff; bp++) { + for (bp = 1; bp < MAXIMAL_B_CUT; bp++) { + if (bessel_radii[bp-1] < rxy) + break; + double fq = C_2PI*bp; E += K0(fq*rxy_d)*cos(fq*z_d); } @@ -337,15 +362,16 @@ int mmm1d_tune(char **log) double maxrad = box_l[2]; /* N_psi = 2, theta=2/3 maximum for rho */ double switch_radius; - if (mmm1d_params.bessel_cutoff < 0 && mmm1d_params.far_switch_radius_2 < 0) { - /* determine besselcutoff and optimal switching radius */ - for (switch_radius = RAD_STEPPING*maxrad; - switch_radius < maxrad; - switch_radius += RAD_STEPPING*maxrad) { - mmm1d_params.bessel_cutoff = determine_bessel_cutoff(switch_radius, mmm1d_params.maxPWerror, MAXIMAL_B_CUT); - /* no reasonable cutoff possible */ - if (mmm1d_params.bessel_cutoff == MAXIMAL_B_CUT) - continue; + if (mmm1d_params.far_switch_radius_2 < 0) { + /* determine besselcutoff and optimal switching radius. Should be around 0.33 */ + for (switch_radius = 0.2*maxrad; + switch_radius < 0.4*maxrad; + switch_radius += 0.025*maxrad) { + if (switch_radius <= bessel_radii[MAXIMAL_B_CUT - 1]) { + // this switching radius is too small for our Bessel series + continue; + } + mmm1d_params.far_switch_radius_2 = SQR(switch_radius); coulomb.method = COULOMB_MMM1D; @@ -360,8 +386,7 @@ int mmm1d_tune(char **log) if (int_time < 0) return ES_ERROR; - sprintf(buffer, "r= %f c= %d t= %f ms\n", - switch_radius, mmm1d_params.bessel_cutoff, int_time); + sprintf(buffer, "r= %f t= %f ms\n", switch_radius, int_time); *log = strcat_alloc(*log, buffer); if (int_time < min_time) { @@ -372,23 +397,16 @@ int mmm1d_tune(char **log) else if (int_time > 2*min_time) break; } - switch_radius = min_rad; + switch_radius = min_rad; mmm1d_params.far_switch_radius_2 = SQR(switch_radius); - mmm1d_params.bessel_cutoff = determine_bessel_cutoff(switch_radius, mmm1d_params.maxPWerror, MAXIMAL_B_CUT); - mmm1d_params.bessel_calculated = 1; } - else if (mmm1d_params.bessel_cutoff < 0) { - /* determine besselcutoff to achieve at least the given pairwise error */ - mmm1d_params.bessel_cutoff = determine_bessel_cutoff(sqrt(mmm1d_params.far_switch_radius_2), - mmm1d_params.maxPWerror, MAXIMAL_B_CUT); - if (mmm1d_params.bessel_cutoff == MAXIMAL_B_CUT) { + else { + if (mmm1d_params.far_switch_radius_2 <= SQR(bessel_radii[MAXIMAL_B_CUT - 1])) { + // this switching radius is too small for our Bessel series *log = strcat_alloc(*log, "could not find reasonable bessel cutoff"); return ES_ERROR; } - mmm1d_params.bessel_calculated = 1; } - else - mmm1d_params.bessel_calculated = 0; coulomb.method = COULOMB_MMM1D; diff --git a/src/mmm1d.hpp b/src/core/mmm1d.hpp similarity index 76% rename from src/mmm1d.hpp rename to src/core/mmm1d.hpp index f2ac55ee1e1..27c15af89f2 100644 --- a/src/mmm1d.hpp +++ b/src/core/mmm1d.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm1d.h MMM1D algorithm for long range coulomb interactions. +/** \file mmm1d.hpp MMM1D algorithm for long range coulomb interactions. Implementation of the MMM1D method for the calculation of the electrostatic interaction in one dimensionally periodic systems. For details on the method see MMM in general. The MMM1D @@ -38,18 +38,10 @@ typedef struct { /** square of the switching radius */ double far_switch_radius_2; - /** cutoff of the bessel sum */ - int bessel_cutoff; - /** Wether to recalculate the Bessel cutoff automatically. - If some parameters like the box dimensions change, the current - Bessel cutoff may not be suitable to achieve the required accuracy - anymore. If the user did not specify the Bessel cutoff explicitly, - this flag is 1, and whenever necessary, the Bessel cutoff is - recalculated. - */ - int bessel_calculated; /** required accuracy */ double maxPWerror; + /** cutoff of the bessel sum. only used by the GPU implementation */ + int bessel_cutoff; } MMM1D_struct; extern MMM1D_struct mmm1d_params; @@ -58,14 +50,9 @@ extern MMM1D_struct mmm1d_params; if you set this parameters. @param switch_rad at which xy-distance the calculation switches from the far to the near formula. If -1, this parameter will be tuned automatically. - @param bessel_cutoff the cutoff for the bessel sum, aka far formula. Normally set this - to -1, then the cutoff is automatically determined using the error formula. @param maxPWerror the maximal allowed error for the potential and the forces without the prefactors, i. e. for the pure lattice 1/r-sum. */ -int MMM1D_set_params(double switch_rad, int bessel_cutoff, double maxPWerror); - -/** recalculate the polygamma taylor series. */ -void MMM1D_recalcTables(); +int MMM1D_set_params(double switch_rad, double maxPWerror); /// check that MMM1D can run with the current parameters int MMM1D_sanity_checks(); diff --git a/src/mmm2d.cpp b/src/core/mmm2d.cpp similarity index 93% rename from src/mmm2d.cpp rename to src/core/mmm2d.cpp index 852655d249f..efec88034af 100644 --- a/src/mmm2d.cpp +++ b/src/core/mmm2d.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm2d.c MMM2D algorithm for long range coulomb interaction. +/** \file mmm2d.cpp MMM2D algorithm for long range coulomb interaction. * - * For more information about MMM2D, see \ref mmm2d.h "mmm2d.h". + * For more information about MMM2D, see \ref mmm2d.hpp "mmm2d.h". */ #include @@ -126,7 +126,7 @@ static double max_near, min_far; /// static double self_energy; -MMM2D_struct mmm2d_params = { 1e100, 10, 1, 0, 0, 1, 1, 1 }; +MMM2D_struct mmm2d_params = { 1e100, 10, 1, 0, 0, 0, 0, 1, 1, 1 }; /** return codes for \ref MMM2D_tune_near and \ref MMM2D_tune_far */ /*@{*/ @@ -547,35 +547,18 @@ static void setup_z_force() int np, c, i; double pref = coulomb.prefactor*C_2PI*ux*uy; Particle *part; - double *lclimgebot=NULL,*lclimgetop=NULL; int e_size=1,size = 2; - double e, e_di_l, e_di_h; - - double fac_imgsum; - - /* in case of metallic boundary conditions on both sides, we get an infinite array, - which only exists for charge neutral systems. But in this case, we can as well - not sum up the force array, as the net force per image is 0 */ - if (mmm2d_params.delta_mult != 1.0) { - fac_imgsum = 1/(1 - mmm2d_params.delta_mult); - } - else { - fac_imgsum = 0; - } - - if (mmm2d_params.dielectric_contrast_on) - clear_vec(lclimge, size); + + /* there is NO contribution from images here, unlike claimed in Tyagi et al. + Please refer to the Entropy + article of Arnold, Kesselheim, Breitsprecher et al, 2013, for details. */ if(this_node==0) { - - lclimgebot=blwentry(lclcblk,0,e_size); - clear_vec(lclimgebot, e_size); + clear_vec(blwentry(lclcblk,0,e_size), e_size); } if(this_node==n_nodes-1) { - - lclimgetop=abventry(lclcblk,n_layers+1,e_size); - clear_vec(lclimgetop, e_size); + clear_vec(abventry(lclcblk,n_layers+1,e_size), e_size); } /* calculate local cellblks. partblks don't make sense */ @@ -584,42 +567,12 @@ static void setup_z_force() part = cells[c].part; lclcblk[size*c] = 0; for (i = 0; i < np; i++) { - lclcblk[size*c] += part[i].p.q; - - if (mmm2d_params.dielectric_contrast_on) { - e_di_l = (mmm2d_params.delta_mult*mmm2d_params.delta_mid_bot - + mmm2d_params.delta_mult)*fac_imgsum; - if (c==1 && this_node==0) { - e = mmm2d_params.delta_mid_bot; - lclimgebot[QQEQQP] += part[i].p.q*e; - } - else - e_di_l += mmm2d_params.delta_mid_bot; - - e_di_h = (mmm2d_params.delta_mult*mmm2d_params.delta_mid_top - + mmm2d_params.delta_mult)*fac_imgsum; + lclcblk[size*c] += part[i].p.q; - if (c==n_layers && this_node==n_nodes-1) { - e = mmm2d_params.delta_mid_top; - lclimgetop[QQEQQP] += part[i].p.q*e; - } - else - e_di_h += mmm2d_params.delta_mid_top; - - lclimge[QQEQQP] += part[i].p.q*e_di_l; - lclimge[QQEQQM] += part[i].p.q*e_di_h; - } } lclcblk[size*c] *= pref; - lclcblk[size*c+1] = lclcblk[size*c]; - } + lclcblk[size*c+1] = lclcblk[size*c]; - if (mmm2d_params.dielectric_contrast_on) { - scale_vec(pref, lclimge, size); - if(this_node==0) - scale_vec(pref, blwentry(lclcblk, 0, e_size), e_size); - if(this_node==n_nodes-1) - scale_vec(pref, abventry(lclcblk, n_layers + 1, e_size), e_size); } } @@ -630,6 +583,26 @@ static void add_z_force() Particle *part; double *othcblk; int size = 2; + double field_tot=0; + + /* Const. potential: subtract global dipole moment */ + if (mmm2d_params.const_pot_on) { + double gbl_dm_z = 0; + double lcl_dm_z = 0; + + for (c = 0; c < local_cells.n; c++) { + int npl = local_cells.cell[c]->n; + Particle *pl = local_cells.cell[c]->part; + for (i = 0; i < npl; i++) { + lcl_dm_z += pl[i].p.q*(pl[i].r.p[2] + pl[i].l.i[2]*box_l[2]); + } + } + MPI_Allreduce(&lcl_dm_z, &gbl_dm_z, 1, MPI_DOUBLE, MPI_SUM, comm_cart); + + field_induced = gbl_dm_z * coulomb.prefactor*4*M_PI*ux*uy*uz; + field_applied = mmm2d_params.pot_diff * uz; + field_tot = field_induced + field_applied; + } for (c = 1; c <= n_layers; c++) { othcblk = block(gblcblk, c - 1, size); @@ -637,7 +610,7 @@ static void add_z_force() np = cells[c].n; part = cells[c].part; for (i = 0; i < np; i++) { - part[i].f.f[2] += part[i].p.q*add; + part[i].f.f[2] += part[i].p.q*(add+field_tot); LOG_FORCES(fprintf(stderr, "%d: part %d force %10.3g %10.3g %10.3g\n", this_node, part[i].p.identity, part[i].f.f[0], part[i].f.f[1], part[i].f.f[2])); @@ -694,6 +667,26 @@ static double z_energy() } } + + /* total dipole moment term, for capacitor feature */ + if (mmm2d_params.const_pot_on) { + double gbl_dm_z = 0; + double lcl_dm_z = 0; + + for (c = 0; c < local_cells.n; c++) { + int npl = local_cells.cell[c]->n; + Particle *pl = local_cells.cell[c]->part; + for (i = 0; i < npl; i++) { + lcl_dm_z += pl[i].p.q*(pl[i].r.p[2] + pl[i].l.i[2]*box_l[2]); + } + } + MPI_Allreduce(&lcl_dm_z, &gbl_dm_z, 1, MPI_DOUBLE, MPI_SUM, comm_cart); + // zero potential difference contribution + eng += gbl_dm_z*gbl_dm_z * coulomb.prefactor*2*M_PI*ux*uy*uz; + // external potential shift contribution + eng += mmm2d_params.pot_diff * uz * gbl_dm_z; + } + return eng; } @@ -1198,14 +1191,14 @@ static void add_force_contribution(int p, int q) if (p == 0) { setup_z_force(); - if (mmm2d_params.dielectric_contrast_on) - gather_image_contributions(1); - else - clear_image_contributions(1); + //Clear image contr. calculated for p,q <> 0 + clear_image_contributions(1); distribute(1, 1.); + add_z_force(); checkpoint("************2piz", 0, 0, 1); + } else { omega = C_2PI*ux*p; @@ -1327,7 +1320,7 @@ double MMM2D_add_far(int f, int e) else { q2 = mmm2d_params.far_cut2 - SQR(ux*(p - 1)); if (q2 > 0) - q = 1 + box_l[1]*(int)ceil(sqrt(q2)); + q = 1 + (int)ceil(box_l[1]*sqrt(q2)); else q = 1; /* just to be on the safe side... */ @@ -1519,8 +1512,9 @@ void add_mmm2d_coulomb_pair_force(double charge_factor, #ifdef ADDITIONAL_CHECKS if (d[2] >box_l[1]/2) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{024 near formula called for too distant particle pair} "); + ostringstream msg; + msg <<"near formula called for too distant particle pair"; + runtimeError(msg); return; } #endif @@ -1600,8 +1594,9 @@ void add_mmm2d_coulomb_pair_force(double charge_factor, fprintf(stderr, "MMM2D: some particles left the assumed slab, precision might be lost\n"); } if (end < 0) { - char *errtxt = runtime_error(100); - ERROR_SPRINTF(errtxt, "{MMM2D: distance was negative, coordinates probably out of range } "); + ostringstream msg; + msg <<"MMM2D: distance was negative, coordinates probably out of range"; + runtimeError(msg); end = 0; } end = complexCutoff[end]; @@ -1832,7 +1827,7 @@ void MMM2D_self_energy() * COMMON PARTS ****************************************/ -int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double delta_bot) +int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double delta_bot, int const_pot_on, double pot_diff) { int err; @@ -1842,18 +1837,28 @@ int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double } mmm2d_params.maxPWerror = maxPWerror; - - if (delta_top != 0.0 || delta_bot != 0.0) { + + if (const_pot_on==1) { + mmm2d_params.dielectric_contrast_on = 1; + mmm2d_params.delta_mid_top = -1; + mmm2d_params.delta_mid_bot = -1; + mmm2d_params.delta_mult = 1; + mmm2d_params.const_pot_on = 1; + mmm2d_params.pot_diff= pot_diff; + } + else if (delta_top != 0.0 || delta_bot != 0.0) { mmm2d_params.dielectric_contrast_on = 1; mmm2d_params.delta_mid_top = delta_top; mmm2d_params.delta_mid_bot = delta_bot; mmm2d_params.delta_mult = delta_top*delta_bot; + mmm2d_params.const_pot_on = 0; } else { mmm2d_params.dielectric_contrast_on = 0; mmm2d_params.delta_mid_top = 0; mmm2d_params.delta_mid_bot = 0; mmm2d_params.delta_mult = 0; + mmm2d_params.const_pot_on = 0; } MMM2D_setup_constants(); @@ -1890,18 +1895,19 @@ int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double int MMM2D_sanity_checks() { - char *errtxt; if (!PERIODIC(0) || !PERIODIC(1) || PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{025 MMM2D requires periodicity 1 1 0} "); + ostringstream msg; + msg <<"MMM2D requires periodicity 1 1 0"; + runtimeError(msg); return 1; } if (cell_structure.type != CELL_STRUCTURE_LAYERED && cell_structure.type != CELL_STRUCTURE_NSQUARE) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{026 MMM2D at present requires layered (or n-square) cellsystem} "); + ostringstream msg; + msg <<"MMM2D at present requires layered (or n-square) cellsystem"; + runtimeError(msg); return 1; } return 0; @@ -1910,14 +1916,14 @@ int MMM2D_sanity_checks() void MMM2D_init() { int err; - char *errtxt; if (MMM2D_sanity_checks()) return; MMM2D_setup_constants(); if ((err = MMM2D_tune_near(mmm2d_params.maxPWerror))) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{027 MMM2D auto-retuning: %s} ", mmm2d_errors[err]); + ostringstream msg; + msg <<"MMM2D auto-retuning: " << mmm2d_errors[err]; + runtimeError(msg); coulomb.method = COULOMB_NONE; return; } @@ -1925,15 +1931,17 @@ void MMM2D_init() (cell_structure.type == CELL_STRUCTURE_LAYERED && n_nodes*n_layers < 3)) { mmm2d_params.far_cut = 0.0; if (mmm2d_params.dielectric_contrast_on) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{027 MMM2D auto-retuning: IC requires layered cellsystem with > 3 layers} "); + ostringstream msg; + msg <<"MMM2D auto-retuning: IC requires layered cellsystem with > 3 layers"; + runtimeError(msg); } } else { if (mmm2d_params.far_calculated) { if ((err = MMM2D_tune_far(mmm2d_params.maxPWerror))) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{028 MMM2D auto-retuning: %s} ", mmm2d_errors[err]); + ostringstream msg; + msg <<"MMM2D auto-retuning: "<< mmm2d_errors[err]; + runtimeError(msg); coulomb.method = COULOMB_NONE; return; } @@ -1969,9 +1977,11 @@ void MMM2D_dielectric_layers_force_contribution() double charge_factor; double a[3]; double force[3]={0, 0, 0}; + double pref = coulomb.prefactor*C_2PI*ux*uy; if (!mmm2d_params.dielectric_contrast_on) return; - + + // First and last layer near field force contribution if(this_node==0) { c=1; celll = &cells[c]; @@ -1988,6 +1998,8 @@ void MMM2D_dielectric_layers_force_contribution() dist2 = sqrlen(d); charge_factor=p1->p.q*pl[j].p.q*mmm2d_params.delta_mid_bot; add_mmm2d_coulomb_pair_force(charge_factor, d, sqrt(dist2), dist2, force); + /* remove unwanted 2 pi |z| part (cancels due to charge neutrality) */ + force[2] -= pref*charge_factor; } for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; @@ -2010,6 +2022,8 @@ void MMM2D_dielectric_layers_force_contribution() dist2 = sqrlen(d); charge_factor=p1->p.q*pl[j].p.q*mmm2d_params.delta_mid_top; add_mmm2d_coulomb_pair_force(charge_factor, d, sqrt(dist2), dist2, force); + /* remove unwanted 2 pi |z| part (cancels due to charge neutrality) */ + force[2] += pref*charge_factor; } for (j = 0; j < 3; j++) { p1->f.f[j] += force[j]; @@ -2029,8 +2043,7 @@ double MMM2D_dielectric_layers_energy_contribution() double charge_factor; double a[3]; double eng=0.0; - // prefactor for the charged plate interaction removal - double corr_pref = coulomb.prefactor*C_2PI*ux*uy; + double pref = coulomb.prefactor*C_2PI*ux*uy; if (!mmm2d_params.dielectric_contrast_on) return 0.0; @@ -2047,7 +2060,8 @@ double MMM2D_dielectric_layers_energy_contribution() layered_get_mi_vector(d, p1->r.p, a); dist2 = sqrlen(d); charge_factor = mmm2d_params.delta_mid_bot*p1->p.q*pl[j].p.q; - eng+=mmm2d_coulomb_pair_energy(charge_factor, d, dist2, sqrt(dist2)) + corr_pref*charge_factor*d[2]; + /* last term removes unwanted 2 pi |z| part (cancels due to charge neutrality) */ + eng+=mmm2d_coulomb_pair_energy(charge_factor, d, dist2, sqrt(dist2)) + pref*charge_factor*d[2]; } } } @@ -2064,11 +2078,13 @@ double MMM2D_dielectric_layers_energy_contribution() layered_get_mi_vector(d, p1->r.p, a); dist2 = sqrlen(d); charge_factor=mmm2d_params.delta_mid_top*p1->p.q*pl[j].p.q; - eng+=mmm2d_coulomb_pair_energy(charge_factor, d, dist2, sqrt(dist2)) - corr_pref*charge_factor*d[2]; + /* last term removes unwanted 2 pi |z| part (cancels due to charge neutrality) */ + eng+=mmm2d_coulomb_pair_energy(charge_factor, d, dist2, sqrt(dist2)) - pref*charge_factor*d[2]; } } } - return 0.5*eng; + + return 0.5*eng; } #endif diff --git a/src/mmm2d.hpp b/src/core/mmm2d.hpp similarity index 94% rename from src/mmm2d.hpp rename to src/core/mmm2d.hpp index 41b626d124c..e9a43e4b436 100644 --- a/src/mmm2d.hpp +++ b/src/core/mmm2d.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm2d.h MMM2D algorithm for long range coulomb interaction +/** \file mmm2d.hpp MMM2D algorithm for long range coulomb interaction in 2d+h geometries. Implementation of the MMM2D method for the calculation of the electrostatic interaction for two dimensionally periodic systems. For details on the method see MMM general. The @@ -50,6 +50,9 @@ typedef struct { int far_calculated; /// whether there is dielectric contrast int dielectric_contrast_on; + /// cont. potential parameters + int const_pot_on; + double pot_diff; /** dielectric contrasts at the bottom and top of the simulation cell */ double delta_mid_top, delta_mid_bot, delta_mult; } MMM2D_struct; @@ -67,7 +70,7 @@ extern MMM2D_struct mmm2d_params; @param delta_top dielectric contrast at top of the simulation box @param delta_mid dielectric contrast in the middle of the simulation box */ -int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double delta_mid); +int MMM2D_set_params(double maxPWerror, double far_cut, double delta_top, double delta_bot, int const_pot_on, double pot_diff); /** the general long range force/energy calculation */ double MMM2D_add_far(int f, int e); diff --git a/src/modes.cpp b/src/core/modes.cpp similarity index 86% rename from src/modes.cpp rename to src/core/modes.cpp index 627d304b427..6da8833852d 100644 --- a/src/modes.cpp +++ b/src/core/modes.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,8 +19,8 @@ along with this program. If not, see . */ -/** \file modes.c - Implementation of \ref modes.h "modes.h" +/** \file modes.cpp + Implementation of \ref modes.hpp "modes.h" */ #include "modes.hpp" @@ -63,7 +63,7 @@ double stray_cut_off = 10000000.0; void fold_all ( void ) { int i ; - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,xdir); fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,ydir); fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,zdir); @@ -82,10 +82,10 @@ double calc_zref ( int tmpzdir ) { /* Find the mean z position of folded particles*/ zref = 0; - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { zref += partCfg[i].r.p[zdir]; } - zref = zref/(double)(n_total_particles); + zref = zref/(double)(n_part); return zref; } @@ -109,19 +109,19 @@ void map_to_2dgrid() { /* Find the grid normal */ for ( i = 0 ; i < 3 ; i++) { if ( mode_grid_3d[i] == 0 ) { - if (zdir != -1 ) { /* grid normal must be unique */ - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{029 fft_modes_init: grid dimensions are <%d,%d,%d>, but one and only one must be = 0} ", - mode_grid_3d[0],mode_grid_3d[1],mode_grid_3d[2]); + if (zdir != -1 ) { /* grid normal must be unique */ + ostringstream msg; + msg <<"fft_modes_init: grid dimensions are <" << mode_grid_3d[0] << "," << mode_grid_3d[1] << "," << mode_grid_3d[2] << ">, but one and only one must be = 0"; + runtimeError(msg); return; } else { zdir = i; } } else if ( mode_grid_3d[i] < 0 ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{030 fft_modes_init: grid dimensions are <%d,%d,%d>, but all must be >= 0} ", - mode_grid_3d[0],mode_grid_3d[1],mode_grid_3d[2]); + ostringstream msg; + msg <<"fft_modes_init: grid dimensions are <" << mode_grid_3d[0] << "," << mode_grid_3d[1] << "," << mode_grid_3d[2] << ">, but all must be >= 0"; + runtimeError(msg); return; } else { @@ -131,9 +131,9 @@ void map_to_2dgrid() { } /* Check that grid normal was found */ if ( zdir == -1 ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{031 fft_modes_init: grid dimensions are <%d,%d,%d>, but one and only one must be = 0} ", - mode_grid_3d[0],mode_grid_3d[1],mode_grid_3d[2]); + ostringstream msg; + msg <<"fft_modes_init: grid dimensions are <" << mode_grid_3d[0] << "," << mode_grid_3d[1] << "," << mode_grid_3d[2] << ">, but one and only one must be = 0"; + runtimeError(msg); return; } STAT_TRACE(fprintf(stderr, @@ -143,17 +143,17 @@ void map_to_2dgrid() { /* Now that we know the grid normal check that the other two dimensions are equal and multiples of 2 */ if ( mode_grid_3d[xdir] != mode_grid_3d[ydir] ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{032 fft_modes_init: grid dimensions are <%d,%d,%d>, but two must be equal and the other 0} ", - mode_grid_3d[xdir],mode_grid_3d[ydir],mode_grid_3d[zdir]); + ostringstream msg; + msg <<"fft_modes_init: grid dimensions are <" << mode_grid_3d[xdir] << "," << mode_grid_3d[ydir] << "," << mode_grid_3d[zdir] << ">, but two must be equal and the other 0"; + runtimeError(msg); return; } if ( (mode_grid_3d[xdir]/2.0 - floor(mode_grid_3d[xdir]/2.0) > MODES2D_NUM_TOL) || (mode_grid_3d[ydir]/2.0 - floor(mode_grid_3d[ydir]/2.0) > MODES2D_NUM_TOL) ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{033 fft_modes_init: grid dimensions are <%d,%d,%d>. All non zero values must be integer multiples of 2} ", - mode_grid_3d[xdir],mode_grid_3d[ydir],mode_grid_3d[zdir]); + ostringstream msg; + msg <<"fft_modes_init: grid dimensions are <" << mode_grid_3d[xdir] << "," << mode_grid_3d[ydir] << "," << mode_grid_3d[zdir] << ">, All non zero values must be integer multiples of 2"; + runtimeError(msg); return; } } @@ -194,8 +194,9 @@ int orient_order(double* result, double* stored_dirs) updatePartCfg(WITHOUT_BONDS); /* Make sure particles are sorted */ if (!sortPartCfg()) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{035 could not sort partCfg, particles have to start at 0 and have consecutive identities} "); + ostringstream msg; + msg <<"could not sort partCfg, particles have to start at 0 and have consecutive identities"; + runtimeError(msg); return ES_ERROR; } @@ -352,8 +353,9 @@ int get_lipid_orients(IntList* l_orient) { double* height_grid; if ( xdir + ydir + zdir == -3 || mode_grid_3d[xdir] <= 0 || mode_grid_3d[ydir] <= 0 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{036 cannot calculate lipid orientations with uninitialized grid} "); + ostringstream msg; + msg <<"cannot calculate lipid orientations with uninitialized grid"; + runtimeError(msg); return ES_ERROR; } @@ -369,14 +371,17 @@ int get_lipid_orients(IntList* l_orient) { /* Update particles */ updatePartCfg(WITHOUT_BONDS); //Make sure particles are sorted + if (!sortPartCfg()) { - fprintf(stderr,"%d,could not sort partCfg \n",this_node); + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); return -1; } - if ( !calc_fluctuations(height_grid, 1) ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } "); + ostringstream msg; + msg <<"calculation of height grid failed"; + runtimeError(msg); return -1; } @@ -426,8 +431,9 @@ int modes2d(fftw_complex* modes, int switch_fluc) { if ( mode_grid_changed ) { STAT_TRACE(fprintf(stderr,"%d,initializing fftw for mode analysis \n",this_node)); if ( xdir + ydir + zdir == -3 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{092 attempt to perform mode analysis with uninitialized grid} "); + ostringstream msg; + msg <<"attempt to perform mode analysis with uninitialized grid"; + runtimeError(msg); return -1; } @@ -452,14 +458,17 @@ int modes2d(fftw_complex* modes, int switch_fluc) { /* Update particles */ updatePartCfg(WITHOUT_BONDS); //Make sure particles are sorted + if (!sortPartCfg()) { - fprintf(stderr,"%d,could not sort partCfg \n",this_node); + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); return -1; } - if ( !calc_fluctuations(height_grid, switch_fluc)) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } "); + ostringstream msg; + msg <<"calculation of height grid failed"; + runtimeError(msg); return -1; } @@ -510,14 +519,16 @@ int bilayer_density_profile_sphere (IntList *beadids, double rrange , DoubleList updatePartCfg(WITHOUT_BONDS); //Make sure particles are sorted if (!sortPartCfg()) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{094 could not sort partCfg} "); + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); return -1; } if ( density_profile == NULL ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{095 density_profile not initialized in calc_bilayer_density_profile } "); + ostringstream msg; + msg <<"density_profile not initialized in calc_bilayer_density_profile"; + runtimeError(msg); return -1; } @@ -525,7 +536,7 @@ int bilayer_density_profile_sphere (IntList *beadids, double rrange , DoubleList fold_all( ); - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { for ( j = 0 ; j < nbeadtypes ; j++ ) { if ( beadids->e[j] == partCfg[i].p.type ) { /* What is the relative height compared to the grid */ @@ -535,9 +546,10 @@ int bilayer_density_profile_sphere (IntList *beadids, double rrange , DoubleList /* If the particle is within our zrange then add it to the profile */ if ( ( -rrange < relativeradius) && ( relativeradius < rrange) ) { thisbin = (int)(floor((relativeradius+rrange)/binwidth)); - if ( thisbin < 0 || thisbin >= density_profile[j].max ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{095 bin is outside range } "); + if ( thisbin < 0 || thisbin >= density_profile[j].max ) { + ostringstream msg; + msg <<"bin is outside range "; + runtimeError(msg); return -1; } @@ -599,8 +611,9 @@ int bilayer_density_profile ( IntList *beadids, double hrange , DoubleList *dens /* Check to see that there is a mode grid to work with */ if ( xdir + ydir + zdir == -3 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{092 attempt to perform mode analysis with uninitialized grid} "); + ostringstream msg; + msg <<"attempt to perform mode analysis with uninitialized grid"; + runtimeError(msg); return -1; } @@ -613,8 +626,9 @@ int bilayer_density_profile ( IntList *beadids, double hrange , DoubleList *dens /* Calculate the height grid which also ensures that particle config is updated */ if ( !calc_fluctuations(tmp_height_grid, 1) ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } "); + ostringstream msg; + msg <<"calculation of height grid failed"; + runtimeError(msg); return -1; } @@ -624,14 +638,15 @@ int bilayer_density_profile ( IntList *beadids, double hrange , DoubleList *dens binwidth = hrange*2.0/(double)(nbins); if ( density_profile == NULL ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{095 density_profile not initialized in calc_bilayer_density_profile } "); + ostringstream msg; + msg <<"density_profile not initialized in calc_bilayer_density_profile"; + runtimeError(msg); return -1; } zref = calc_zref( tmpzdir ); - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { for ( j = 0 ; j < nbeadtypes ; j++ ) { if ( beadids->e[j] == partCfg[i].p.type ) { @@ -701,8 +716,9 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { } else { if (switch_fluc == 0) { STAT_TRACE(fprintf(stderr,"%d,calculating thickness \n",this_node)); } else { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{097 Wrong argument in calc_fluctuations function} "); + ostringstream msg; + msg <<"Wrong argument in calc_fluctuations function"; + runtimeError(msg); return -1; } } @@ -733,15 +749,17 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { if ( xdir + ydir + zdir == -3 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{092 attempt to calculate height grid / thickness with uninitialized grid} "); + ostringstream msg; + msg <<"attempt to calculate height grid / thickness with uninitialized grid"; + runtimeError(msg); return -1; } if ( height_grid == NULL ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{093 you must allocate memory for the height grid / thickness first} "); + ostringstream msg; + msg <<"you must allocate memory for the height grid / thickness first"; + runtimeError(msg); return -1; } @@ -773,8 +791,9 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { updatePartCfg(WITHOUT_BONDS); //Make sure particles are sorted if (!sortPartCfg()) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{094 could not sort partCfg} "); + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); return -1; } @@ -784,7 +803,7 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { zref = calc_zref( zdir ); /* Calculate an initial height function of all particles */ - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { gi = floor( partCfg[i].r.p[xdir]/grid_size[xdir] ); gj = floor( partCfg[i].r.p[ydir]/grid_size[ydir] ); height_grid[gj + gi*mode_grid_3d[xdir]] += partCfg[i].r.p[zdir]; @@ -809,7 +828,7 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { /* Calculate the non normalized height function based on all lipids */ nup = ndown = nstray = nrealstray = 0; - for (i = 0 ; i < n_total_particles ; i++) { + for (i = 0 ; i < n_part ; i++) { gi = floor( partCfg[i].r.p[xdir]/grid_size[xdir] ); gj = floor( partCfg[i].r.p[ydir]/grid_size[ydir] ); @@ -901,9 +920,10 @@ int calc_fluctuations ( double* height_grid, int switch_fluc ) { } } } - if ( nonzerocnt == 0 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{095 hole in membrane} "); + if ( nonzerocnt == 0 ) { + ostringstream msg; + msg <<"hole in membrane"; + runtimeError(msg); return -1; } gapcnt++; diff --git a/src/modes.hpp b/src/core/modes.hpp similarity index 96% rename from src/modes.hpp rename to src/core/modes.hpp index f6f84f7ec53..127e2f7ab18 100644 --- a/src/modes.hpp +++ b/src/core/modes.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef MODES_H #define MODES_H -/** \file modes.h +/** \file modes.hpp PLEASE INSERT DESCRIPTION */ @@ -62,7 +62,7 @@ extern int zdir; extern int mode_grid_changed; /** Parameter indicating distance beyond which a lipid is said to have - left the membrane the default value is set in \ref modes.c */ + left the membrane the default value is set in \ref modes.cpp */ extern double stray_cut_off; /* Exported Functions */ diff --git a/src/mol_cut.cpp b/src/core/mol_cut.cpp similarity index 91% rename from src/mol_cut.cpp rename to src/core/mol_cut.cpp index 96d84a96a25..65652acb906 100644 --- a/src/mol_cut.cpp +++ b/src/core/mol_cut.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mol_cut.c +/** \file mol_cut.cpp * - * Implementation of \ref mol_cut.h + * Implementation of \ref mol_cut.hpp */ #include "utils.hpp" diff --git a/src/mol_cut.hpp b/src/core/mol_cut.hpp similarity index 96% rename from src/mol_cut.hpp rename to src/core/mol_cut.hpp index 2e4f6357263..a3372d66c57 100644 --- a/src/mol_cut.hpp +++ b/src/core/mol_cut.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/molforces.cpp b/src/core/molforces.cpp similarity index 94% rename from src/molforces.cpp rename to src/core/molforces.cpp index 7c466433488..26fa6288ccd 100644 --- a/src/molforces.cpp +++ b/src/core/molforces.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -29,7 +29,7 @@ #include "communication.hpp" #include "forces.hpp" -/** \file molforces.c +/** \file molforces.cpp * Routines for calculating and applying trap forces upon molecules. * This trap force can be set to * - a harmonic potential with a restlength of zero on the molecular centre of mass @@ -38,7 +38,7 @@ * The centre of mass can be fixed to an absolute position or to a relative position in the * simulation box. * The molecular trap forces is distributed evenly upon all particles in a molecule. - * (see \ref topology.c and \ref molforces.c) + * (see \ref topology.cpp and \ref molforces.cpp) */ #ifdef MOLFORCES @@ -80,8 +80,9 @@ void calc_trap_force() if ( !topo_part_info_synced ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{ 093 can't calculate moltrap: must execute analyse set topo_part_sync first }"); + ostringstream msg; + msg <<"can't calculate moltrap: must execute analyse set topo_part_sync first"; + runtimeError(msg); return; } else { @@ -132,8 +133,9 @@ void get_local_trapped_mols (IntList *local_trapped_mols) for(i = 0; i < local_cells.cell[c]->n; i++) { mol = local_cells.cell[c]->part[i].p.mol_id; if ( mol >= n_molecules ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol); + ostringstream msg; + msg <<"can't calculate molforces no such molecule as " << mol ; + runtimeError(msg); return; } @@ -185,8 +187,9 @@ void calc_local_mol_info (IntList *local_trapped_mols) for(i = 0; i < np; i++) { mol = p[i].p.mol_id; if ( mol >= n_molecules ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol); + ostringstream msg; + msg <<"can't calculate molforces no such molecule as " << mol; + runtimeError(msg); return; } @@ -201,7 +204,12 @@ void calc_local_mol_info (IntList *local_trapped_mols) if (fixed) { topology[mol].mass += PMASS(p[i]); /* Unfold the particle */ +#ifdef LEES_EDWARDS + unfold_position(p[i].r.p, p[i].m.v, p[i].l.i); +#else unfold_position(p[i].r.p,p[i].l.i); +#endif + for ( j = 0 ; j < 3 ; j++ ) { topology[mol].f[j] += p[i].f.f[j]; topology[mol].com[j] += p[i].r.p[j]*PMASS(p[i]); @@ -377,8 +385,9 @@ void calc_mol_info () { /* check to see if all the topology information has been synced to the various slave nodes */ if ( !topo_part_info_synced ) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{ 093 can't calculate molforces: must execute analyse set topo_part_sync first }"); + ostringstream msg; + msg << "can't calculate molforces: must execute analyse set topo_part_sync first"; + runtimeError(msg); return; } diff --git a/src/molforces.hpp b/src/core/molforces.hpp similarity index 91% rename from src/molforces.hpp rename to src/core/molforces.hpp index e3f8f39dc65..1c93c6bb7c2 100644 --- a/src/molforces.hpp +++ b/src/core/molforces.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -23,7 +23,7 @@ #include "utils.hpp" #include "grid.hpp" -/** \file molforces.h +/** \file molforces.hpp * Routines for calculating and applying trap forces upon molecules. * This trap force can be set to * - a harmonic potential with a restlength of zero on the molecular centre of mass @@ -32,7 +32,7 @@ * The centre of mass can be fixed to an absolute position or to a relative position in the * simulation box. * The molecular trap forces is distributed evenly upon all particles in a molecule. - * (see file \ref topology.c and file \ref molforces.c) + * (see file \ref topology.cpp and file \ref molforces.cpp) */ #ifdef MOLFORCES diff --git a/src/morse.cpp b/src/core/morse.cpp similarity index 96% rename from src/morse.cpp rename to src/core/morse.cpp index 0b69892a066..11533834ad0 100644 --- a/src/morse.cpp +++ b/src/core/morse.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file morse.c +/** \file morse.cpp * - * Implementation of \ref morse.h + * Implementation of \ref morse.hpp */ #include "morse.hpp" #include "communication.hpp" diff --git a/src/morse.hpp b/src/core/morse.hpp similarity index 98% rename from src/morse.hpp rename to src/core/morse.hpp index c3f440f89ea..1a3ca86dc20 100644 --- a/src/morse.hpp +++ b/src/core/morse.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef _MORSE_H #define _MORSE_H -/** \file morse.h +/** \file morse.hpp * Routines to calculate the lennard jones energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/mpifake/mpi.cpp b/src/core/mpifake/mpi.cpp similarity index 97% rename from src/mpifake/mpi.cpp rename to src/core/mpifake/mpi.cpp index 865d1c82d54..c762b17d543 100644 --- a/src/mpifake/mpi.cpp +++ b/src/core/mpifake/mpi.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mpi.c +/** \file mpi.cpp * * For more information about MPIFake, see \ref mpi.h "mpi.h". */ @@ -134,6 +134,11 @@ int MPI_Type_vector(int count, int length, int stride, } int MPI_Type_hvector(int count, int length, int stride, + MPI_Datatype oldtype, MPI_Datatype *newtype) { + return MPI_Type_create_hvector(count, length, stride, oldtype, newtype); +} + +int MPI_Type_create_hvector(int count, int length, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype) { struct mpifake_dtype *ntype; diff --git a/src/mpifake/mpi.h b/src/core/mpifake/mpi.h similarity index 91% rename from src/mpifake/mpi.h rename to src/core/mpifake/mpi.h index f1814990881..c1c8240c8b3 100644 --- a/src/mpifake/mpi.h +++ b/src/core/mpifake/mpi.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -24,8 +24,8 @@ you do not have to have any MPI implementation like LAM or MPICH installed. */ -#ifndef MPI_H -#define MPI_H +#ifndef _MPI_H +#define _MPI_H #include #include @@ -35,10 +35,6 @@ void errexit(); -#ifndef inline - #define inline static inline -#endif - /********************************** REMARK **********************/ /* This is the fake MPI header of Espresso, and has nothing to */ @@ -102,6 +98,7 @@ int mpifake_sendrecv(void *s, int scount, MPI_Datatype sdtype, #define MPI_REQUEST_NULL NULL #define MPI_ANY_SOURCE 0 +#define MPI_ANY_TAG 0 #define MPI_IN_PLACE (void*)0x1 @@ -126,6 +123,7 @@ int MPI_Type_struct(int count, int *lengths, MPI_Aint *disps, MPI_Datatype *oldt int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype); int MPI_Type_vector(int count, int length, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype); int MPI_Type_hvector(int count, int length, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype); +int MPI_Type_create_hvector(int count, int length, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype); inline int MPI_Init(int *a, char ***b) { return MPI_SUCCESS; } inline int MPI_Finalize(void) { return MPI_SUCCESS; } @@ -143,12 +141,20 @@ inline int MPI_Comm_free(MPI_Comm *comm) { return MPI_SUCCESS; } inline int MPI_Type_commit(MPI_Datatype *dtype) { return MPI_SUCCESS; } inline int MPI_Type_free(MPI_Datatype *dtype) { free(*dtype); *dtype = NULL; return MPI_SUCCESS; } inline int MPI_Type_extent(MPI_Datatype dtype, MPI_Aint *pextent) { *pextent = dtype->upper - dtype->lower; return MPI_SUCCESS; } +inline int MPI_Type_get_extent(MPI_Datatype dtype, MPI_Aint *lower, MPI_Aint *pextent) { + *lower = dtype->lower; + *pextent = dtype->upper - dtype->lower; + return MPI_SUCCESS; +} inline int MPI_Barrier(MPI_Comm comm) { return MPI_SUCCESS; } inline int MPI_Waitall(int count, MPI_Request *reqs, MPI_Status *stats) { return MPI_SUCCESS; } inline int MPI_Wait(MPI_Request *reqs, MPI_Status *stats) { return MPI_SUCCESS; } -inline int MPI_Errhandler_create(MPI_Handler_function *errfunc, MPI_Errhandler *errhdl) { return MPI_SUCCESS; } -inline int MPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhdl) { return MPI_SUCCESS; } +inline int MPI_Comm_create_errhandler(MPI_Handler_function *errfunc, MPI_Errhandler *errhdl) { return MPI_SUCCESS; } +inline int MPI_Comm_set_errhandler(MPI_Comm comm, MPI_Errhandler errhdl) { return MPI_SUCCESS; } inline int MPI_Bcast(void *buff, int count, MPI_Datatype datatype, int root, MPI_Comm comm) { return MPI_SUCCESS; } +inline int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status) { return MPI_SUCCESS; } +inline int MPI_Get_count(const MPI_Status *status, MPI_Datatype datatype, int *count) { count = 0; return MPI_SUCCESS; } + #ifndef GNU_MPIFAKE_DEBUG diff --git a/src/myconfig-default.hpp b/src/core/myconfig-default.hpp similarity index 80% rename from src/myconfig-default.hpp rename to src/core/myconfig-default.hpp index e0ba22276d7..37e5963d691 100644 --- a/src/myconfig-default.hpp +++ b/src/core/myconfig-default.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/* This is the default myconfig.h-file. If no other myconfig-file is +/* This is the default myconfig.hpp-file. If no other myconfig-file is found, this file is used. + + DO NOT MODIFY THIS FILE! It should be modified *only* by the + maintainers of ESPResSo, as it has a profound impact on many users, + in particular newbies. */ /* global features */ #define PARTIAL_PERIODIC diff --git a/src/nemd.cpp b/src/core/nemd.cpp similarity index 94% rename from src/nemd.cpp rename to src/core/nemd.cpp index 77ca6c89d74..adc0de6256d 100644 --- a/src/nemd.cpp +++ b/src/core/nemd.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file nemd.c +/** \file nemd.cpp - For more information see \ref nemd.h + For more information see \ref nemd.hpp */ #include "nemd.hpp" #include @@ -74,8 +74,9 @@ void nemd_init(int n_slabs, int n_exchange, double shear_rate) /* check node grid */ if( n_nodes > 1 ) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{037 NEMD is a single node feature} "); + ostringstream msg; + msg <<"NEMD is a single node feature"; + runtimeError(msg); return; } @@ -151,8 +152,9 @@ void nemd_change_momentum() INTEG_TRACE(fprintf(stderr,"%d: parts_in_slabs: top %d mid %d\n",this_node,top_slab->n_parts_in_slab,mid_slab->n_parts_in_slab)); if(mid_slab->n_fastest != nemddata.n_exchange || top_slab->n_fastest != nemddata.n_exchange) { - char *errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{038 nemd_exchange_momentum: Not enough particles in slab!} "); + ostringstream msg; + msg <<"nemd_exchange_momentum: Not enough particles in slab!"; + runtimeError(msg); /* cannot continue */ return; } diff --git a/src/nemd.hpp b/src/core/nemd.hpp similarity index 98% rename from src/nemd.hpp rename to src/core/nemd.hpp index c32570977d1..dd8ec5e756c 100644 --- a/src/nemd.hpp +++ b/src/core/nemd.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef NEMD_H #define NEMD_H -/** \file nemd.h +/** \file nemd.hpp This file contains the implementation of the NEMD (Non Equilibrium Molecular Dynamics) algorithm. It allows one to shear a system diff --git a/src/npt.hpp b/src/core/npt.hpp similarity index 97% rename from src/npt.hpp rename to src/core/npt.hpp index b3ce2961da3..d5f76096fdd 100644 --- a/src/npt.hpp +++ b/src/core/npt.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file npt.h +/** \file npt.hpp exports for the NPT code, which otherwise is really spread all over... */ diff --git a/src/nsquare.cpp b/src/core/nsquare.cpp similarity index 97% rename from src/nsquare.cpp rename to src/core/nsquare.cpp index cac09ec3182..3b9f59b8c0c 100644 --- a/src/nsquare.cpp +++ b/src/core/nsquare.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file nsquare.c +/** \file nsquare.cpp * - * Implementation of \ref nsquare.h "nsquare.h". + * Implementation of \ref nsquare.hpp "nsquare.h". */ #include @@ -31,7 +31,7 @@ #include "ghosts.hpp" #include "forces.hpp" #include "pressure.hpp" -#include "energy.hpp" +#include "energy_inline.hpp" #include "constraint.hpp" Cell *local; @@ -164,7 +164,7 @@ void nsq_balance_particles(int global_flag) int pp = cells_get_n_particles(); int *ppnode = (int*)malloc(n_nodes*sizeof(int)); /* minimal difference between node shares */ - int minshare = n_total_particles/n_nodes; + int minshare = n_part/n_nodes; int maxshare = minshare + 1; CELL_TRACE(fprintf(stderr, "%d: nsq_balance_particles: load %d-%d\n", this_node, minshare, maxshare)); @@ -256,6 +256,7 @@ void nsq_calculate_ia() #ifdef CONSTRAINTS add_constraints_forces(pt1); #endif + add_external_potential_forces(pt1); if (rebuild_verletlist) memcpy(pt1->l.p_old, pt1->r.p, 3*sizeof(double)); @@ -310,6 +311,7 @@ void nsq_calculate_energies() #ifdef CONSTRAINTS add_constraints_energy(pt1); #endif + add_external_potential_energy(pt1); if (rebuild_verletlist) memcpy(pt1->l.p_old, pt1->r.p, 3*sizeof(double)); diff --git a/src/nsquare.hpp b/src/core/nsquare.hpp similarity index 97% rename from src/nsquare.hpp rename to src/core/nsquare.hpp index ba59270d2b4..ae483debc6b 100644 --- a/src/nsquare.hpp +++ b/src/core/nsquare.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef NSQUARE_H #define NSQUARE_H -/** \file nsquare.h +/** \file nsquare.hpp This file contains the code for a simple n^2 particle loop. The nsquare cell system performs a full n^2 particle interaction diff --git a/src/object-in-fluid/area_force_global.cpp b/src/core/object-in-fluid/area_force_global.cpp similarity index 93% rename from src/object-in-fluid/area_force_global.cpp rename to src/core/object-in-fluid/area_force_global.cpp index 4bef57807fb..a3d04922719 100644 --- a/src/object-in-fluid/area_force_global.cpp +++ b/src/core/object-in-fluid/area_force_global.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/** \file area_force_global.h +/** \file area_force_global.hpp * Routines to calculate the AREA_FORCE_GLOBAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "area_force_global.hpp" diff --git a/src/object-in-fluid/area_force_global.hpp b/src/core/object-in-fluid/area_force_global.hpp similarity index 69% rename from src/object-in-fluid/area_force_global.hpp rename to src/core/object-in-fluid/area_force_global.hpp index 34b79b1f444..7c3c817c6d2 100644 --- a/src/object-in-fluid/area_force_global.hpp +++ b/src/core/object-in-fluid/area_force_global.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_AREA_FORCE_GLOBAL_H #define _OBJECT_IN_FLUID_AREA_FORCE_GLOBAL_H -/** \file area_force_global.h +/** \file area_force_global.hpp * Routines to calculate the AREA_FORCE_GLOBAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -37,7 +37,7 @@ int area_force_global_set_params(int bond_type, double A0_g, double ka_g); /************************************************************/ -/** called in force_calc() from within forces.c +/** called in force_calc() from within forces.cpp * calculates the global area for a cell before the forces are handled * sums up parts for area with mpi_reduce from local triangles * synchronization with allreduce @@ -53,10 +53,13 @@ inline void calc_area_global(double *area, int molType){ //first-fold-then-the-s Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; +#ifdef LEES_EDWARDS + double vv[3]; +#endif int img[3]; Bonded_ia_parameters *iaparams; - int type_num, type, n_partners,id; - char *errtxt; + int type_num, n_partners,id; + BondedInteraction type; int test=0; @@ -82,32 +85,44 @@ inline void calc_area_global(double *area, int molType){ //first-fold-then-the-s test++; /* fetch particle 2 */ p2 = local_particles[p1->bl.e[j++]]; - if (!p2) { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{area calc 078 bond broken between particles %d and %d (particles not stored on the same node - area_force_global1); n %d max %d} ", - p1->p.identity, p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p2) { + ostringstream msg; + msg <<"area calc: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - area_force_global1); n " << p1->bl.n << " max " << p1->bl.max ; + runtimeError(msg); return; } /* fetch particle 3 */ //if(n_partners>2){ p3 = local_particles[p1->bl.e[j++]]; - if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{area calc 079 bond broken between particles %d, %d and %d (particles not stored on the same node); n %d max %d} ", - p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p3) { + ostringstream msg; + msg <<"area calc: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - area_force_global1); n " << p1->bl.n << " max " << p1->bl.max ; + runtimeError(msg); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); - fold_position(p11, img); - +#ifdef LEES_EDWARDS + fold_position(p11, vv, img); +#else + fold_position(p11, img); +#endif + memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); - fold_position(p22, img); +#ifdef LEES_EDWARDS + fold_position(p22, vv, img); +#else + fold_position(p22, img); +#endif memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); - fold_position(p33, img); +#ifdef LEES_EDWARDS + fold_position(p33, vv, img); +#else + fold_position(p33, img); +#endif get_n_triangle(p11,p22,p33,norm); @@ -134,11 +149,14 @@ inline void add_area_global_force(double area, int molType){ //first-fold-then- Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; +#ifdef LEES_EDWARDS + double vv[3]; +#endif int img[3]; Bonded_ia_parameters *iaparams; - int type_num, type, n_partners,id; - char *errtxt; + int type_num, n_partners,id; + BondedInteraction type; int test=0; @@ -166,32 +184,44 @@ inline void add_area_global_force(double area, int molType){ //first-fold-then- test++; /* fetch particle 2 */ p2 = local_particles[p1->bl.e[j++]]; - if (!p2) { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"add area {078 bond broken between particles %d and %d (particles not stored on the same node - area_force_global2)}; n %d max %d ", - p1->p.identity, p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p2) { + ostringstream msg; + msg <<"add area: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - area_force_global2); n " << p1->bl.n << " max " << p1->bl.max ; + runtimeError(msg); return; } /* fetch particle 3 */ //if(n_partners>2){ p3 = local_particles[p1->bl.e[j++]]; - if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"add area {079 bond broken between particles %d, %d and %d (particles not stored on the same node)}; n %d max %d ", - p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p3) { + ostringstream msg; + msg <<"add area: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node); n " << p1->bl.n << " max " << p1->bl.max; + runtimeError(msg); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); - fold_position(p11, img); +#ifdef LEES_EDWARDS + fold_position(p11, vv, img); +#else + fold_position(p11, img); +#endif memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); - fold_position(p22, img); +#ifdef LEES_EDWARDS + fold_position(p22, vv, img); +#else + fold_position(p22, img); +#endif memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); - fold_position(p33, img); +#ifdef LEES_EDWARDS + fold_position(p33, vv, img); +#else + fold_position(p33, img); +#endif diff --git a/src/object-in-fluid/area_force_local.cpp b/src/core/object-in-fluid/area_force_local.cpp similarity index 93% rename from src/object-in-fluid/area_force_local.cpp rename to src/core/object-in-fluid/area_force_local.cpp index aec55ad4f04..0d5fd966d6b 100644 --- a/src/object-in-fluid/area_force_local.cpp +++ b/src/core/object-in-fluid/area_force_local.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/** \file area_force_local.h +/** \file area_force_local.hpp * Routines to calculate the AREA_FORCE_LOCAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "area_force_local.hpp" diff --git a/src/object-in-fluid/area_force_local.hpp b/src/core/object-in-fluid/area_force_local.hpp similarity index 90% rename from src/object-in-fluid/area_force_local.hpp rename to src/core/object-in-fluid/area_force_local.hpp index d6bde58a94c..8a98c2ee695 100644 --- a/src/object-in-fluid/area_force_local.hpp +++ b/src/core/object-in-fluid/area_force_local.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_AREA_FORCE_LOCAL_H #define _OBJECT_IN_FLUID_AREA_FORCE_LOCAL_H -/** \file area_force_local.h +/** \file area_force_local.hpp * Routines to calculate the AREA_FORCE_LOCAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -50,19 +50,34 @@ inline int calc_area_force_local(Particle *p1, Particle *p2, Particle *p3, int k; double A, aa, h[3], rh[3], hn; double p11[3],p22[3],p33[3]; +#ifdef LEES_EDWARDS + double vv[3]; +#endif int img[3]; memcpy(p11, p1->r.p, 3*sizeof(double)); memcpy(img, p1->l.i, 3*sizeof(int)); - fold_position(p11, img); - +#ifdef LEES_EDWARDS + fold_position(p11, vv, img); +#else + fold_position(p11, img); +#endif memcpy(p22, p2->r.p, 3*sizeof(double)); memcpy(img, p2->l.i, 3*sizeof(int)); - fold_position(p22, img); + +#ifdef LEES_EDWARDS + fold_position(p22, vv, img); +#else + fold_position(p22, img); +#endif memcpy(p33, p3->r.p, 3*sizeof(double)); memcpy(img, p3->l.i, 3*sizeof(int)); - fold_position(p33, img); +#ifdef LEES_EDWARDS + fold_position(p33, vv, img); +#else + fold_position(p33, img); +#endif for(k=0;k<3;k++) h[k]=1.0/3.0 *(p11[k]+p22[k]+p33[k]); //volume+=A * -n[2]/dn * h[2]; diff --git a/src/object-in-fluid/bending_force.cpp b/src/core/object-in-fluid/bending_force.cpp similarity index 90% rename from src/object-in-fluid/bending_force.cpp rename to src/core/object-in-fluid/bending_force.cpp index aa88e99935f..34bebfac5ec 100644 --- a/src/object-in-fluid/bending_force.cpp +++ b/src/core/object-in-fluid/bending_force.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,7 +17,7 @@ along with this program. If not, see . */ -/** \file bending_force.h Routines to calculate the bending_force energy or/and +/** \file bending_force.hpp Routines to calculate the bending_force energy or/and * and force for a particle quadruple (two triangles that have 2 particles in common) */ diff --git a/src/object-in-fluid/bending_force.hpp b/src/core/object-in-fluid/bending_force.hpp similarity index 90% rename from src/object-in-fluid/bending_force.hpp rename to src/core/object-in-fluid/bending_force.hpp index de05ae10b8e..69fe9fc957b 100644 --- a/src/object-in-fluid/bending_force.hpp +++ b/src/core/object-in-fluid/bending_force.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,7 +18,7 @@ */ #ifndef _OBJECT_IN_FLUID_BENDING_FORCE_H #define _OBJECT_IN_FLUID_BENDING_FORCE_H -/** \file bending_force.h Routines to calculate the bending_force energy or/and +/** \file bending_force.hpp Routines to calculate the bending_force energy or/and * and force for a particle quadruple (two triangles that have 2 particles in common) */ @@ -27,6 +27,11 @@ #include "particle_data.hpp" #include "grid.hpp" +/*use a !locally defined only! macro for the imaging call, just for tidiness.*/ +#ifdef LEES_EDWARDS +#define fold_position(a, b) fold_position(a, vv, b) +#endif + /// set bending_force parameters int bending_force_set_params(int bond_type, double phi0, double kb); @@ -48,6 +53,9 @@ inline int calc_bending_force(Particle *p2, Particle *p1, Particle *p3, Particle double n1[3],n2[3],dn1,dn2,phi,aa,fac,penal; int k; double fp1[3],fp2[3],fp3[3],fp4[3]; +#ifdef LEES_EDWARDS + double vv[3]; +#endif int img[3]; memcpy(fp1, p1->r.p, 3*sizeof(double)); @@ -90,6 +98,6 @@ inline int calc_bending_force(Particle *p2, Particle *p1, Particle *p3, Particle } return 0; } - +#undef fold_position #endif diff --git a/src/object-in-fluid/stretching_force.cpp b/src/core/object-in-fluid/stretching_force.cpp similarity index 90% rename from src/object-in-fluid/stretching_force.cpp rename to src/core/object-in-fluid/stretching_force.cpp index b168fad33e2..d5b80df71fe 100644 --- a/src/object-in-fluid/stretching_force.cpp +++ b/src/core/object-in-fluid/stretching_force.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -16,9 +16,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file stretching_force.c +/** \file stretching_force.cpp * - * Implementation of \ref stretching_force.h + * Implementation of \ref stretching_force.hpp */ #include "stretching_force.hpp" diff --git a/src/object-in-fluid/stretching_force.hpp b/src/core/object-in-fluid/stretching_force.hpp similarity index 96% rename from src/object-in-fluid/stretching_force.hpp rename to src/core/object-in-fluid/stretching_force.hpp index 2bd17f9468e..bb2b3d94222 100644 --- a/src/object-in-fluid/stretching_force.hpp +++ b/src/core/object-in-fluid/stretching_force.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -23,10 +23,10 @@ #include "interaction_data.hpp" #include "particle_data.hpp" -/** \file stretching_force.h +/** \file stretching_force.hpp * Routines to calculate the STRETCHING_FORCE Energy or/and STRETCHING_FORCE force * for a particle pair. (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ /************************************************************/ diff --git a/src/object-in-fluid/stretchlin_force.cpp b/src/core/object-in-fluid/stretchlin_force.cpp similarity index 90% rename from src/object-in-fluid/stretchlin_force.cpp rename to src/core/object-in-fluid/stretchlin_force.cpp index 73170224db5..00da30b825e 100644 --- a/src/object-in-fluid/stretchlin_force.cpp +++ b/src/core/object-in-fluid/stretchlin_force.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -16,9 +16,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file stretchlin_force.c +/** \file stretchlin_force.cpp * - * Implementation of \ref stretchlin_force.h + * Implementation of \ref stretchlin_force.hpp */ #include "stretchlin_force.hpp" diff --git a/src/object-in-fluid/stretchlin_force.hpp b/src/core/object-in-fluid/stretchlin_force.hpp similarity index 96% rename from src/object-in-fluid/stretchlin_force.hpp rename to src/core/object-in-fluid/stretchlin_force.hpp index 6bdcbe519da..f279234cfb0 100644 --- a/src/object-in-fluid/stretchlin_force.hpp +++ b/src/core/object-in-fluid/stretchlin_force.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -23,10 +23,10 @@ #include "interaction_data.hpp" #include "particle_data.hpp" -/** \file stretchlin_force.h +/** \file stretchlin_force.hpp * Routines to calculate the STRETCHLIN_FORCE Energy or/and STRETCHLIN_FORCE force * for a particle pair. (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ /************************************************************/ diff --git a/src/object-in-fluid/volume_force.cpp b/src/core/object-in-fluid/volume_force.cpp similarity index 93% rename from src/object-in-fluid/volume_force.cpp rename to src/core/object-in-fluid/volume_force.cpp index 881cf7368b4..bfc0a75d6db 100644 --- a/src/object-in-fluid/volume_force.cpp +++ b/src/core/object-in-fluid/volume_force.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2013 The ESPResSo project + Copyright (C) 2010,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany This file is part of ESPResSo. @@ -18,10 +18,10 @@ along with this program. If not, see . */ -/** \file volume_force.h +/** \file volume_force.hpp * Routines to calculate the VOLUME_FORCE energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "volume_force.hpp" diff --git a/src/object-in-fluid/volume_force.hpp b/src/core/object-in-fluid/volume_force.hpp similarity index 73% rename from src/object-in-fluid/volume_force.hpp rename to src/core/object-in-fluid/volume_force.hpp index 706d29410d7..72459d24828 100644 --- a/src/object-in-fluid/volume_force.hpp +++ b/src/core/object-in-fluid/volume_force.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_VOLUME_FORCE_H #define _OBJECT_IN_FLUID_VOLUME_FORCE_H -/** \file volume_force.h +/** \file volume_force.hpp * Routines to calculate the VOLUME_FORCE energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -32,6 +32,11 @@ #include "grid.hpp" +//use a !locally defined only! macro for the imaging call, just for tidiness. +#ifdef LEES_EDWARDS +#define fold_position(a, b) fold_position(a, vvle, b) +#endif + /** set parameters for the VOLUME_FORCE potential. */ int volume_force_set_params(int bond_type, double V0, double kv); @@ -39,7 +44,7 @@ int volume_force_set_params(int bond_type, double V0, double kv); /************************************************************/ -/** called in force_calc() from within forces.c +/** called in force_calc() from within forces.cpp * calculates the volume for a cell before the forces are handled * sums up parts for volume with mpi_reduce from Dupin2007 (Equ. 13) * sends volume via mpi_send to nodes @@ -55,11 +60,14 @@ inline void calc_volume(double *volume, int molType){ //first-fold-then-the-same Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; +#ifdef LEES_EDWARDS + double vvle[3]; +#endif int img[3]; Bonded_ia_parameters *iaparams; - int type_num, type, n_partners, id; - char *errtxt; + int type_num, n_partners, id; + BondedInteraction type; //int test=0; //printf("rank%d, molType2: %d\n", rank,molType); @@ -83,18 +91,18 @@ inline void calc_volume(double *volume, int molType){ //first-fold-then-the-same if(type == BONDED_IA_VOLUME_FORCE && id == molType){ // BONDED_IA_VOLUME_FORCE with correct molType !!!!!!!!!!!!! needs area force local !!!!!!!!!!!!!!!!!! p2 = local_particles[p1->bl.e[j++]]; if (!p2) { - printf("broken: particles sum %d, id %d, partn %d, bond %d\n", np,id,n_partners,type_num); - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{volume calc 078 bond broken between particles %d and %d (particles not stored on the same node - volume_force1)} ", - p1->p.identity, p1->bl.e[j-1]); + printf("broken: particles sum %d, id %d, partn %d, bond %d\n", np,id,n_partners,type_num); + ostringstream msg; + msg <<"volume calc: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - volume_force1)"; + runtimeError(msg); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; - if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{volume calc 079 bond broken between particles %d, %d and %d (particles not stored on the same node); n %d max %d} ", - p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p3) { + ostringstream msg; + msg <<"volume calc: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node); n " << p1->bl.n << " max " << p1->bl.max; + runtimeError(msg); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); @@ -136,9 +144,12 @@ inline void add_volume_force(double volume, int molType){ //first-fold-then-the Cell *cell; Particle *p, *p1, *p2, *p3; double p11[3],p22[3],p33[3]; +#ifdef LEES_EDWARDS + double vvle[3]; +#endif Bonded_ia_parameters *iaparams; - int type_num, type, n_partners, id; - char *errtxt; + int type_num, n_partners, id; + BondedInteraction type; int test=0; @@ -164,18 +175,18 @@ inline void add_volume_force(double volume, int molType){ //first-fold-then-the test++; /* fetch particle 2 */ p2 = local_particles[p1->bl.e[j++]]; - if (!p2) { - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{volume add 078 bond broken between particles %d and %d (particles not stored on the same node - volume_force2)} ", - p1->p.identity, p1->bl.e[j-1]); + if (!p2) { + ostringstream msg; + msg <<"volume add: bond broken between particles " << p1->p.identity << " and " << p1->bl.e[j-1] << " (particles not stored on the same node - volume_force2)"; + runtimeError(msg); return; } /* fetch particle 3 */ p3 = local_particles[p1->bl.e[j++]]; - if (!p3) { - errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{volume add 079 bond broken between particles %d, %d and %d (particles not stored on the same node); n %d max %d} ", - p1->p.identity, p1->bl.e[j-2], p1->bl.e[j-1],p1->bl.n,p1->bl.max); + if (!p3) { + ostringstream msg; + msg <<"volume calc: bond broken between particles " << p1->p.identity << ", " << p1->bl.e[j-2] << " and " << p1->bl.e[j-1] << " (particles not stored on the same node); n " << p1->bl.n << " max " << p1->bl.max; + runtimeError(msg); return; } memcpy(p11, p1->r.p, 3*sizeof(double)); @@ -217,5 +228,6 @@ inline void add_volume_force(double volume, int molType){ //first-fold-then-the } +#undef fold_position #endif diff --git a/src/overlap.cpp b/src/core/overlap.cpp similarity index 93% rename from src/overlap.cpp rename to src/core/overlap.cpp index 731872c9f06..33576ba9734 100644 --- a/src/overlap.cpp +++ b/src/core/overlap.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file overlap.c +/** \file overlap.cpp * - * Implementation of \ref overlap.h + * Implementation of \ref overlap.hpp */ #include "utils.hpp" #include "overlap.hpp" @@ -29,7 +29,7 @@ #ifdef OVERLAPPED -int overlapped_bonded_set_params(int bond_type, int overlap_type, +int overlapped_bonded_set_params(int bond_type, OverlappedBondedInteraction overlap_type, char * filename) { int i, scan_success = 0, size; diff --git a/src/overlap.hpp b/src/core/overlap.hpp similarity index 92% rename from src/overlap.hpp rename to src/core/overlap.hpp index 0aa579837f5..3f5371ec580 100644 --- a/src/overlap.hpp +++ b/src/core/overlap.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -23,13 +23,13 @@ #ifndef _OVERLAP_H #define _OVERLAP_H -/** \file overlap.h +/** \file overlap.hpp * Routines to calculate the energy and/or force * for bonds, angles and dihedrals as a sum of N functions in the forms: * bonds --- parameter: [N, a_i, b_i, c_i], function: U(bond) = sum_(i=1,N) {a_i*exp[-(bond-b_i)^2 /(c_i^2)]}. * angles--- parameter: [N, a_i, b_i, c_i], function: U(cos(angl)) = sum_(i=1,N) {a_i*exp[-(cos(angl)-b_i)^2 / (2 * c_i^2)]}. * dihedrals---parameter: [N, a_i, b_i, c_i], function: U(dihe)= sum_(i=1,N) {a_i*(1+Math.cos(c_i*dihe+b_i))}. - * Require feature OVERLAPPED compiled in myconfig.h (for more info of FEATURES, see \ref config.h ). + * Require feature OVERLAPPED compiled in myconfig.hpp (for more info of FEATURES, see \ref config.hpp ). */ #ifdef OVERLAPPED @@ -37,18 +37,18 @@ /** Bonded overlapped potentials: Reads overlapped parameters from a file. ia_params are then communicated to each node \warning No checking is performed for the file read!! */ -int overlapped_bonded_set_params(int bond_type, int overlap_type, - char * filename); +int overlapped_bonded_set_params(int bond_type, OverlappedBondedInteraction overlap_type, + char * filename); /** Computes the two body overlapped bonded force. - Adds this force to the particle forces in forces.h (see \ref tclcommand_inter). + Adds this force to the particle forces in forces.hpp (see \ref tclcommand_inter). @param p1 Pointer to first particle. @param p2 Pointer to second/middle particle. @param iaparams bond type number of the angle interaction (see \ref tclcommand_inter). @param dx particle distance vector @param force returns force of particle 1 @return 0. - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int calc_overlap_bond_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force[3]) { @@ -92,7 +92,7 @@ inline int calc_overlap_bond_force(Particle *p1, Particle *p2, Bonded_ia_paramet @param dx particle distance vector @param _energy returns energy of this interaction @return 0. - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int overlap_bond_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy) { @@ -117,7 +117,7 @@ inline int overlap_bond_energy(Particle *p1, Particle *p2, Bonded_ia_parameters } /** Computes the three body overlapped angle interaction force. - Adds this force to the particle forces in forces.h (see \ref tclcommand_inter). + Adds this force to the particle forces in forces.hpp (see \ref tclcommand_inter). @param p_mid Pointer to second/middle particle. @param p_left Pointer to first/left particle. @param p_right Pointer to third/right particle. @@ -125,7 +125,7 @@ inline int overlap_bond_energy(Particle *p1, Particle *p2, Bonded_ia_parameters @param force1 returns force of particle 1 @param force2 returns force of particle 2 @return 0 - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int calc_overlap_angle_force(Particle *p_mid, Particle *p_left, Particle *p_right, Bonded_ia_parameters *iaparams, @@ -187,7 +187,7 @@ inline int calc_overlap_angle_force(Particle *p_mid, Particle *p_left, @param iaparams bond type number of the angle interaction (see \ref tclcommand_inter). @param _energy return energy pointer. @return 0. - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int overlap_angle_energy(Particle *p_mid, Particle *p_left, Particle *p_right, Bonded_ia_parameters *iaparams, @@ -232,14 +232,14 @@ inline int overlap_angle_energy(Particle *p_mid, Particle *p_left, } /** Computes the four body overlapped dihedral interaction force. - Adds this force to the particle forces in forces.h (see \ref tclcommand_inter). + Adds this force to the particle forces in forces.hpp (see \ref tclcommand_inter). @param p1, p2, p3, p4 define the angle between the planes p1,p2,p3 and p2,p3,p4 @param iaparams bond type number of the angle interaction (see \ref tclcommand_inter). @param force1 returns force of particle 1 @param force2 returns force of particle 2 @param force3 returns force of particle 3 @return 0 - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int calc_overlap_dihedral_force(Particle *p2, Particle *p1, Particle *p3, Particle *p4, Bonded_ia_parameters *iaparams, @@ -310,7 +310,7 @@ inline int calc_overlap_dihedral_force(Particle *p2, Particle *p1, @param iaparams bond type number of the angle interaction (see \ref tclcommand_inter). @param _energy return energy pointer. @return 0. - Needs feature OVERLAPPED compiled in (see \ref config.h). + Needs feature OVERLAPPED compiled in (see \ref config.hpp). */ inline int overlap_dihedral_energy(Particle *p2, Particle *p1, Particle *p3, Particle *p4, Bonded_ia_parameters *iaparams, diff --git a/src/p3m-common.cpp b/src/core/p3m-common.cpp similarity index 98% rename from src/p3m-common.cpp rename to src/core/p3m-common.cpp index 6e772bce7ee..532c59ee9e2 100644 --- a/src/p3m-common.cpp +++ b/src/core/p3m-common.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file p3m-common.c P3M main file. +/** \file p3m-common.cpp P3M main file. */ #include "p3m-common.hpp" diff --git a/src/p3m-common.hpp b/src/core/p3m-common.hpp similarity index 98% rename from src/p3m-common.hpp rename to src/core/p3m-common.hpp index 4dffe97fa50..5d0866cde57 100644 --- a/src/p3m-common.hpp +++ b/src/core/p3m-common.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _P3M_COMMON_H #define _P3M_COMMON_H -/** \file p3m-common.h common functions for dipolar and charge p3m. +/** \file p3m-common.hpp common functions for dipolar and charge p3m. * * We use here a P3M (Particle-Particle Particle-Mesh) method based * on the Ewald summation. Details of the used method can be found in diff --git a/src/p3m-dipolar.cpp b/src/core/p3m-dipolar.cpp similarity index 97% rename from src/p3m-dipolar.cpp rename to src/core/p3m-dipolar.cpp index 30f92b7bb8d..30f1b194663 100644 --- a/src/p3m-dipolar.cpp +++ b/src/core/p3m-dipolar.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file p3m-dipolar.c P3M algorithm for long range magnetic dipole-dipole interaction. +/** \file p3m-dipolar.cpp P3M algorithm for long range magnetic dipole-dipole interaction. * NB: In general the magnetic dipole-dipole functions bear the same name than the charge-charge but, adding in front of the name a D @@ -441,7 +441,7 @@ double dp3m_average_dipolar_self_energy(double box_l, int mesh) { MPI_Reduce(&node_phi, &phi, 1, MPI_DOUBLE, MPI_SUM, 0, comm_cart); - phi*=PI/3./box_l/pow(mesh,3); + phi*=PI/3./box_l/pow(mesh,3.0); return phi ; @@ -1174,7 +1174,7 @@ double calc_surface_term(int force_flag, int energy_flag) } #ifdef ROTATION if (force_flag) { - //fprintf(stderr," number of particles= %d ",n_total_particles); + //fprintf(stderr," number of particles= %d ",n_part); double *sumix = (double *) malloc(sizeof(double)*n_local_part); double *sumiy = (double *) malloc(sizeof(double)*n_local_part); @@ -1186,7 +1186,7 @@ double calc_surface_term(int force_flag, int energy_flag) sumiz[i]=mx[i]*a[1]-my[i]*a[0]; } - // for (i = 0; i < n_total_particles; i++){ + // for (i = 0; i < n_part; i++){ // fprintf(stderr,"part %d, correccions torque x:%le, y:%le, z:%le\n",i,sumix[i],sumiy[i],sumiz[i]); // } @@ -1687,8 +1687,9 @@ static double dp3m_mc_time(char **log, int mesh, int cao, /* check whether we are running P3M+DLC, and whether we leave a reasonable gap space */ if (coulomb.Dmethod == DIPOLAR_MDLC_P3M) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{dipolar P3M: tuning when dlc needs to be fixed} "); + ostringstream msg; + msg <<"dipolar P3M: tuning when dlc needs to be fixed"; + runtimeError(msg); } /* check whether this radius is too large, so that we would use less cells than allowed */ @@ -1875,11 +1876,6 @@ int dp3m_adaptive_tune(char **logger) P3M_TRACE(fprintf(stderr,"%d: dp3m_adaptive_tune\n",this_node)); - if (skin == -1) { - *logger = strcat_alloc(*logger, "p3m cannot be tuned, since the skin is not yet set"); - return ES_ERROR; - } - /* preparation */ mpi_bcast_event(P3M_COUNT_DIPOLES); @@ -1905,7 +1901,7 @@ int dp3m_adaptive_tune(char **logger) be obtained with smaller meshes, but normally not all these meshes have to be tested */ mesh_max = tmp_mesh * 256; - /* avoid using more than 1 GB of FFT arrays (per default, see config.h) */ + /* avoid using more than 1 GB of FFT arrays (per default, see config.hpp) */ if (mesh_max > P3M_MAX_MESH) mesh_max = P3M_MAX_MESH; } @@ -2279,18 +2275,19 @@ void dp3m_calc_local_ca_mesh() { int dp3m_sanity_checks_boxl() { - char *errtxt; int i, ret = 0; for(i=0;i<3;i++) { /* check k-space cutoff */ if(dp3m.params.cao_cut[i] >= 0.5*box_l[i]) { - errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{039 dipolar P3M_init: k-space cutoff %g is larger than half of box dimension %g} ",dp3m.params.cao_cut[i],box_l[i]); + ostringstream msg; + msg <<"dipolar P3M_init: k-space cutoff " << dp3m.params.cao_cut[i] << " is larger than half of box dimension " << box_l[i]; + runtimeError(msg); ret = 1; } if(dp3m.params.cao_cut[i] >= local_box_l[i]) { - errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{040 dipolar P3M_init: k-space cutoff %g is larger than local box dimension %g} ",dp3m.params.cao_cut[i],local_box_l[i]); + ostringstream msg; + msg <<"dipolar P3M_init: k-space cutoff " << dp3m.params.cao_cut[i] << " is larger than local box dimension " << local_box_l[i]; + runtimeError(msg); ret = 1; } } @@ -2302,59 +2299,60 @@ int dp3m_sanity_checks_boxl() { int dp3m_sanity_checks() { - char *errtxt; int ret = 0; if (!PERIODIC(0) || !PERIODIC(1) || !PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{041 dipolar P3M requires periodicity 1 1 1} "); + ostringstream msg; + msg <<"dipolar P3M requires periodicity 1 1 1"; + runtimeError(msg); ret = 1; } /* if (n_nodes != 1) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{110 dipolar P3M does not run in parallel} "); + ostringstream msg; + msg <<"dipolar P3M does not run in parallel"; + runtimeError(msg); ret = 1; } */ if (cell_structure.type != CELL_STRUCTURE_DOMDEC) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{042 dipolar P3M at present requires the domain decomposition cell system} "); + ostringstream msg; + msg <<"dipolar P3M at present requires the domain decomposition cell system"; + runtimeError(msg); ret = 1; } if( (box_l[0] != box_l[1]) || (box_l[1] != box_l[2]) ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{043 dipolar P3M requires a cubic box} "); + ostringstream msg; + msg <<"dipolar P3M requires a cubic box"; + runtimeError(msg); ret = 1; } if( (dp3m.params.mesh[0] != dp3m.params.mesh[1]) || (dp3m.params.mesh[1] != dp3m.params.mesh[2]) ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{044 dipolar P3M requires a cubic mesh} "); + ostringstream msg; + msg <<"dipolar P3M requires a cubic mesh"; + runtimeError(msg); ret = 1; } if (dp3m_sanity_checks_boxl()) ret = 1; - if (skin == -1) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{047 dipolar P3M_init: skin is not yet set} "); - ret = 1; - } - if( dp3m.params.mesh[0] == 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{045 dipolar P3M_init: mesh size is not yet set} "); + ostringstream msg; + msg <<"dipolar P3M_init: mesh size is not yet set"; + runtimeError(msg); ret = 1; } if( dp3m.params.cao == 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{046 dipolar P3M_init: cao is not yet set} "); + ostringstream msg; + msg <<"dipolar P3M_init: cao is not yet set"; + runtimeError(msg); ret = 1; } if(node_grid[0] < node_grid[1] || node_grid[1] < node_grid[2]) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{046 dipolar P3M_init: node grid must be sorted, largest first} "); + ostringstream msg; + msg <<"dipolar P3M_init: node grid must be sorted, largest first"; + runtimeError(msg); ret = 1; } diff --git a/src/p3m-dipolar.hpp b/src/core/p3m-dipolar.hpp similarity index 98% rename from src/p3m-dipolar.hpp rename to src/core/p3m-dipolar.hpp index 5a246f7976e..80977eb4ad3 100644 --- a/src/p3m-dipolar.hpp +++ b/src/core/p3m-dipolar.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _P3M_MAGNETOSTATICS_H #define _P3M_MAGNETOSTATICS_H -/** \file p3m-dipolar.h P3M algorithm for long range magnetic dipole-dipole interaction. +/** \file p3m-dipolar.hpp P3M algorithm for long range magnetic dipole-dipole interaction. * * We use here a P3M (Particle-Particle Particle-Mesh) method based * on the dipolar Ewald summation. Details of the used method can be found in diff --git a/src/p3m.cpp b/src/core/p3m.cpp similarity index 93% rename from src/p3m.cpp rename to src/core/p3m.cpp index c28739fbd8f..7332a67d1aa 100644 --- a/src/p3m.cpp +++ b/src/core/p3m.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -222,6 +222,16 @@ static void p3m_tune_aliasing_sums(int nx, int ny, int nz, int mesh[3], double mesh_i[3], int cao, double alpha_L_i, double *alias1, double *alias2); +/** Template parameterized calculation of the charge assignment to be called by wrapper. + \param cao charge assignment order. +*/ +template +static void p3m_do_charge_assign(); + +template +void p3m_do_assign_charge(double q, + double real_pos[3], + int cp_cnt); /*@}*/ @@ -505,8 +515,37 @@ void p3m_interpolate_charge_assignment_function() } +/* Template wrapper for p3m_do_charge_assign() */ +void p3m_charge_assign() { + switch(p3m.params.cao) + { + case 1: + p3m_do_charge_assign<1>(); + break; + case 2: + p3m_do_charge_assign<2>(); + break; + case 3: + p3m_do_charge_assign<3>(); + break; + case 4: + p3m_do_charge_assign<4>(); + break; + case 5: + p3m_do_charge_assign<5>(); + break; + case 6: + p3m_do_charge_assign<6>(); + break; + case 7: + p3m_do_charge_assign<7>(); + break; + } +} + /* assign the charges */ -void p3m_charge_assign() +template +void p3m_do_charge_assign() { Cell *cell; Particle *p; @@ -523,7 +562,7 @@ void p3m_charge_assign() for(i = 0; i < np; i++) { if( p[i].p.q != 0.0 ) { - p3m_assign_charge(p[i].p.q, p[i].r.p, cp_cnt); + p3m_do_assign_charge(p[i].p.q, p[i].r.p, cp_cnt); cp_cnt++; } } @@ -533,7 +572,36 @@ void p3m_charge_assign() #endif } -void p3m_assign_charge(double q, +/* Template wrapper for p3m_do_assign_charge() */ +void p3m_assign_charge(double q, double real_pos[3], int cp_cnt) { + switch(p3m.params.cao) { + case 1: + p3m_do_assign_charge<1>(q, real_pos, cp_cnt); + break; + case 2: + p3m_do_assign_charge<2>(q, real_pos, cp_cnt); + break; + case 3: + p3m_do_assign_charge<3>(q, real_pos, cp_cnt); + break; + case 4: + p3m_do_assign_charge<4>(q, real_pos, cp_cnt); + break; + case 5: + p3m_do_assign_charge<5>(q, real_pos, cp_cnt); + break; + case 6: + p3m_do_assign_charge<6>(q, real_pos, cp_cnt); + break; + case 7: + p3m_do_assign_charge<7>(q, real_pos, cp_cnt); + break; + } +} + + +template +void p3m_do_assign_charge(double q, double real_pos[3], int cp_cnt) { @@ -556,7 +624,7 @@ void p3m_assign_charge(double q, // make sure we have enough space if (cp_cnt >= p3m.ca_num) p3m_realloc_ca_fields(cp_cnt + 1); // do it here, since p3m_realloc_ca_fields may change the address of p3m.ca_frac - cur_ca_frac = p3m.ca_frac + p3m.params.cao3*cp_cnt; + cur_ca_frac = p3m.ca_frac + cao*cao*cao*cp_cnt; #endif for(d=0;d<3;d++) { @@ -580,7 +648,7 @@ void p3m_assign_charge(double q, fprintf(stderr,"%d: allowed coordinates: %f - %f\n", this_node,my_left[d] - skin, my_right[d] + skin); } - if( (nmp + p3m.params.cao) > p3m.local_mesh.dim[d] ) { + if( (nmp + cao) > p3m.local_mesh.dim[d] ) { fprintf(stderr,"%d: rs_mesh overflow! (pos %f, nmp=%d)\n", this_node, real_pos[d],nmp); fprintf(stderr,"%d: allowed coordinates: %f - %f\n", this_node, my_left[d] - skin, my_right[d] + skin); @@ -593,12 +661,12 @@ void p3m_assign_charge(double q, #endif if (p3m.params.inter == 0) { - for(i0=0; i0 static void P3M_assign_forces(double force_prefac, int d_rs) { Cell *cell; @@ -670,9 +739,9 @@ static void P3M_assign_forces(double force_prefac, int d_rs) if( (q=p[i].p.q) != 0.0 ) { #ifdef P3M_STORE_CA_FRAC q_ind = p3m.ca_fmp[cp_cnt]; - for(i0=0; i0(force_prefac, d_rs); + break; + case 2: + P3M_assign_forces<2>(force_prefac, d_rs); + break; + case 3: + P3M_assign_forces<3>(force_prefac, d_rs); + break; + case 4: + P3M_assign_forces<4>(force_prefac, d_rs); + break; + case 5: + P3M_assign_forces<5>(force_prefac, d_rs); + break; + case 6: + P3M_assign_forces<6>(force_prefac, d_rs); + break; + case 7: + P3M_assign_forces<7>(force_prefac, d_rs); + break; + } } } /* if(force_flag) */ @@ -1478,11 +1573,6 @@ int p3m_adaptive_tune(char **log) { char b[3*ES_INTEGER_SPACE + 3*ES_DOUBLE_SPACE + 128]; int tune_mesh = 0; //boolean to indicate if mesh should be tuned - if (skin == -1) { - *log = strcat_alloc(*log, "p3m cannot be tuned, since the skin is not yet set"); - return ES_ERROR; - } - if (p3m.params.epsilon != P3M_EPSILON_METALLIC) { if( !((box_l[0] == box_l[1]) && (box_l[1] == box_l[2]))) { @@ -1514,14 +1604,19 @@ int p3m_adaptive_tune(char **log) { /* this limits the tried meshes if the accuracy cannot be obtained with smaller meshes, but normally not all these meshes have to be tested */ - /* avoid using more than 1 GB of FFT arrays (per default, see config.h) */ + /* avoid using more than 1 GB of FFT arrays (per default, see config.hpp) */ P3M_TRACE(fprintf(stderr, "%d: starting with meshdensity %lf, using at most %lf.\n", this_node, mesh_density_min, mesh_density_max)); } else if ( p3m.params.mesh[1] == -1 && p3m.params.mesh[2] == -1) { mesh_density = mesh_density_min = mesh_density_max = p3m.params.mesh[0] / box_l[0]; p3m.params.mesh[1] = mesh_density*box_l[1]+0.5; - p3m.params.mesh[2] = mesh_density*box_l[2]+0.5; + p3m.params.mesh[2] = mesh_density*box_l[2]+0.5; + if ( p3m.params.mesh[1]%2 == 1 ) p3m.params.mesh[1]++; //Make sure that the mesh is even in all directions + if ( p3m.params.mesh[2]%2 == 1 ) p3m.params.mesh[2]++; + + sprintf(b, "fixed mesh %d %d %d\n", p3m.params.mesh[0], p3m.params.mesh[1], p3m.params.mesh[2]); + *log = strcat_alloc(*log, b); } else { mesh_density = mesh_density_min = mesh_density_max = p3m.params.mesh[0] / box_l[0]; @@ -1574,7 +1669,7 @@ int p3m_adaptive_tune(char **log) { tmp_mesh[2] = p3m.params.mesh[2]; } - if(tmp_mesh[0] % 2) + if(tmp_mesh[0] % 2) //Make sure that the mesh is even in all directions tmp_mesh[0]++; if(tmp_mesh[1] % 2) tmp_mesh[1]++; @@ -1818,18 +1913,20 @@ void p3m_init_a_ai_cao_cut() { int p3m_sanity_checks_boxl() { - char *errtxt; + //char *errtxt; int i, ret = 0; for(i=0;i<3;i++) { /* check k-space cutoff */ if(p3m.params.cao_cut[i] >= 0.5*box_l[i]) { - errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{039 P3M_init: k-space cutoff %g is larger than half of box dimension %g} ",p3m.params.cao_cut[i],box_l[i]); + ostringstream msg; + msg <<"P3M_init: k-space cutoff " << p3m.params.cao_cut[i] << " is larger than half of box dimension " << box_l[i]; + runtimeError(msg); ret = 1; } if(p3m.params.cao_cut[i] >= local_box_l[i]) { - errtxt = runtime_error(128 + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{040 P3M_init: k-space cutoff %g is larger than local box dimension %g} ",p3m.params.cao_cut[i],local_box_l[i]); + ostringstream msg; + msg <<"P3M_init: k-space cutoff " << p3m.params.cao_cut[i] << " is larger than local box dimension " << local_box_l[i]; + runtimeError(msg); ret = 1; } } @@ -1843,54 +1940,55 @@ int p3m_sanity_checks_boxl() { int p3m_sanity_checks() { - char *errtxt; int ret = 0; if (!PERIODIC(0) || !PERIODIC(1) || !PERIODIC(2)) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{041 P3M requires periodicity 1 1 1} "); + ostringstream msg; + msg <<"P3M requires periodicity 1 1 1"; + runtimeError(msg); ret = 1; } if (cell_structure.type != CELL_STRUCTURE_DOMDEC) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{042 P3M at present requires the domain decomposition cell system} "); + ostringstream msg; + msg << "P3M at present requires the domain decomposition cell system"; + runtimeError(msg); ret = 1; } if (p3m_sanity_checks_boxl()) ret = 1; if( p3m.params.mesh[0] == 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{045 P3M_init: mesh size is not yet set} "); + ostringstream msg; + msg <<"P3M_init: mesh size is not yet set"; + runtimeError(msg); ret = 1; } if( p3m.params.cao == 0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{046 P3M_init: cao is not yet set} "); - ret = 1; - } - if (skin == -1) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{047 P3M_init: skin is not yet set} "); + ostringstream msg; + msg <<"P3M_init: cao is not yet set"; + runtimeError(msg); ret = 1; } if (p3m.params.alpha < 0.0 ) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{048 P3M_init: alpha must be >0} "); + ostringstream msg; + msg <<"P3M_init: alpha must be >0"; + runtimeError(msg); ret = 1; } if(node_grid[0] < node_grid[1] || node_grid[1] < node_grid[2]) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{048a P3M_init: node grid must be sorted, largest first} "); + ostringstream msg; + msg <<"P3M_init: node grid must be sorted, largest first"; + runtimeError(msg); ret = 1; } if (p3m.params.epsilon != P3M_EPSILON_METALLIC) { if( !((p3m.params.mesh[0] == p3m.params.mesh[1]) && - (p3m.params.mesh[1] == p3m.params.mesh[2]))) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{049 P3M_init: Nonmetallic epsilon requires cubic box} "); + (p3m.params.mesh[1] == p3m.params.mesh[2]))) { + ostringstream msg; + msg <<"P3M_init: Nonmetallic epsilon requires cubic box"; + runtimeError(msg); ret = 1; } } diff --git a/src/p3m.hpp b/src/core/p3m.hpp similarity index 97% rename from src/p3m.hpp rename to src/core/p3m.hpp index 408f8e9a66c..ba171f5df3c 100644 --- a/src/p3m.hpp +++ b/src/core/p3m.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _P3M_H #define _P3M_H -/** \file p3m.h P3M algorithm for long range coulomb interaction. +/** \file p3m.hpp P3M algorithm for long range coulomb interaction. * * We use a P3M (Particle-Particle Particle-Mesh) method based on the * Ewald summation. Details of the used method can be found in @@ -189,12 +189,13 @@ enum P3M_TUNE_ERROR { P3M_TUNE_FAIL = 1, P3M_TUNE_NOCUTOFF = 2, P3M_TUNE_CAOTOLA The function returns a log of the performed tuning. - The function is based on routines of the program HE_Q.c written by M. Deserno. + The function is based on routines of the program HE_Q.cpp written by M. Deserno. */ /** assign the physical charges using the tabulated charge assignment function. If store_ca_frac is true, then the charge fractions are buffered in cur_ca_fmp and cur_ca_frac. */ + void p3m_charge_assign(); /** assign a single charge into the current charge grid. cp_cnt gives the a running index, diff --git a/src/core/p3m_gpu.hpp b/src/core/p3m_gpu.hpp new file mode 100644 index 00000000000..420e63d98bd --- /dev/null +++ b/src/core/p3m_gpu.hpp @@ -0,0 +1,48 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _P3M_GPU_H +#define _P3M_GPU_H + +//NOTE :if one wants to use doubles it requires cuda compute capability 1.3 +#define _P3M_GPU_FLOAT +//#define _P3M_GPU_REAL_DOUBLE + +#ifdef _P3M_GPU_FLOAT +#define REAL_TYPE float +#define CUFFT_TYPE_COMPLEX cufftComplex +#define CUFFT_FFT cufftExecC2C +#define CUFFT_PLAN_FLAG CUFFT_C2C +#endif + +#ifdef _P3M_GPU_REAL_DOUBLE +#define REAL_TYPE double +#define CUFFT_TYPE_COMPLEX cufftDoubleComplex +#define CUFFT_FFT cufftExecZ2Z +#define CUFFT_PLAN_FLAG CUFFT_Z2Z +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void p3m_gpu_init(int cao, int mesh, REAL_TYPE alpha, REAL_TYPE box); + void p3m_gpu_add_farfield_force(); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/core/p3m_gpu_cuda.cu b/src/core/p3m_gpu_cuda.cu new file mode 100644 index 00000000000..5aacc51bce4 --- /dev/null +++ b/src/core/p3m_gpu_cuda.cu @@ -0,0 +1,689 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** \file p3m_gpu_cuda.cu + * + * Cuda (.cu) file for the P3M electrostatics method. + * Header file \ref p3m_gpu.hpp . + */ + +#include +#include +#include + +#include +#include "cuda_interface.hpp" +#include "cuda_utils.hpp" +#include "config.hpp" +#include "p3m_gpu.hpp" +#include "utils.hpp" +#include "EspressoSystemInterface.hpp" + +#ifdef ELECTROSTATICS + +struct dummytypename { + CUFFT_TYPE_COMPLEX *charge_mesh; + CUFFT_TYPE_COMPLEX *force_mesh; + REAL_TYPE *G_hat; + REAL_TYPE *G_hat_host; + cufftHandle fft_plan; + int cao, mesh; + REAL_TYPE alpha; + int npart; + REAL_TYPE box; +} p3m_gpu_data; + +static char p3m_gpu_data_initialized = 0; + +#define SQR(A) ((A)*(A)) + +__host__ __device__ inline double csinc(double d) +{ +#define epsi 0.1 + +#define c2 -0.1666666666667e-0 +#define c4 0.8333333333333e-2 +#define c6 -0.1984126984127e-3 +#define c8 0.2755731922399e-5 + + double PId = PI*d, PId2; + + if (fabs(d)>epsi) + return sin(PId)/PId; + else { + PId2 = SQR(PId); + return 1.0 + PId2*(c2+PId2*(c4+PId2*(c6+PId2*c8))); + } +} + +__host__ __device__ void static Aliasing_sums_ik ( int cao, REAL_TYPE box, REAL_TYPE alpha, int mesh, int NX, int NY, int NZ, + REAL_TYPE *Zaehler, REAL_TYPE *Nenner ) { + REAL_TYPE S1,S2,S3; + REAL_TYPE fak1,fak2,zwi; + int MX,MY,MZ; + REAL_TYPE NMX,NMY,NMZ; + REAL_TYPE NM2; + REAL_TYPE expo, TE; + REAL_TYPE Leni = 1.0/box; + + fak1 = 1.0/ ( REAL_TYPE ) mesh; + fak2 = SQR ( PI/ ( alpha ) ); + + Zaehler[0] = Zaehler[1] = Zaehler[2] = *Nenner = 0.0; + + for ( MX = -P3M_BRILLOUIN; MX <= P3M_BRILLOUIN; MX++ ) { + NMX = ( ( NX > mesh/2 ) ? NX - mesh : NX ) + mesh*MX; + S1 = pow ( csinc(fak1*NMX ), 2*cao ); + for ( MY = -P3M_BRILLOUIN; MY <= P3M_BRILLOUIN; MY++ ) { + NMY = ( ( NY > mesh/2 ) ? NY - mesh : NY ) + mesh*MY; + S2 = S1*pow ( csinc (fak1*NMY ), 2*cao ); + for ( MZ = -P3M_BRILLOUIN; MZ <= P3M_BRILLOUIN; MZ++ ) { + NMZ = ( ( NZ > mesh/2 ) ? NZ - mesh : NZ ) + mesh*MZ; + S3 = S2*pow ( csinc( fak1*NMZ ), 2*cao ); + + NM2 = SQR ( NMX*Leni ) + SQR ( NMY*Leni ) + SQR ( NMZ*Leni ); + *Nenner += S3; + + expo = fak2*NM2; + TE = exp ( -expo ); + zwi = S3 * TE/NM2; + Zaehler[0] += NMX*zwi*Leni; + Zaehler[1] += NMY*zwi*Leni; + Zaehler[2] += NMZ*zwi*Leni; + } + } + } +} + +/* Calculate influence function */ +#if 1 +// host version, not used anywhere +void static calculate_influence_function ( int cao, int mesh, REAL_TYPE box, REAL_TYPE alpha, REAL_TYPE *G_hat ) { + + int NX,NY,NZ; + REAL_TYPE Dnx,Dny,Dnz; + REAL_TYPE Zaehler[3]={0.0,0.0,0.0},Nenner=0.0; + REAL_TYPE zwi; + int ind = 0; + REAL_TYPE Leni = 1.0/box; + + for ( NX=0; NX mesh/2 ) ? NX - mesh : NX; + Dny = ( NY > mesh/2 ) ? NY - mesh : NY; + Dnz = ( NZ > mesh/2 ) ? NZ - mesh : NZ; + + zwi = Dnx*Zaehler[0]*Leni + Dny*Zaehler[1]*Leni + Dnz*Zaehler[2]*Leni; + zwi /= ( ( SQR ( Dnx*Leni ) + SQR ( Dny*Leni ) + SQR ( Dnz*Leni ) ) * SQR ( Nenner ) ); + G_hat[ind] = 2.0 * zwi / PI; + } + } + } + } +} +#endif + +__global__ void calculate_influence_function_device ( int cao, int mesh, REAL_TYPE box, REAL_TYPE alpha, REAL_TYPE *G_hat ) { + + int NX,NY,NZ; + REAL_TYPE Dnx,Dny,Dnz; + REAL_TYPE Zaehler[3]={0.0,0.0,0.0},Nenner=0.0; + REAL_TYPE zwi; + int ind = 0; + REAL_TYPE Leni = 1.0/box; + + NX = blockDim.x * blockIdx.x + threadIdx.x; + NY = threadIdx.y; + NZ = threadIdx.z; + + if(NX >= mesh) + return; + + ind = NX*mesh*mesh + NY * mesh + NZ; + + if ( ( NX==0 ) && ( NY==0 ) && ( NZ==0 ) ) + G_hat[ind]=0.0; + else if ( ( NX% ( mesh/2 ) == 0 ) && ( NY% ( mesh/2 ) == 0 ) && ( NZ% ( mesh/2 ) == 0 ) ) + G_hat[ind]=0.0; + else { + Aliasing_sums_ik ( cao, box, alpha, mesh, NX, NY, NZ, Zaehler, &Nenner ); + + Dnx = ( NX > mesh/2 ) ? NX - mesh : NX; + Dny = ( NY > mesh/2 ) ? NY - mesh : NY; + Dnz = ( NZ > mesh/2 ) ? NZ - mesh : NZ; + + zwi = Dnx*Zaehler[0]*Leni + Dny*Zaehler[1]*Leni + Dnz*Zaehler[2]*Leni; + zwi /= ( ( SQR ( Dnx*Leni ) + SQR ( Dny*Leni ) + SQR ( Dnz*Leni ) ) * SQR ( Nenner ) ); + G_hat[ind] = 2.0 * zwi / PI; + } +} + + +//NOTE :if one wants to use the function below it requires cuda compute capability 1.3 +#ifdef _P3M_GPU_REAL_DOUBLE +__device__ double atomicAdd (double* address, double val) +{ + unsigned long long int* address_as_ull = + (unsigned long long int*)address; + unsigned long long int old = *address_as_ull, assumed; + do { + assumed = old; + old = atomicCAS(address_as_ull, assumed, + __double_as_longlong(val + + __longlong_as_double(assumed))); + } while (assumed != old); + return __longlong_as_double(old); +} +#endif + +/** atomic add function for several cuda architectures + */ + +#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 // for Fermi, atomicAdd supports floats +//atomicAdd supports floats already, do nothing +#elif __CUDA_ARCH__ >= 110 +#warning Using slower atomicAdd emulation +__device__ inline void atomicAdd(float* address, float value){ + // float-atomic-add from + // [url="http://forums.nvidia.com/index.php?showtopic=158039&view=findpost&p=991561"] + float old = value; + while ((old = atomicExch(address, atomicExch(address, 0.0f)+old))!=0.0f); +} +#else +#error I need at least compute capability 1.1 +#endif + + + +__device__ unsigned int getThreadIndexP3M() { //rename is dumb but can't import same fnc from cuda_common + + return blockIdx.y * gridDim.x * blockDim.x + + blockDim.x * blockIdx.x + + threadIdx.x; +} + +template +__global__ void apply_diff_op( CUFFT_TYPE_COMPLEX *mesh, const int mesh_size, CUFFT_TYPE_COMPLEX *force_mesh, const REAL_TYPE box ) { + int linear_index = mesh_size*mesh_size*blockIdx.x + mesh_size * blockIdx.y + threadIdx.x; + int n; + + switch( dim ) { + case 0: + n = blockIdx.x; + break; + case 1: + n = blockIdx.y; + break; + case 2: + n = threadIdx.x; + break; + } + + n = ( n == mesh_size/2 ) ? 0.0 : n; + n = ( n > mesh_size/2) ? n - mesh_size : n; + + force_mesh[linear_index].x = -2.0 * PI * n * mesh[linear_index].y / box; + force_mesh[linear_index].y = 2.0 * PI * n * mesh[linear_index].x / box; +} + + +__device__ inline int wrap_index(const int ind, const int mesh) { + if(ind < 0) + return ind + mesh; + else if(ind >= mesh) + return ind - mesh; + else + return ind; +} + +__device__ REAL_TYPE caf(int i, REAL_TYPE x, int cao_value) { + switch (cao_value) { + case 1 : return 1.0; + case 2 : { + switch (i) { + case 0: return 0.5-x; + case 1: return 0.5+x; + default: + return 0.0; + } + } + case 3 : { + switch (i) { + case 0: return 0.5*SQR(0.5 - x); + case 1: return 0.75 - SQR(x); + case 2: return 0.5*SQR(0.5 + x); + default: + return 0.0; + } + case 4 : { + switch (i) { + case 0: return ( 1.0+x*( -6.0+x*( 12.0-x* 8.0)))/48.0; + case 1: return (23.0+x*(-30.0+x*(-12.0+x*24.0)))/48.0; + case 2: return (23.0+x*( 30.0+x*(-12.0-x*24.0)))/48.0; + case 3: return ( 1.0+x*( 6.0+x*( 12.0+x* 8.0)))/48.0; + default: + return 0.0; + } + } + case 5 : { + switch (i) { + case 0: return ( 1.0+x*( -8.0+x*( 24.0+x*(-32.0+x*16.0))))/384.0; + case 1: return ( 19.0+x*(-44.0+x*( 24.0+x*( 16.0-x*16.0))))/ 96.0; + case 2: return (115.0+x* x*(-120.0+x* x*48.0)) /192.0; + case 3: return ( 19.0+x*( 44.0+x*( 24.0+x*(-16.0-x*16.0))))/ 96.0; + case 4: return ( 1.0+x*( 8.0+x*( 24.0+x*( 32.0+x*16.0))))/384.0; + default: + return 0.0; + } + } + case 6 : { + switch (i) { + case 0: return ( 1.0+x*( -10.0+x*( 40.0+x*( -80.0+x*( 80.0-x* 32.0)))))/3840.0; + case 1: return (237.0+x*(-750.0+x*( 840.0+x*(-240.0+x*(-240.0+x*160.0)))))/3840.0; + case 2: return (841.0+x*(-770.0+x*(-440.0+x*( 560.0+x*( 80.0-x*160.0)))))/1920.0; + case 3: return (841.0+x*(+770.0+x*(-440.0+x*(-560.0+x*( 80.0+x*160.0)))))/1920.0; + case 4: return (237.0+x*( 750.0+x*( 840.0+x*( 240.0+x*(-240.0-x*160.0)))))/3840.0; + case 5: return ( 1.0+x*( 10.0+x*( 40.0+x*( 80.0+x*( 80.0+x* 32.0)))))/3840.0; + default: + return 0.0; + } + } + case 7 : { + switch (i) { + case 0: return ( 1.0+x*( -12.0+x*( 60.0+x*( -160.0+x*( 240.0+x*(-192.0+x* 64.0))))))/46080.0; + case 1: return ( 361.0+x*( -1416.0+x*( 2220.0+x*(-1600.0+x*( 240.0+x*( 384.0-x*192.0))))))/23040.0; + case 2: return (10543.0+x*(-17340.0+x*( 4740.0+x*( 6880.0+x*(-4080.0+x*(-960.0+x*960.0))))))/46080.0; + case 3: return ( 5887.0+x* x*(-4620.0+x* x*( 1680.0-x* x*320.0))) /11520.0; + case 4: return (10543.0+x*( 17340.0+x*( 4740.0+x*(-6880.0+x*(-4080.0+x*( 960.0+x*960.0))))))/46080.0; + case 5: return ( 361.0+x*( 1416.0+x*( 2220.0+x*( 1600.0+x*( 240.0+x*(-384.0-x*192.0))))))/23040.0; + case 6: return ( 1.0+x*( 12.0+x*( 60.0+x*( 160.0+x*( 240.0+x*( 192.0+x* 64.0))))))/46080.0; + default: + return 0.0; + } + } + }} + return 0.0; +} + +__global__ void apply_influence_function( CUFFT_TYPE_COMPLEX *mesh, int mesh_size, REAL_TYPE *G_hat ) { + int linear_index = mesh_size*mesh_size*blockIdx.x + mesh_size * blockIdx.y + threadIdx.x; + mesh[linear_index].x *= G_hat[linear_index]; + mesh[linear_index].y *= G_hat[linear_index]; +} + +__global__ void assign_charges(const CUDA_particle_data * const pdata, + CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const + REAL_TYPE hi) { + /** id of the particle **/ + int id = blockIdx.x; + /** position relative to the closest gird point **/ + REAL_TYPE m_pos[3]; + /** index of the nearest mesh point **/ + int nmp_x, nmp_y, nmp_z; + + CUDA_particle_data p = pdata[id]; + + m_pos[0] = p.p[0] * hi - pos_shift; + m_pos[1] = p.p[1] * hi - pos_shift; + m_pos[2] = p.p[2] * hi - pos_shift; + + nmp_x = (int) floor(m_pos[0] + 0.5); + nmp_y = (int) floor(m_pos[1] + 0.5); + nmp_z = (int) floor(m_pos[2] + 0.5); + + m_pos[0] -= nmp_x; + m_pos[1] -= nmp_y; + m_pos[2] -= nmp_z; + + nmp_x = wrap_index(nmp_x + threadIdx.x, m_size); + nmp_y = wrap_index(nmp_y + threadIdx.y, m_size); + nmp_z = wrap_index(nmp_z + threadIdx.z, m_size); + + atomicAdd( &(mesh[m_size*m_size*nmp_x + m_size*nmp_y + nmp_z].x), caf(threadIdx.x, m_pos[0], cao)*caf(threadIdx.y, m_pos[1], cao)*caf(threadIdx.z, m_pos[2], cao)*p.q); +} + +__global__ void assign_forces(const CUDA_particle_data * const pdata, CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const + REAL_TYPE hi, CUDA_particle_force * lb_particle_force_gpu, REAL_TYPE prefactor, int dim) { + /** id of the particle **/ + int id = blockIdx.x; + /** position relative to the closest gird point **/ + REAL_TYPE m_pos[3]; + /** index of the nearest mesh point **/ + int nmp_x, nmp_y, nmp_z; + + CUDA_particle_data p = pdata[id]; + + m_pos[0] = p.p[0] * hi - pos_shift; + m_pos[1] = p.p[1] * hi - pos_shift; + m_pos[2] = p.p[2] * hi - pos_shift; + + nmp_x = (int) floor(m_pos[0] + 0.5); + nmp_y = (int) floor(m_pos[1] + 0.5); + nmp_z = (int) floor(m_pos[2] + 0.5); + + m_pos[0] -= nmp_x; + m_pos[1] -= nmp_y; + m_pos[2] -= nmp_z; + + nmp_x = wrap_index(nmp_x + threadIdx.x, m_size); + nmp_y = wrap_index(nmp_y + threadIdx.y, m_size); + nmp_z = wrap_index(nmp_z + threadIdx.z, m_size); + + atomicAdd( &(lb_particle_force_gpu[id].f[dim]), (float)(-prefactor*mesh[m_size*m_size*nmp_x + m_size*nmp_y + nmp_z].x*caf(threadIdx.x, m_pos[0], cao)*caf(threadIdx.y, m_pos[1], cao)*caf(threadIdx.z, m_pos[2], cao)*p.q)); + +} + +__global__ void assign_forces_3(const CUDA_particle_data * const pdata, CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const + REAL_TYPE hi, CUDA_particle_force * lb_particle_force_gpu, REAL_TYPE prefactor, int dim) { + /** id of the particle **/ + int id = blockIdx.x; + extern __shared__ REAL_TYPE force[]; + /** position relative to the closest gird point **/ + REAL_TYPE m_pos[3]; + /** index of the nearest mesh point **/ + int nmp_x, nmp_y, nmp_z; + + CUDA_particle_data p = pdata[id]; + + m_pos[0] = p.p[0] * hi - pos_shift; + m_pos[1] = p.p[1] * hi - pos_shift; + m_pos[2] = p.p[2] * hi - pos_shift; + + nmp_x = (int) floor(m_pos[0] + 0.5); + nmp_y = (int) floor(m_pos[1] + 0.5); + nmp_z = (int) floor(m_pos[2] + 0.5); + + m_pos[0] -= nmp_x; + m_pos[1] -= nmp_y; + m_pos[2] -= nmp_z; + + nmp_x = wrap_index(nmp_x + threadIdx.x, m_size); + nmp_y = wrap_index(nmp_y + threadIdx.y, m_size); + nmp_z = wrap_index(nmp_z + threadIdx.z, m_size); + + int l_ind = cao*cao*threadIdx.x + cao*threadIdx.y + threadIdx.z; + + force[l_ind] = (float)(-prefactor*mesh[m_size*m_size*nmp_x + m_size*nmp_y + nmp_z].x*caf(threadIdx.x, m_pos[0], cao)*caf(threadIdx.y, m_pos[1], cao)*caf(threadIdx.z, m_pos[2], cao)*p.q); + + if(l_ind == 0) + for(int i = 1; i < cao*cao*cao; i++) { + force[0] += force[i]; + lb_particle_force_gpu[id].f[dim] += force[0]; + } +} + + +__global__ void assign_forces_2(const CUDA_particle_data * const pdata, CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const + REAL_TYPE hi, CUDA_particle_force * lb_particle_force_gpu, REAL_TYPE prefactor, int dim, int n_part) { + /** id of the particle **/ + int id = blockIdx.x*blockDim.x + threadIdx.x; + + if(id >= n_part) + return; + + /** position relative to the closest gird point **/ + REAL_TYPE m_pos[3]; + /** index of the nearest mesh point **/ + int nmp_x, nmp_y, nmp_z; + REAL_TYPE caf_x, caf_y, caf_z; + int mp_x, mp_y, mp_z; + REAL_TYPE force = 0.0; + + CUDA_particle_data p = pdata[id]; + + m_pos[0] = p.p[0] * hi - pos_shift; + m_pos[1] = p.p[1] * hi - pos_shift; + m_pos[2] = p.p[2] * hi - pos_shift; + + nmp_x = (int) floor(m_pos[0] + 0.5); + nmp_y = (int) floor(m_pos[1] + 0.5); + nmp_z = (int) floor(m_pos[2] + 0.5); + + m_pos[0] -= nmp_x; + m_pos[1] -= nmp_y; + m_pos[2] -= nmp_z; + + for(int i = 0; i < cao; i++) { + caf_x = caf(i, m_pos[0], cao)*p.q; + mp_x = wrap_index(nmp_x + i, m_size); + for(int j = 0; j < cao; j++) { + caf_y = caf(j, m_pos[1], cao); + mp_y = wrap_index(nmp_y + j, m_size); + for(int k = 0; k < cao; k++) { + caf_z = caf(k, m_pos[2], cao); + mp_z = wrap_index(nmp_z + k, m_size); + force += (float)(-prefactor*mesh[m_size*m_size*mp_x + m_size*mp_y + mp_z].x*caf_x*caf_y*caf_z); + } + } + } + lb_particle_force_gpu[id].f[dim] += force; +} + +extern "C" { + + /* Init the internal datastructures of the P3M GPU. + * Mainly allocation on the device and influence function calculation. + * Be advised: this needs mesh^3*5*sizeof(REAL_TYPE) of device memory. + */ + + void p3m_gpu_init(int cao, int mesh, REAL_TYPE alpha, REAL_TYPE box) { + int reinit_if = 0, mesh_changed = 0; + + espressoSystemInterface.requestParticleStructGpu(); + + if ( this_node == 0 ) { + + + p3m_gpu_data.npart = gpu_get_global_particle_vars_pointer_host()->number_of_particles; + + if((p3m_gpu_data_initialized == 0) || (p3m_gpu_data.alpha != alpha)) { + p3m_gpu_data.alpha = alpha; + reinit_if = 1; + } + + if((p3m_gpu_data_initialized == 0) || (p3m_gpu_data.cao != cao)) { + p3m_gpu_data.cao = cao; + reinit_if = 1; + } + + if((p3m_gpu_data_initialized == 0) || (p3m_gpu_data.mesh != mesh)) { + p3m_gpu_data.mesh = mesh; + mesh_changed = 1; + reinit_if = 1; + } + + if((p3m_gpu_data_initialized == 0) || (p3m_gpu_data.box != box)) { + p3m_gpu_data.box = box; + reinit_if = 1; + } + + int mesh3 = mesh*mesh*mesh; + + if((p3m_gpu_data_initialized == 1) && (mesh_changed == 1)) { + cudaFree(p3m_gpu_data.charge_mesh); + cudaFree(p3m_gpu_data.force_mesh); + cudaFree(p3m_gpu_data.G_hat); + + free(p3m_gpu_data.G_hat_host); + + cufftDestroy(p3m_gpu_data.fft_plan); + + p3m_gpu_data_initialized = 0; + } + + if(p3m_gpu_data_initialized == 0 && mesh > 0) { + cudaMalloc((void **)&(p3m_gpu_data.charge_mesh), mesh3*sizeof(CUFFT_TYPE_COMPLEX)); + cudaMalloc((void **)&(p3m_gpu_data.force_mesh), mesh3*sizeof(CUFFT_TYPE_COMPLEX)); + cudaMalloc((void **)&(p3m_gpu_data.G_hat), mesh3*sizeof(REAL_TYPE)); + + p3m_gpu_data.G_hat_host = (REAL_TYPE *)malloc(mesh3*sizeof(REAL_TYPE)); + + cufftPlan3d(&(p3m_gpu_data.fft_plan), mesh, mesh, mesh, CUFFT_PLAN_FLAG); + } + + if(((reinit_if == 1) || (p3m_gpu_data_initialized == 0)) && mesh > 0) { + // // Calculate influence function of host. + calculate_influence_function( cao, mesh, box, alpha, p3m_gpu_data.G_hat_host); + + // // Copy influence function to device. + cudaMemcpy( p3m_gpu_data.G_hat, p3m_gpu_data.G_hat_host, mesh3*sizeof(REAL_TYPE), cudaMemcpyHostToDevice); + dim3 grid(1,1,1); + dim3 block(1,1,1); + block.y = mesh; + block.z = 1; + block.x = 512 / mesh + 1; + grid.x = mesh / block.x + 1; + grid.z = mesh; + + // printf("mesh %d, grid (%d %d %d), block (%d %d %d)\n", mesh, grid.x, grid.y, grid.z, block.x, block.y, block.z); + + // KERNELCALL(calculate_influence_function_device,grid,block,(cao, mesh, box, alpha, p3m_gpu_data.G_hat)); + cudaThreadSynchronize(); + } + p3m_gpu_data_initialized = 1; + } + } + + void p3m_gpu_add_farfield_force() { + + CUDA_particle_data* lb_particle_gpu; + CUDA_particle_force* lb_particle_force_gpu; + + int mesh = p3m_gpu_data.mesh; + int mesh3 = mesh*mesh*mesh; + int cao = p3m_gpu_data.cao; + REAL_TYPE box = p3m_gpu_data.box; + + lb_particle_gpu = gpu_get_particle_pointer(); + lb_particle_force_gpu = gpu_get_particle_force_pointer(); + + p3m_gpu_data.npart = gpu_get_global_particle_vars_pointer_host()->number_of_particles; + + if(p3m_gpu_data.npart == 0) + return; + + dim3 gridAssignment(p3m_gpu_data.npart,1,1); + dim3 threadsAssignment(cao,cao,cao); + + dim3 gridConv(mesh,mesh,1); + dim3 threadsConv(mesh,1,1); + + REAL_TYPE pos_shift = (REAL_TYPE)((cao-1)/2); + REAL_TYPE hi = mesh/box; + REAL_TYPE prefactor = 1.0/(box*box*box*2.0); + + cuda_safe_mem(cudaMemset( p3m_gpu_data.charge_mesh, 0, mesh3*sizeof(CUFFT_TYPE_COMPLEX))); + + KERNELCALL(assign_charges, gridAssignment, threadsAssignment, (lb_particle_gpu,p3m_gpu_data.charge_mesh,mesh,cao,pos_shift,hi)); + + if (CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.charge_mesh, p3m_gpu_data.charge_mesh, CUFFT_FORWARD) != CUFFT_SUCCESS){ + fprintf(stderr, "CUFFT error: ExecZ2Z Forward failed\n"); + return; + } + + KERNELCALL( apply_influence_function, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.G_hat)); + + // KERNELCALL(apply_diff_op<0>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 0)); + + // KERNELCALL(apply_diff_op<1>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 1)); + + // KERNELCALL(apply_diff_op<2>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 2)); + + // /** assign_forces_3 **/ + + // KERNELCALL(apply_diff_op<0>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // assign_forces_3<<>>(lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 0); + + // KERNELCALL(apply_diff_op<1>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // assign_forces_3<<>>(lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 1); + + // KERNELCALL(apply_diff_op<2>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + // CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + // assign_forces_3<<>>(lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 2); + + //const int n_part = p3m_gpu_data.npart; + //int n_blocks = n_part / 24 + 1; + + dim3 gridAssignment2(1,1,1); + dim3 threadsAssignment2(1,1,1); + if(p3m_gpu_data.npart <= 512) { + threadsAssignment2.x = p3m_gpu_data.npart; + } else { + threadsAssignment2.x = 512; + if((p3m_gpu_data.npart % 512) == 0) { + gridAssignment2.x = p3m_gpu_data.npart / 512; + } + else { + gridAssignment2.x = p3m_gpu_data.npart / 512 + 1; + } + } + + KERNELCALL(apply_diff_op<0>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + KERNELCALL(assign_forces_2, gridAssignment2, threadsAssignment2, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 0, p3m_gpu_data.npart)); + + KERNELCALL(apply_diff_op<1>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + KERNELCALL(assign_forces_2, gridAssignment2, threadsAssignment2, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 1, p3m_gpu_data.npart)); + + KERNELCALL(apply_diff_op<2>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); + + CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); + + KERNELCALL(assign_forces_2, gridAssignment2, threadsAssignment2, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 2, p3m_gpu_data.npart)); + + } + +} + +#endif /* ELECTROSTATICS */ diff --git a/src/particle_data.cpp b/src/core/particle_data.cpp similarity index 92% rename from src/particle_data.cpp rename to src/core/particle_data.cpp index f9d14f36a96..d726f757865 100644 --- a/src/particle_data.cpp +++ b/src/core/particle_data.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file particle_data.c +/** \file particle_data.cpp This file contains everything related to particle storage. If you want to add a new property to the particles, it is probably a good idea to modify \ref Particle to give scripts access to that property. You always have to modify two positions: first the @@ -26,7 +26,7 @@ section where you have to find a nice and short name for your property to appear in the Tcl code. Then you just parse your part out of argc and argv. - The corresponding header file is particle_data.h. + The corresponding header file is particle_data.hpp. */ #include #include @@ -56,17 +56,16 @@ /************************************************ * variables ************************************************/ -#ifdef GRANDCANONICAL +// List of particles for grandcanonical simulations TypeOfIndex Type; IndexOfType Index; TypeList *type_array; int number_of_type_lists; int GC_init; -int Type_array_init; -#endif +int Type_array_init = 0; int max_seen_particle = -1; -int n_total_particles = 0; +int n_part = 0; int max_particle_node = 0; int *particle_node = NULL; int max_local_particles = 0; @@ -115,7 +114,10 @@ void init_particle(Particle *part) #ifdef SHANCHEN int ii; for(ii=0;ii<2*LB_COMPONENTS;ii++){ - part->p.solvation[ii]=0; + part->p.solvation[ii]=0.0; + } + for(ii=0;iir.composition[ii]=0.0; } #endif @@ -273,10 +275,6 @@ void init_particle(Particle *part) part->l.ghost = 0; #endif -#ifdef ADRESS - part->p.adress_weight = 1.0; -#endif - #ifdef LANGEVIN_PER_PARTICLE part->p.T = -1.0; part->p.gamma = -1.0; @@ -296,27 +294,42 @@ void free_particle(Particle *part) { * organizational functions ************************************************/ -void updatePartCfg(int bonds_flag) +int updatePartCfg(int bonds_flag) { int j; if(partCfg) - return; + return 1; - partCfg = (Particle*)malloc(n_total_particles*sizeof(Particle)); + partCfg = (Particle*)malloc(n_part*sizeof(Particle)); if (bonds_flag != WITH_BONDS) mpi_get_particles(partCfg, NULL); else mpi_get_particles(partCfg,&partCfg_bl); - for(j=0; j= n_bonded_ia) { - char *errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{048 invalid/unknown bonded interaction type %d}", bond[0]); + ostringstream msg; + msg <<"invalid/unknown bonded interaction type " << bond[0]; + runtimeError(msg); return ES_ERROR; } } @@ -1105,7 +1107,6 @@ int remove_particle(int part) { int pnode; -#ifdef GRANDCANONICAL Particle *cur_par = (Particle *) malloc (sizeof(Particle)); if (get_particle_data(part, cur_par) == ES_ERROR ) return ES_ERROR; @@ -1113,7 +1114,6 @@ int remove_particle(int part) free(cur_par); if (remove_id_type_array(part, type) == ES_ERROR ) return ES_ERROR; -#endif if (!particle_node) build_particle_node(); @@ -1188,7 +1188,13 @@ void local_place_particle(int part, double p[3], int _new) pp[0] = p[0]; pp[1] = p[1]; pp[2] = p[2]; + +#ifdef LEES_EDWARDS + double vv[3]={0.,0.,0.}; + fold_position(pp, vv, i); +#else fold_position(pp, i); +#endif if (_new) { /* allocate particle anew */ @@ -1214,6 +1220,12 @@ void local_place_particle(int part, double p[3], int _new) PART_TRACE(fprintf(stderr, "%d: local_place_particle: got particle id=%d @ %f %f %f\n", this_node, part, p[0], p[1], p[2])); +#ifdef LEES_EDWARDS + pt->m.v[0] += vv[0]; + pt->m.v[1] += vv[1]; + pt->m.v[2] += vv[2]; +#endif + memcpy(pt->r.p, pp, 3*sizeof(double)); memcpy(pt->l.i, i, 3*sizeof(int)); #ifdef BOND_CONSTRAINT @@ -1225,7 +1237,7 @@ void local_remove_all_particles() { Cell *cell; int c; - n_total_particles = 0; + n_part = 0; max_seen_particle = -1; for (c = 0; c < local_cells.n; c++) { Particle *p; @@ -1265,7 +1277,7 @@ void added_particle(int part) { int i; - n_total_particles++; + n_part++; if (part > max_seen_particle) { realloc_local_particles(part); @@ -1500,12 +1512,10 @@ void recv_particles(ParticleList *particles, int node) #endif PART_TRACE(fprintf(stderr, "%d: recv_particles got particle %d\n", this_node, p->p.identity)); -#ifdef ADDITIONAL_CHECKS if (local_particles[p->p.identity] != NULL) { fprintf(stderr, "%d: transmitted particle %d is already here...\n", this_node, p->p.identity); errexit(); } -#endif } update_local_particles(particles); @@ -1594,7 +1604,7 @@ void auto_exclusion(int distance) init_intlist(&partners[p]); /* determine initial connectivity */ - for (p = 0; p < n_total_particles; p++) { + for (p = 0; p < n_part; p++) { part1 = &partCfg[p]; p1 = part1->p.identity; for (i = 0; i < part1->bl.n;) { @@ -1650,8 +1660,6 @@ void auto_exclusion(int distance) #endif -#ifdef GRANDCANONICAL - int init_gc(void){ if ( type_array == (TypeList *) NULL) { //stores the number of currently available type_list's @@ -1710,12 +1718,12 @@ int init_type_array(int type){ } int t_c = 0; //index - type_array[Index.type[type]].id_list = (int *) malloc (sizeof (int) * n_total_particles); - for (int i=0; iid_list[temp[1]]; -// return temp; -//} - int delete_particle_of_type(int type) { int *p_id, *index_id; p_id=(int *) malloc (sizeof(int)); @@ -1896,31 +1888,10 @@ int delete_particle_of_type(int type) { // takes also care of removing the index from the array return ES_ERROR; } -// //update array: -// printf ("delete part update array\n"); -// -// if ( *index_id == max ) { -// type_array[in_type].id_list[*index_id] = -1; -// } else { -// int temp=type_array[in_type].id_list[max]; -// type_array[in_type].id_list[max] = -1; -// type_array[in_type].id_list[*index_id]=temp; -// } -// type_array[in_type].max_entry--; -// free(p_id); -// free(index_id); -// printf ("returned ok\n"); return ES_OK; } int add_particle_to_list(int part_id, int type){ -// Particle *cur_par = (Particle *) malloc(sizeof(Particle)); -// if (cur_par == (Particle *) 0 ) -// return ES_ERROR; -// if (get_particle_data(part_id, cur_par) == ES_ERROR ) -// return ES_ERROR; -// -// int type = cur_par->p.type; int l_err=1; int already_in = 0; // int already_in_other_list = 0; @@ -1946,22 +1917,6 @@ int add_particle_to_list(int part_id, int type){ if ( already_in ) { return ES_OK; } -// int other_type_in = -1; -// int other_list_id = -1; -// for (int j=0; j= (double ) type_array[in_type].cur_size/2.0 ) if (reallocate_type_array(type)== ES_ERROR) @@ -1970,8 +1925,6 @@ int add_particle_to_list(int part_id, int type){ //add particle id to list: type_array[in_type].id_list[max]=part_id; type_array[in_type].max_entry++; -// free(cur_par); -// printf("added part %d to type list of type %d\n", part_id, type); return ES_OK; } @@ -1988,7 +1941,6 @@ int gc_status(int type){ return ES_ERROR; } int in_type = Index.type[type]; - //printf("ids of particles with type %d\n", type); for (int i = 0; imax=0; -// for (int i=0; in; i++){ -// if (plist->part[i]->type == type){ -// list->list->identifier=plist->part[i]->identity; -// list->type=type; -// list->list->next=malloc( sizeof (struct type_list) ); -// list->max++; -// } -// } -// list->next= (type_list_item *)0; -// // restore list to root pointer -// list=root; -// return ES_OK -//} + + + + +// The following functions are used by the python interface to obtain +// properties of a particle, which are only compiled in in some configurations +// This is needed, because cython does not support conditional compilation +// within a ctypedef definition + + +#ifdef ROTATION +void pointer_to_omega_body(Particle* p, double*& res) +{ + res=p->m.omega; +} + +void pointer_to_torque_lab(Particle* p, double*& res) +{ + res=p->f.torque; +} + +void pointer_to_quat(Particle* p, double*& res) +{ + res=p->r.quat; +} + +void pointer_to_quatu(Particle* p, double*& res) +{ + res=p->r.quatu; +} +#endif + +#ifdef ELECTROSTATICS +void pointer_to_q(Particle* p, double*& res) +{ + res =&(p->p.q); +} +#endif + +#ifdef VIRTUAL_SITES +void pointer_to_virtual(Particle* p, int*& res) +{ + res=&(p->p.isVirtual); +} +#endif + +#ifdef VIRTUAL_SITES_RELATIVE +void pointer_to_vs_relative(Particle* p, int*& res1,double*& res2) +{ + res1=&(p->p.vs_relative_to_particle_id); + res2=&(p->p.vs_relative_distance); +} +#endif + + +#ifdef MASS +void pointer_to_mass(Particle* p, double*& res) +{ + res=&(p->p.mass); +} +#endif + + +#ifdef DIPOLES +void pointer_to_dip(Particle* p, double*& res) +{ +res=p->r.dip; +} + +void pointer_to_dipm(Particle* p, double*& res) +{ +res=&(p->p.dipm); +} #endif + diff --git a/src/particle_data.hpp b/src/core/particle_data.hpp similarity index 95% rename from src/particle_data.hpp rename to src/core/particle_data.hpp index ee0da7b09af..b7339d37263 100644 --- a/src/particle_data.hpp +++ b/src/core/particle_data.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,14 +20,13 @@ */ #ifndef _PARTICLE_DATA_H #define _PARTICLE_DATA_H -/** \file particle_data.h +/** \file particle_data.hpp For more information on particle_data, - see \ref particle_data.c "particle_data.c" + see \ref particle_data.cpp "particle_data.c" */ #include "utils.hpp" -#include "global.hpp" /************************************************ * defines @@ -115,7 +114,7 @@ typedef struct { #endif #ifdef VIRTUAL_SITES - /** is particle virual + /** is particle virtual 0 = real particle else = virual particle */ int isVirtual; @@ -131,11 +130,6 @@ typedef struct { #endif #endif -#ifdef ADRESS - /** particles adress weight */ - double adress_weight; -#endif - #ifdef LANGEVIN_PER_PARTICLE double T; double gamma; @@ -169,6 +163,10 @@ typedef struct { double p_old[3]; #endif +#ifdef SHANCHEN + double composition[LB_COMPONENTS]; +#endif + } ParticlePosition; /** Force information on a particle. Forces of ghost particles are @@ -286,6 +284,9 @@ typedef struct { int n; /** Number of particles that fit in until a resize is needed */ int max; +#ifdef LEES_EDWARDS + int myIndex[3]; +#endif } ParticleList; /************************************************ @@ -300,7 +301,7 @@ typedef struct { */ extern int max_seen_particle; /** total number of particles on all nodes. */ -extern int n_total_particles; +extern int n_part; /** Capacity of the \ref particle_node / \ref local_particles. */ extern int max_particle_node; @@ -677,7 +678,7 @@ void remove_all_bonds_to(int part); information in \ref partCfg to be valid you should set the value of to \ref WITH_BONDS. */ -void updatePartCfg(int bonds_flag ); +int updatePartCfg(int bonds_flag ); /** release the partCfg array. Use this function, since it also frees the bonds, if they are used. @@ -788,7 +789,6 @@ void auto_exclusion(int distance); and not already in the list. */ void add_partner(IntList *il, int i, int j, int distance); -#ifdef GRANDCANONICAL //value that is returned in the case there was no error, but the type was not yet indexed #define NOT_INDEXED -3 //struct that associates the index used for the type_list and the real particle type @@ -803,15 +803,6 @@ typedef struct { int * index; } TypeOfIndex; -extern TypeOfIndex Type; -//index.max_entry=0; -//index->type = (int *) 0; - -extern IndexOfType Index; -//tindex.max_entry=0; -//tindex->type = (int *) 0; - - typedef struct { int max_entry; int cur_size; @@ -822,26 +813,15 @@ typedef struct { extern TypeList *type_array; extern int number_of_type_lists; +extern TypeOfIndex Type; +extern IndexOfType Index; + // flag indicating init_gc was called extern int GC_init; // flag that indicates that the function init_type_array was called already extern int Type_array_init; -/** linked list for particles of a given type */ -//typedef struct { -// int identifier; -// struct type_list_item *next; -//} type_list item; -// -//typedef struct { -// struct type_list_item *list; -// int type; -// int max; -//} type_list - -/** vars and fields */ - int init_gc(void); /** init particle lists */ @@ -861,9 +841,8 @@ int update_particle_array(int type); /* find a particle of given type and return its id */ int find_particle_type(int type, int *id); -/** return an array with real particle id and the corresponding index of typelist */ -//static int *find_particle_type(int type); +/** return an array with real particle id and the corresponding index of typelist */ int find_particle_type_id(int type, int *id, int *in_id ); /** delete one randomly chosen particle of given type @@ -875,6 +854,41 @@ int add_particle_to_list(int part_id, int type); // print out a list of currently indexed ids int gc_status(int type); int number_of_particles_with_type(int type, int *number); + + +// The following functions are used by the python interface to obtain +// properties of a particle, which are only compiled in in some configurations +// This is needed, because cython does not support conditional compilation +// within a ctypedef definition + + +#ifdef ROTATION +void pointer_to_omega_body(Particle* p, double*& res); + +void pointer_to_torque_lab(Particle* p, double*& res); + +void pointer_to_quat(Particle* p, double*& res); +void pointer_to_quatu(Particle* p, double*& res); + +#endif + +#ifdef ELECTROSTATICS +void pointer_to_q(Particle* p, double*& res); #endif +#ifdef VIRTUAL_SITES +void pointer_to_virtual(Particle* p, int*& res); +#endif + +#ifdef VIRTUAL_SITES_RELATIVE +void pointer_to_vs_relative(Particle* p, int*& res1,double*& res2); +#endif + +#ifdef MASS +void pointer_to_mass(Particle* p, double*& res); +#endif + +void pointer_to_dip(Particle* P, double*& res); + +void pointer_to_dipm(Particle* P, double*& res); #endif diff --git a/src/polymer.cpp b/src/core/polymer.cpp similarity index 95% rename from src/polymer.cpp rename to src/core/polymer.cpp index caacf54ba85..6ce2f3662f0 100644 --- a/src/polymer.cpp +++ b/src/core/polymer.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file polymer.c +/** \file polymer.cpp This file contains everything needed to create a start-up configuration of (partially charged) polymer chains with counterions and salt molecules, assigning velocities to the particles and crosslinking the polymers if necessary. - The corresponding header file is polymer.h. + The corresponding header file is polymer.hpp. Created: 27.02.2003 by BAM Based upon 'polymer.tcl' by BAM (20.02.2003). @@ -42,7 +42,7 @@ #include "random.hpp" #include "integrate.hpp" #include "constraint.hpp" - +#include "global.hpp" @@ -58,17 +58,18 @@ int mindist3(int part_id, double r_catch, int *ids) { double dx,dy,dz; int i, me, caught=0; - partCfgMD = (Particle*)malloc(n_total_particles*sizeof(Particle)); + partCfgMD = (Particle*)malloc(n_part*sizeof(Particle)); mpi_get_particles(partCfgMD, NULL); me = -1; /* Since 'mpi_get_particles' returns the particles unsorted, it's most likely that 'partCfgMD[i].p.identity != i' --> prevent that! */ - for(i=0; i v_max); + v[0] = v_max * 2.*(d_random()-.5) * time_step; + v[1] = v_max * 2.*(d_random()-.5) * time_step; + v[2] = v_max * 2.*(d_random()-.5) * time_step; + // note that time_step == -1, as long as it is not yet set + } while ( sqrt(SQR(v[0])+SQR(v[1])+SQR(v[2])) > v_max * fabs(time_step)); v_av[0]+=v[0]; v_av[1]+=v[1]; v_av[2]+=v[2]; if (set_particle_v(i, v)==ES_ERROR) { fprintf(stderr, "INTERNAL ERROR: failed upon setting one of the velocities in Espresso (current average: %f)!\n", @@ -504,7 +515,8 @@ double velocitiesC(double v_max, int part_id, int N_T) { fprintf(stderr, "Aborting...\n"); errexit(); } } - return ( sqrt(SQR(v_av[0])+SQR(v_av[1])+SQR(v_av[2])) ); + // note that time_step == -1, as long as it is not yet set + return ( sqrt(SQR(v_av[0])+SQR(v_av[1])+SQR(v_av[2])) / fabs(time_step) ); } double maxwell_velocitiesC(int part_id, int N_T) { @@ -537,7 +549,8 @@ double maxwell_velocitiesC(int part_id, int N_T) { fprintf(stderr, "Aborting...\n"); errexit(); } } - return ( sqrt(SQR(v_av[0])+SQR(v_av[1])+SQR(v_av[2])) ); + // note that time_step == -1, as long as it is not yet set + return ( sqrt(SQR(v_av[0])+SQR(v_av[1])+SQR(v_av[2])) / fabs(time_step) ); } int collectBonds(int mode, int part_id, int N_P, int MPC, int type_bond, int **bond_out, int ***bonds_out) { @@ -547,12 +560,12 @@ int collectBonds(int mode, int part_id, int N_P, int MPC, int type_bond, int **b IntList *bl; Particle *prt, *sorted; bl = (IntList*)malloc(1*sizeof(IntList)); - prt = (Particle*)malloc(n_total_particles*sizeof(Particle)); + prt = (Particle*)malloc(n_part*sizeof(Particle)); mpi_get_particles(prt, bl); /* Sort the received informations. */ - sorted = (Particle*)malloc(n_total_particles*sizeof(Particle)); - for(i = 0; i < n_total_particles; i++) + sorted = (Particle*)malloc(n_part*sizeof(Particle)); + for(i = 0; i < n_part; i++) memcpy(&sorted[prt[i].p.identity], &prt[i], sizeof(Particle)); free(prt); prt = sorted; @@ -648,7 +661,7 @@ int crosslinkC(int N_P, int MPC, int part_id, double r_catch, int link_dist, int for (i=0; i < N_P; i++) { for (k=0; k<2; k++) { if (bond[i*MPC+k*(MPC-1)] == 1) { - links[2*i+k] = (int*)malloc(n_total_particles*sizeof(int)); + links[2*i+k] = (int*)malloc(n_part*sizeof(int)); link[2*i+k] = mindist3(i*MPC+k*(MPC-1)+part_id, r_catch, links[2*i+k]); links[2*i+k] = (int*)realloc(links[2*i+k],link[2*i+k]*sizeof(int)); } diff --git a/src/polymer.hpp b/src/core/polymer.hpp similarity index 98% rename from src/polymer.hpp rename to src/core/polymer.hpp index e92ab1afa37..75308c0217c 100644 --- a/src/polymer.hpp +++ b/src/core/polymer.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,14 +20,14 @@ */ #ifndef POLYMER_H #define POLYMER_H -/** \file polymer.h +/** \file polymer.hpp This file contains everything needed to create a start-up configuration of (partially charged) polymer chains with counterions and salt molecules, assigning velocities to the particles and crosslinking the polymers if necessary. - For more information on polymer, see \ref polymer.c "polymer.c" + For more information on polymer, see \ref polymer.cpp "polymer.c" */ #include "particle_data.hpp" diff --git a/src/polynom.hpp b/src/core/polynom.hpp similarity index 96% rename from src/polynom.hpp rename to src/core/polynom.hpp index 69cef4c4e37..cdfa32f4e6a 100644 --- a/src/polynom.hpp +++ b/src/core/polynom.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file polynom.h +/** \file polynom.hpp Datatypes and functions for polynomials. Evaluation possible both as Taylor and Chebychev series. Note that the length of the double list is equal to the order of the polynomial plus 1, so that Polynom->n does not give diff --git a/src/pressure.cpp b/src/core/pressure.cpp similarity index 96% rename from src/pressure.cpp rename to src/core/pressure.cpp index eba725fca95..e6537f5196e 100644 --- a/src/pressure.cpp +++ b/src/core/pressure.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file pressure.c - Implementation of \ref pressure.h "pressure.h". +/** \file pressure.cpp + Implementation of \ref pressure.hpp "pressure.h". */ #include "pressure.hpp" #include "cells.hpp" @@ -85,7 +85,7 @@ void pressure_calc(double *result, double *result_t, double *result_nb, double * int n, i; double volume = box_l[0]*box_l[1]*box_l[2]; - if (!check_obs_calc_initialized()) + if (!interactions_sanity_checks()) return; init_virials(&virials); @@ -182,8 +182,14 @@ void calc_long_range_virials() fprintf(stderr, "WARNING: pressure calculated, but MMM2D pressure not implemented\n"); break; case COULOMB_MMM1D: + case COULOMB_MMM1D_GPU: fprintf(stderr, "WARNING: pressure calculated, but MMM1D pressure not implemented\n"); break; + case COULOMB_EWALD_GPU: + fprintf(stderr, "WARNING: pressure calculated, but Ewald pressure not implemented\n"); + break; + default: + break; } #endif /*ifdef ELECTROSTATICS */ @@ -218,6 +224,8 @@ void calc_long_range_virials() break; } #endif + default: + break; } #endif /*ifdef DIPOLES */ } @@ -251,6 +259,9 @@ void init_virials(Observable_stat *stat) case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: n_dipolar = 0; break; case DIPOLAR_DS: n_dipolar = 0; break; case DIPOLAR_P3M: n_dipolar = 2; break; + default: + n_dipolar = 0; + break; } #endif #ifdef VIRTUAL_SITES_RELATIVE @@ -306,6 +317,7 @@ void init_p_tensor(Observable_stat *stat) case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: n_dipolar = 0; break; case DIPOLAR_DS: n_dipolar = 0; break; case DIPOLAR_P3M: n_dipolar = 2; break; + default: n_dipolar = 0; } #endif #ifdef VIRTUAL_SITES_RELATIVE @@ -362,14 +374,16 @@ int getintersection(double pos1[3], double pos2[3],int given, int get, double va //PTENSOR_TRACE(fprintf(stderr,"%d: getintersection: p1 is %f %f %f p2 is %f %f %f p2r is %f %f %f newvalue is %f\n",this_node,pos1[0],pos1[1],pos1[2],pos2[0],pos2[1],pos2[2],p2r[0],p2r[1],p2r[2],value);); if ((value)*(p2r[given]) < -0.0001) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{analyze stress_profile: getintersection: intersection is not between the two given particles - %e is not between %e and %e and box size is %e, given is %d\n ",value,0.0,p2r[given],box_size[given],given); + ostringstream msg; + msg <<"analyze stress_profile: getintersection: intersection is not between the two given particles - " << value << " is not between " << 0.0 << " and " << p2r[given] << " and box size is " << box_size[given] << ", given is " << given << "\n"; + runtimeError(msg); return 0; } else if (given == get) { *answer = drem_down(value + pos1[given],box_size[given]);; } else if (0==p2r[given]) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{analyze stress_profile: getintersection: intersection is a line, not a point - value is %g same as %g and %g\n",value,0.0,p2r[given]); + ostringstream msg; + msg <<"analyze stress_profile: getintersection: intersection is a line, not a point - value is " << value << " same as " << 0.0 << " and " << p2r[given] << "\n"; + runtimeError(msg); return 0; } else { *answer = drem_down(pos1[get]+p2r[get]/p2r[given]*value,box_size[get]); @@ -761,8 +775,9 @@ int distribute_tensors(DoubleList *TensorInBin, double *force, int bins[3], doub PTENSOR_TRACE(fprintf(stderr,"%d: distribute_tensors: calclength is %e and length is %e\n}",this_node,calclength,length);); if (calclength - length >0.0000000001) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{%d: analyze stress_profile: bug in distribute tensor code - calclength is %e and length is %e}",this_node,calclength,length); + ostringstream msg; + msg << this_node << ": analyze stress_profile: bug in distribute tensor code - calclength is " << calclength << " and length is " << length; + runtimeError(msg); return 0; } free(occupiedzbins); @@ -829,7 +844,7 @@ int get_nonbonded_interaction(Particle *p1, Particle *p2, double *force) get_mi_vector(d, p1->r.p, p2->r.p); dist2 = SQR(d[0]) + SQR(d[1]) + SQR(d[2]); dist = sqrt(dist2); - calc_non_bonded_pair_force_simple(p1,p2,d,dist,dist2,force); + calc_non_bonded_pair_force(p1,p2,d,dist,dist2,force); #ifdef ELECTROSTATICS if (coulomb.method != COULOMB_NONE) { switch (coulomb.method) { @@ -932,15 +947,11 @@ int local_stress_tensor_calc(DoubleList *TensorInBin, int bins[3], int periodic[ skin from on opposite sides of the box overlaps then we produce an error message. To code dround this would be creating unnecessary work since I can't imagine when we might want that */ - if (skin < 0.0) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{analyze stress_profile: parameter skin not set}"); - return 0; - } for (i=0;i<3;i++) { if ((! periodic[i]) && (range[i] + 2*skin +2*max_cut > box_l[i])) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{analyze stress_profile: Analyzed box (%g) with skin+max_cut(%g) is larger than simulation box (%g).\n",range[i],skin+max_cut,box_l[i]); + ostringstream msg; + msg <<"analyze stress_profile: Analyzed box (" << range[i] << ") with skin+max_cut(" << skin+max_cut << ") is larger than simulation box (" << box_l[i] << ").\n"; + runtimeError(msg); return 0; } range_start[i] = drem_down(range_start[i],box_l[i]); diff --git a/src/pressure.hpp b/src/core/pressure.hpp similarity index 89% rename from src/pressure.hpp rename to src/core/pressure.hpp index bdc12eeaf4e..9f4220310ca 100644 --- a/src/pressure.hpp +++ b/src/core/pressure.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,19 +18,18 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file pressure.h - Pressure calculation. Really similar to \ref energy.h "energy.h". +/** \file pressure.hpp + Pressure calculation. Really similar to \ref energy.hpp "energy.h". */ -#ifndef _PRESSURE_H -#define _PRESSURE_H +#ifndef _PRESSURE_HPP +#define _PRESSURE_HPP #include "utils.hpp" #include "integrate.hpp" #include "statistics.hpp" #include "thermostat.hpp" -#include "adresso.hpp" -#include "forces.hpp" +#include "forces_inline.hpp" #include "npt.hpp" /** \name Exported Variables */ @@ -76,7 +75,7 @@ inline void add_non_bonded_pair_virials(Particle *p1, Particle *p2, double d[3], int p1molid, p2molid, k, l; double force[3] = {0, 0, 0}; - calc_non_bonded_pair_force_simple(p1, p2,d, dist, dist2,force); + calc_non_bonded_pair_force(p1, p2,d, dist, dist2, force); *obsstat_nonbonded(&virials, p1->p.type, p2->p.type) += d[0]*force[0] + d[1]*force[1] + d[2]*force[2]; @@ -155,14 +154,7 @@ inline void add_non_bonded_pair_virials(Particle *p1, Particle *p2, double d[3], inline void calc_bonded_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, int *i, double dx[3], double force[3]) { #ifdef TABULATED - char* errtxt; -#endif - -#ifdef ADRESS - int j; - double force_weight=1; - //adress_bonded_force_weight(p1); - if (force_weightp.identity); + ostringstream msg; + msg <<"calc_bonded_force: tabulated bond type of atom " << p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -210,7 +203,7 @@ inline void calc_bonded_force(Particle *p1, Particle *p2, Bonded_ia_parameters * #ifdef OVERLAPPED case BONDED_IA_OVERLAPPED: // printf("BONDED OVERLAP, Particle: %d, P2: %d TYPE_OVERLAP: %d\n",p1->p.identity,p2->p.identity,iparams->p.tab.type); - char *errtxt; + //char *errtxt; switch(iaparams->p.overlap.type) { case OVERLAP_BOND_LENGTH: calc_overlap_bond_force(p1, p2, iaparams, dx, force); break; @@ -219,8 +212,9 @@ inline void calc_bonded_force(Particle *p1, Particle *p2, Bonded_ia_parameters * case OVERLAP_BOND_DIHEDRAL: (*i)+=2; force[0] = force[1] = force[2] = 0; break; default: - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{081 calc_bonded_force: overlapped bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg <<"calc_bonded_force: overlapped bond type of atom " << p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -239,15 +233,6 @@ inline void calc_bonded_force(Particle *p1, Particle *p2, Bonded_ia_parameters * force[0] = force[1] = force[2] = 0; break; } -#ifdef ADRESS - if((get_mol_com_particle(p1))->p.identity == (get_mol_com_particle(p2))->p.identity) - force_weight = 1.0; - else - force_weight=adress_non_bonded_force_weight(p1,p2); - for (j=0;j<3;j++){ - force[j]*=force_weight; - } -#endif } @@ -257,7 +242,7 @@ inline void calc_three_body_bonded_forces(Particle *p1, Particle *p2, Particle * Bonded_ia_parameters *iaparams, double force1[3], double force2[3], double force3[3]) { #ifdef TABULATED - char* errtxt; + //char* errtxt; #endif switch(iaparams->type) { @@ -289,8 +274,9 @@ inline void calc_three_body_bonded_forces(Particle *p1, Particle *p2, Particle * calc_angle_3body_tabulated_forces(p1, p2, p3, iaparams, force1, force2, force3); break; default: - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{081 calc_bonded_force: tabulated bond type of atom %d unknown\n", p1->p.identity); + ostringstream msg; + msg <<"calc_bonded_force: tabulated bond type of atom " << p1->p.identity << " unknown\n"; + runtimeError(msg); return; } break; @@ -312,7 +298,7 @@ inline void calc_three_body_bonded_forces(Particle *p1, Particle *p2, Particle * inline void add_bonded_virials(Particle *p1) { double dx[3], force[3] = {0,0,0}; - char *errtxt; + //char *errtxt; Particle *p2; Bonded_ia_parameters *iaparams; @@ -330,9 +316,9 @@ inline void add_bonded_virials(Particle *p1) // for harmonic spring: // if cutoff was defined and p2 is not there it is anyway outside the cutoff, see calc_maximal_cutoff() if ((type_num==BONDED_IA_HARMONIC)&&(iaparams->p.harmonic.r_cut>0)) return; - errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{088 bond broken between particles %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[i-1]); + ostringstream msg; + msg <<"bond broken between particles " << p1->p.identity << " and " << p1->bl.e[i-1] << " (particles not stored on the same node)"; + runtimeError(msg); return; } @@ -361,14 +347,14 @@ inline void add_three_body_bonded_stress(Particle *p1) { double force2[3]; double force3[3]; - char *errtxt; + //char *errtxt; Particle *p2; Particle *p3; Bonded_ia_parameters *iaparams; int i, k, j, l; int type_num; - int type; + BondedInteraction type; i = 0; while(i < p1->bl.n) { @@ -480,8 +466,9 @@ inline void add_three_body_bonded_stress(Particle *p1) { i = i + 4; } else { - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"add_three_body_bonded_stress: match not found for particle %d.\n", p1->p.identity); + ostringstream msg; + msg <<"add_three_body_bonded_stress: match not found for particle " << p1->p.identity << ".\n"; + runtimeError(msg); } } #endif @@ -496,8 +483,9 @@ inline void add_three_body_bonded_stress(Particle *p1) { } #endif else { - errtxt = runtime_error(128 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"add_three_body_bonded_stress: match not found for particle %d.\n", p1->p.identity); + ostringstream msg; + msg <<"add_three_body_bonded_stress: match not found for particle " << p1->p.identity << ".\n"; + runtimeError(msg); } } } diff --git a/src/core/quartic.cpp b/src/core/quartic.cpp new file mode 100644 index 00000000000..60d22be8f53 --- /dev/null +++ b/src/core/quartic.cpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file quartic.cpp + * + * Implementation of \ref quartic.hpp + */ +#include "quartic.hpp" +#include "communication.hpp" + +int quartic_set_params(int bond_type, double k0, double k1, double r,double r_cut) +{ + if(bond_type < 0) + return ES_ERROR; + + make_bond_type_exist(bond_type); + + bonded_ia_params[bond_type].p.quartic.k0 = k0; + bonded_ia_params[bond_type].p.quartic.k1 = k1; + bonded_ia_params[bond_type].p.quartic.r = r; + bonded_ia_params[bond_type].p.quartic.r_cut = r_cut; + bonded_ia_params[bond_type].type = BONDED_IA_QUARTIC; + bonded_ia_params[bond_type].num = 1; + + /* broadcast interaction parameters */ + mpi_bcast_ia_params(bond_type, -1); + + return ES_OK; +} diff --git a/src/core/quartic.hpp b/src/core/quartic.hpp new file mode 100644 index 00000000000..3334922302f --- /dev/null +++ b/src/core/quartic.hpp @@ -0,0 +1,96 @@ +/* + Copyright (C) 2010,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _QUARTIC_HPP +#define _QUARTIC_HPP +/** \file quartic.hpp + * Routines to calculate the HARMONIC Energy or/and HARMONIC force + * for a particle pair. + * \ref forces.cpp +*/ + +/************************************************************/ + +#include "utils.hpp" +#include "interaction_data.hpp" +#include "particle_data.hpp" +#include "random.hpp" + +/// set the parameters for the quartic potential +int quartic_set_params(int bond_type, double k0, double k1, double r,double r_cut); + +/** Computes the QUARTIC pair force and adds this + force to the particle forces (see \ref interaction_data.cpp). + @param p1 Pointer to first particle. + @param p2 Pointer to second/middle particle. + @param iaparams bond type number of the angle interaction (see \ref interaction_data.cpp). + @param dx particle distance vector + @param force returns force of particle 1 + @return 0. +*/ +inline int calc_quartic_pair_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force[3]) +{ + int i; + double fac; + double dist2 = sqrlen(dx); + double dist = sqrt(dist2); + double dr; + + if ((iaparams->p.quartic.r_cut > 0.0) && + (dist > iaparams->p.quartic.r_cut)) + return 1; + + dr = dist - iaparams->p.quartic.r; + if (fabs(dr) > ROUND_ERROR_PREC) { + if(dist>ROUND_ERROR_PREC) { /* Regular case */ + fac = dr / dist; + } else { /* dx[] == 0: the force is undefined. Let's use a random direction */ + for(i=0;i<3;i++) dx[i] = d_random()-0.5; + fac = dr / sqrt(sqrlen(dx)); + } + } else { + fac=0; + } + + for(i=0;i<3;i++) + force[i] = -(iaparams->p.quartic.k0 + iaparams->p.quartic.k1 * dr * dr ) * fac*dx[i]; + + ONEPART_TRACE(if(p1->p.identity==check_id) fprintf(stderr,"%d: OPT: QUARTIC f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p1->f.f[0],p1->f.f[1],p1->f.f[2],p2->p.identity,dist2,fac)); + ONEPART_TRACE(if(p2->p.identity==check_id) fprintf(stderr,"%d: OPT: QUARTIC f = (%.3e,%.3e,%.3e) with part id=%d at dist %f fac %.3e\n",this_node,p2->f.f[0],p2->f.f[1],p2->f.f[2],p1->p.identity,dist2,fac)); + + return 0; +} + +inline int quartic_pair_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy) +{ + double dist2 = sqrlen(dx); + double dist = sqrt(dist2); + + if ((iaparams->p.quartic.r_cut > 0.0) && + (dist > iaparams->p.quartic.r_cut)) + return 1; + + double dr2 = SQR(dist - iaparams->p.quartic.r); + + *_energy = 0.5*iaparams->p.quartic.k0*dr2 + 0.25 * iaparams->p.quartic.k1 * SQR(dr2); + return 0; +} + +#endif diff --git a/src/random.cpp b/src/core/random.cpp similarity index 97% rename from src/random.cpp rename to src/core/random.cpp index 17fc63f5256..64dd248cd6e 100644 --- a/src/random.cpp +++ b/src/core/random.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -26,7 +26,7 @@ #include "random.hpp" #include "communication.hpp" -/** \file random.c A random generator. +/** \file random.cpp A random generator. Be sure to run init_random() before you use any of the generators. */ /* Stuff for Franks ran1-generator */ @@ -65,10 +65,11 @@ void init_random_seed(long seed) /* This random generator is bad I know {why, Frank? It's the same as the one in l_random!}, thats why its only {no, in l_random as well!} used for the seed (see Num. Rec. 7.1.) */ - if(seed < 1) { + if (seed < 1) { fprintf(stderr,"The initial seed of the random number generator must be a positive integer!\n"); fprintf(stderr,"Using 0 will result in a plain 0-sequence, hence it's forbidden (you used: %ld)!\n",seed); - fflush(NULL); errexit(); + fflush(NULL); + errexit(); } idumInit = idum = seed; RANDOM_TRACE(fprintf(stderr, "%d: Init random with seed %ld in 'random.c'\n",this_node,idum)); diff --git a/src/random.hpp b/src/core/random.hpp similarity index 69% rename from src/random.hpp rename to src/core/random.hpp index 75d39635e4b..f7430ccec48 100644 --- a/src/random.hpp +++ b/src/core/random.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef RANDOM_H #define RANDOM_H -/** \file random.h +/** \file random.hpp A random generator */ @@ -166,6 +166,80 @@ inline double gaussian_random(void) { } +/** Generator for Gaussian random numbers. Uses the Box-Muller + * transformation to generate two Gaussian random numbers from two + * uniform random numbers. which generates numbers between -2 sigma and 2 sigma in the form of a Gaussian with standard deviation sigma=1.118591404 resulting in + * an actual standard deviation of 1. + * + * @return Gaussian random number. + * + */ +inline double gaussian_random_cut(void) { + double x1, x2, r2, fac; + static int calc_new = 1; + static double save, curr; + + /* On every second call two gaussian random numbers are calculated + via the Box-Muller transformation. One is returned as the result + and the second one is stored for use on the next call. + */ + + if (calc_new) { + + /* draw two uniform random numbers in the unit circle */ + do { + x1 = 2.0*d_random()-1.0; + x2 = 2.0*d_random()-1.0; + r2 = x1*x1 + x2*x2; + } while (r2 >= 1.0 || r2 == 0.0); + + /* perform Box-Muller transformation */ + fac = sqrt(-2.0*log(r2)/r2); + + // save one number for later use + save = x1*fac*1.042267973; + if ( fabs(save) > 2*1.042267973 ) { + if ( save > 0 ) save = 2*1.042267973; + else save = -2*1.042267973; + } + calc_new = 0; + + // return the second number + curr = x2*fac*1.042267973; + if ( fabs(curr) > 2*1.042267973) { + if ( curr > 0 ) curr = 2*1.042267973; + else curr = -2*1.042267973; + } + return curr; + + /* save one number for later use */ + /* + save = x1*fac*1.118591404; + if ( fabs(save) > 2*1.118591404 ) { + save = (2.0*d_random()-1.0)*2*1.118591404; + } + calc_new = 0; + + // return the second number + curr = x2*fac*1.118591404; + if ( fabs(curr) > 2*1.118591404) { + curr = (2.0*d_random()-1.0)*2*1.118591404; + } + return curr; + */ + + } else { + + calc_new = 1; + + /* return the stored gaussian random number */ + return save; + + } + +} + + /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ /*----------------------------------------------------------*/ diff --git a/src/rattle.cpp b/src/core/rattle.cpp similarity index 92% rename from src/rattle.cpp rename to src/core/rattle.cpp index 202ac99d40b..7fb266233f4 100644 --- a/src/rattle.cpp +++ b/src/core/rattle.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -146,10 +146,10 @@ void compute_pos_corr_vec(int *repeat_) if( ia_params->type == BONDED_IA_RIGID_BOND ) { cnt++; p2 = local_particles[p1->bl.e[k++]]; - if (!p2) { - char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{051 rigid bond broken between particles %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[k-1]); + if (!p2) { + ostringstream msg; + msg <<"rigid bond broken between particles " << p1->p.identity << " and " << p1->bl.e[k-1] << " (particles not stored on the same node)"; + runtimeError(msg); return; } @@ -230,8 +230,9 @@ void correct_pos_shake() cnt++; }// while(repeat) loop if (cnt >= SHAKE_MAX_ITERATIONS) { - char *errtxt = runtime_error(100 + ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "{053 RATTLE failed to converge after %d iterations} ", cnt); + ostringstream msg; + msg <<"RATTLE failed to converge after " << cnt << " iterations"; + runtimeError(msg); } check_resort_particles(); @@ -299,10 +300,10 @@ void compute_vel_corr_vec(int *repeat_) if( ia_params->type == BONDED_IA_RIGID_BOND ) { p2 = local_particles[p1->bl.e[k++]]; - if (!p2) { - char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{054 rigid bond broken between particles %d and %d (particles not stored on the same node)} ", - p1->p.identity, p1->bl.e[k-1]); + if (!p2) { + ostringstream msg; + msg <<"rigid bond broken between particles " << p1->p.identity << " and " << p1->bl.e[k-1] << " (particles not stored on the same node)"; + runtimeError(msg); return; } @@ -443,9 +444,10 @@ void print_bond_len() if(b_ia->type == BONDED_IA_RIGID_BOND) { Particle *p2 = local_particles[p[i].bl.e[k++]]; - if (!p2) { - char *errtxt = runtime_error(128 + 2*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"{056 rigid bond broken between particles %d and %d (particles not stored on the same node)} ", p[i].p.identity, p[i].bl.e[k-1]); + if (!p2) { + ostringstream msg; + msg <<"rigid bond broken between particles " << p[i].p.identity << " and " << p[i].bl.e[k-1] << " (particles not stored on the same node)"; + runtimeError(msg); return; } diff --git a/src/rattle.hpp b/src/core/rattle.hpp similarity index 89% rename from src/rattle.hpp rename to src/core/rattle.hpp index 8fb8e8d53a6..a8970c14fb1 100644 --- a/src/rattle.hpp +++ b/src/core/rattle.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,11 +21,11 @@ #ifndef RATTLE_H #define RATTLE_H -/** \file rattle.h RATTLE Algorithm (Rattle: A "Velocity" Version of the Shake +/** \file rattle.hpp RATTLE Algorithm (Rattle: A "Velocity" Version of the Shake * Algorithm for Molecular Dynamics Calculations, H.C Andersen, * J Comp Phys, 52, 24-34, 1983) * - * For more information see \ref rattle.c "rattle.c". + * For more information see \ref rattle.cpp "rattle.c". */ #include "global.hpp" #include "particle_data.hpp" diff --git a/src/reaction.cpp b/src/core/reaction.cpp similarity index 88% rename from src/reaction.cpp rename to src/core/reaction.cpp index d79feb2f578..4eee38293c7 100644 --- a/src/reaction.cpp +++ b/src/core/reaction.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file reaction.c +/** \file reaction.cpp * */ @@ -27,10 +27,33 @@ #include "initialize.hpp" #include "forces.hpp" #include "errorhandling.hpp" +#include "cells.hpp" +#include "domain_decomposition.hpp" reaction_struct reaction; #ifdef CATALYTIC_REACTIONS + +void reactions_sanity_checks() +{ + + if(reaction.ct_rate != 0.0) { + + if( dd.use_vList == 0 || cell_structure.type != CELL_STRUCTURE_DOMDEC) { + ostringstream msg; + msg <<"The CATALYTIC_REACTIONS feature requires verlet lists and domain decomposition"; + runtimeError(msg); + } + + if(max_cut < reaction.range) { + ostringstream msg; + msg <<"Reaction range of " << reaction.range << " exceeds maximum cutoff of " << max_cut; + runtimeError(msg); + } + } +} + + void local_setup_reaction() { /* Make available the various reaction parameters */ @@ -50,9 +73,10 @@ void local_setup_reaction() { /* Make ESPResSo aware that reactants and catalyst are interacting species */ IA_parameters *data = get_ia_param_safe(reaction.reactant_type, reaction.catalyzer_type); - if(!data) { - char *error_msg = runtime_error(128); - ERROR_SPRINTF(error_msg, "{106 interaction parameters for reaction could not be set} "); + if(!data) { + ostringstream msg; + msg <<"interaction parameters for reaction could not be set"; + runtimeError(msg); } /* Used for the range of the verlet lists */ diff --git a/src/reaction.hpp b/src/core/reaction.hpp similarity index 89% rename from src/reaction.hpp rename to src/core/reaction.hpp index 971f322da26..e66b9b8f66b 100644 --- a/src/reaction.hpp +++ b/src/core/reaction.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef REACTION_H #define REACTION_H -/** \file reaction.h +/** \file reaction.hpp * */ @@ -40,6 +40,8 @@ typedef struct { extern reaction_struct reaction; #ifdef CATALYTIC_REACTIONS +/** sanity checks for the reaction code */ +void reactions_sanity_checks(); /** broadcasts reaction parameters and sets up an entry in the ia_params, so that the verlet radius is equal or bigger than the reaction range. **/ diff --git a/src/reaction_field.cpp b/src/core/reaction_field.cpp similarity index 92% rename from src/reaction_field.cpp rename to src/core/reaction_field.cpp index 1d580eaaf2f..dd564545378 100644 --- a/src/reaction_field.cpp +++ b/src/core/reaction_field.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file reaction_field.c +/** \file reaction_field.cpp * - * Implementation of \ref reaction_field.h + * Implementation of \ref reaction_field.hpp */ #include "reaction_field.hpp" diff --git a/src/reaction_field.hpp b/src/core/reaction_field.hpp similarity index 97% rename from src/reaction_field.hpp rename to src/core/reaction_field.hpp index 5639092f725..bab5cb37ff9 100644 --- a/src/reaction_field.hpp +++ b/src/core/reaction_field.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,11 +20,11 @@ */ #ifndef REACTION_FIELD_H #define REACTION_FIELD_H -/** \file reaction_field.h +/** \file reaction_field.hpp * Routines to calculate the Reaction Field Energy or/and force * for a particle pair. * M. Neumann, J. Chem. Phys 82, 5663 (1985) - * \ref forces.c + * \ref forces.cpp * */ diff --git a/src/rotation.cpp b/src/core/rotation.cpp similarity index 95% rename from src/rotation.cpp rename to src/core/rotation.cpp index 1885ee0c049..2a36e2aeec4 100644 --- a/src/rotation.cpp +++ b/src/core/rotation.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,13 +18,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file rotation.c Molecular dynamics integrator for rotational motion. +/** \file rotation.cpp Molecular dynamics integrator for rotational motion. * * A velocity Verlet algorithm * using quaternions is implemented to tackle rotational motion. A random torque and a friction * term are added to provide the constant NVT conditions. Due to this feature all particles are * treated as 3D objects with 3 translational and 3 rotational degrees of freedom if ROTATION - * flag is set in \ref config.h "config.h". + * flag is set in \ref config.hpp "config.h". */ #include @@ -57,7 +57,7 @@ /** moment of inertia. Currently we define the inertia tensor here to be constant. If it is not spherical the angular velocities have to be refined several times in the \ref convert_torques_propagate_omega. Also the kinetic energy in file - \ref statistics.c is calculated assuming that I[0] = I[1] = I[2] = 1 */ + \ref statistics.cpp is calculated assuming that I[0] = I[1] = I[2] = 1 */ static double I[3] = { 1, 1, 1}; /** \name Privat Functions */ @@ -382,6 +382,17 @@ void convert_torques_body_to_space(Particle *p, double *torque) torque[2] = A[0 + 3*2]*p->f.torque[0] + A[1 + 3*2]*p->f.torque[1] + A[2 + 3*2]*p->f.torque[2]; } +void convert_vel_space_to_body(Particle *p, double *vel_body) +{ + double A[9]; + define_rotation_matrix(p, A); + + vel_body[0] = A[0 + 3*0]*p->m.v[0] + A[0 + 3*1]*p->m.v[1] + A[0 + 3*2]*p->m.v[2]; + vel_body[1] = A[1 + 3*0]*p->m.v[0] + A[1 + 3*1]*p->m.v[1] + A[1 + 3*2]*p->m.v[2]; + vel_body[2] = A[2 + 3*0]*p->m.v[0] + A[2 + 3*1]*p->m.v[1] + A[2 + 3*2]*p->m.v[2]; +} + + /** Multiply two quaternions */ void multiply_quaternions(double a[4], double b[4], double result[4]) { diff --git a/src/rotation.hpp b/src/core/rotation.hpp similarity index 91% rename from src/rotation.hpp rename to src/core/rotation.hpp index a6d9958f807..d62d5615596 100644 --- a/src/rotation.hpp +++ b/src/core/rotation.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef ROTATION_H #define ROTATION_H -/** \file rotation.h +/** \file rotation.hpp This file contains all subroutines required to process rotational motion. */ @@ -49,7 +49,11 @@ void convert_initial_torques(); /** convert angular velocities and torques from the body-fixed frames to space-fixed coordinates */ void convert_omega_body_to_space(Particle *p, double *omega); -void convert_torques_body_to_space(Particle *p, double torque[3]); +void convert_torques_body_to_space(Particle *p, double *torque); + +/** convert velocity form the lab-fixed coordinates + to the body-fixed frame */ +void convert_vel_space_to_body(Particle *p, double *vel_body); /** Here we use quaternions to calculate the rotation matrix which will be used then to transform torques from the laboratory to diff --git a/src/soft_sphere.cpp b/src/core/soft_sphere.cpp similarity index 90% rename from src/soft_sphere.cpp rename to src/core/soft_sphere.cpp index c9e81c40356..08e8b1a2175 100644 --- a/src/soft_sphere.cpp +++ b/src/core/soft_sphere.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file soft_sphere.c +/** \file soft_sphere.cpp * - * Implementation of \ref soft_sphere.h + * Implementation of \ref soft_sphere.hpp */ #include "soft_sphere.hpp" #include "communication.hpp" diff --git a/src/soft_sphere.hpp b/src/core/soft_sphere.hpp similarity index 96% rename from src/soft_sphere.hpp rename to src/core/soft_sphere.hpp index fda16df4794..41f67e08b2f 100644 --- a/src/soft_sphere.hpp +++ b/src/core/soft_sphere.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef soft_H #define soft_H -/** \file soft_sphere.h +/** \file soft_sphere.hpp * Routines to calculate the soft-sphere energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/specfunc.cpp b/src/core/specfunc.cpp similarity index 99% rename from src/specfunc.cpp rename to src/core/specfunc.cpp index fe2e444f578..db5fc86ab8b 100644 --- a/src/specfunc.cpp +++ b/src/core/specfunc.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file specfunc.c - Special functions, see \ref specfunc.h "specfunc.h" +/** \file specfunc.cpp + Special functions, see \ref specfunc.hpp "specfunc.h" */ #include #include "utils.hpp" @@ -27,7 +27,7 @@ #include "polynom.hpp" /* Original gsl header - * specfunc/bessel_K0.c + * specfunc/bessel_K0.cpp * * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman * diff --git a/src/specfunc.hpp b/src/core/specfunc.hpp similarity index 95% rename from src/specfunc.hpp rename to src/core/specfunc.hpp index fdfc191e32e..ff7672ff5dc 100644 --- a/src/specfunc.hpp +++ b/src/core/specfunc.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,16 +18,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file specfunc.h +/** \file specfunc.hpp This file contains implementations for some special functions which are needed by the MMM family of algorithms. This are the modified Hurwitz zeta function and the modified Bessel functions of first - and second kind. The implementations are based on the GSL code (see \ref specfunc.c "specfunc.c" + and second kind. The implementations are based on the GSL code (see \ref specfunc.cpp "specfunc.c" for the original GSL header). The Hurwitz zeta function is evaluated using the Euler-MacLaurin summation formula, the Bessel functions are evaluated using several different Chebychev expansions. Both achieve a precision of nearly machine precision, which is no problem for the Hurwitz zeta function, which is only used when determining the - coefficients for the modified polygamma functions (see \ref mmm-common.h "mmm-common.h"). However, the + coefficients for the modified polygamma functions (see \ref mmm-common.hpp "mmm-common.h"). However, the Bessel functions are actually used in the near formula of MMM2D, which is therefore slightly slower than necessary. On the other hand, the number of terms in the Bessel sum is quite small normally, so that a less precise version will probably not generate a huge computational speed improvement. diff --git a/src/statistics.cpp b/src/core/statistics.cpp similarity index 89% rename from src/statistics.cpp rename to src/core/statistics.cpp index 324b27dd22a..15c0f352c30 100644 --- a/src/statistics.cpp +++ b/src/core/statistics.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics.c +/** \file statistics.cpp This is the place for analysis (so far...). - Implementation of statistics.h + Implementation of statistics.hpp */ #include #include @@ -44,6 +44,13 @@ #include "virtual_sites.hpp" #include "initialize.hpp" +#ifdef LEES_EDWARDS +/** Macro to fold vels as well as posns if Lees Edwards is on*/ +#define fold_coordinate(x,i,d) fold_coordinate(x,v_le,i,d) +#endif + + + /** Previous particle configurations (needed for offline analysis and correlation analysis in \ref tclcommand_analyze) */ double **configs = NULL; int n_configs = 0; int n_part_conf = 0; @@ -72,7 +79,7 @@ double mindist(IntList *set1, IntList *set2) mindist = SQR(box_l[0] + box_l[1] + box_l[2]); updatePartCfg(WITHOUT_BONDS); - for (j=0; j=x_min) { - // distinguish mixed and identical rdf's - if(mixed_flag == 1) start = 0; - else start = (i+1); - //particle loop: p2_types - for(j=start; j=x_min) { - /*see if particles i and j belong to different molecules*/ - if(partCfg[i].p.mol_id!=partCfg[j].p.mol_id) { - p1[0]=configs[k][3*i ];p1[1]=configs[k][3*i+1];p1[2]=configs[k][3*i+2]; - p2[0]=configs[k][3*j ];p2[1]=configs[k][3*j+1];p2[2]=configs[k][3*j+2]; - dist =min_distance(p1, p2); - if(dist > r_min && dist < r_max) { - ind = (int) ( (dist - r_min)*inv_bin_width ); - rdf_tmp[ind]++; - } - cnt++; - } - } - } - } - } - } - } - } - } - // normalization - - for(i=0; i=1)) { C_sum = S_sum = 0.0; - for(p=0; pe[bi] == partCfg[pi].p.type ) { @@ -1146,7 +1091,7 @@ int calc_radial_density_map (int xbins,int ybins,int thetabins,double xrange,dou } } /* Maybe there is a nicer way to do this but now I will just repeat the loop over all particles */ - for ( pi = 0 ; pi < n_total_particles ; pi++ ) { + for ( pi = 0 ; pi < n_part ; pi++ ) { for ( bi = 0 ; bi < nbeadtypes ; bi++ ) { if ( beadids->e[bi] == partCfg[pi].p.type ) { vecsub(center,partCfg[pi].r.p,pvector); @@ -1211,10 +1156,10 @@ double calc_vanhove(int ptype, double rmin, double rmax, int rbins, int tmax, do /* create particle list */ init_intlist(&p); - for(i=0; i. */ -/** \file statistics_chain.c - Implementation of \ref statistics_chain.h "statistics_chain.h". +/** \file statistics_chain.cpp + Implementation of \ref statistics_chain.hpp "statistics_chain.hpp". */ #include "statistics.hpp" #include "utils.hpp" @@ -416,9 +416,9 @@ void init_g123() /* Save particles' current positions (which'll be used as initial position later on) */ - partCoord_g = (float *) realloc(partCoord_g, 3*n_total_particles*sizeof(float)); + partCoord_g = (float *) realloc(partCoord_g, 3*n_part*sizeof(float)); partCM_g = (float *) realloc(partCM_g, 3*chain_n_chains*sizeof(float)); - n_part_g = n_total_particles; + n_part_g = n_part; n_chains_g = chain_n_chains; for(j=0; j. */ -/** \file statistics_cluster.c +/** \file statistics_cluster.cpp * * This file contains the necklace cluster algorithm. It can be used * to identify the substructures 'pearls' and 'strings' on a linear * chain. - * See also \ref statistics_cluster.h + * See also \ref statistics_cluster.hpp */ @@ -254,7 +254,7 @@ int test_mesh_elements(double pos[3], int probe_part_type) int i; double dist,vec[3]; - for (i=0; it = 0; self->finalized=0; @@ -151,14 +153,19 @@ int double_correlation_init(double_correlation* self, double dt, unsigned int ta self->autocorrelation=1; // the default may change later if dim_B != 0 // then input-dependent ones - if (dt <= 0) + if (dt <= 0) { return 2; + } + if ((dt-time_step)<-1e-6*time_step) { return 15; } + // check if dt is a multiple of the md timestep - if ( abs(dt/time_step - round(dt/time_step)>1e-6 ) ) + if ( abs(dt/time_step - round(dt/time_step)) > 1e-6 ) { return 16; + } + self->dt = dt; self->update_frequency = (int) floor(dt/time_step); @@ -167,48 +174,62 @@ int double_correlation_init(double_correlation* self, double dt, unsigned int ta printf("tau_lin: %d\n", tau_lin); if (tau_lin%2) tau_lin+=1; } - if (tau_lin<2) + + if (tau_lin<2) { return 3; - if (tau_lin%2) + } + + if (tau_lin%2) { return 14; + } + self->tau_lin=tau_lin; if (tau_max <= dt) { return 4; } else { //set hierarchy depth which can accomodate at least tau_max - if ( (tau_max/dt) < tau_lin ) + if ( (tau_max/dt) < tau_lin ) { hierarchy_depth = 1; - else + } else { hierarchy_depth=(unsigned int)ceil( 1 + log( (tau_max/dt)/(tau_lin-1) ) / log(2.0) ); + } } + self->tau_max=tau_max; self->hierarchy_depth = hierarchy_depth; - if (window_distance<1) + if (window_distance<1) { return 5; + } + self->window_distance = window_distance; - if (dim_A<1) + if (dim_A<1) { return 6; + } + self->dim_A = dim_A; - if (dim_B==0) - dim_B = dim_A; - else if (dim_B>0) + if (dim_B==0) { + dim_B = dim_A; + } else if (dim_B>0) { self->autocorrelation=0; - else if (dim_A != dim_B) - return 8; - // currently there is no correlation function able to handel observables of different dimensionalities - else + } else { return 7; + } + self->dim_B = dim_B; - if (A == 0) + if (A == 0) { return 9; + } + self->A_obs = A; - if (B == 0 && !self->autocorrelation) + if (B == 0 && !self->autocorrelation) { return 10; + } + self->B_obs = B; @@ -223,6 +244,10 @@ int double_correlation_init(double_correlation* self, double dt, unsigned int ta dim_corr = dim_A; self->corr_operation = &complex_conjugate_product; self->args = NULL; + } else if ( strcmp(corr_operation_name,"tensor_product") == 0 ) { + dim_corr = dim_A*dim_B; + self->corr_operation = &tensor_product; + self->args = NULL; } else if ( strcmp(corr_operation_name,"square_distance_componentwise") == 0 ) { dim_corr = dim_A; self->corr_operation = &square_distance_componentwise; @@ -386,7 +411,7 @@ int double_correlation_get_data( double_correlation* self ) { // Lets find out how far we have to go back in the hierarchy to make space for the new value while (1) { if ( ( (self->t - ((self->tau_lin + 1)*((1<<(i+1))-1) + 1) )% (1<<(i+1)) == 0) ) { - if ( i < (self->hierarchy_depth - 1) && self->n_vals[i]> self->tau_lin) { + if ( i < (int(self->hierarchy_depth) - 1) && self->n_vals[i]> self->tau_lin) { highest_level_to_compress+=1; i++; @@ -415,11 +440,16 @@ int double_correlation_get_data( double_correlation* self ) { self->newest[0] = ( self->newest[0] + 1 ) % (self->tau_lin +1); self->n_vals[0]++; - if ( (*self->A_obs->fun)(self->A_obs->args, self->A[0][self->newest[0]], self->dim_A) != 0 ) + if ( observable_calculate(self->A_obs) != 0 ) return 1; - if (!self->autocorrelation) - if ( (*self->B_obs->fun)(self->B_obs->args, self->B[0][self->newest[0]], self->dim_B) != 0 ) + // copy the result: + memcpy(self->A[0][self->newest[0]], self->A_obs->last_value, self->dim_A*sizeof(double)); + + if (!self->autocorrelation) { + if ( observable_calculate(self->B_obs) != 0 ) return 2; + memcpy(self->B[0][self->newest[0]], self->B_obs->last_value, self->dim_B*sizeof(double)); + } // Now we update the cumulated averages and variances of A and B self->n_data++; @@ -439,7 +469,7 @@ int double_correlation_get_data( double_correlation* self ) { if (!temp) return 4; // Now update the lowest level correlation estimates - for ( j = 0; j < MIN(self->tau_lin+1, self->n_vals[0]); j++) { + for ( j = 0; j < int(MIN(self->tau_lin+1, self->n_vals[0]) ); j++) { index_new = self->newest[0]; index_old = (self->newest[0] - j + self->tau_lin + 1) % (self->tau_lin + 1); // printf("old %d new %d\n", index_old, index_new); @@ -550,7 +580,7 @@ int double_correlation_finalize( double_correlation* self ) { // We only need to update correlation estimates for the higher levels for ( i = ll+1; i < highest_level_to_compress+2; i++) { - for ( j = (tau_lin+1)/2+1; j < MIN(tau_lin+1, self->n_vals[i]); j++) { + for ( j = (tau_lin+1)/2+1; j < int(MIN(tau_lin+1, self->n_vals[i])); j++) { index_new = self->newest[i]; index_old = (self->newest[i] - j + tau_lin + 1) % (tau_lin + 1); index_res = tau_lin + (i-1)*tau_lin/2 + (j - tau_lin/2+1) -1; @@ -638,8 +668,9 @@ int componentwise_product ( double* A, unsigned int dim_A, double* B, unsigned i printf("Error in componentwise product: The vector sizes do not match"); return 5; } - for ( i = 0; i < dim_A; i++ ) + for ( i = 0; i < dim_A; i++ ) { C[i] = A[i]*B[i]; + } return 0; } @@ -658,6 +689,17 @@ int complex_conjugate_product ( double* A, unsigned int dim_A, double* B, unsign return 0; } +int tensor_product ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ) { + unsigned int i,j; + for ( i = 0; i < dim_A; i++ ) + { + for ( j = 0; j < dim_B; j++ ) + { + C[i*dim_B + j] = A[i]*B[j]; + } + } + return 0; +} int square_distance_componentwise ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ) { unsigned int i; @@ -671,7 +713,6 @@ int square_distance_componentwise ( double* A, unsigned int dim_A, double* B, un return 0; } - int fcs_acf ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ) { DoubleList *wsquare = (DoubleList*)args; if (args == NULL ) @@ -695,9 +736,7 @@ int fcs_acf ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, doub void autoupdate_correlations() { for (unsigned i=0; icorrelations[i].dt*0.99999) { - //printf("updating %d\n", i); correlations[i].last_update=sim_time; double_correlation_get_data(&correlations[i]); } diff --git a/src/statistics_correlation.hpp b/src/core/statistics_correlation.hpp similarity index 98% rename from src/statistics_correlation.hpp rename to src/core/statistics_correlation.hpp index 77498676e18..a2d5fc101fd 100644 --- a/src/statistics_correlation.hpp +++ b/src/core/statistics_correlation.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -325,6 +325,8 @@ int componentwise_product ( double* A, unsigned int dim_A, double* B, unsigned i int complex_conjugate_product ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ); +int tensor_product ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ); + int fcs_acf ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ); int square_distance_componentwise ( double* A, unsigned int dim_A, double* B, unsigned int dim_B, double* C, unsigned int dim_corr, void *args ); diff --git a/src/statistics_fluid.cpp b/src/core/statistics_fluid.cpp similarity index 89% rename from src/statistics_fluid.cpp rename to src/core/statistics_fluid.cpp index 998b69c1116..297b08479e6 100644 --- a/src/statistics_fluid.cpp +++ b/src/core/statistics_fluid.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_fluid.c +/** \file statistics_fluid.cpp * * Fluid related analysis functions. - * Implementation of \ref statistics_fluid.h. + * Implementation of \ref statistics_fluid.hpp. * */ @@ -79,9 +79,9 @@ void lb_calc_fluid_momentum(double *result) { } } - momentum[0] *= lblattice.agrid/lbpar.tau; - momentum[1] *= lblattice.agrid/lbpar.tau; - momentum[2] *= lblattice.agrid/lbpar.tau; + momentum[0] *= lbpar.agrid/lbpar.tau; + momentum[1] *= lbpar.agrid/lbpar.tau; + momentum[2] *= lbpar.agrid/lbpar.tau; MPI_Reduce(momentum, result, 3, MPI_DOUBLE, MPI_SUM, 0, comm_cart); @@ -94,20 +94,29 @@ void lb_calc_fluid_temp(double *result) { int x, y, z, index; double rho, j[3]; double temp = 0.0; + int number_of_non_boundary_nodes = 0; for (x=1; x<=lblattice.grid[0]; x++) { for (y=1; y<=lblattice.grid[1]; y++) { for (z=1; z<=lblattice.grid[2]; z++) { + index = get_linear_index(x,y,z,lblattice.halo_grid); - - lb_calc_local_fields(index, &rho, j, NULL); - temp += scalar(j,j); +#ifdef LB_BOUNDARIES + if ( !lbfields[index].boundary ) +#endif + { + lb_calc_local_fields(index, &rho, j, NULL); + temp += scalar(j,j); + number_of_non_boundary_nodes++; + } } } } - temp *= 1./(3.*lbpar.rho[0]*lblattice.grid_volume*lbpar.tau*lbpar.tau*lblattice.agrid)/n_nodes; + // @Todo: lblattice.agrid is 3d. What to use here? + temp *= 1./(3.*lbpar.rho[0]*number_of_non_boundary_nodes* + lbpar.tau*lbpar.tau*lbpar.agrid)/n_nodes; MPI_Reduce(&temp, result, 1, MPI_DOUBLE, MPI_SUM, 0, comm_cart); } @@ -120,7 +129,8 @@ void lb_collect_boundary_forces(double *result) { for (int j = 0; j < 3; j++) boundary_forces[3*i+j]=lb_boundaries[i].force[j]; - MPI_Reduce(boundary_forces, result, 3*n_lb_boundaries, MPI_DOUBLE, MPI_SUM, 0, comm_cart); + MPI_Reduce(boundary_forces, result, 3*n_lb_boundaries, + MPI_DOUBLE, MPI_SUM, 0, comm_cart); free(boundary_forces); #endif } @@ -147,7 +157,7 @@ void lb_calc_densprof(double *result, int *params) { dir[(pdir+1)%3] = x1; dir[(pdir+2)%3] = x2; - newroot = map_lattice_to_node(&lblattice, dir, grid); + newroot = lblattice.map_lattice_to_node(dir, grid); map_node_array(this_node, node_pos); if ( (grid[(pdir+1)%3] == node_pos[(pdir+1)%3]) @@ -159,7 +169,7 @@ void lb_calc_densprof(double *result, int *params) { MPI_Comm_rank(slice_comm, &subrank); if (this_node == newroot) - result = (double*) realloc(result,box_l[pdir]/lblattice.agrid*sizeof(double)); + result = (double*) realloc(result,box_l[pdir]/lblattice.agrid[pdir]*sizeof(double)); if (involved) { @@ -231,7 +241,7 @@ void lb_calc_velprof(double *result, int *params) { //fprintf(stderr,"%d: (%d,%d,%d)\n",this_node,dir[0],dir[1],dir[2]); - newroot = map_lattice_to_node(&lblattice, dir, grid); + newroot = lblattice.map_lattice_to_node(dir, grid); map_node_array(this_node, node_pos); //fprintf(stderr,"%d: newroot=%d (%d,%d,%d)\n",this_node,newroot,grid[0],grid[1],grid[2]); @@ -245,7 +255,7 @@ void lb_calc_velprof(double *result, int *params) { MPI_Comm_rank(slice_comm, &subrank); if (this_node == newroot) - result = (double*) realloc(result,box_l[pdir]/lblattice.agrid*sizeof(double)); + result = (double*) realloc(result,box_l[pdir]/lblattice.agrid[pdir]*sizeof(double)); //fprintf(stderr,"%d (%d,%d): result=%p vcomp=%d pdir=%d x1=%d x2=%d involved=%d\n",this_node,subrank,newroot,result,vcomp,pdir,x1,x2,involved); @@ -266,7 +276,7 @@ void lb_calc_velprof(double *result, int *params) { velprof[dir[pdir]-1] = 0.0; } else { //velprof[dir[pdir]-1] = local_j / (SQR(lbpar.agrid)*lbpar.tau); - velprof[dir[pdir]-1] = j[vcomp]/rho * lblattice.agrid/lbpar.tau; + velprof[dir[pdir]-1] = j[vcomp]/rho * lbpar.agrid/lbpar.tau; //fprintf(stderr,"%f %f %f\n",velprof[dir[pdir]-1],local_j,local_rho); } diff --git a/src/statistics_fluid.hpp b/src/core/statistics_fluid.hpp similarity index 91% rename from src/statistics_fluid.hpp rename to src/core/statistics_fluid.hpp index 37ddc7dd438..ef0a8b4ecf6 100644 --- a/src/statistics_fluid.hpp +++ b/src/core/statistics_fluid.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_fluid.h +/** \file statistics_fluid.hpp * * Fluid related analysis functions. - * Header file for \ref statistics_fluid.c. + * Header file for \ref statistics_fluid.cpp. * */ diff --git a/src/statistics_molecule.cpp b/src/core/statistics_molecule.cpp similarity index 80% rename from src/statistics_molecule.cpp rename to src/core/statistics_molecule.cpp index fefedf66d91..22a2e60690d 100644 --- a/src/statistics_molecule.cpp +++ b/src/core/statistics_molecule.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_molecule.c +/** \file statistics_molecule.cpp - see \ref statistics_molecule.h + see \ref statistics_molecule.hpp */ #include "statistics_molecule.hpp" #include "errorhandling.hpp" @@ -33,12 +33,20 @@ int analyze_fold_molecules(float *coord, double shift[3]) int mol_size, ind; double cm_tmp, com[3]; + #ifdef LEES_EDWARDS + if(lees_edwards_offset != 0.0 ){ + fprintf(stderr, "Error: Folding molecules not supported under Lees-Edwards.\n"); + exit(8); + } + #endif + /* check molecule information */ if ( n_molecules < 0 ) return ES_ERROR; if (!sortPartCfg()) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{059 analyze_fold_molecules: could not sort particle config, particle ids not consecutive?} "); + ostringstream msg; + msg <<"analyze_fold_molecules: could not sort particle config, particle ids not consecutive?"; + runtimeError(msg); return ES_ERROR; } @@ -60,10 +68,10 @@ int analyze_fold_molecules(float *coord, double shift[3]) cm_tmp += coord[ind]; } cm_tmp /= (double)mol_size; - if(cm_tmp < -10e-6 || cm_tmp > box_l[i]+10e-6) { - char *errtxt = runtime_error(128 + ES_INTEGER_SPACE + 2*ES_DOUBLE_SPACE); - ERROR_SPRINTF(errtxt,"{060 analyze_fold_molecules: chain center of mass is out of range (coord %d: %.14f not in box_l %.14f)} ", - i,cm_tmp,box_l[i]); + if(cm_tmp < -10e-6 || cm_tmp > box_l[i]+10e-6) { + ostringstream msg; + msg <<"analyze_fold_molecules: chain center of mass is out of range (coord " << i << ": " << cm_tmp << " not in box_l " << box_l[i] << ")"; + runtimeError(msg); return ES_ERROR; } } diff --git a/src/statistics_molecule.hpp b/src/core/statistics_molecule.hpp similarity index 93% rename from src/statistics_molecule.hpp rename to src/core/statistics_molecule.hpp index 1216549fd72..3d4d526942d 100644 --- a/src/statistics_molecule.hpp +++ b/src/core/statistics_molecule.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,11 +20,11 @@ */ #ifndef STATISTICS_MOLECULE_H #define STATISTICS_MOLECULE_H -/** \file statistics_molecule.h +/** \file statistics_molecule.hpp This file contains the code for statistics on the data using the molecule information set with analyse set, as it is described in - the file \ref topology.h. + the file \ref topology.hpp. */ #include "utils.hpp" diff --git a/src/statistics_observable.cpp b/src/core/statistics_observable.cpp similarity index 56% rename from src/statistics_observable.cpp rename to src/core/statistics_observable.cpp index dd5d9ed046d..aee68730611 100644 --- a/src/statistics_observable.cpp +++ b/src/core/statistics_observable.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -23,15 +23,49 @@ #include "pressure.hpp" #include "rotation.hpp" +#ifdef LEES_EDWARDS +#define fold_position(x,i) fold_position(x,v_le,i) +#define unfold_position(x,i) unfold_position(x,v_le,i) +#endif + observable** observables = 0; int n_observables = 0; +int observables_autoupdate = 0; + +void observable_init(observable* self) { + self->last_update = 0; + self->autoupdate = 0; + self->autoupdate_dt = 0; +} + +int observable_calculate(observable* self) { + int temp = 0; + if (self->calculate!=0) + temp=(self->calculate)(self); + self->last_update = sim_time; + return temp; +} + +int observable_update(observable* self) { + int temp = 0; + if (self->update!=0) + temp=(self->update)(self); + self->last_update = sim_time; + return temp; +} -int observable_particle_velocities(void* idlist, double* A, unsigned int n_A) { +int observable_calc_particle_velocities(observable* self) { + double* A = self->last_value; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*i + 0] = partCfg[ids->e[i]].m.v[0]/time_step; A[3*i + 1] = partCfg[ids->e[i]].m.v[1]/time_step; @@ -40,15 +74,66 @@ int observable_particle_velocities(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_particle_angular_momentum(void* idlist, double* A, unsigned int n_A) { +int observable_calc_particle_body_velocities(observable* self) { + double* A = self->last_value; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; + for (int i = 0; in; i++ ) { + if (ids->e[i] >= n_part) + return 1; + +#ifdef ROTATION + + double RMat[9]; + double vel_lab[3]; + double vel_body[3]; + + vel_lab[0] = partCfg[ids->e[i]].m.v[0]/time_step; + vel_lab[1] = partCfg[ids->e[i]].m.v[1]/time_step; + vel_lab[2] = partCfg[ids->e[i]].m.v[2]/time_step; + define_rotation_matrix(&partCfg[ids->e[i]], RMat); + + vel_body[0] = RMat[0 + 3*0]*vel_lab[0] + RMat[0 + 3*1]*vel_lab[1] + RMat[0 + 3*2]*vel_lab[2]; + vel_body[1] = RMat[1 + 3*0]*vel_lab[0] + RMat[1 + 3*1]*vel_lab[1] + RMat[1 + 3*2]*vel_lab[2]; + vel_body[2] = RMat[2 + 3*0]*vel_lab[0] + RMat[2 + 3*1]*vel_lab[1] + RMat[2 + 3*2]*vel_lab[2]; + + A[3*i + 0] = vel_body[0]; + A[3*i + 1] = vel_body[1]; + A[3*i + 2] = vel_body[2]; + +#else + + A[3*i + 0] = 0.0; + A[3*i + 1] = 0.0; + A[3*i + 2] = 0.0; + +#endif + + } + return 0; +} + +int observable_calc_particle_angular_momentum(observable* self) { + double* A = self->last_value; + IntList* ids; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for ( int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; - #ifdef ROTATION +#ifdef ROTATION double RMat[9]; double omega[3]; @@ -61,25 +146,64 @@ int observable_particle_angular_momentum(void* idlist, double* A, unsigned int n A[3*i + 1] = omega[1]; A[3*i + 2] = omega[2]; - #else +#else A[3*i + 0] = 0.0; A[3*i + 1] = 0.0; A[3*i + 2] = 0.0; - #endif +#endif + + } + return 0; +} + +int observable_calc_particle_body_angular_momentum(observable* self) { + double* A = self->last_value; + IntList* ids; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; + for ( int i = 0; in; i++ ) { + if (ids->e[i] >= n_part) + return 1; + +#ifdef ROTATION + + A[3*i + 0] = partCfg[ids->e[i]].m.omega[0]; + A[3*i + 1] = partCfg[ids->e[i]].m.omega[1]; + A[3*i + 2] = partCfg[ids->e[i]].m.omega[2]; + +#else + + A[3*i + 0] = 0.0; + A[3*i + 1] = 0.0; + A[3*i + 2] = 0.0; + +#endif + } return 0; } #ifdef ELECTROSTATICS -int observable_particle_currents(void* idlist, double* A, unsigned int n_A) { +int observable_calc_particle_currents(observable* self) { + double* A = self->last_value; double charge; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; charge = partCfg[ids->e[i]].p.q; A[3*i + 0] = charge * partCfg[ids->e[i]].m.v[0]/time_step; @@ -89,14 +213,20 @@ int observable_particle_currents(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_currents(void* idlist, double* A, unsigned int n_A) { +int observable_calc_currents(observable* self) { + double* A = self->last_value; double charge; double j[3] = {0. , 0., 0. } ; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] > n_total_particles) + if (ids->e[i] > n_part) return 1; charge = partCfg[ids->e[i]].p.q; j[0] += charge * partCfg[ids->e[i]].m.v[0]/time_step; @@ -109,14 +239,20 @@ int observable_currents(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_dipole_moment(void* idlist, double* A, unsigned int n_A) { +int observable_calc_dipole_moment(observable* self) { + double* A = self->last_value; double charge; double j[3] = {0. , 0., 0. } ; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] > n_total_particles) + if (ids->e[i] > n_part) return 1; charge = partCfg[ids->e[i]].p.q; j[0] += charge * partCfg[ids->e[i]].r.p[0]; @@ -130,14 +266,20 @@ int observable_dipole_moment(void* idlist, double* A, unsigned int n_A) { } #endif -int observable_com_velocity(void* idlist, double* A, unsigned int n_A) { +int observable_calc_com_velocity(observable* self) { + double* A = self->last_value; double v_com[3] = { 0. , 0., 0. } ; double total_mass = 0; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; v_com[0] += PMASS(partCfg[ids->e[i]])*partCfg[ids->e[i]].m.v[0]/time_step; v_com[1] += PMASS(partCfg[ids->e[i]])*partCfg[ids->e[i]].m.v[1]/time_step; @@ -150,7 +292,8 @@ int observable_com_velocity(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_blocked_com_velocity(void* idlist, double* A, unsigned int n_A) { +int observable_calc_blocked_com_velocity(observable* self) { + double* A = self->last_value; unsigned int i; unsigned int block; unsigned int n_blocks; @@ -158,15 +301,20 @@ int observable_blocked_com_velocity(void* idlist, double* A, unsigned int n_A) { unsigned int id; double total_mass = 0; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; - n_blocks=n_A/3; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; + n_blocks=self->n/3; blocksize=ids->n/n_blocks; for ( block = 0; block < n_blocks; block++ ) { total_mass = 0; for ( i = 0; i < blocksize; i++ ) { id = ids->e[block*blocksize+i]; - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*block+0] += PMASS(partCfg[id])*partCfg[id].m.v[0]/time_step; A[3*block+1] += PMASS(partCfg[id])*partCfg[id].m.v[1]/time_step; @@ -180,7 +328,8 @@ int observable_blocked_com_velocity(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_blocked_com_position(void* idlist, double* A, unsigned int n_A) { +int observable_calc_blocked_com_position(observable* self) { + double* A = self->last_value; unsigned int i; unsigned int block; unsigned int n_blocks; @@ -188,15 +337,20 @@ int observable_blocked_com_position(void* idlist, double* A, unsigned int n_A) { unsigned int id; double total_mass = 0; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; - n_blocks=n_A/3; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; + n_blocks=self->n/3; blocksize=ids->n/n_blocks; for ( block = 0; block < n_blocks; block++ ) { total_mass = 0; for ( i = 0; i < blocksize; i++ ) { id = ids->e[block*blocksize+i]; - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*block+0] += PMASS(partCfg[id])*partCfg[id].r.p[0]; A[3*block+1] += PMASS(partCfg[id])*partCfg[id].r.p[1]; @@ -210,14 +364,20 @@ int observable_blocked_com_position(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_com_position(void* idlist, double* A, unsigned int n_A) { +int observable_calc_com_position(observable* self) { + double* A = self->last_value; double p_com[3] = { 0. , 0., 0. } ; double total_mass = 0; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; p_com[0] += PMASS(partCfg[ids->e[i]])*partCfg[ids->e[i]].r.p[0]; p_com[1] += PMASS(partCfg[ids->e[i]])*partCfg[ids->e[i]].r.p[1]; @@ -231,13 +391,19 @@ int observable_com_position(void* idlist, double* A, unsigned int n_A) { } -int observable_com_force(void* idlist, double* A, unsigned int n_A) { +int observable_calc_com_force(observable* self) { + double* A = self->last_value; double f_com[3] = { 0. , 0., 0. } ; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; f_com[0] += partCfg[ids->e[i]].f.f[0]/time_step/time_step*2; f_com[1] += partCfg[ids->e[i]].f.f[1]/time_step/time_step*2; @@ -250,21 +416,27 @@ int observable_com_force(void* idlist, double* A, unsigned int n_A) { } -int observable_blocked_com_force(void* idlist, double* A, unsigned int n_A) { +int observable_calc_blocked_com_force(observable* self) { + double* A = self->last_value; unsigned int i; unsigned int block; unsigned int n_blocks; unsigned int blocksize; unsigned int id; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; - n_blocks=n_A/3; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; + n_blocks=self->n/3; blocksize=ids->n/n_blocks; for ( block = 0; block < n_blocks; block++ ) { for ( i = 0; i < blocksize; i++ ) { id = ids->e[block*blocksize+i]; - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*block+0] += partCfg[id].f.f[0]/time_step/time_step*2; A[3*block+1] += partCfg[id].f.f[1]/time_step/time_step*2; @@ -275,22 +447,32 @@ int observable_blocked_com_force(void* idlist, double* A, unsigned int n_A) { } -int observable_density_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_density_profile(observable* self) { + double* A = self->last_value; int binx, biny, binz; double ppos[3]; int img[3]; IntList* ids; profile_data* pdata; - sortPartCfg(); - pdata=(profile_data*) pdata_; +#ifdef LEES_EDWARDS + double v_le[3]; +#endif + + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + pdata=(profile_data*) self->container; ids=pdata->id_list; double bin_volume=(pdata->maxx-pdata->minx)*(pdata->maxy-pdata->miny)*(pdata->maxz-pdata->minz)/pdata->xbins/pdata->ybins/pdata->zbins; - for (unsigned i = 0; in; i++ ) { A[i]=0; } for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; /* We use folded coordinates here */ memcpy(ppos, partCfg[ids->e[i]].r.p, 3*sizeof(double)); @@ -307,18 +489,19 @@ int observable_density_profile(void* pdata_, double* A, unsigned int n_A) { } #ifdef LB -int observable_lb_velocity_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_lb_velocity_profile(observable* self) { + double* A = self->last_value; unsigned int i, j, k; unsigned int maxi, maxj, maxk; double xoffset, yoffset, zoffset; double x_incr, y_incr, z_incr; double p[3], v[3]; profile_data* pdata; - pdata=(profile_data*) pdata_; + pdata=(profile_data*) self->container; int linear_index; - for ( i = 0; in; i++ ) { A[i]=0; } double normalization_factor = 1.; @@ -376,7 +559,7 @@ int observable_lb_velocity_profile(void* pdata_, double* A, unsigned int n_A) { } } - for ( i = 0; in; i++ ) { A[i]*=normalization_factor; } @@ -386,7 +569,45 @@ int observable_lb_velocity_profile(void* pdata_, double* A, unsigned int n_A) { #endif #ifdef LB -int observable_lb_radial_velocity_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_lb_radial_velocity_profile(observable* self) { + double* A = self->last_value; + void* pdata = self->container; + unsigned int n_A = self->n; + +#ifdef LB_GPU + if (lattice_switch & LATTICE_LB_GPU) + return statistics_observable_lbgpu_radial_velocity_profile((radial_profile_data*) pdata, A, n_A); +#endif + + if (!(lattice_switch & LATTICE_LB)) + return ES_ERROR; + + if (n_nodes==1) { + mpi_observable_lb_radial_velocity_profile_parallel(pdata, A, n_A); + return ES_OK; + } else { + mpi_observable_lb_radial_velocity_profile(); + MPI_Bcast(pdata, sizeof(radial_profile_data), MPI_BYTE, 0, comm_cart); + double* data = (double*) malloc(n_A*sizeof(double)); + mpi_observable_lb_radial_velocity_profile_parallel(pdata, data, n_A); + MPI_Reduce(data, A, n_A, MPI_DOUBLE, MPI_SUM, 0, comm_cart); + free(data); + return ES_OK; + } +} + +void mpi_observable_lb_radial_velocity_profile_slave_implementation() { + radial_profile_data pdata; + MPI_Bcast(&pdata, sizeof(radial_profile_data), MPI_BYTE, 0, comm_cart); + unsigned int n_A=3*pdata.rbins*pdata.phibins*pdata.zbins; + double* data = (double*) malloc(n_A*sizeof(double)); + mpi_observable_lb_radial_velocity_profile_parallel(&pdata, data, n_A); + MPI_Reduce(data, 0, n_A, MPI_DOUBLE, MPI_SUM, 0, comm_cart); + free(data); + +} + +int mpi_observable_lb_radial_velocity_profile_parallel(void* pdata_, double* A, unsigned int n_A) { unsigned int i, j, k; unsigned int maxi, maxj, maxk; double roffset, phioffset, zoffset; @@ -440,6 +661,11 @@ int observable_lb_radial_velocity_profile(void* pdata_, double* A, unsigned int p[0]=r*cos(phi)+pdata->center[0]; p[1]=r*sin(phi)+pdata->center[1]; p[2]=z+pdata->center[2]; + if ( p[0] < my_left[0] || p[0]>my_right[0] + || p[1] < my_left[1] || p[1]>my_right[1] + || p[2] < my_left[2] || p[2]>my_right[2] ) + continue; + if (lb_lbfluid_get_interpolated_velocity(p, v)!=0) return 1; linear_index = 0; @@ -480,26 +706,36 @@ void transform_to_cylinder_coordinates(double x, double y, double z_, double* r, *phi = atan2(y,x); } -int observable_radial_density_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_radial_density_profile(observable* self) { + double* A = self->last_value; int binr, binphi, binz; double ppos[3]; double r, phi, z; int img[3]; double bin_volume; IntList* ids; - sortPartCfg(); +#ifdef LEES_EDWARDS + double v_le[3]; +#endif + + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } radial_profile_data* pdata; - pdata=(radial_profile_data*) pdata_; + pdata=(radial_profile_data*) self->container; ids=pdata->id_list; double rbinsize=(pdata->maxr - pdata->minr)/pdata->rbins; double phibinsize=(pdata->maxphi - pdata->minphi)/pdata->phibins; double zbinsize=(pdata->maxz - pdata->minz)/pdata->zbins; - for (unsigned i = 0; i< n_A; i++ ) { + for (int i = 0; i< self->n; i++ ) { A[i]=0; } for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; /* We use folded coordinates here */ memcpy(ppos, partCfg[ids->e[i]].r.p, 3*sizeof(double)); @@ -519,36 +755,79 @@ int observable_radial_density_profile(void* pdata_, double* A, unsigned int n_A) return 0; } -int observable_radial_flux_density_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_radial_flux_density_profile(observable* self) { + double* A = self->last_value; int binr, binphi, binz; double ppos[3]; + double unfolded_ppos[3]; double r, phi, z; int img[3]; double bin_volume; IntList* ids; - sortPartCfg(); +#ifdef LEES_EDWARDS + double v_le[3]; +#endif + + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } radial_profile_data* pdata; - pdata=(radial_profile_data*) pdata_; + pdata=(radial_profile_data*) self->container; ids=pdata->id_list; double rbinsize=(pdata->maxr - pdata->minr)/pdata->rbins; double phibinsize=(pdata->maxphi - pdata->minphi)/pdata->phibins; double zbinsize=(pdata->maxz - pdata->minz)/pdata->zbins; double v[3]; double v_r, v_phi, v_z; + + if (self->last_update==sim_time) { + return ES_ERROR; + } - for (unsigned i = 0; i< n_A; i++ ) { + for (int i = 0; i< self->n; i++ ) { A[i]=0; } + double* old_positions=(double*) pdata->container; + if (old_positions[0] == CONST_UNITITIALIZED) { + for (int i = 0; in; i++ ) { + memcpy(unfolded_ppos, partCfg[ids->e[i]].r.p, 3*sizeof(double)); + memcpy(img, partCfg[ids->e[i]].l.i, 3*sizeof(int)); + unfold_position(unfolded_ppos, img); + old_positions[3*i+0]=unfolded_ppos[0]; + old_positions[3*i+1]=unfolded_ppos[1]; + old_positions[3*i+2]=unfolded_ppos[2]; + } + return 0; + } for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; /* We use folded coordinates here */ - v[0]=partCfg[ids->e[i]].m.v[0]/time_step; - v[1]=partCfg[ids->e[i]].m.v[1]/time_step; - v[2]=partCfg[ids->e[i]].m.v[2]/time_step; + memcpy(unfolded_ppos, partCfg[ids->e[i]].r.p, 3*sizeof(double)); + memcpy(img, partCfg[ids->e[i]].l.i, 3*sizeof(int)); + unfold_position(unfolded_ppos, img); + v[0]=(unfolded_ppos[0] - old_positions[3*i+0]); + v[1]=(unfolded_ppos[1] - old_positions[3*i+1]); + v[2]=(unfolded_ppos[2] - old_positions[3*i+2]); memcpy(ppos, partCfg[ids->e[i]].r.p, 3*sizeof(double)); memcpy(img, partCfg[ids->e[i]].l.i, 3*sizeof(int)); fold_position(ppos, img); + // The position of the particle is by definition the middle of old and new position + ppos[0]+=0.5*v[0]; ppos[1]+=0.5*v[1]; ppos[2]+=0.5*v[2]; + fold_position(ppos, img); + v[0]/=(sim_time - self->last_update); + v[1]/=(sim_time - self->last_update); + v[2]/=(sim_time - self->last_update); + if (i==0) { +// printf("(%3.4f) %f %f %f\n", sim_time-self->last_update, v[2], partCfg[ids->e[i]].m.v[2]/time_step,v[2]* partCfg[ids->e[i]].m.v[2]/time_step/time_step); +// printf("(%3.3f) %f %f", sim_time, old_positions[3*i+2], unfolded_ppos[2]); + } + old_positions[3*i+0]=unfolded_ppos[0]; + old_positions[3*i+1]=unfolded_ppos[1]; + old_positions[3*i+2]=unfolded_ppos[2]; transform_to_cylinder_coordinates(ppos[0]-pdata->center[0], ppos[1]-pdata->center[1], ppos[2]-pdata->center[2], &r, &phi, &z); binr =(int)floor((r-pdata->minr)/rbinsize); binphi=(int)floor((phi-pdata->minphi)/phibinsize); @@ -567,16 +846,26 @@ int observable_radial_flux_density_profile(void* pdata_, double* A, unsigned int return 0; } -int observable_flux_density_profile(void* pdata_, double* A, unsigned int n_A) { +int observable_calc_flux_density_profile(observable* self) { + double* A = self->last_value; int binx, biny, binz; double ppos[3]; double x, y, z; int img[3]; double bin_volume; IntList* ids; - sortPartCfg(); +#ifdef LEES_EDWARDS + double v_le[3]; +#endif + + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } profile_data* pdata; - pdata=(profile_data*) pdata_; + pdata=(profile_data*) self->container; ids=pdata->id_list; double xbinsize=(pdata->maxx - pdata->minx)/pdata->xbins; double ybinsize=(pdata->maxy - pdata->miny)/pdata->ybins; @@ -584,11 +873,11 @@ int observable_flux_density_profile(void* pdata_, double* A, unsigned int n_A) { double v[3]; double v_x, v_y, v_z; - for (unsigned i = 0; i< n_A; i++ ) { + for (int i = 0; i< self->n; i++ ) { A[i]=0; } for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; /* We use folded coordinates here */ v[0]=partCfg[ids->e[i]].m.v[0]*time_step; @@ -618,12 +907,18 @@ int observable_flux_density_profile(void* pdata_, double* A, unsigned int n_A) { return 0; } -int observable_particle_positions(void* idlist, double* A, unsigned int n_A) { +int observable_calc_particle_positions(observable* self) { + double* A = self->last_value; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*i + 0] = partCfg[ids->e[i]].r.p[0]; A[3*i + 1] = partCfg[ids->e[i]].r.p[1]; @@ -632,12 +927,18 @@ int observable_particle_positions(void* idlist, double* A, unsigned int n_A) { return 0; } -int observable_particle_forces(void* idlist, double* A, unsigned int n_A) { +int observable_calc_particle_forces(observable* self) { + double* A = self->last_value; IntList* ids; - sortPartCfg(); - ids=(IntList*) idlist; + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + ids=(IntList*) self->container; for (int i = 0; in; i++ ) { - if (ids->e[i] >= n_total_particles) + if (ids->e[i] >= n_part) return 1; A[3*i + 0] = partCfg[ids->e[i]].f.f[0]/time_step/time_step*2; A[3*i + 1] = partCfg[ids->e[i]].f.f[1]/time_step/time_step*2; @@ -647,16 +948,27 @@ int observable_particle_forces(void* idlist, double* A, unsigned int n_A) { } -int observable_stress_tensor(void* params_p, double* A, unsigned int n_A) { - sortPartCfg(); - observable_compute_stress_tensor(1,A,n_A); +int observable_stress_tensor(observable* self) { + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } + observable_compute_stress_tensor(1,self->last_value,self->n); return 0; } -int observable_stress_tensor_acf_obs(void* params_p, double* A, unsigned int n_A) { +int observable_calc_stress_tensor_acf_obs(observable* self) { + double* A = self->last_value; double stress_tensor[9]; - sortPartCfg(); + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } observable_compute_stress_tensor(1,stress_tensor,9); A[0]=stress_tensor[1]; A[1]=stress_tensor[5]; @@ -667,53 +979,89 @@ int observable_stress_tensor_acf_obs(void* params_p, double* A, unsigned int n_A return 0; } -int observable_structure_factor(void* params_p, double* A, unsigned int n_A) { +int observable_update_average(observable* self) { + observable_average_container* data = (observable_average_container*) self->container; + data->n_sweeps++; + int error = observable_calculate(data->reference_observable); + if ( error != 0) + return 1; + double factor = 1 / (double) data->n_sweeps; + for (int i =0; in; i++) { + self->last_value[i] = (1-factor)*self->last_value[i] + factor*data->reference_observable->last_value[i]; + } + return 0; +} + +int observable_reset_average(observable* self) { + observable_average_container* data = (observable_average_container*) self->container; + data->n_sweeps=0; + int error = observable_calculate(data->reference_observable); + for (int i =0; in; i++) { + self->last_value[i] = 0; + } + return error; +} + + +int observable_calc_structure_factor(observable* self) { + double* A = self->last_value; // FIXME Currently scattering length is hardcoded as 1.0 int l; int order, order2, n; double twoPI_L, C_sum, S_sum, qr; -// DoubleList *scattering_length; - observable_sf_params* params; - params = (observable_sf_params*)params_p; -// scattering_length = params->scattering_length; const double scattering_length=1.0; - order = params->order; + int* tmp = (int*)self->container; + order = *tmp; order2=order*order; twoPI_L = 2*PI/box_l[0]; - sortPartCfg(); + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } - for(unsigned int p=0; pn; p++) { A[p] = 0.0; } l=0; - //printf("n_A: %d, dim_sf: %d\n",n_A, params.dim_sf); fflush(stdout); - for (int i=-order; i<=order; i++) { - for (int j=-order; j<=order; j++) { - for (int k=-order; k<=order; k++) { - n = i*i + j*j + k*k; - if ((n<=order2) && (n>=1)) { - C_sum = S_sum = 0.0; - //printf("l: %d, n: %d %d %d\n",l,i,j,k); fflush(stdout); - for(int p=0; pn: %d, dim_sf: %d\n",n_A, params.dim_sf); fflush(stdout); + for(int i=-order; i<=order; i++) { + for(int j=-order; j<=order; j++) { + for(int k=-order; k<=order; k++) { + n = i*i + j*j + k*k; + if (n<=order2) { + C_sum = S_sum = 0.0; + //printf("l: %d, n: %d %d %d\n",l,i,j,k); fflush(stdout); + for(int p=0; pn/2;k++) { + //devide by the sqrt(number_of_particle) due to complex product and no k-vector averaging so far + A[l] /= sqrt(n_part); + A[l+1] /= sqrt(n_part); + l=l+2; + } //printf("finished calculating sf\n"); fflush(stdout); return 0; } -int observable_interacts_with (void* params_p, double* A, unsigned int n_A) { - iw_params *params=(iw_params*)params_p; +int observable_calc_interacts_with (observable* self) { + double* A = self->last_value; + iw_params *params=(iw_params*) self->container; IntList* ids1; IntList* ids2; int i,j; @@ -723,15 +1071,20 @@ int observable_interacts_with (void* params_p, double* A, unsigned int n_A) { double pos1[3], pos2[3], dist[3]; ids1=params->ids1; ids2=params->ids2; - sortPartCfg(); + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg"; + runtimeError(msg); + return -1; + } for ( i = 0; in; i++ ) { - if (ids1->e[i] >= n_total_particles) + if (ids1->e[i] >= n_part) return 1; pos1[0]=partCfg[ids1->e[i]].r.p[0]; pos1[1]=partCfg[ids1->e[i]].r.p[1]; pos1[2]=partCfg[ids1->e[i]].r.p[2]; for ( j = 0; jn; j++ ) { - if (ids2->e[j] >= n_total_particles) + if (ids2->e[j] >= n_part) return 1; if (ids2->e[j] == ids1->e[i]) // do not count self-interaction :-) continue; @@ -752,6 +1105,17 @@ int observable_interacts_with (void* params_p, double* A, unsigned int n_A) { } +void autoupdate_observables() { + int i; + for (i=0; iautoupdate); + if (observables[i]->autoupdate && sim_time-observables[i]->last_update>observables[i]->autoupdate_dt*0.99999) { +// printf("updating %d\n", i); + observable_update(observables[i]); + } + } +} + diff --git a/src/core/statistics_observable.hpp b/src/core/statistics_observable.hpp new file mode 100644 index 00000000000..36bcdbadc9d --- /dev/null +++ b/src/core/statistics_observable.hpp @@ -0,0 +1,163 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _STATISTICS_OBSERVABLE_H +#define _STATISTICS_OBSERVABLE_H + +#include "config.hpp" +#include "utils.hpp" +#include +#include +#include + + +#define CONST_UNITITIALIZED 1e-23 + +struct s_observable; + +struct s_observable { + char* obs_name; + void* container; + int n; + int (*update) ( struct s_observable* obs ); + int (*calculate) ( struct s_observable* obs ); + double* last_value; + double last_update; + int autoupdate; + double autoupdate_dt; +}; + +typedef struct s_observable observable; + +extern observable** observables; +extern int n_observables; + +// flag if autoupdates are necessary. +extern int observables_autoupdate; + +void autoupdate_observables(); + +void observable_init(observable* self); +int observable_calculate(observable* self); +int observable_update(observable* self); + +/* Here we have the particular observables listed */ +int observable_calc_particle_velocities(observable* self_); +int observable_calc_particle_body_velocities(observable* self_); +int observable_calc_particle_angular_momentum(observable* self_); +int observable_calc_particle_body_angular_momentum(observable* self_); +int observable_calc_com_velocity(observable* self); +int observable_calc_blocked_com_velocity(observable* self); +/** Obtain the particle positions. + * TODO: Folded or unfolded? + */ +int observable_calc_particle_positions(observable* self); +int observable_calc_particle_forces(observable* self); +int observable_calc_com_force(observable* self); +int observable_calc_blocked_com_force(observable* self); +int observable_stress_tensor(observable* self); +int observable_calc_stress_tensor_acf_obs(observable* self); +int observable_calc_com_position(observable* self); +int observable_calc_blocked_com_position(observable* self); + +#ifdef ELECTROSTATICS +int observable_calc_particle_currents(observable* self); +int observable_calc_currents(observable* self); +int observable_calc_dipole_moment(observable* self); +#endif + +#ifdef LB +int mpi_observable_lb_radial_velocity_profile_parallel(void* pdata_, double* A, unsigned int n_A); +#endif + +int observable_update_average(observable* self); +int observable_reset_average(observable* self); +typedef struct { + observable* reference_observable; + unsigned int n_sweeps; +} observable_average_container; + +/** Calculate structure factor from positions and scattering length */ +int observable_calc_structure_factor(observable* self); +typedef struct { +// FIXME finish the implementation of scattering length + IntList* id_list; + DoubleList *scattering_length; // Scattering lengths of particles + int order; + int dim_sf; // number of q vectors + int *q_vals; // values of q vectors + double *q_density; // number of q vectors per bin + // entries for spherical averaging +} observable_sf_params; + +/** See if particles from idList1 interact with any of the particles in idList2 +input parameters are passed via struct iw_params +*/ +int observable_calc_interacts_with(observable* self); +typedef struct { + double cutoff; + IntList *ids1; + IntList *ids2; +} iw_params; + + +/** Do nothing */ +int observable_calc_obs_nothing (observable* self); + +int observable_calc_flux_density_profile(observable* self); +typedef struct { + IntList* id_list; + double minx; + double maxx; + double miny; + double maxy; + double minz; + double maxz; + int xbins; + int ybins; + int zbins; + void* container; +} profile_data; + +int observable_calc_density_profile(observable* self); + +int observable_calc_lb_velocity_profile(observable* self); + +int observable_calc_radial_density_profile(observable* self); +int observable_calc_radial_flux_density_profile(observable* self); +int observable_calc_lb_radial_velocity_profile(observable* self); +typedef struct { + IntList* id_list; + double minr; + double maxr; + double minphi; + double maxphi; + double minz; + double maxz; + double center[3]; + double axis[3]; + int phibins; + int rbins; + int zbins; + void* container; +} radial_profile_data; + +void mpi_observable_lb_radial_velocity_profile_slave_implementation(); + + +#endif diff --git a/src/statistics_wallstuff.cpp b/src/core/statistics_wallstuff.cpp similarity index 97% rename from src/statistics_wallstuff.cpp rename to src/core/statistics_wallstuff.cpp index fc1f2471eb7..0e5219a4e73 100644 --- a/src/statistics_wallstuff.cpp +++ b/src/core/statistics_wallstuff.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 The ESPResSo project + Copyright (C) 2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -45,7 +45,7 @@ void wall_sort_particles() // 2. for each particle, find the box and put its // identity there - for(int i=0; i wallstuff_boundaries.e[wallstuff_boundaries.n-1]) @@ -213,7 +213,7 @@ void calc_scaling(double *g, int bin, int boxes, double rclocal) // char buffer[TCL_INTEGER_SPACE + TCL_DOUBLE_SPACE + 2]; double rclocal2=rclocal*rclocal, neigh[wallstuff_part_in_bin[bin].n]; // 12 was set up in initialization as max neighbours in 2d - int limit=pow(2,boxes); + int limit= 1L << boxes; double sum_sai_r[limit][limit], sum_sai_m[limit][limit], sai_r, sai_m; int division[limit][limit] ; double ystep=box_l[1]/(double)limit, zstep=box_l[2]/(double)limit; @@ -266,8 +266,11 @@ void calc_scaling(double *g, int bin, int boxes, double rclocal) sai_r = sai_m = 0.0; } //printf("bin %d nb %d i %d sin %e cos %e\n", bin,nb, i, sinus, cosinus); - +#ifdef LEES_EDWARDS + fold_position(partCfg[p].r.p,partCfg[p].m.v,partCfg[p].l.i); +#else fold_position(partCfg[p].r.p, partCfg[p].l.i); +#endif double y=partCfg[p].r.p[1]; double z=partCfg[p].r.p[2]; int line=(int)(y/ystep); @@ -306,7 +309,7 @@ void calc_scaling2 (double *g, int bin, int boxes, double rclocal) // char buffer[TCL_INTEGER_SPACE + TCL_DOUBLE_SPACE + 2]; double rclocal2=rclocal*rclocal, neigh[wallstuff_part_in_bin[bin].n]; - int limit=pow(2,boxes); + int limit= 1L << boxes; double sum_sai_r[limit][limit], sum_sai_m[limit][limit], sai_r, sai_m; // 12 was set up in initialization as max neighbours in 2d int division[limit][limit],neighbour[limit][limit][13] ; @@ -370,7 +373,11 @@ void calc_scaling2 (double *g, int bin, int boxes, double rclocal) } //printf("bin %d nb %d i %d sin %e cos %e\n", bin,nb, i, sinus, cosinus); +#ifdef LEES_EDWARDS + fold_position(partCfg[p].r.p,partCfg[p].m.v,partCfg[p].l.i); +#else fold_position(partCfg[p].r.p, partCfg[p].l.i); +#endif double y=partCfg[p].r.p[1]; double z=partCfg[p].r.p[2]; int line=(int)(y/ystep); diff --git a/src/statistics_wallstuff.hpp b/src/core/statistics_wallstuff.hpp similarity index 97% rename from src/statistics_wallstuff.hpp rename to src/core/statistics_wallstuff.hpp index ae1878226ea..0c0e7a26886 100644 --- a/src/statistics_wallstuff.hpp +++ b/src/core/statistics_wallstuff.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 The ESPResSo project + Copyright (C) 2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/src/steppot.cpp b/src/core/steppot.cpp similarity index 91% rename from src/steppot.cpp rename to src/core/steppot.cpp index 7690a5edf34..66fe94b6445 100644 --- a/src/steppot.cpp +++ b/src/core/steppot.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file steppot.c +/** \file steppot.cpp * - * Implementation of \ref steppot.h + * Implementation of \ref steppot.hpp */ #include "steppot.hpp" diff --git a/src/steppot.hpp b/src/core/steppot.hpp similarity index 95% rename from src/steppot.hpp rename to src/core/steppot.hpp index 649e5f613ca..867fb518036 100644 --- a/src/steppot.hpp +++ b/src/core/steppot.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,10 @@ #ifndef STEPPOT_H #define STEPPOT_H -/** \file steppot.h +/** \file steppot.hpp * Routines to calculate the smooth step potential energy and/or force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/subt_lj.cpp b/src/core/subt_lj.cpp similarity index 91% rename from src/subt_lj.cpp rename to src/core/subt_lj.cpp index 161c56b606a..e4ac71b8b67 100644 --- a/src/subt_lj.cpp +++ b/src/core/subt_lj.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file subt_lj.c +/** \file subt_lj.cpp * - * Implementation of \ref subt_lj.h + * Implementation of \ref subt_lj.hpp */ #include "subt_lj.hpp" diff --git a/src/subt_lj.hpp b/src/core/subt_lj.hpp similarity index 97% rename from src/subt_lj.hpp rename to src/core/subt_lj.hpp index b30586a061d..fca36484685 100644 --- a/src/subt_lj.hpp +++ b/src/core/subt_lj.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,10 +20,10 @@ */ #ifndef SUBT_LJ_H #define SUBT_LJ_H -/** \file subt_lj.h +/** \file subt_lj.hpp * Routines to subtract the LENNARD-JONES Energy and/or the LENNARD-JONES force * for a particle pair. - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" #include "interaction_data.hpp" diff --git a/src/tab.cpp b/src/core/tab.cpp similarity index 97% rename from src/tab.cpp rename to src/core/tab.cpp index 3aecd151ca3..906ed89c761 100644 --- a/src/tab.cpp +++ b/src/core/tab.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file tab.c +/** \file tab.cpp * - * Implementation of \ref tab.h + * Implementation of \ref tab.hpp */ #include "tab.hpp" @@ -109,7 +109,7 @@ int tabulated_set_params(int part_type_a, int part_type_b, char* filename) return 0; } -int tabulated_bonded_set_params(int bond_type, int tab_type, char * filename) +int tabulated_bonded_set_params(int bond_type, TabulatedBondedInteraction tab_type, char * filename) { int i, token = 0, size; double dummr; diff --git a/src/tab.hpp b/src/core/tab.hpp similarity index 94% rename from src/tab.hpp rename to src/core/tab.hpp index a36bda09a61..d4aa9ce3200 100644 --- a/src/tab.hpp +++ b/src/core/tab.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,11 +21,11 @@ #ifndef _TAB_H #define _TAB_H -/** \file tab.h +/** \file tab.hpp * Routines to calculate the energy and/or force * for a particle pair or bonds via interpolating from lookup tables. - * \ref forces.c - * Needs feature TABULATED compiled in (see \ref config.h). + * \ref forces.cpp + * Needs feature TABULATED compiled in (see \ref config.hpp). */ #include "utils.hpp" @@ -78,10 +78,10 @@ int tabulated_set_params(int part_type_a, int part_type_b, char* filename);
  • 6 parameter out of bounds */ -int tabulated_bonded_set_params(int bond_type, int tab_type, char * filename); +int tabulated_bonded_set_params(int bond_type, TabulatedBondedInteraction tab_type, char * filename); /** Add a non-bonded pair force by linear interpolation from a table. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline void add_tabulated_pair_force(Particle *p1, Particle *p2, IA_parameters *ia_params, double d[3], double dist, double force[3]) { @@ -123,7 +123,7 @@ inline void add_tabulated_pair_force(Particle *p1, Particle *p2, IA_parameters * } /** Add a non-bonded pair energy by linear interpolation from a table. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline double tabulated_pair_energy(Particle *p1, Particle *p2, IA_parameters *ia_params, double d[3], double dist) { double phi, dindex; @@ -160,7 +160,7 @@ inline double tabulated_pair_energy(Particle *p1, Particle *p2, IA_parameters *i /** check the tabulated forcecap to see that it is sensible \warning This routine will probably give strange results if forcecap is applied before the table is loaded. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ void check_tab_forcecap(double force_cap); /* BONDED INTERACTIONS */ @@ -169,7 +169,7 @@ void check_tab_forcecap(double force_cap); \ref Bonded_ia_parameters). The force is calculated by linear interpolation between the closest tabulated values. There is no check for the upper bound! - Needs feature TABULATED compiled in (see \ref config.h).*/ + Needs feature TABULATED compiled in (see \ref config.hpp).*/ inline double bonded_tab_force_lookup(double val, Bonded_ia_parameters *iaparams) { int ind; @@ -189,7 +189,7 @@ inline double bonded_tab_force_lookup(double val, Bonded_ia_parameters *iaparams Bonded_ia_parameters). The force is calculated by linear interpolation between the closest tabulated values. There is no check for the upper bound! - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline double bonded_tab_energy_lookup(double val, Bonded_ia_parameters *iaparams) { int ind; @@ -211,7 +211,7 @@ inline double bonded_tab_energy_lookup(double val, Bonded_ia_parameters *iaparam connecting vector between the particles. For distances smaller than the tabulated range it uses a linear extrapolation based on the first two tabulated force values. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int calc_tab_bond_force(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double force[3]) { int i; @@ -236,7 +236,7 @@ inline int calc_tab_bond_force(Particle *p1, Particle *p2, Bonded_ia_parameters p2. For distances smaller than the tabulated range it uses a quadratic extrapolation based on the first two tabulated force values and the first tabulated energy value. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int tab_bond_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iaparams, double dx[3], double *_energy) { double dist = sqrt(sqrlen(dx)); @@ -271,7 +271,7 @@ inline int tab_bond_energy(Particle *p1, Particle *p2, Bonded_ia_parameters *iap forces. The forces are scaled with the invers length of the connecting vectors. It is assumed that the potential is tabulated for all angles between 0 and Pi. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int calc_tab_angle_force(Particle *p_mid, Particle *p_left, Particle *p_right, Bonded_ia_parameters *iaparams, double force1[3], double force2[3]) @@ -372,7 +372,7 @@ inline void calc_angle_3body_tabulated_forces(Particle *p_mid, Particle *p_left, type_num (see \ref Bonded_ia_parameters) between particles p_left, p_mid and p_right. It is assumed that the potential is tabulated for all angles between 0 and Pi. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int tab_angle_energy(Particle *p_mid, Particle *p_left, Particle *p_right, Bonded_ia_parameters *iaparams, double *_energy) @@ -396,7 +396,7 @@ inline int tab_angle_energy(Particle *p_mid, Particle *p_left, /** Calculate a tabulated dihedral force with number type_num (see \ref Bonded_ia_parameters) between particles p1. p2, p3 and p4 and add it to the particle forces. This function is not tested yet. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int calc_tab_dihedral_force(Particle *p2, Particle *p1, Particle *p3, Particle *p4, Bonded_ia_parameters *iaparams, double force2[3], double force1[3], double force3[3]) @@ -444,7 +444,7 @@ inline int calc_tab_dihedral_force(Particle *p2, Particle *p1, /** Calculate and return a tabulated dihedral energy with number type_num (see \ref Bonded_ia_parameters) between particles p1. p2, p3 and p4. This function is not tested yet. - Needs feature TABULATED compiled in (see \ref config.h). */ + Needs feature TABULATED compiled in (see \ref config.hpp). */ inline int tab_dihedral_energy(Particle *p2, Particle *p1, Particle *p3, Particle *p4, Bonded_ia_parameters *iaparams, double *_energy) diff --git a/src/thermostat.cpp b/src/core/thermostat.cpp similarity index 81% rename from src/thermostat.cpp rename to src/core/thermostat.cpp index 1fe4fa9cc52..a8bd481e1f2 100644 --- a/src/thermostat.cpp +++ b/src/core/thermostat.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file thermostat.c - Implementation of \ref thermostat.h "thermostat.h" +/** \file thermostat.cpp + Implementation of \ref thermostat.hpp "thermostat.h" */ #include "thermostat.hpp" #include "communication.hpp" @@ -27,10 +27,15 @@ #include "npt.hpp" #include "ghmc.hpp" +#if (!defined(FLATNOISE) && !defined(GAUSSRANDOMCUT) && !defined(GAUSSRANDOM)) +#define FLATNOISE +#endif + + /* thermostat switch */ int thermo_switch = THERMO_OFF; /** Temperature */ -double temperature = -1.0; +double temperature = 0.0; /* LANGEVIN THERMOSTAT */ /* Langevin friction coefficient gamma. */ @@ -66,11 +71,23 @@ double nptiso_pref4; void thermo_init_langevin() { langevin_pref1 = -langevin_gamma/time_step; +#if defined (FLATNOISE) langevin_pref2 = sqrt(24.0*temperature*langevin_gamma/time_step); - +#elif defined (GAUSSRANDOMCUT) || defined (GAUSSRANDOM) + langevin_pref2 = sqrt(2.0*temperature*langevin_gamma/time_step); +#else +#error No Noise defined +#endif + #ifdef ROTATION langevin_gamma_rotation = langevin_gamma/3; +#if defined (FLATNOISE) langevin_pref2_rotation = sqrt(24.0*temperature*langevin_gamma_rotation/time_step); +#elif defined (GAUSSRANDOMCUT) || defined (GAUSSRANDOM) + langevin_pref2_rotation = sqrt(2.0*temperature*langevin_gamma_rotation/time_step); +#else +#error No Noise defined +#endif THERMO_TRACE(fprintf(stderr,"%d: thermo_init_langevin: langevin_gamma_rotation=%f, langevin_pref2_rotation=%f",this_node, langevin_gamma_rotation,langevin_pref2_rotation)); #endif THERMO_TRACE(fprintf(stderr,"%d: thermo_init_langevin: langevin_pref1=%f, langevin_pref2=%f",this_node,langevin_pref1,langevin_pref2)); @@ -80,10 +97,19 @@ void thermo_init_langevin() void thermo_init_npt_isotropic() { if (nptiso.piston != 0.0) { +#if defined (FLATNOISE) nptiso_pref1 = -nptiso_gamma0*0.5 * time_step; nptiso_pref2 = sqrt(12.0*temperature*nptiso_gamma0*time_step) * time_step; nptiso_pref3 = -nptiso_gammav*(1.0/nptiso.piston)*0.5*time_step; nptiso_pref4 = sqrt(12.0*temperature*nptiso_gammav*time_step); +#elif defined (GAUSSRANDOMCUT) || defined (GAUSSRANDOM) + nptiso_pref1 = -nptiso_gamma0*0.5 * time_step; + nptiso_pref2 = sqrt(1.0*temperature*nptiso_gamma0*time_step) * time_step; + nptiso_pref3 = -nptiso_gammav*(1.0/nptiso.piston)*0.5*time_step; + nptiso_pref4 = sqrt(1.0*temperature*nptiso_gammav*time_step); +#else +#error No Noise defined +#endif THERMO_TRACE(fprintf(stderr,"%d: thermo_init_npt_isotropic: nptiso_pref1=%f, nptiso_pref2=%f, nptiso_pref3=%f, nptiso_pref4=%f \n",this_node,nptiso_pref1,nptiso_pref2,nptiso_pref3,nptiso_pref4)); } else { diff --git a/src/thermostat.hpp b/src/core/thermostat.hpp similarity index 54% rename from src/thermostat.hpp rename to src/core/thermostat.hpp index b7c0758073f..e2a53762de2 100644 --- a/src/thermostat.hpp +++ b/src/core/thermostat.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _THERMOSTAT_H #define _THERMOSTAT_H -/** \file thermostat.h +/** \file thermostat.hpp */ @@ -49,6 +49,10 @@ /*@}*/ +#if (!defined(FLATNOISE) && !defined(GAUSSRANDOMCUT) && !defined(GAUSSRANDOM)) +#define FLATNOISE +#endif + /************************************************ * exported variables ************************************************/ @@ -97,6 +101,25 @@ void thermo_heat_up(); /** pendant to \ref thermo_heat_up */ void thermo_cool_down(); +#ifdef LEES_EDWARDS +/** locally defined funcion to find Vx relative to the LE shear frame + @param i coordinate index + @param vel velocity vector + @param pos position vector + @return adjusted (or not) i^th velocity coordinate */ +inline double le_frameV(int i, double *vel, double *pos) { + + double relY; + + if( i == 0 ){ + relY = pos[1] * box_l_i[1] - 0.5; + return( vel[0] - relY * lees_edwards_rate ); + } + else + return vel[i]; +} +#endif + #ifdef NPT /** add velocity-dependend noise and friction for NpT-sims to the particle's velocity @param dt_vj j-component of the velocity scaled by time_step dt @@ -104,7 +127,15 @@ void thermo_cool_down(); inline double friction_therm0_nptiso(double dt_vj) { extern double nptiso_pref1, nptiso_pref2; if(thermo_switch & THERMO_NPT_ISO) +#if defined (FLATNOISE) return ( nptiso_pref1*dt_vj + nptiso_pref2*(d_random()-0.5) ); +#elif defined (GAUSSRANDOMCUT) + return ( nptiso_pref1*dt_vj + nptiso_pref2*gaussian_random_cut() ); +#elif defined (GAUSSRANDOM) + return ( nptiso_pref1*dt_vj + nptiso_pref2*gaussian_random() ); +#else +#error No Noise defined +#endif return 0.0; } @@ -112,7 +143,15 @@ inline double friction_therm0_nptiso(double dt_vj) { inline double friction_thermV_nptiso(double p_diff) { extern double nptiso_pref3, nptiso_pref4; if(thermo_switch & THERMO_NPT_ISO) +#if defined (FLATNOISE) return ( nptiso_pref3*p_diff + nptiso_pref4*(d_random()-0.5) ); +#elif defined (GAUSSRANDOMCUT) + return ( nptiso_pref3*p_diff + nptiso_pref4*gaussian_random_cut() ); +#elif defined (GAUSSRANDOM) + return ( nptiso_pref3*p_diff + nptiso_pref4*gaussian_random() ); +#else +#error No Noise defined +#endif return 0.0; } #endif @@ -161,6 +200,8 @@ inline void friction_thermo_langevin(Particle *p) #endif { #ifdef LANGEVIN_PER_PARTICLE + +#if defined (FLATNOISE) if(p->p.gamma >= 0.) { langevin_pref1_temp = -p->p.gamma/time_step; @@ -168,8 +209,13 @@ inline void friction_thermo_langevin(Particle *p) langevin_pref2_temp = sqrt(24.0*p->p.T*p->p.gamma/time_step); else langevin_pref2_temp = sqrt(24.0*temperature*p->p.gamma/time_step); - +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1_temp* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*(d_random()-0.5)*massf; +#else p->f.f[j] = langevin_pref1_temp*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*(d_random()-0.5)*massf; +#endif + } else { if(p->p.T >= 0.) @@ -177,10 +223,109 @@ inline void friction_thermo_langevin(Particle *p) else langevin_pref2_temp = langevin_pref2; +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*(d_random()-0.5)*massf; +#else p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*(d_random()-0.5)*massf; +#endif + } +#elif defined (GAUSSRANDOMCUT) + if(p->p.gamma >= 0.) { + langevin_pref1_temp = -p->p.gamma/time_step; + + if(p->p.T >= 0.) + langevin_pref2_temp = sqrt(2.0*p->p.T*p->p.gamma/time_step); + else + langevin_pref2_temp = sqrt(2.0*temperature*p->p.gamma/time_step); + +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1_temp* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*gaussian_random_cut()*massf; #else + p->f.f[j] = langevin_pref1_temp*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*gaussian_random_cut()*massf; +#endif + } + else { + if(p->p.T >= 0.) + langevin_pref2_temp = sqrt(2.0*p->p.T*langevin_gamma/time_step); + else + langevin_pref2_temp = langevin_pref2; + +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*gaussian_random_cut()*massf; +#else + p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*gaussian_random_cut()*massf; +#endif + } +#elif defined (GAUSSRANDOM) + if(p->p.gamma >= 0.) { + langevin_pref1_temp = -p->p.gamma/time_step; + + if(p->p.T >= 0.) + langevin_pref2_temp = sqrt(2.0*p->p.T*p->p.gamma/time_step); + else + langevin_pref2_temp = sqrt(2.0*temperature*p->p.gamma/time_step); + +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1_temp* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*gaussian_random()*massf; +#else + p->f.f[j] = langevin_pref1_temp*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*gaussian_random()*massf; +#endif + } + else { + if(p->p.T >= 0.) + langevin_pref2_temp = sqrt(2.0*p->p.T*langevin_gamma/time_step); + else + langevin_pref2_temp = langevin_pref2; + +#ifdef LEES_EDWARDS + p->f.f[j] = langevin_pref1* + le_frameV(j, p->m.v, p->r.p)*PMASS(*p) + langevin_pref2_temp*gaussian_random()*massf; +#else + p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2_temp*gaussian_random()*massf; +#endif + } +#else +#error No Noise defined +#endif + + +#else + +#ifdef LEES_EDWARDS +/*******************different shapes of noise */ +#if defined (FLATNOISE) + p->f.f[j] = langevin_pref1*le_frameV(j, p->m.v, p->r.p) + * PMASS(*p) + langevin_pref2*(d_random()-0.5)*massf; +#elif defined (GAUSSRANDOMCUT) + p->f.f[j] = langevin_pref1*le_frameV(j, p->m.v, p->r.p) + * PMASS(*p) + langevin_pref2*gaussian_random_cut()*massf; +#elif defined (GAUSSRANDOM) + p->f.f[j] = langevin_pref1*le_frameV(j, p->m.v, p->r.p) + * PMASS(*p) + langevin_pref2*gaussian_random()*massf; +#else +#error No Noise defined +#endif +/*******************end different shapes of noise */ + +#else //ndef LEES_EDWARDS +/*******************different shapes of noise */ +#if defined (FLATNOISE) p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2*(d_random()-0.5)*massf; +#elif defined (GAUSSRANDOMCUT) + p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2*gaussian_random_cut()*massf; +#elif defined (GAUSSRANDOM) + p->f.f[j] = langevin_pref1*p->m.v[j]*PMASS(*p) + langevin_pref2*gaussian_random()*massf; +#else +#error No Noise defined +#endif +/*******************end different shapes of noise */ +#endif //end ifdef LEES_EDWARDS + #endif } #ifdef EXTERNAL_FORCES @@ -224,11 +369,27 @@ inline void friction_thermo_langevin_rotation(Particle *p) #endif for ( j = 0 ; j < 3 ; j++) { +#if defined (FLATNOISE) #ifdef ROTATIONAL_INERTIA - p->f.torque[j] = -langevin_gamma*p->m.omega[j] *p->p.rinertia[j] + langevin_pref2*sqrt(p->p.rinertia[j]) * (d_random()-0.5); - #else - p->f.torque[j] = -langevin_gamma*p->m.omega[j] + langevin_pref2*(d_random()-0.5); - #endif + p->f.torque[j] = -langevin_gamma*p->m.omega[j] *p->p.rinertia[j] + langevin_pref2*sqrt(p->p.rinertia[j]) * (d_random()-0.5); + #else + p->f.torque[j] = -langevin_gamma*p->m.omega[j] + langevin_pref2*(d_random()-0.5); + #endif +#elif defined (GAUSSRANDOMCUT) + #ifdef ROTATIONAL_INERTIA + p->f.torque[j] = -langevin_gamma*p->m.omega[j] *p->p.rinertia[j] + langevin_pref2*sqrt(p->p.rinertia[j]) * gaussian_random_cut(); + #else + p->f.torque[j] = -langevin_gamma*p->m.omega[j] + langevin_pref2*gaussian_random_cut(); + #endif +#elif defined (GAUSSRANDOM) + #ifdef ROTATIONAL_INERTIA + p->f.torque[j] = -langevin_gamma*p->m.omega[j] *p->p.rinertia[j] + langevin_pref2*sqrt(p->p.rinertia[j]) * gaussian_random(); + #else + p->f.torque[j] = -langevin_gamma*p->m.omega[j] + langevin_pref2*gaussian_random(); + #endif +#else +#error No Noise defined +#endif } ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LANG f = (%.3e,%.3e,%.3e)\n",this_node,p->f.f[0],p->f.f[1],p->f.f[2])); THERMO_TRACE(fprintf(stderr,"%d: Thermo: P %d: force=(%.3e,%.3e,%.3e)\n",this_node,p->p.identity,p->f.f[0],p->f.f[1],p->f.f[2])); diff --git a/src/topology.cpp b/src/core/topology.cpp similarity index 96% rename from src/topology.cpp rename to src/core/topology.cpp index 73e6c9f2d6e..aec6265f3e8 100644 --- a/src/topology.cpp +++ b/src/core/topology.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,11 +19,11 @@ along with this program. If not, see . */ -/** \file topology.c +/** \file topology.cpp * * This file contains functions for handling the system topology. * - * For more information see topology.h + * For more information see topology.hpp * */ #include "utils.hpp" diff --git a/src/topology.hpp b/src/core/topology.hpp similarity index 97% rename from src/topology.hpp rename to src/core/topology.hpp index f2173c1cf13..6f1ddbf7337 100644 --- a/src/topology.hpp +++ b/src/core/topology.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef TOPOLOGY_H #define TOPOLOGY_H -/** \file topology.h +/** \file topology.hpp * * This file contains functions for handling the system topology. */ diff --git a/src/tunable_slip.cpp b/src/core/tunable_slip.cpp similarity index 98% rename from src/tunable_slip.cpp rename to src/core/tunable_slip.cpp index 2a65087c62b..04395adf913 100644 --- a/src/tunable_slip.cpp +++ b/src/core/tunable_slip.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tunable_slip.hpp b/src/core/tunable_slip.hpp similarity index 94% rename from src/tunable_slip.hpp rename to src/core/tunable_slip.hpp index 50fd8302cf1..32e5aea80de 100644 --- a/src/tunable_slip.hpp +++ b/src/core/tunable_slip.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _TUNABLE_SLIP_H #define _TUNABLE_SLIP_H -/** \file tunable_slip.h +/** \file tunable_slip.hpp * Routines to generate tunable-slip boundary conditions. * J.Smiatek, M.P. Allen, F. Schmid: * "Tunable-slip boundaries for coarse-grained simulations of fluid flow", Europ. Phys. J. E 26, 115 (2008) diff --git a/src/tuning.cpp b/src/core/tuning.cpp similarity index 88% rename from src/tuning.cpp rename to src/core/tuning.cpp index b8c3eedfe59..0f473d026a8 100644 --- a/src/tuning.cpp +++ b/src/core/tuning.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file tuning.c - Implementation of tuning.h . +/** \file tuning.cpp + Implementation of tuning.hpp . */ #include #include @@ -49,14 +49,13 @@ double time_force_calc(int default_samples) int rds = timing_samples > 0 ? timing_samples : default_samples; int i; - if (mpi_integrate(0)) + if (mpi_integrate(0, 0)) return -1; /* perform force calculation test */ markTime(); for (i = 0; i < rds; i++) { - mpi_bcast_event(INVALIDATE_SYSTEM); - if (mpi_integrate(0)) + if (mpi_integrate(0, -1)) return -1; } markTime(); diff --git a/src/tuning.hpp b/src/core/tuning.hpp similarity index 95% rename from src/tuning.hpp rename to src/core/tuning.hpp index 53251ce9697..2df4aa0dc3c 100644 --- a/src/tuning.hpp +++ b/src/core/tuning.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file tuning.h +/** \file tuning.hpp This contains a timing loop for the force calculation. Via the global variable timings you can specify how many force evaluations are sampled. Via \ref markTime and \ref diffTime you can also easily time anything other than the force evaluation. diff --git a/src/utils.hpp b/src/core/utils.hpp similarity index 97% rename from src/utils.hpp rename to src/core/utils.hpp index 68265ca67ac..1a83da99d4e 100644 --- a/src/utils.hpp +++ b/src/core/utils.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _UTILS_H #define _UTILS_H -/** \file utils.h +/** \file utils.hpp * Small functions that are useful not only for one modul. * just some nice utilities... @@ -33,7 +33,9 @@ #include #include "config.hpp" #include "debug.hpp" -#include "errorhandling.hpp" +#ifdef LEES_EDWARDS +#include "lees_edwards.hpp" +#endif /*************************************************************/ /** \name Mathematical, physical and chemical constants. */ @@ -93,6 +95,13 @@ typedef struct { int max; } DoubleList; +inline void errexit() { +#ifdef FORCE_CORE + core(); +#endif + exit(1); +} + /*************************************************************/ /** \name Dynamic memory allocation. */ /*************************************************************/ @@ -899,16 +908,27 @@ inline double distance2vec(double pos1[3], double pos2[3], double vec[3]) inline double unfolded_distance(double pos1[3], int image_box1[3], double pos2[3], int image_box2[3], double box_l[3]) { - int i; double dist = 0; double lpos1[3],lpos2[3]; - for(i=0;i<3;i++){ - lpos1[i] = pos1[i]; - lpos2[i] = pos2[i]; - lpos1[i] += image_box1[i]*box_l[i]; - lpos2[i] += image_box2[i]*box_l[i]; - dist += SQR(lpos1[i]-lpos2[i]); - } + + /*unrolling the loop so can neatly add Lees-Edwards: + *compiler probably unrolls anyway*/ + lpos1[0] = pos1[0] + image_box1[0]*box_l[0]; + lpos2[0] = pos2[0] + image_box2[0]*box_l[0]; +#ifdef LEES_EDWARDS + lpos1[0] += image_box1[1] * lees_edwards_offset; + lpos2[0] += image_box2[1] * lees_edwards_offset; +#endif + dist = SQR(lpos1[0]-lpos2[0]); + + lpos1[1] = pos1[1] + image_box1[1]*box_l[1]; + lpos2[1] = pos2[1] + image_box2[1]*box_l[1]; + dist += SQR(lpos1[1]-lpos2[1]); + + lpos1[2] = pos1[2] + image_box1[2]*box_l[2]; + lpos2[2] = pos2[2] + image_box2[2]*box_l[2]; + dist += SQR(lpos1[2]-lpos2[2]); + return sqrt(dist); } /*@}*/ diff --git a/src/uwerr.cpp b/src/core/uwerr.cpp similarity index 98% rename from src/uwerr.cpp rename to src/core/uwerr.cpp index 620bb5beebd..fb7fbacde2e 100644 --- a/src/uwerr.cpp +++ b/src/core/uwerr.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file uwerr.c +/** \file uwerr.cpp */ #include diff --git a/src/uwerr.hpp b/src/core/uwerr.hpp similarity index 93% rename from src/uwerr.hpp rename to src/core/uwerr.hpp index 597cd691b8f..520ac4d9d45 100644 --- a/src/uwerr.hpp +++ b/src/core/uwerr.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef _UWERR_H #define _UWERR_H -/** \file uwerr.h +/** \file uwerr.hpp * */ double UWerr_dsum_double(double * v, double * w, int len); diff --git a/src/verlet.cpp b/src/core/verlet.cpp similarity index 95% rename from src/verlet.cpp rename to src/core/verlet.cpp index 57a1daa8b2a..309b5108353 100644 --- a/src/verlet.cpp +++ b/src/core/verlet.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file verlet.c Verlet list. - * For more information see \ref verlet.h "verlet.h" +/** \file verlet.cpp Verlet list. + * For more information see \ref verlet.hpp "verlet.h" */ #include #include @@ -33,10 +33,11 @@ #include "communication.hpp" #include "grid.hpp" #include "forces.hpp" -#include "energy.hpp" +#include "energy_inline.hpp" #include "pressure.hpp" #include "domain_decomposition.hpp" #include "constraint.hpp" +#include "external_potential.hpp" /** Granularity of the verlet list */ #define LIST_INCREMENT 20 @@ -105,7 +106,7 @@ void build_verlet_lists() int estimate, sum=0; fprintf(stderr,"%d: build_verlet_list_and_force_calc:\n",this_node); /* estimate number of interactions: (0.5*n_part*ia_volume*density)/n_nodes */ - estimate = 0.5*n_total_particles*(4.0/3.0*PI*pow(max_range_nonbonded2,1.5))*(n_total_particles/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; + estimate = 0.5*n_part*(4.0/3.0*PI*pow(max_range_nonbonded2,1.5))*(n_part/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; if (!dd.use_vList) { fprintf(stderr, "%d: build_verlet_lists, but use_vList == 0\n", this_node); errexit(); } #endif @@ -179,6 +180,7 @@ void calculate_verlet_ia() #ifdef CONSTRAINTS add_constraints_forces(&p1[i]); #endif + add_external_potential_forces(&p1[i]); } /* Loop cell neighbors */ @@ -211,7 +213,7 @@ void build_verlet_lists_and_calc_verlet_ia() fprintf(stderr,"%d: build_verlet_list_and_calc_verlet_ia:\n",this_node); /* estimate number of interactions: (0.5*n_part*ia_volume*density)/n_nodes */ - estimate = 0.5*n_total_particles*(4.0/3.0*PI*pow(max_range_nonbonded2,1.5))*(n_total_particles/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; + estimate = 0.5*n_part*(4.0/3.0*PI*pow(max_range_nonbonded2,1.5))*(n_part/(box_l[0]*box_l[1]*box_l[2]))/n_nodes; if (!dd.use_vList) { fprintf(stderr, "%d: build_verlet_lists, but use_vList == 0\n", this_node); errexit(); } #endif @@ -242,6 +244,7 @@ void build_verlet_lists_and_calc_verlet_ia() #ifdef CONSTRAINTS add_constraints_forces(&p1[i]); #endif + add_external_potential_forces(&p1[i]); memcpy(p1[i].l.p_old, p1[i].r.p, 3*sizeof(double)); j_start = i+1; } @@ -305,6 +308,7 @@ void calculate_verlet_energies() #ifdef CONSTRAINTS add_constraints_energy(&p1[i]); #endif + add_external_potential_energy(&p1[i]); } /* no interaction set */ diff --git a/src/verlet.hpp b/src/core/verlet.hpp similarity index 96% rename from src/verlet.hpp rename to src/core/verlet.hpp index 3fb85ca7731..6226c8185f3 100644 --- a/src/verlet.hpp +++ b/src/core/verlet.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ */ #ifndef VERLET_H #define VERLET_H -/** \file verlet.h +/** \file verlet.hpp * * This file contains routines to setup and handle interaction pair * lists (verlet pair lists) for the non bonded interactions. @@ -47,7 +47,7 @@ * For energy and pressure calculations using verlet pair lists use * \ref calculate_verlet_energies and \ref calculate_verlet_virials. * - * For more information see \ref verlet.c "verlet.c". + * For more information see \ref verlet.cpp "verlet.c". */ #include "particle_data.hpp" diff --git a/src/virtual_sites.cpp b/src/core/virtual_sites.cpp similarity index 95% rename from src/virtual_sites.cpp rename to src/core/virtual_sites.cpp index da432622024..1dd4f38ab27 100644 --- a/src/virtual_sites.cpp +++ b/src/core/virtual_sites.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -73,7 +73,7 @@ void update_mol_pos() int update_mol_pos_cfg(){ int i; - for(i=0; ip.mol_id; if (mol_id < 0) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"Particle does not have a mol id! pnr=%i\n", - calling_p->p.identity); + ostringstream msg; + msg <<"Particle does not have a mol id! pnr= " << calling_p->p.identity << "\n"; + runtimeError(msg); return NULL; } for (i=0;ip.identity); + ostringstream msg; + msg <<"No com found in get_mol_com_particleParticle does not exist in put_mol_force_on_parts! pnr= " << calling_p->p.identity << "\n"; + runtimeError(msg); return NULL; return calling_p; @@ -295,13 +304,15 @@ double get_mol_dist(Particle *p1,Particle *p2){ p2_com=get_mol_com_particle(p2); #ifdef VIRTUAL_SITES_DEBUG if (p1_com==NULL){ - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"COM Particle not found for particle in get_mol_dist id=%i\n",p1->p.identity); + ostringstream msg; + msg <<"COM Particle not found for particle in get_mol_dist id= " << p1->p.identity << "\n"; + runtimeError(msg); dist[0]=dist[1]=dist[2]=0.0; } if (p2_com==NULL){ - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"COM Particle not found for particle in get_mol_dist id=%i\n",p2->p.identity); + ostringstream msg; + msg <<"COM Particle not found for particle in get_mol_dist id= " << p2->p.identity << "\n"; + runtimeError(msg); dist[0]=dist[1]=dist[2]=0.0; } #endif @@ -353,11 +364,6 @@ void calc_force_between_mol(int mol_id1,int mol_id2,double force[3]){ int i,j; Particle *p1,*p2; double vec12[3],dist2,dist; -#ifdef ADRESS - int l; - double weight; - double temp_force[3]={0,0,0}; -#endif force[0]=force[1]=force[2]=0.0; for (i=0;ir.p, p2->r.p); dist2=sqrlen(vec12); dist=sqrt(dist2); -#ifdef ADRESS - for(l=0;l<3;l++) - temp_force[l]=0; -#ifdef EXCLUSIONS - if(do_nonbonded(p1,p2)) -#endif - { - calc_non_bonded_pair_force_from_partcfg_simple(p1,p2,vec12,dist,dist2,temp_force); - weight = adress_non_bonded_force_weight(p1,p2); - for(l=0;l<3;l++) - force[l] += weight*temp_force[l]; - } -#else #ifdef EXCLUSIONS if(do_nonbonded(p1,p2)) #endif - calc_non_bonded_pair_force_from_partcfg_simple(p1,p2,vec12,dist,dist2,force); -#endif - + calc_non_bonded_pair_force_from_partcfg_simple(p1,p2,vec12,dist,dist2,force); } } diff --git a/src/virtual_sites_com.hpp b/src/core/virtual_sites_com.hpp similarity index 97% rename from src/virtual_sites_com.hpp rename to src/core/virtual_sites_com.hpp index dfe9b96e364..e86d780ec3f 100644 --- a/src/virtual_sites_com.hpp +++ b/src/core/virtual_sites_com.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/virtual_sites_relative.cpp b/src/core/virtual_sites_relative.cpp similarity index 89% rename from src/virtual_sites_relative.cpp rename to src/core/virtual_sites_relative.cpp index ebb95ea5ca1..38cd5ae0557 100644 --- a/src/virtual_sites_relative.cpp +++ b/src/core/virtual_sites_relative.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -16,12 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include "config.hpp" -#ifdef VIRTUAL_SITES_RELATIVE #include "virtual_sites_relative.hpp" #include "rotation.hpp" +#ifdef VIRTUAL_SITES_RELATIVE + // This is the "relative" implementation for virtual sites. // Virtual particles are placed relative to the position of a real particle @@ -42,8 +42,9 @@ void update_mol_pos_particle(Particle *p) // Check, if a real particle was found if (!p_real) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt,"virtual_sites_relative.c - update_mol_pos_particle(): No real particle associated with virtual site.\n"); + ostringstream msg; + msg <<"virtual_sites_relative.cpp - update_mol_pos_particle(): No real particle associated with virtual site.\n"; + runtimeError(msg); return; } @@ -106,8 +107,9 @@ void update_mol_vel_particle(Particle *p) // Check, if a real particle was found if (!p_real) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "virtual_sites_relative.c - update_mol_pos_particle(): No real particle associated with virtual site.\n"); + ostringstream msg; + msg <<"virtual_sites_relative.cpp - update_mol_pos_particle(): No real particle associated with virtual site.\n"; + runtimeError(msg); return; } @@ -201,8 +203,9 @@ int vs_relate_to(int part_num, int relate_to) Particle p_current,p_relate_to; if ((get_particle_data(relate_to,&p_relate_to)!=ES_OK) || (get_particle_data(part_num,&p_current)!=ES_OK)) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "Could not retrieve particle data for the given id"); + ostringstream msg; + msg <<"Could not retrieve particle data for the given id"; + runtimeError(msg); return ES_ERROR; } @@ -212,8 +215,9 @@ int vs_relate_to(int part_num, int relate_to) // Set the particle id of the particle we want to relate to and the distnace if (set_particle_vs_relative(part_num, relate_to, sqrt(sqrlen(d))) == ES_ERROR) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "setting the vs_relative attributes failed"); + ostringstream msg; + msg <<"setting the vs_relative attributes failed"; + runtimeError(msg); return ES_ERROR; } @@ -222,7 +226,10 @@ int vs_relate_to(int part_num, int relate_to) // If so, warn user double l=sqrt(sqrlen(d)); if (l>min_global_cut) { - printf("Warning: The distance between virtual and non-virtual particle (%f) is\nlarger than the minimum global cutoff (%f). This may lead to incorrect simulations\nunder certain conditions. Use \"setmd min_global_cut\" to increase the minimum cutoff.\n",l,min_global_cut); + ostringstream msg; + msg << "Warning: The distance between virtual and non-virtual particle (" << l << ") is\nlarger than the minimum global cutoff (" << min_global_cut << "). This may lead to incorrect simulations\nunder certain conditions. Use \"setmd min_global_cut\" to increase the minimum cutoff.\n"; + runtimeWarning(msg); + return ES_ERROR; } // Now, calculate the quaternions which specify the angle between @@ -282,9 +289,9 @@ int vs_relate_to(int part_num, int relate_to) // Save the quaternions in the particle if (set_particle_quat(part_num, quat) == ES_ERROR) { - char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); - ERROR_SPRINTF(errtxt, "set particle position first"); - + ostringstream msg; + msg <<"set particle position first"; + runtimeError(msg); return ES_ERROR; } @@ -295,7 +302,7 @@ int vs_relate_to(int part_num, int relate_to) // Rigid body conribution to scalar pressure and stress tensor void vs_relative_pressure_and_stress_tensor(double* pressure, double* stress_tensor) { - // Division by 3 volume is somewhere else. (pressure.c after all presure calculations) + // Division by 3 volume is somewhere else. (pressure.cpp after all presure calculations) // Iterate over all the particles in the local cells diff --git a/src/virtual_sites_relative.hpp b/src/core/virtual_sites_relative.hpp similarity index 96% rename from src/virtual_sites_relative.hpp rename to src/core/virtual_sites_relative.hpp index 85a3ae4d968..d3ec587fac7 100644 --- a/src/virtual_sites_relative.hpp +++ b/src/core/virtual_sites_relative.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2010,2011 Rudolf Weeber This file is part of ESPResSo. diff --git a/src/vmdsock.cpp b/src/core/vmdsock.cpp similarity index 98% rename from src/vmdsock.cpp rename to src/core/vmdsock.cpp index d0953f48fab..90e0e8ce3f8 100644 --- a/src/vmdsock.cpp +++ b/src/core/vmdsock.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file vmdsock.c +/** \file vmdsock.cpp This is from NAMD, DO NOT CHANGE! */ diff --git a/src/vmdsock.hpp b/src/core/vmdsock.hpp similarity index 95% rename from src/vmdsock.hpp rename to src/core/vmdsock.hpp index 37d66f1ab05..d5cf85686d1 100644 --- a/src/vmdsock.hpp +++ b/src/core/vmdsock.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file vmdsock.h +/** \file vmdsock.hpp DO NOT CHANGE !!! *** diff --git a/src/cuda_is_cpp.cpp b/src/cuda_is_cpp.cpp deleted file mode 100644 index e15cfb31ca6..00000000000 --- a/src/cuda_is_cpp.cpp +++ /dev/null @@ -1 +0,0 @@ -static void iamheretofuckautotools() {} diff --git a/src/errorhandling.cpp b/src/errorhandling.cpp deleted file mode 100644 index 9cb6306cc26..00000000000 --- a/src/errorhandling.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2010,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file errorhandling.c - Implementation of \ref errorhandling.h "errorhandling.h". -*/ -#include -#include -#include -#include "utils.hpp" -#include "errorhandling.hpp" -#include "communication.hpp" - -/******************* exported variables **********************/ -/** buffer for error messages during the integration process. NULL if no errors occured. */ -char *error_msg; -int n_error_msg = 0; - -/******************* exported functions **********************/ - -char *runtime_error(int errlen) -{ - /* the true length of the string will be in general shorter than n_error_msg, - at least if numbers are involved */ - int curend = error_msg ? strlen(error_msg) : 0; - n_error_msg = curend + errlen + 1; - - error_msg = (char*)realloc(error_msg, n_error_msg); - return error_msg + curend; -} - -int check_runtime_errors() -{ - int n_all_error_msg; - MPI_Allreduce(&n_error_msg, &n_all_error_msg, 1, MPI_INT, MPI_SUM, comm_cart); - return n_all_error_msg; -} - -void errexit() -{ -#ifdef FORCE_CORE - core(); -#endif - exit(1); -} - -static void sigint_handler(int sig) -{ - /* without this exit handler the nodes might exit asynchronously - * without calling MPI_Finalize, which may cause MPI to hang - * (e.g. this handler makes CTRL-c work properly with poe) - * - * NOTE: mpirun installs its own handler for SIGINT/SIGTERM - * and takes care of proper cleanup and exit */ - - char *errtxt; - - static int numcalls = 0; - if (numcalls++ > 0) exit(sig); // catch sig only once - - /* we use runtime_error to indicate that sig was called; - * upon next call of mpi_gather_runtime_errors all nodes - * will clean up and exit. */ - errtxt = runtime_error(64); - ERROR_SPRINTF(errtxt, "{000 caught signal %d} ",sig); -} - -void register_sigint_handler() -{ - signal(SIGINT, sigint_handler); -} diff --git a/src/errorhandling.hpp b/src/errorhandling.hpp deleted file mode 100644 index 3e0a817ab90..00000000000 --- a/src/errorhandling.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - Copyright (C) 2010,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file errorhandling.h - This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter - combinations. See section "Errorhandling for developers" for details on the error format and - how to use this. -*/ -#ifndef ERRORHANDLING_H -#define ERRORHANDLING_H - -/** buffer for error messages during the integration process. */ -extern char *error_msg; -extern int n_error_msg; - -/* request space for leaving an error message to be passed to the master node. - Also takes care of the error counter. - @param errlen maximal length of the error message. If you use sprintf to create the error - message, remember to use ES_INTEGER/DOUBLE_SPACE as usual - @return where to put the (null-terminated) string */ -char *runtime_error(int errlen); - -#define ERROR_SPRINTF sprintf - -/** check for runtime errors on all nodes. This has to be called on all nodes synchronously. - @return the number of characters in the error messages of all nodes together. */ -int check_runtime_errors(); - -/** exit ungracefully, core dump if switched on. */ -void errexit(); - -/** register a handler for sigint that translates it into an background error. */ -void register_sigint_handler(); - -#endif diff --git a/config/featuredefs.py b/src/featuredefs.py similarity index 94% rename from config/featuredefs.py rename to src/featuredefs.py index ec5ad07b247..3c8c54059ae 100644 --- a/config/featuredefs.py +++ b/src/featuredefs.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013 The ESPResSo project +# Copyright (C) 2013,2014 The ESPResSo project # Copyright (C) 2012 Olaf Lenz # # This file is part of ESPResSo. @@ -37,11 +37,11 @@ def toCPPExpr(expr): expr = re.sub('([A-Z0-9_]+)', 'defined(\\1)', expr) return expr - - class defs: def __init__(self, filename): # complete set of all defined features + allfeatures = set() + # allfeatures minus externals and derived features = set() # list of implications (pairs of feature -> implied feature) implications = list() @@ -67,7 +67,7 @@ def __init__(self, filename): # Register the feature feature = tokens.pop(0) - features.add(feature) + allfeatures.add(feature) # get the keyword if len(tokens) > 0: @@ -94,7 +94,7 @@ def __init__(self, filename): raise SyntaxError(" external", line) if feature in derived: raise SyntaxError("External feature is already defined as derived above:", line); - implied = set(map((lambda (x,y):y), implications)) + implied = set(map((lambda x_y:x_y[1]), implications)) if feature in implied: raise SyntaxError("External feature is implied above:", line); externals.add(feature) @@ -122,8 +122,9 @@ def __init__(self, filename): raise SyntaxError(" notest", line) notestfeatures.add(feature) - features = features.difference(derived) + features = allfeatures.difference(derived) features = features.difference(externals) + self.allfeatures = allfeatures self.features = features self.requirements = requirements self.implications = implications @@ -149,7 +150,7 @@ def check_validity(self, activated): # handle requirements featurevars=dict() - derived = map((lambda(x,y,z):x), self.derivations) + derived = list(map((lambda x_y_z:x_y_z[0]), self.derivations)) allfeatures = self.features.union(derived, self.externals) for feature in allfeatures: featurevars[feature] = feature in newset diff --git a/src/features.def b/src/features.def index 863e532390a..97ebdabecb4 100644 --- a/src/features.def +++ b/src/features.def @@ -1,11 +1,16 @@ # Feature definitions # +# The definitions are used for +# * generation of src/config-features.hpp, which checks the sanity of +# the various features and their combinations +# * generation of myconfig-sample.hpp +# # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. # -# Lines commented with '/* ... */' or '//' are copied to myconfig-sample.h +# Lines commented with '/* ... */' or '//' are copied to myconfig-sample.hpp # Lines commented with '#' are ignored /* Generic features */ @@ -18,74 +23,76 @@ COMFORCE COMFIXED MOLFORCES BOND_CONSTRAINT -MODES requires FFTW +MODES requires FFTW BOND_VIRTUAL LANGEVIN_PER_PARTICLE -COLLISION_DETECTION +COLLISION_DETECTION implies GHOST_FLAG, GHOSTS_HAVE_BONDS +LEES_EDWARDS requires not ELECTROSTATICS, not LB METADYNAMICS NEMD NPT GHMC CATALYTIC_REACTIONS -GRANDCANONICAL /* Rotation */ ROTATION -ROTATIONAL_INERTIA implies ROTATION -BOND_CONSTRAINT requires not ROTATION -ROTATION_PER_PARTICLE implies ROTATION +ROTATIONAL_INERTIA implies ROTATION +BOND_CONSTRAINT requires not ROTATION +ROTATION_PER_PARTICLE implies ROTATION /* Adress */ -ADRESS implies MOL_CUT, VIRTUAL_SITES_COM, TABULATED -ADRESS requires not ROTATION and not GAY_BERNE -MOL_CUT implies VIRTUAL_SITES_COM +MOL_CUT implies VIRTUAL_SITES_COM /* Electrostatics */ ELECTROSTATICS -P3M equals ELECTROSTATICS and FFTW -INTER_RF implies ELECTROSTATICS +P3M equals ELECTROSTATICS and FFTW +INTER_RF implies ELECTROSTATICS +MMM1D_GPU requires CUDA and PARTIAL_PERIODIC and ELECTROSTATICS +EWALD_GPU requires CUDA and ELECTROSTATICS /* Magnetostatics */ DIPOLES -DP3M equals DIPOLES and FFTW +DP3M equals DIPOLES and FFTW /* Virtual sites features */ -VIRTUAL_SITES_COM requires not VIRTUAL_SITES_RELATIVE -VIRTUAL_SITES_RELATIVE requires not VIRTUAL_SITES_COM -VIRTUAL_SITES_RELATIVE implies ROTATION -VIRTUAL_SITES equals VIRTUAL_SITES_COM or VIRTUAL_SITES_RELATIVE -VIRTUAL_SITES_NO_VELOCITY require VIRTUAL_SITES_RELATIVE -VIRTUAL_SITES_THERMOSTAT require VIRTUAL_SITES_RELATIVE -THERMOSTAT_IGNORE_NON_VIRTUAL implies VIRTUAL_SITES_THERMOSTAT +VIRTUAL_SITES_COM requires not VIRTUAL_SITES_RELATIVE +VIRTUAL_SITES_RELATIVE requires not VIRTUAL_SITES_COM +VIRTUAL_SITES_RELATIVE implies ROTATION +VIRTUAL_SITES equals VIRTUAL_SITES_COM or VIRTUAL_SITES_RELATIVE +VIRTUAL_SITES_NO_VELOCITY require VIRTUAL_SITES_RELATIVE +VIRTUAL_SITES_THERMOSTAT require VIRTUAL_SITES_RELATIVE +THERMOSTAT_IGNORE_NON_VIRTUAL implies VIRTUAL_SITES_THERMOSTAT /* DPD features */ DPD -TRANS_DPD implies DPD -DPD_MASS_RED requires not DPD_MASS_LIN -DPD_MASS_LIN requires not DPD_MASS_RED -DPD_MASS equals DPD_MASS_RED or DPD_MASS_LIN -DPD_MASS implies MASS, DPD -TUNABLE_SLIP implies DPD +TRANS_DPD implies DPD +DPD_MASS_RED requires not DPD_MASS_LIN +DPD_MASS_LIN requires not DPD_MASS_RED +DPD_MASS equals DPD_MASS_RED or DPD_MASS_LIN +DPD_MASS implies MASS, DPD +TUNABLE_SLIP implies DPD /* Alternative implementation of DPD */ INTER_DPD /* Lattice-Boltzmann features */ LB -LB_GPU requires CUDA -LB_BOUNDARIES implies LB, CONSTRAINTS -LB_BOUNDARIES_GPU implies LB_GPU, CONSTRAINTS -LB_ELECTROHYDRODYNAMICS implies LB -LATTICE equals LB or LB_GPU -USE_TEMPORARY equals LB or LB_GPU -SHANCHEN implies LB_GPU -SHANCHEN requires not LB_BOUNDARIES_GPU +LB_GPU requires CUDA +LB_BOUNDARIES implies LB, CONSTRAINTS +LB_BOUNDARIES_GPU implies LB_GPU, CONSTRAINTS +LB_ELECTROHYDRODYNAMICS implies LB +ELECTROKINETICS implies LB_GPU, EXTERNAL_FORCES, ELECTROSTATICS +EK_BOUNDARIES implies ELECTROKINETICS, LB_GPU, LB_BOUNDARIES_GPU, CONSTRAINTS, EXTERNAL_FORCES, ELECTROSTATICS +EK_REACTION implies ELECTROKINETICS, LB_GPU, EXTERNAL_FORCES, ELECTROSTATICS +LATTICE equals LB or LB_GPU +SHANCHEN implies LB_GPU +SHANCHEN requires not ELECTROKINETICS /* Interaction features */ TABULATED LENNARD_JONES LJ_WARN_WHEN_CLOSE -LENNARD_JONES_GENERIC +LENNARD_JONES_GENERIC implies LENNARD_JONES LJCOS LJCOS2 LJ_ANGLE @@ -99,38 +106,43 @@ MORSE BUCKINGHAM SOFT_SPHERE HAT -GAY_BERNE implies ROTATION +GAY_BERNE implies ROTATION OVERLAPPED /* Fluid-Structure Interactions (object in fluid) */ AREA_FORCE_GLOBAL VOLUME_FORCE -BOND_ANGLE requires not BOND_ANGLE_OLD +BOND_ANGLE requires not BOND_ANGLE_OLD BOND_ANGLEDIST -BOND_ANGLEDIST_HARMONIC implies BOND_ANGLEDIST, CONSTRAINTS +BOND_ANGLEDIST_HARMONIC implies BOND_ANGLEDIST, CONSTRAINTS BOND_ENDANGLEDIST -BOND_ENDANGLEDIST_HARMONIC implies BOND_ENDANGLEDIST, CONSTRAINTS +BOND_ENDANGLEDIST_HARMONIC implies BOND_ENDANGLEDIST, CONSTRAINTS /* Obsolete features. To be removed. */ /* Old Bond angle */ /* Note: Activate ONLY ONE bonded angle potential out of the following! */ -BOND_ANGLE_HARMONIC requires not BOND_ANGLE_COSINE and not BOND_ANGLE_COSSQUARE -BOND_ANGLE_COSINE requires not BOND_ANGLE_HARMONIC and not BOND_ANGLE_COSSQUARE -BOND_ANGLE_COSSQUARE requires not BOND_ANGLE_HARMONIC and not BOND_ANGLE_COSINE -BOND_ANGLE_OLD equals BOND_ANGLE_HARMONIC or BOND_ANGLE_COSINE or BOND_ANGLE_COSSQUARE -BOND_ANGLE_HARMONIC notest -BOND_ANGLE_COSINE notest -BOND_ANGLE_COSSQUARE notest -BOND_ANGLE_OLD notest +BOND_ANGLE_HARMONIC requires not BOND_ANGLE_COSINE and not BOND_ANGLE_COSSQUARE +BOND_ANGLE_COSINE requires not BOND_ANGLE_HARMONIC and not BOND_ANGLE_COSSQUARE +BOND_ANGLE_COSSQUARE requires not BOND_ANGLE_HARMONIC and not BOND_ANGLE_COSINE +BOND_ANGLE_OLD equals BOND_ANGLE_HARMONIC or BOND_ANGLE_COSINE or BOND_ANGLE_COSSQUARE +BOND_ANGLE_HARMONIC notest +BOND_ANGLE_COSINE notest +BOND_ANGLE_COSSQUARE notest +BOND_ANGLE_OLD notest /* Strange features. Use only if you know what you are doing! */ /* activate the old dihedral form */ -OLD_DIHEDRAL notest +OLD_DIHEDRAL notest /* turn off nonbonded interactions within molecules */ -NO_INTRA_NB notest +NO_INTRA_NB notest +/* add an int to the particle marking ghosts. Only visible on C level */ +GHOST_FLAG notest +/* ghost particles also have the bond information. */ +GHOSTS_HAVE_BONDS notest + /* Debugging */ ADDITIONAL_CHECKS @@ -151,6 +163,7 @@ FFT_DEBUG RANDOM_DEBUG FORCE_DEBUG THERMO_DEBUG +LE_DEBUG LJ_DEBUG MORSE_DEBUG ESR_DEBUG @@ -176,6 +189,6 @@ ONEPART_DEBUG # External switches # Switches that are set by configure or gcc, not to be set manually -CUDA external -FFTW external -TK external +CUDA external +FFTW external +TK external diff --git a/src/forces.cpp b/src/forces.cpp deleted file mode 100644 index fa8c35a5db7..00000000000 --- a/src/forces.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file forces.c Force calculation. - * - * For more information see \ref forces.h "forces.h". -*/ -#include -#include -#include -#include -#include -#include "utils.hpp" -#include "thermostat.hpp" -#include "pressure.hpp" -#include "communication.hpp" -#include "ghosts.hpp" -#include "verlet.hpp" -#include "grid.hpp" -#include "cells.hpp" -#include "particle_data.hpp" -#include "interaction_data.hpp" -#include "rotation.hpp" -#include "forces.hpp" -#include "elc.hpp" -#include "lattice.hpp" -#include "lb.hpp" -#include "nsquare.hpp" -#include "layered.hpp" -#include "domain_decomposition.hpp" -#include "magnetic_non_p3m_methods.hpp" -#include "mdlc_correction.hpp" -#include "virtual_sites.hpp" -#include "constraint.hpp" -#include "lbgpu.hpp" -#include "iccp3m.hpp" -#include "p3m_gpu.hpp" -#include "cuda_interface.hpp" - -/************************************************************/ -/* local prototypes */ -/************************************************************/ - -/** Calculate long range forces (P3M, MMM2d...). */ -void calc_long_range_forces(); - -/** initialize real particle forces with thermostat forces and - ghost particle forces with zero. */ -void init_forces(); - -/************************************************************/ - -void force_calc() -{ - -#if defined(LB_GPU) || (defined(ELECTROSTATICS) && defined(CUDA)) - - copy_part_data_to_gpu(); - -#endif - -#ifdef LB_GPU -#ifdef SHANCHEN - if (lattice_switch & LATTICE_LB_GPU && this_node == 0) lattice_boltzmann_calc_shanchen_gpu(); -#endif // SHANCHEN - - // transfer_momentum_gpu check makes sure the LB fluid doesn't get updated on integrate 0 - // this_node==0 makes sure it is the master node where the gpu exists - if (lattice_switch & LATTICE_LB_GPU && transfer_momentum_gpu && this_node==0 ) lb_calc_particle_lattice_ia_gpu(); -#endif // LB_GPU - -#ifdef ELECTROSTATICS - if (iccp3m_initialized && iccp3m_cfg.set_flag) - iccp3m_iteration(); - else -#endif - init_forces(); - - switch (cell_structure.type) { - case CELL_STRUCTURE_LAYERED: - layered_calculate_ia(); - break; - case CELL_STRUCTURE_DOMDEC: - if(dd.use_vList) { - if (rebuild_verletlist) - build_verlet_lists_and_calc_verlet_ia(); - else - calculate_verlet_ia(); - } - else - calc_link_cell(); - break; - case CELL_STRUCTURE_NSQUARE: - nsq_calculate_ia(); - - } - -#ifdef VOLUME_FORCE - double volume=0.; - - for (int i=0;i< MAX_OBJECTS_IN_FLUID;i++){ - calc_volume(&volume,i); - if (volume<1e-100) break; - add_volume_force(volume,i); - } -#endif - -#ifdef AREA_FORCE_GLOBAL - double area=0.; - - for (int i=0;i< MAX_OBJECTS_IN_FLUID;i++){ - calc_area_global(&area,i); - if (area<1e-100) break; - add_area_global_force(area,i); - } -#endif - - calc_long_range_forces(); - -#ifdef LB - if (lattice_switch & LATTICE_LB) calc_particle_lattice_ia() ; -#endif - -#ifdef COMFORCE - calc_comforce(); -#endif - -#ifdef METADYNAMICS - /* Metadynamics main function */ - meta_perform(); -#endif - -#if defined(LB_GPU) || (defined(ELECTROSTATICS) && defined(CUDA)) - copy_forces_from_GPU(); -#endif - -/* this must be the last force to be calculated (Mehmet)*/ -#ifdef COMFIXED - calc_comfixed(); -#endif - -} - -/************************************************************/ - -void calc_long_range_forces() -{ -#ifdef ELECTROSTATICS - /* calculate k-space part of electrostatic interaction. */ - if (!(iccp3m_initialized && iccp3m_cfg.set_flag)) { - switch (coulomb.method) { - #ifdef P3M - case COULOMB_ELC_P3M: - if (elc_params.dielectric_contrast_on) { - ELC_P3M_modify_p3m_sums_both(); - ELC_p3m_charge_assign_both(); - ELC_P3M_self_forces(); - } - else - p3m_charge_assign(); - - p3m_calc_kspace_forces(1,0); - - if (elc_params.dielectric_contrast_on) - ELC_P3M_restore_p3m_sums(); - - ELC_add_force(); - - break; -#ifdef CUDA - case COULOMB_P3M_GPU: - if (this_node == 0) p3m_gpu_add_farfield_force(); - #ifdef NPT - printf("NPT can not be used in conjunction with the GPU P3M\n"); //TODO fix this? - exit(1); //TODO ALTERNATIVELY CHECK IF BAROSTAT IS ACTUALLY ON - #endif - break; -#endif - case COULOMB_P3M: - p3m_charge_assign(); - #ifdef NPT - if(integ_switch == INTEG_METHOD_NPT_ISO) - nptiso.p_vir[0] += p3m_calc_kspace_forces(1,1); - else - #endif - p3m_calc_kspace_forces(1,0); - break; - #endif - case COULOMB_MAGGS: - maggs_calc_forces(); - break; - case COULOMB_MMM2D: - MMM2D_add_far_force(); - MMM2D_dielectric_layers_force_contribution(); - } - } -#endif /*ifdef ELECTROSTATICS */ - -#ifdef DIPOLES - /* calculate k-space part of the magnetostatic interaction. */ - switch (coulomb.Dmethod) { -#ifdef DP3M - case DIPOLAR_MDLC_P3M: - add_mdlc_force_corrections(); - //fall through - case DIPOLAR_P3M: - dp3m_dipole_assign(); -#ifdef NPT - if(integ_switch == INTEG_METHOD_NPT_ISO) { - nptiso.p_vir[0] += dp3m_calc_kspace_forces(1,1); - fprintf(stderr,"dipolar_P3M at this moment is added to p_vir[0]\n"); - } else -#endif - dp3m_calc_kspace_forces(1,0); - - break; -#endif - case DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA: - dawaanr_calculations(1,0); - break; - case DIPOLAR_MDLC_DS: - add_mdlc_force_corrections(); - //fall through - case DIPOLAR_DS: - magnetic_dipolar_direct_sum_calculations(1,0); - break; - } -#endif /*ifdef DIPOLES */ -} - -/************************************************************/ - -/** initialize the forces for a real particle */ -inline void init_local_particle_force(Particle *part) -{ -#ifdef ADRESS - double new_weight; - if (ifParticleIsVirtual(part)) { - new_weight = adress_wf_vector(part->r.p); -#ifdef ADRESS_INIT - double old_weight = part->p.adress_weight; - - if(new_weight>0 && old_weight==0){ - double rand_cm_pos[3], rand_cm_vel[3], rand_weight, new_pos, old_pos; - int it, dim, this_mol_id=part->p.mol_id, rand_mol_id, rand_type; - int n_ats_this_mol=topology[this_mol_id].part.n, n_ats_rand_mol; - - //look for a random explicit particle - rand_type=-1; - rand_weight=-1; - rand_mol_id=-1; - n_ats_rand_mol=-1; - - while(rand_type != part->p.type || rand_weight != 1 || n_ats_rand_mol != n_ats_this_mol){ - rand_mol_id = i_random(n_molecules); - rand_type = local_particles[(topology[rand_mol_id].part.e[0])]->p.type; - rand_weight = local_particles[(topology[rand_mol_id].part.e[0])]->p.adress_weight; - n_ats_rand_mol = topology[rand_mol_id].part.n; - - if(!ifParticleIsVirtual(local_particles[(topology[rand_mol_id].part.e[0])])) - fprintf(stderr,"No virtual site found on molecule %d, with %d total molecules.\n",rand_mol_id, n_molecules); - } - - //store CM position and velocity - for(dim=0;dim<3;dim++){ - rand_cm_pos[dim]=local_particles[(topology[rand_mol_id].part.e[0])]->r.p[dim]; - rand_cm_vel[dim]=local_particles[(topology[rand_mol_id].part.e[0])]->m.v[dim]; - } - - //assign new positions and velocities to the atoms - for(it=0;itr.p[dim]; - new_pos = local_particles[topology[rand_mol_id].part.e[it]]->r.p[dim]-rand_cm_pos[dim]+part->r.p[dim]; - //MAKE SURE THEY ARE IN THE SAME BOX - while(new_pos-old_pos>box_l[dim]*0.5) - new_pos=new_pos-box_l[dim]; - while(new_pos-old_pos<-box_l[dim]*0.5) - new_pos=new_pos+box_l[dim]; - - local_particles[(topology[this_mol_id].part.e[it])]->r.p[dim] = new_pos; - local_particles[(topology[this_mol_id].part.e[it])]->m.v[dim] = local_particles[(topology[rand_mol_id].part.e[it])]->m.v[dim]-rand_cm_vel[dim]+part->m.v[dim]; - } - } - } - } -#endif - part->p.adress_weight=new_weight; - } -#endif - if ( thermo_switch & THERMO_LANGEVIN ) - friction_thermo_langevin(part); - else { - part->f.f[0] = 0; - part->f.f[1] = 0; - part->f.f[2] = 0; - } - -#ifdef EXTERNAL_FORCES - if(part->l.ext_flag & PARTICLE_EXT_FORCE) { - part->f.f[0] += part->l.ext_force[0]; - part->f.f[1] += part->l.ext_force[1]; - part->f.f[2] += part->l.ext_force[2]; - } -#endif - -#ifdef ROTATION - { - double scale; - /* set torque to zero */ - part->f.torque[0] = 0; - part->f.torque[1] = 0; - part->f.torque[2] = 0; - - #ifdef EXTERNAL_FORCES - if(part->l.ext_flag & PARTICLE_EXT_TORQUE) { - part->f.torque[0] += part->l.ext_torque[0]; - part->f.torque[1] += part->l.ext_torque[1]; - part->f.torque[2] += part->l.ext_torque[2]; - } - #endif - - /* and rescale quaternion, so it is exactly of unit length */ - scale = sqrt( SQR(part->r.quat[0]) + SQR(part->r.quat[1]) + - SQR(part->r.quat[2]) + SQR(part->r.quat[3])); - part->r.quat[0]/= scale; - part->r.quat[1]/= scale; - part->r.quat[2]/= scale; - part->r.quat[3]/= scale; - } -#endif - -#ifdef ADRESS - /* #ifdef THERMODYNAMIC_FORCE */ - if(ifParticleIsVirtual(part)) - if(part->p.adress_weight > 0 && part->p.adress_weight < 1) - add_thermodynamic_force(part); - /* #endif */ -#endif -} - -/** initialize the forces for a ghost particle */ -inline void init_ghost_force(Particle *part) -{ -#ifdef ADRESS - if (ifParticleIsVirtual(part)) { - part->p.adress_weight=adress_wf_vector(part->r.p); - } -#endif - - part->f.f[0] = 0; - part->f.f[1] = 0; - part->f.f[2] = 0; - -#ifdef ROTATION - { - double scale; - /* set torque to zero */ - part->f.torque[0] = 0; - part->f.torque[1] = 0; - part->f.torque[2] = 0; - - /* and rescale quaternion, so it is exactly of unit length */ - scale = sqrt( SQR(part->r.quat[0]) + SQR(part->r.quat[1]) + - SQR(part->r.quat[2]) + SQR(part->r.quat[3])); - part->r.quat[0]/= scale; - part->r.quat[1]/= scale; - part->r.quat[2]/= scale; - part->r.quat[3]/= scale; - } -#endif -} - -void init_forces() -{ - Cell *cell; - Particle *p; - int np, c, i; - - /* The force initialization depends on the used thermostat and the - thermodynamic ensemble */ - -#ifdef NPT - /* reset virial part of instantaneous pressure */ - if(integ_switch == INTEG_METHOD_NPT_ISO) - nptiso.p_vir[0] = nptiso.p_vir[1] = nptiso.p_vir[2] = 0.0; -#endif - - - /* initialize forces with langevin thermostat forces - or zero depending on the thermostat - set torque to zero for all and rescale quaternions - */ - for (c = 0; c < local_cells.n; c++) { - cell = local_cells.cell[c]; - p = cell->part; - np = cell->n; - for (i = 0; i < np; i++) - init_local_particle_force(&p[i]); - } - -#ifdef ADRESS -#ifdef ADRESS_INIT - /* update positions of atoms reinitialized when crossing from CG to hybrid zone - done previously in init_local_particle_force */ - ghost_communicator(&cell_structure.update_ghost_pos_comm); -#endif -#endif - - /* initialize ghost forces with zero - set torque to zero for all and rescale quaternions - */ - for (c = 0; c < ghost_cells.n; c++) { - cell = ghost_cells.cell[c]; - p = cell->part; - np = cell->n; - for (i = 0; i < np; i++) - init_ghost_force(&p[i]); - } - -#ifdef CONSTRAINTS - init_constraint_forces(); -#endif -} - - -// This function is no longer called from force_calc(). -// The check was moved to rescale_fores() to avoid an additional iteration over all particles -void check_forces() -{ - Cell *cell; - Particle *p; - int np, c, i; - - for (c = 0; c < local_cells.n; c++) { - cell = local_cells.cell[c]; - p = cell->part; - np = cell->n; - for (i = 0; i < np; i++) { - check_particle_force(&p[i]); - } - } - - for (c = 0; c < ghost_cells.n; c++) { - cell = ghost_cells.cell[c]; - p = cell->part; - np = cell->n; - for (i = 0; i < np; i++) - check_particle_force(&p[i]); - } -} - -void init_forces_ghosts() -{ - Cell *cell; - Particle *p; - int np, c, i; - - for (c = 0; c < ghost_cells.n; c++) { - cell = ghost_cells.cell[c]; - p = cell->part; - np = cell->n; - for (i = 0; i < np; i++) - init_ghost_force(&p[i]); - } -} - - diff --git a/src/lattice.cpp b/src/lattice.cpp deleted file mode 100644 index 618956d5f94..00000000000 --- a/src/lattice.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file lattice.c - * - * Lattice data structures - * - */ - -#include "utils.hpp" -#include "grid.hpp" -#include "lattice.hpp" - -/** Switch determining the type of lattice dynamics. A value of zero - * means that there is no lattice dynamics. Different types can be - * combined by or'ing the respective flags. - * So far, only \ref LATTICE_OFF and \ref LATTICE_LB exist. - */ -int lattice_switch = LATTICE_OFF ; - -#ifdef LATTICE - -/** Initialize lattice. - * - * This function initializes the variables describing the lattice - * layout. Important: The lattice data is not allocated here! - * - * \param lattice pointer to the lattice - * \param agrid lattice spacing - * \param tau time step for lattice dynamics - */ -void init_lattice(Lattice *lattice, double agrid, double tau) { - - int dir; - - /* determine the number of local lattice nodes */ - lattice->grid[0] = local_box_l[0]/agrid; - lattice->grid[1] = local_box_l[1]/agrid; - lattice->grid[2] = local_box_l[2]/agrid; - - /* sanity checks */ - for (dir=0;dir<3;dir++) { - /* check if local_box_l is compatible with lattice spacing */ - if (fabs(local_box_l[dir]-lattice->grid[dir]*agrid) > ROUND_ERROR_PREC*box_l[dir]) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{097 Lattice spacing agrid=%f is incompatible with local_box_l[%d]=%f (box_l[%d]=%f node_grid[%d]=%d) %f} ",agrid,dir,local_box_l[dir],dir,box_l[dir],dir,node_grid[dir],local_box_l[dir]-lattice->grid[dir]*agrid); - return; - } - } - - /* set the lattice spacing */ - lattice->agrid = agrid ; - lattice->tau = tau ; - - LATTICE_TRACE(fprintf(stderr,"%d: box_l (%.3f,%.3f,%.3f) grid (%d,%d,%d) node_neighbors (%d,%d,%d,%d,%d,%d)\n",this_node,local_box_l[0],local_box_l[1],local_box_l[2],lattice->grid[0],lattice->grid[1],lattice->grid[2],node_neighbors[0],node_neighbors[1],node_neighbors[2],node_neighbors[3],node_neighbors[4],node_neighbors[5])); - - /* determine the number of total nodes including halo */ - lattice->halo_grid[0] = lattice->grid[0] + 2 ; - lattice->halo_grid[1] = lattice->grid[1] + 2 ; - lattice->halo_grid[2] = lattice->grid[2] + 2 ; - - lattice->grid_volume = lattice->grid[0]*lattice->grid[1]*lattice->grid[2] ; - lattice->halo_grid_volume = lattice->halo_grid[0]*lattice->halo_grid[1]*lattice->halo_grid[2] ; - lattice->halo_grid_surface = lattice->halo_grid_volume - lattice->grid_volume ; - lattice->halo_offset = get_linear_index(1,1,1,lattice->halo_grid) ; - -} - -#endif /* LATTICE */ diff --git a/src/lattice.hpp b/src/lattice.hpp deleted file mode 100644 index c3b5f33ac1a..00000000000 --- a/src/lattice.hpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file lattice.h - * - * Lattice data structures - * - */ -/** Lattice Boltzmann */ -#define LATTICE_LB 1 - -/** Lattice Boltzmann */ -#define LATTICE_LB_GPU 2 - -#ifndef LATTICE_H -#define LATTICE_H - -#include -#include "utils.hpp" -#include "grid.hpp" -#include "particle_data.hpp" - -extern int lattice_switch; - -#define index_t long - -/** Lattice off */ -#define LATTICE_OFF 0 - -#ifdef LATTICE - - -/** Switch determining the type of lattice dynamics. A value of zero - * means that there is no lattice dynamics. Different types can be - * combined by or'ing the respective flags. - * So far, only \ref LATTICE_OFF and \ref LATTICE_LB exist. - */ - -/** Data structure describing a lattice. - * Contains the lattice layout and pointers to the data fields. - * For parallelization purposes, it is assumed that a halo region - * surrounds the local lattice sites. - */ -typedef struct _Lattice { - - /** number of local lattice sites in each direction (excluding halo) */ - int grid[3] ; - /** number of lattice sites in each direction including halo */ - int halo_grid[3] ; - - /** total number (volume) of local lattice sites (excluding halo) */ - index_t grid_volume; - /** total number (volume) of lattice sites (including halo) */ - index_t halo_grid_volume; - /** number of lattice sites in the halo region */ - index_t halo_grid_surface; - /** offset for number of halo sites stored in front of the local - lattice sites */ - index_t halo_offset; - - /** lattice constant */ - double agrid ; - /** time step of lattice dynamics */ - double tau ; - - /** pointer to the fields living on the lattice. - * For complex lattice data, this can be a struct holding - * pointers to the actual data. */ - void *fields; - /** pointer to the actual lattice data. - * This can be a contiguous field of arbitrary data. */ - void *data; - - /** particle representation of this lattice. This is needed to - * specify interactions between particles and the lattice. - * Actually used are only the identity and the type. */ - Particle part_rep; - - /** datatypes that describe the data layout of the lattice. */ - MPI_Datatype datatype; - struct _Fieldtype *fieldtype; - -} Lattice; - -/** Initialize lattice. - * - * This function initializes the variables describing the lattice - * layout. Important: The lattice data is not allocated here! - * - * \param lattice pointer to the lattice - * \param agrid lattice spacing - * \param tau time step for lattice dynamics - */ -void init_lattice(Lattice *lattice, double agrid, double tau); - -/** Map a global lattice site to the node grid. - * - * This function determines the processor responsible for - * the specified lattice site. The coordinates of the site are - * taken as global coordinates and are returned as local coordinates. - * - * \param lattice pointer to the lattice - * \param ind global coordinates of the lattice site (Input) - * \param grid local coordinates of the lattice site (Output) - * \return index of the node for the lattice site - */ -inline int map_lattice_to_node(Lattice *lattice, int *ind, int *grid) { - - /* determine coordinates in node_grid */ - grid[0] = (int)floor(ind[0]*lattice->agrid*box_l_i[0]*node_grid[0]); - grid[1] = (int)floor(ind[1]*lattice->agrid*box_l_i[1]*node_grid[1]); - grid[2] = (int)floor(ind[2]*lattice->agrid*box_l_i[2]*node_grid[2]); - - //fprintf(stderr,"%d: (%d,%d,%d)\n",this_node,grid[0],grid[1],grid[2]); - - /* change from global to local lattice coordinates (+1 is for halo) */ - ind[0] = ind[0] - grid[0]*lattice->grid[0] + 1; - ind[1] = ind[1] - grid[1]*lattice->grid[1] + 1; - ind[2] = ind[2] - grid[2]*lattice->grid[2] + 1; - - /* return linear index into node array */ - return map_array_node(grid); -} - -/** Map a local lattice site to the global position. - * - * This function determines the processor responsible for - * the specified lattice site. The coordinates of the site are - * taken as global coordinates andcoordinates of the site are - * taken as global coordinates and are returned as local coordinates. - * - * \param lattice pointer to the lattice - * \param ind global coordinates of the lattice site (Input) - * \param grid local coordinates of the lattice site (Output) - * \return index of the node for the lattice site - */ -inline int map_lattice_to_position(Lattice *lattice, int *ind, int *grid) { - return 0; -} - -/** Map a spatial position to the surrounding lattice sites. - * - * This function takes a global spatial position and determines the - * surrounding elementary cell of the lattice for this position. - * The distance fraction in each direction is also calculated. - *
    Remarks: - *
      - *
    • The spatial position has to be in the local domain.
    • - *
    • The lattice sites of the elementary cell are returned as local indices
    • - *
    - * \param lattice pointer to the lattice (Input) - * \param pos spatial position (Input) - * \param node_index local indices of the surrounding lattice sites (Output) - * \param delta distance fraction of pos from the surrounding - * elementary cell, 6 directions (Output) - */ -inline void map_position_to_lattice(Lattice *lattice, const double pos[3], index_t node_index[8], double delta[6]) { - - int dir,ind[3] ; - double lpos, rel; - - /* determine the elementary lattice cell containing the particle - and the relative position of the particle in this cell */ - for (dir=0;dir<3;dir++) { - - rel = (lpos = pos[dir] - my_left[dir])/lattice->agrid + 0.5; // +1 for halo offset - ind[dir] = (int)floor(rel); - - /* surrounding elementary cell is not completely inside this box, - adjust if this is due to round off errors */ - if (ind[dir] < 0) { - if (abs(rel) < ROUND_ERROR_PREC) { - ind[dir] = 0; // TODO - } else { - fprintf(stderr,"%d: map_position_to_lattice: position (%f,%f,%f) not inside a local plaquette in dir %d ind[dir]=%d rel=%f lpos=%f.\n",this_node,pos[0],pos[1],pos[2],dir,ind[dir],rel,lpos); - } - } - else if (ind[dir] > lattice->grid[dir]) { - if (lpos - local_box_l[dir] < ROUND_ERROR_PREC*local_box_l[dir]) - ind[dir] = lattice->grid[dir]; - else - fprintf(stderr,"%d: map_position_to_lattice: position (%f,%f,%f) not inside a local plaquette in dir %d ind[dir]=%d rel=%f lpos=%f.\n",this_node,pos[0],pos[1],pos[2],dir,ind[dir],rel,lpos); - } - - delta[3+dir] = rel - ind[dir]; // delta_x/a - delta[dir] = 1.0 - delta[3+dir]; - - } - - node_index[0] = get_linear_index(ind[0],ind[1],ind[2],lattice->halo_grid); - node_index[1] = node_index[0] + 1; - node_index[2] = node_index[0] + lattice->halo_grid[0]; - node_index[3] = node_index[0] + lattice->halo_grid[0] + 1; - node_index[4] = node_index[0] + lattice->halo_grid[0]*lattice->halo_grid[1]; - node_index[5] = node_index[4] + 1; - node_index[6] = node_index[4] + lattice->halo_grid[0]; - node_index[7] = node_index[4] + lattice->halo_grid[0] + 1; - -} - -/** Map a spatial position to the surrounding lattice sites. - * - * This function takes a global spatial position and determines the - * surrounding elementary cell of the lattice for this position. - * The distance fraction in each direction is also calculated. - *
    Remarks: - *
      - *
    • The spatial position is given in global coordinates.
    • - *
    • The lattice sites of the elementary cell are returned as local indices
    • - *
    - * \param pos spatial position (Input) - * \param ind global index of the lower left lattice site (Output) - * \param delta distance fraction of pos from the surrounding - * elementary cell, 6 directions (Output) - * \param tmp_agrid lattice mesh distance - */ - -inline void map_position_to_lattice_global (double pos[3], int ind[3], double delta[6], double tmp_agrid) { -//not sure why I don't have access to agrid here so I make a temp var and pass it to this function - int i; - double rel[3]; - // fold the position onto the local box, note here ind is used as a dummy variable - for (i=0;i<3;i++) { - pos[i] = pos[i]-0.5*tmp_agrid; - } - - fold_position (pos,ind); - - // convert the position into lower left grid point - for (i=0;i<3;i++) { - rel[i] = (pos[i])/tmp_agrid; - } - - // calculate the index of the position - for (i=0;i<3;i++) { - ind[i] = floor(rel[i]); - } - - // calculate the linear interpolation weighting - for (i=0;i<3;i++) { - delta[3+i] = rel[i] - ind[i]; - delta[i] = 1 - delta[3+i]; - } - -} - -#endif /* LATTICE */ - -#endif /* LATTICE_H */ diff --git a/src/lb.cpp b/src/lb.cpp deleted file mode 100644 index 7578e49a4da..00000000000 --- a/src/lb.cpp +++ /dev/null @@ -1,3500 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file lb.c - * - * Lattice Boltzmann algorithm for hydrodynamic degrees of freedom. - * - * Includes fluctuating LB and coupling to MD particles via frictional - * momentum transfer. - * - */ - -#include -#include -#include "utils.hpp" -#include "communication.hpp" -#include "grid.hpp" -#include "domain_decomposition.hpp" -#include "interaction_data.hpp" -#include "thermostat.hpp" -#include "lattice.hpp" -#include "halo.hpp" -#include "lb-d3q19.hpp" -#include "lb-boundaries.hpp" -#include "lb.hpp" - -int lb_components = LB_COMPONENTS; // global variable holding the number of fluid components (see global.c) - -#ifdef LB - - -#ifdef ADDITIONAL_CHECKS -static void lb_check_halo_regions(); -#endif - -/** Flag indicating momentum exchange between particles and fluid */ -int transfer_momentum = 0; - -/** Struct holding the Lattice Boltzmann parameters */ -// LB_Parameters lbpar = { .rho={0.0}, .viscosity={0.0}, .bulk_viscosity={-1.0}, .agrid=-1.0, .tau=-1.0, .friction={0.0}, .ext_force={ 0.0, 0.0, 0.0},.rho_lb_units={0.},.gamma_odd={0.}, .gamma_even={0.} }; -LB_Parameters lbpar = { - // rho - {0.0}, - // viscosity - {0.0}, - // bulk_viscosity - {-1.0}, - // agrid - -1.0, - // tau - -1.0, - // friction - {0.0}, - // ext_force - { 0.0, 0.0, 0.0}, - // rho_lb_units - {0.}, - // gamma_odd - {0.}, - // gamma_even - {0.}, - // resend_halo - 0 -}; - -/** The DnQm model to be used. */ -LB_Model lbmodel = { 19, d3q19_lattice, d3q19_coefficients, d3q19_w, NULL, 1./3. }; -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * ! MAKE SURE THAT D3Q19 is #undefined WHEN USING OTHER MODELS ! - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* doesn't work yet */ -#ifndef D3Q19 -#error The implementation only works for D3Q19 so far! -#endif -#ifndef GAUSSRANDOM -#define GAUSSRANDOM -#endif -/** The underlying lattice structure */ -Lattice lblattice = { {0,0,0}, {0,0,0}, 0, 0, 0, 0, -1.0, -1.0, NULL, NULL }; - -/** Pointer to the velocity populations of the fluid nodes */ -double **lbfluid[2] = { NULL, NULL }; - -/** Pointer to the hydrodynamic fields of the fluid nodes */ -LB_FluidNode *lbfields = NULL; - -/** Communicator for halo exchange between processors */ -HaloCommunicator update_halo_comm = { 0, NULL }; - -/** \name Derived parameters */ -/*@{*/ -/** Flag indicating whether fluctuations are present. */ -static int fluct; - -/** relaxation rate of shear modes */ -double gamma_shear = 0.0; -/** relaxation rate of bulk modes */ -double gamma_bulk = 0.0; -/** relaxation of the odd kinetic modes */ -static double gamma_odd = 0.0; -/** relaxation of the even kinetic modes */ -static double gamma_even = 0.0; -/** amplitudes of the fluctuations of the modes */ -static double lb_phi[19]; -/** amplitude of the fluctuations in the viscous coupling */ -static double lb_coupl_pref = 0.0; -/** amplitude of the fluctuations in the viscous coupling with gaussian random numbers */ -static double lb_coupl_pref2 = 0.0; -/*@}*/ - -/** The number of velocities of the LB model. - * This variable is used for convenience instead of having to type lbmodel.n_veloc everywhere. */ -/* TODO: Remove convenience variables */ -static int n_veloc; - -/** Lattice spacing. - * This variable is used for convenience instead of having to type lbpar.agrid everywhere. */ -static double agrid; - -/** Lattice Boltzmann time step - * This variable is used for convenience instead of having to type lbpar.tau everywhere. */ -static double tau; - -/** measures the MD time since the last fluid update */ -static double fluidstep=0.0; - -#ifdef ADDITIONAL_CHECKS -/** counts the random numbers drawn for fluctuating LB and the coupling */ -static int rancounter=0; -/** counts the occurences of negative populations due to fluctuations */ -static int failcounter=0; -#endif - -/***********************************************************************/ -#endif - -#if defined (LB) || defined (LB_GPU) - -/* *********************** C Interface part *************************************/ -/* ******************************************************************************/ - -#ifdef SHANCHEN - -int lb_lbfluid_set_shanchen_coupling(double *p_coupling) { -#ifdef LB_GPU - int ii,jj,n=0; - switch(LB_COMPONENTS){ - case 1: - lbpar_gpu.coupling[0] = (float)p_coupling[0]; - lbpar_gpu.coupling[1] = (float)p_coupling[1]; - break; - default: - for(ii=0;ii 1 ) { - return -1; - } - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - lbpar_gpu.gamma_odd[ii] = (float)p_gamma_odd[ii]; - on_lb_params_change_gpu(0); -#endif - } else { -#ifdef LB - lbpar.gamma_odd[ii] = gamma_odd = p_gamma_odd[ii]; - mpi_bcast_lb_params(0); -#endif - } - } - return 0; -} - -int lb_lbfluid_set_gamma_even(double *p_gamma_even){// - - for(int ii=0;ii 1 ) { - return -1; - } - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - lbpar_gpu.gamma_even[ii] = (float)p_gamma_even[ii]; - on_lb_params_change_gpu(0); -#endif - } else { -#ifdef LB - lbpar.gamma_even[ii] = gamma_even = p_gamma_even[ii]; - mpi_bcast_lb_params(0); -#endif - } - } - return 0; -} -int lb_lbfluid_set_friction(double * p_friction){// - - - for(int ii=0;ii ROUND_ERROR_PREC) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{097 Lattice spacing p_agrid=%f is incompatible with box_l[%i]=%f, factor=%d err= %g} ",p_agrid,dir,box_l[dir],tmp[dir],fabs(box_l[dir]-tmp[dir]*p_agrid)); - } - } - lbpar_gpu.number_of_nodes = lbpar_gpu.dim_x * lbpar_gpu.dim_y * lbpar_gpu.dim_z; - on_lb_params_change_gpu(LBPAR_AGRID); -#endif - } else { -#ifdef LB - lbpar.agrid = agrid = p_agrid; - mpi_bcast_lb_params(LBPAR_AGRID); -#endif - } - return 0; -} - - - -int lb_lbfluid_set_tau(double p_tau){ - if ( p_tau <= 0 ) { - return -1; - } - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - lbpar_gpu.tau = (float)p_tau; - on_lb_params_change_gpu(0); -#endif - } else { -#ifdef LB - lbpar.tau = p_tau; - mpi_bcast_lb_params(0); -#endif - } - return 0; -} - - -int lb_lbfluid_set_ext_force(double p_fx, double p_fy, double p_fz) { - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - /* external force density is stored in MD units */ - lbpar_gpu.ext_force[0] = (float)p_fx; - lbpar_gpu.ext_force[1] = (float)p_fy; - lbpar_gpu.ext_force[2] = (float)p_fz; - lbpar_gpu.external_force = 1; - lb_reinit_extern_nodeforce_GPU(&lbpar_gpu); -#endif - } else { -#ifdef LB - lbpar.ext_force[0] = p_fx; - lbpar.ext_force[1] = p_fy; - lbpar.ext_force[2] = p_fz; - mpi_bcast_lb_params(LBPAR_EXTFORCE); -#endif - } - return 0; -} - -int lb_lbfluid_get_density(double* p_dens){ -// TODO: implement all lb_lbfluid_get_*() correctly for all components!! - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_dens = lbpar_gpu.rho[0]; -#endif - } else { -#ifdef LB - *p_dens = lbpar.rho[0]; -#endif - } - return 0; -} -int lb_lbfluid_get_visc(double* p_visc){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_visc = lbpar_gpu.viscosity[0]; -#endif - } else { -#ifdef LB - *p_visc = lbpar.viscosity[0]; -#endif - } - return 0; -} - -int lb_lbfluid_get_bulk_visc(double* p_bulk_visc){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_bulk_visc = lbpar_gpu.bulk_viscosity[0]; -#endif - } else { -#ifdef LB - *p_bulk_visc = lbpar.bulk_viscosity[0]; -#endif - } - return 0; -} - -int lb_lbfluid_get_gamma_odd(double* p_gamma_odd){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_gamma_odd = lbpar_gpu.gamma_odd[0]; -#endif - } else { -#ifdef LB - *p_gamma_odd = lbpar.gamma_odd[0]; -#endif - } -return 0; -} - -int lb_lbfluid_get_gamma_even(double* p_gamma_even){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_gamma_even = lbpar_gpu.gamma_even[0]; -#endif - } else { -#ifdef LB - *p_gamma_even = lbpar.gamma_even[0]; -#endif - } - return 0; -} - -int lb_lbfluid_get_agrid(double* p_agrid){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_agrid = lbpar_gpu.agrid; -#endif - } else { -#ifdef LB - *p_agrid = lbpar.agrid; -#endif - } - return 0; -} - -int lb_lbfluid_get_ext_force(double* p_fx, double* p_fy, double* p_fz){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - *p_fx = lbpar_gpu.ext_force[0]; - *p_fy = lbpar_gpu.ext_force[1]; - *p_fz = lbpar_gpu.ext_force[2]; -#endif - } else { -#ifdef LB - *p_fx = lbpar.ext_force[0]; - *p_fy = lbpar.ext_force[1]; - *p_fz = lbpar.ext_force[2]; -#endif - } - return 0; -} - -int lb_lbfluid_print_vtk_boundary(char* filename) { - FILE* fp = fopen(filename, "w"); - - if(fp == NULL) - return 1; - - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - unsigned int* bound_array; - bound_array = (unsigned int*) malloc(lbpar_gpu.number_of_nodes*sizeof(unsigned int)); - lb_get_boundary_flags_GPU(bound_array); - - int j; - /** print of the calculated phys values */ - fprintf(fp, "# vtk DataFile Version 2.0\nlbboundaries\nASCII\nDATASET STRUCTURED_POINTS\nDIMENSIONS %u %u %u\nORIGIN %f %f %f\nSPACING %f %f %f\nPOINT_DATA %u\nSCALARS OutArray floats 1\nLOOKUP_TABLE default\n", lbpar_gpu.dim_x, lbpar_gpu.dim_y, lbpar_gpu.dim_z, lbpar_gpu.agrid*0.5, lbpar_gpu.agrid*0.5, lbpar_gpu.agrid*0.5, lbpar_gpu.agrid, lbpar_gpu.agrid, lbpar_gpu.agrid, lbpar_gpu.number_of_nodes); - for(j=0; jrho[ii]); - } -#endif // LB_GPU - } else { -#ifdef LB - index_t index; - int node, grid[3], ind_shifted[3]; - double rho; double j[3]; double pi[6]; - - ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; - node = map_lattice_to_node(&lblattice,ind_shifted,grid); - index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); - - mpi_recv_fluid(node,index,&rho,j,pi); - // unit conversion - rho *= 1/lbpar.agrid/lbpar.agrid/lbpar.agrid; - *p_rho = rho; -#endif - } - return 0; -} - -int lb_lbnode_get_u(int* ind, double* p_u) { - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - static LB_rho_v_pi_gpu *host_print_values=NULL; - if(host_print_values==NULL) host_print_values= (LB_rho_v_pi_gpu *) malloc(sizeof(LB_rho_v_pi_gpu)); - - int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; - lb_print_node_GPU(single_nodeindex, host_print_values); - - p_u[0] = (double)(host_print_values[0].v[0]); - p_u[1] = (double)(host_print_values[0].v[1]); - p_u[2] = (double)(host_print_values[0].v[2]); -#endif - } else { -#ifdef LB - index_t index; - int node, grid[3], ind_shifted[3]; - double rho; double j[3]; double pi[6]; - - ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; - node = map_lattice_to_node(&lblattice,ind_shifted,grid); - index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); - - mpi_recv_fluid(node,index,&rho,j,pi); - // unit conversion - p_u[0] = j[0]/rho/tau/lbpar.agrid; - p_u[1] = j[1]/rho/tau/lbpar.agrid; - p_u[2] = j[2]/rho/tau/lbpar.agrid; -#endif - } - return 0; -} - - -/** calculates the fluid velocity at a given position of the - * lattice. Note that it can lead to undefined behaviour if the - * position is not within the local lattice. This version of the function - * can be called without the position needing to be on the local processor. - * Note that this gives a slightly different version then the values used to - * couple to MD beads when near a wall, see lb_lbfluid_get_interpolated_velocity. - */ - -int lb_lbfluid_get_interpolated_velocity_global (double* p, double* v) { - double local_v[3] = {0, 0, 0}, delta[6]; //velocity field, relative positions to surrounding nodes - int ind[3] = {0,0,0}, tmpind[3]; //node indices - int x, y, z; //counters - - // convert the position into lower left grid point - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - map_position_to_lattice_global(p, ind, delta, lbpar_gpu.agrid); -#endif - } else { -#ifdef LB - map_position_to_lattice_global(p, ind, delta, lbpar.agrid); -#endif - } - - //set the initial velocity to zero in all directions - v[0] = 0; - v[1] = 0; - v[2] = 0; - for (z=0;z<2;z++) { - for (y=0;y<2;y++) { - for (x=0;x<2;x++) { - //give the index of the neighbouring nodes - tmpind[0] = ind[0]+x; - tmpind[1] = ind[1]+y; - tmpind[2] = ind[2]+z; - - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - if (tmpind[0] == lbpar_gpu.dim_x) tmpind[0] =0; - if (tmpind[1] == lbpar_gpu.dim_y) tmpind[1] =0; - if (tmpind[2] == lbpar_gpu.dim_z) tmpind[2] =0; -#endif - } else { -#ifdef LB - if (tmpind[0] == box_l[0]/lbpar.agrid) tmpind[0] =0; - if (tmpind[1] == box_l[1]/lbpar.agrid) tmpind[1] =0; - if (tmpind[2] == box_l[2]/lbpar.agrid) tmpind[2] =0; - -#endif - } - -//printf (" %d %d %d %f %f %f\n", tmpind[0], tmpind[1],tmpind[2],v[0], v[1], v[2]); -exit(printf("TODO:adapt for SHANCHEN (%s:%d)\n",__FILE__,__LINE__)); - lb_lbnode_get_u(tmpind, local_v); - - - v[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[0]; - v[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[1]; - v[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_v[2]; - - } - } - } - - return 0; -} - -int lb_lbnode_get_pi(int* ind, double* p_pi) { -// TODO implement correctly for all components! - - double p0 = 0; - - lb_lbnode_get_pi_neq(ind, p_pi); - - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - p0 = lbpar_gpu.rho[0]*lbpar_gpu.agrid*lbpar_gpu.agrid/lbpar_gpu.tau/lbpar_gpu.tau/3.; -#endif - } else { -#ifdef LB - p0 = lbpar.rho[0]*lbpar.agrid*lbpar.agrid/lbpar.tau/lbpar.tau/3.; -#endif - } - - p_pi[0] += p0; - p_pi[2] += p0; - p_pi[5] += p0; - - return 0; -} - -int lb_lbnode_get_pi_neq(int* ind, double* p_pi) { - - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - static LB_rho_v_pi_gpu *host_print_values=NULL; - if(host_print_values==NULL) host_print_values= (LB_rho_v_pi_gpu *) malloc(sizeof(LB_rho_v_pi_gpu)); - - int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; - lb_print_node_GPU(single_nodeindex, host_print_values); - for (int i = 0; i<6; i++) { - p_pi[i]=host_print_values->pi[i]; - } - return 0; -#endif - } else { -#ifdef LB - index_t index; - int node, grid[3], ind_shifted[3]; - double rho; double j[3]; double pi[6]; - - ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; - node = map_lattice_to_node(&lblattice,ind_shifted,grid); - index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); - - mpi_recv_fluid(node,index,&rho,j,pi); - // unit conversion // TODO: Check Unit Conversion! - p_pi[0] = pi[0]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; - p_pi[1] = pi[1]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; - p_pi[2] = pi[2]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; - p_pi[3] = pi[3]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; - p_pi[4] = pi[4]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; - p_pi[5] = pi[5]/tau/tau/lbpar.agrid/lbpar.agrid/lbpar.agrid; -#endif - } - return 0; -} - -int lb_lbnode_get_boundary(int* ind, int* p_boundary) { - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - unsigned int host_flag; - int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; - lb_get_boundary_flag_GPU(single_nodeindex, &host_flag); - p_boundary[0] = host_flag; -#endif - } else { -#ifdef LB - index_t index; - int node, grid[3], ind_shifted[3]; - - ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; - node = map_lattice_to_node(&lblattice,ind_shifted,grid); - index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); - - mpi_recv_fluid_boundary_flag(node,index,p_boundary); -#endif - } - return 0; -} - -#endif // SHANCHEN - -int lb_lbnode_get_pop(int* ind, double* p_pop) { - if (lattice_switch & LATTICE_LB_GPU) { - fprintf(stderr, "Not implemented for GPU\n"); - } else { -#ifdef LB - index_t index; - int node, grid[3], ind_shifted[3]; - - ind_shifted[0] = ind[0]; ind_shifted[1] = ind[1]; ind_shifted[2] = ind[2]; - node = map_lattice_to_node(&lblattice,ind_shifted,grid); - index = get_linear_index(ind_shifted[0],ind_shifted[1],ind_shifted[2],lblattice.halo_grid); - mpi_recv_fluid_populations(node, index, p_pop); -#endif - } - return 0; -} - -int lb_lbnode_set_rho(int* ind, double *p_rho){ - if (lattice_switch & LATTICE_LB_GPU) { -#ifdef LB_GPU - float host_rho[LB_COMPONENTS]; - int single_nodeindex = ind[0] + ind[1]*lbpar_gpu.dim_x + ind[2]*lbpar_gpu.dim_x*lbpar_gpu.dim_y; - int i; - for(i=0;i 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(1,0,0,lblattice.halo_grid); - for (z=0; z 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(lblattice.grid[0],0,0,lblattice.halo_grid); - for (z=0; z 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(0,1,0,lblattice.halo_grid); - for (z=0; z 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(0,lblattice.grid[1],0,lblattice.halo_grid); - for (z=0; z 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(0,0,1,lblattice.halo_grid); - for (y=0; y 1) { - MPI_Sendrecv(sbuf, count, MPI_DOUBLE, snode, REQ_HALO_SPREAD, - rbuf, count, MPI_DOUBLE, rnode, REQ_HALO_SPREAD, - comm_cart, &status); - } else { - memcpy(rbuf,sbuf,count*sizeof(double)); - } - - buffer = rbuf; - index = get_linear_index(0,0,lblattice.grid[2],lblattice.halo_grid); - for (y=0; y=lbpar.agrid/2.0) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{104 LB requires either no Verlet lists or that the skin of the verlet list to be less than half of lattice-Boltzmann grid spacing.} "); - ret = -1; - } - - - if (thermo_switch & ~THERMO_LB) { - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{122 LB must not be used with other thermostats} "); - ret = 1; - } - - return ret; - -} - -/***********************************************************************/ - -/** (Pre-)allocate memory for data structures */ -void lb_pre_init() { - n_veloc = lbmodel.n_veloc; - lbfluid[0] = (double**) malloc(2*lbmodel.n_veloc*sizeof(double *)); - lbfluid[0][0] = (double*) malloc(2*lblattice.halo_grid_volume*lbmodel.n_veloc*sizeof(double)); -} - -/** (Re-)allocate memory for the fluid and initialize pointers. */ -static void lb_realloc_fluid() { - int i; - - LB_TRACE(printf("reallocating fluid\n")); - - lbfluid[0] = (double**) realloc(*lbfluid,2*lbmodel.n_veloc*sizeof(double *)); - lbfluid[0][0] = (double*) realloc(**lbfluid,2*lblattice.halo_grid_volume*lbmodel.n_veloc*sizeof(double)); - lbfluid[1] = (double **)lbfluid[0] + lbmodel.n_veloc; - lbfluid[1][0] = (double *)lbfluid[0][0] + lblattice.halo_grid_volume*lbmodel.n_veloc; - - for (i=0; isource_node = comm.halo_info[i].source_node; - hinfo->dest_node = comm.halo_info[i].dest_node; - hinfo->s_offset = comm.halo_info[i].s_offset; - hinfo->r_offset = comm.halo_info[i].r_offset; - hinfo->type = comm.halo_info[i].type; - - /* generate the vector datatype for the structure of lattices we - * have to use hvector here because the extent of the subtypes - * does not span the full lattice and hence we cannot get the - * correct vskip out of them */ - - MPI_Aint extent; - MPI_Type_extent(MPI_DOUBLE,&extent); - MPI_Type_hvector(lbmodel.n_veloc,1,lblattice.halo_grid_volume*extent,comm.halo_info[i].datatype,&hinfo->datatype); - MPI_Type_commit(&hinfo->datatype); - - halo_create_field_hvector(lbmodel.n_veloc,1,lblattice.halo_grid_volume*sizeof(double),comm.halo_info[i].fieldtype,&hinfo->fieldtype); - } - - release_halo_communication(&comm); -} - -/** (Re-)initializes the fluid. */ -void lb_reinit_parameters() { - int i; - - n_veloc = lbmodel.n_veloc; - - agrid = lbpar.agrid; - tau = lbpar.tau; - - if (lbpar.viscosity[0] > 0.0) { - /* Eq. (80) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). */ - // unit conversion: viscosity - gamma_shear = 1. - 2./(6.*lbpar.viscosity[0]*tau/(agrid*agrid)+1.); - } - - if (lbpar.bulk_viscosity[0] > 0.0) { - /* Eq. (81) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). */ - // unit conversion: viscosity - gamma_bulk = 1. - 2./(9.*lbpar.bulk_viscosity[0]*tau/(agrid*agrid)+1.); - } - - gamma_odd = lbpar.gamma_odd[0]; - gamma_even = lbpar.gamma_even[0]; - - double mu = 0.0; - - if (temperature > 0.0) { /* fluctuating hydrodynamics ? */ - - fluct = 1; - - /* Eq. (51) Duenweg, Schiller, Ladd, PRE 76(3):036704 (2007). - * Note that the modes are not normalized as in the paper here! */ - mu = temperature/lbmodel.c_sound_sq*tau*tau/(agrid*agrid); - //mu *= agrid*agrid*agrid; // Marcello's conjecture -#ifdef D3Q19 - double (*e)[19] = d3q19_modebase; -#else - double **e = lbmodel.e; -#endif - for (i=0; i<3; i++) lb_phi[i] = 0.0; - lb_phi[4] = sqrt(mu*e[19][4]*(1.-SQR(gamma_bulk))); - for (i=5; i<10; i++) lb_phi[i] = sqrt(mu*e[19][i]*(1.-SQR(gamma_shear))); - for (i=10; i=factor) { - fluidstep=0; - -#ifdef PULL - lb_stream_collide(); -#else - lb_collide_stream(); -#endif - } - -} - -/***********************************************************************/ -/** \name Coupling part */ -/***********************************************************************/ -/*@{*/ - - -/** Coupling of a single particle to viscous fluid with Stokesian friction. - * - * Section II.C. Ahlrichs and Duenweg, JCP 111(17):8225 (1999) - * - * @param p The coupled particle (Input). - * @param force Coupling force between particle and fluid (Output). - */ -inline void lb_viscous_coupling(Particle *p, double force[3]) { - int x,y,z; - index_t node_index[8]; - double delta[6]; - double *local_f, interpolated_u[3],delta_j[3]; - -#if 0 // I have no idea what this should be for! - if(!(p->l.ext_flag & COORD_FIXED(0)) && !(p->l.ext_flag & COORD_FIXED(1)) && !(p->l.ext_flag & COORD_FIXED(2))) -#endif - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: f = (%.3e,%.3e,%.3e)\n",this_node,p->f.f[0],p->f.f[1],p->f.f[2])); - - /* determine elementary lattice cell surrounding the particle - and the relative position of the particle in this cell */ - map_position_to_lattice(&lblattice,p->r.p,node_index,delta); - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB delta=(%.3f,%.3f,%.3f,%.3f,%.3f,%.3f) pos=(%.3f,%.3f,%.3f)\n",this_node,delta[0],delta[1],delta[2],delta[3],delta[4],delta[5],p->r.p[0],p->r.p[1],p->r.p[2])); - - /* calculate fluid velocity at particle's position - this is done by linear interpolation - (Eq. (11) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ - lb_lbfluid_get_interpolated_velocity(p->r.p, interpolated_u); - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB u = (%.16e,%.3e,%.3e) v = (%.16e,%.3e,%.3e)\n",this_node,interpolated_u[0],interpolated_u[1],interpolated_u[2],p->m.v[0],p->m.v[1],p->m.v[2])); - - /* calculate viscous force - * take care to rescale velocities with time_step and transform to MD units - * (Eq. (9) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ -#ifdef LB_ELECTROHYDRODYNAMICS - force[0] = - lbpar.friction[0] * (p->m.v[0]/time_step - interpolated_u[0] - p->p.mu_E[0]); - force[1] = - lbpar.friction[0] * (p->m.v[1]/time_step - interpolated_u[1] - p->p.mu_E[1]); - force[2] = - lbpar.friction[0] * (p->m.v[2]/time_step - interpolated_u[2] - p->p.mu_E[2]); -#else - force[0] = - lbpar.friction[0] * (p->m.v[0]/time_step - interpolated_u[0]); - force[1] = - lbpar.friction[0] * (p->m.v[1]/time_step - interpolated_u[1]); - force[2] = - lbpar.friction[0] * (p->m.v[2]/time_step - interpolated_u[2]); -#endif - - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB f_drag = (%.6e,%.3e,%.3e)\n",this_node,force[0],force[1],force[2])); - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB f_random = (%.6e,%.3e,%.3e)\n",this_node,p->lc.f_random[0],p->lc.f_random[1],p->lc.f_random[2])); - - force[0] = force[0] + p->lc.f_random[0]; - force[1] = force[1] + p->lc.f_random[1]; - force[2] = force[2] + p->lc.f_random[2]; - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB f_tot = (%.6e,%.3e,%.3e)\n",this_node,force[0],force[1],force[2])); - - /* transform momentum transfer to lattice units - (Eq. (12) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ - delta_j[0] = - force[0]*time_step*tau/agrid; - delta_j[1] = - force[1]*time_step*tau/agrid; - delta_j[2] = - force[2]*time_step*tau/agrid; - - for (z=0;z<2;z++) { - for (y=0;y<2;y++) { - for (x=0;x<2;x++) { - - local_f = lbfields[node_index[(z*2+y)*2+x]].force; - - local_f[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[0]; - local_f[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[1]; - local_f[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*delta_j[2]; - - } - } - } - -} - -int lb_lbfluid_get_interpolated_velocity(double* p, double* v) { - index_t node_index[8], index; - double delta[6]; - double local_rho, local_j[3], interpolated_u[3]; - double modes[19]; - int x,y,z; - double pos[3]; - -#ifdef LB_BOUNDARIES - double lbboundary_mindist, distvec[3]; - int boundary_no; - int boundary_flag=-1; // 0 if more than agrid/2 away from the boundary, 1 if 0lbpar.agrid/2) { - boundary_flag=0; - pos[0]=p[0]; - pos[1]=p[1]; - pos[2]=p[2]; - } else if (lbboundary_mindist > 0 ) { - boundary_flag=1; - pos[0]=p[0] - distvec[0]+ distvec[0]/lbboundary_mindist*lbpar.agrid/2.; - pos[1]=p[1] - distvec[1]+ distvec[1]/lbboundary_mindist*lbpar.agrid/2.; - pos[2]=p[2] - distvec[2]+ distvec[2]/lbboundary_mindist*lbpar.agrid/2.; - } else { - boundary_flag=2; - v[0]= lb_boundaries[boundary_no].velocity[0]*lbpar.agrid/lbpar.tau; - v[1]= lb_boundaries[boundary_no].velocity[1]*lbpar.agrid/lbpar.tau; - v[2]= lb_boundaries[boundary_no].velocity[2]*lbpar.agrid/lbpar.tau; - return 0; // we can return without interpolating - } -#else - pos[0]=p[0]; - pos[1]=p[1]; - pos[2]=p[2]; -#endif - - /* determine elementary lattice cell surrounding the particle - and the relative position of the particle in this cell */ - map_position_to_lattice(&lblattice,pos,node_index,delta); - - /* calculate fluid velocity at particle's position - this is done by linear interpolation - (Eq. (11) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ - interpolated_u[0] = interpolated_u[1] = interpolated_u[2] = 0.0 ; - - for (z=0;z<2;z++) { - for (y=0;y<2;y++) { - for (x=0;x<2;x++) { - - index = node_index[(z*2+y)*2+x]; - -#ifdef LB_BOUNDARIES - if (lbfields[index].boundary) { - local_rho=lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid; - local_j[0] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[0]; - local_j[1] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[0]; - local_j[2] = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid*lb_boundaries[lbfields[index].boundary-1].velocity[0]; - } else { - lb_calc_modes(index, modes); - local_rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid + modes[0]; - local_j[0] = modes[1]; - local_j[1] = modes[2]; - local_j[2] = modes[3]; - } -#else - lb_calc_modes(index, modes); - local_rho = lbpar.rho[0]*lbpar.agrid*lbpar.agrid*lbpar.agrid + modes[0]; - local_j[0] = modes[1]; - local_j[1] = modes[2]; - local_j[2] = modes[3]; -#endif - interpolated_u[0] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[0]/(local_rho); - interpolated_u[1] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[1]/(local_rho); - interpolated_u[2] += delta[3*x+0]*delta[3*y+1]*delta[3*z+2]*local_j[2]/(local_rho) ; - - } - } - } -#ifdef LB_BOUNDARIES - if (boundary_flag==1) { - v[0]=lbboundary_mindist/(lbpar.agrid/2.)*interpolated_u[0]+(1-lbboundary_mindist/(lbpar.agrid/2.))*lb_boundaries[boundary_no].velocity[0]; - v[1]=lbboundary_mindist/(lbpar.agrid/2.)*interpolated_u[1]+(1-lbboundary_mindist/(lbpar.agrid/2.))*lb_boundaries[boundary_no].velocity[1]; - v[2]=lbboundary_mindist/(lbpar.agrid/2.)*interpolated_u[2]+(1-lbboundary_mindist/(lbpar.agrid/2.))*lb_boundaries[boundary_no].velocity[2]; - } else { - v[0] = interpolated_u[0]; - v[1] = interpolated_u[1]; - v[2] = interpolated_u[2]; - } -#else - v[0] = interpolated_u[0]; - v[1] = interpolated_u[1]; - v[2] = interpolated_u[2]; -#endif - v[0] *= lbpar.agrid/lbpar.tau; - v[1] *= lbpar.agrid/lbpar.tau; - v[2] *= lbpar.agrid/lbpar.tau; - return 0; - -} - - -/** Calculate particle lattice interactions. - * So far, only viscous coupling with Stokesian friction is - * implemented. - * Include all particle-lattice forces in this function. - * The function is called from \ref force_calc. - * - * Parallelizing the fluid particle coupling is not straightforward - * because drawing of random numbers makes the whole thing nonlocal. - * One way to do it is to treat every particle only on one node, i.e. - * the random numbers need not be communicated. The particles that are - * not fully inside the local lattice are taken into account via their - * ghost images on the neighbouring nodes. But this requires that the - * correct values of the surrounding lattice nodes are available on - * the respective node, which means that we have to communicate the - * halo regions before treating the ghost particles. Moreover, after - * determining the ghost couplings, we have to communicate back the - * halo region such that all local lattice nodes have the correct values. - * Thus two communication phases are involved which will most likely be - * the bottleneck of the computation. - * - * Another way of dealing with the particle lattice coupling is to - * treat a particle and all of it's images explicitly. This requires the - * communication of the random numbers used in the calculation of the - * coupling force. The problem is now that, if random numbers have to - * be redrawn, we cannot efficiently determine which particles and which - * images have to be re-calculated. We therefore go back to the outset - * and go through the whole system again until no failure occurs during - * such a sweep. In the worst case, this is very inefficient because - * many things are recalculated although they actually don't need. - * But we can assume that this happens extremely rarely and then we have - * on average only one communication phase for the random numbers, which - * probably makes this method preferable compared to the above one. - */ -void calc_particle_lattice_ia() { - int i, c, np; - Cell *cell ; - Particle *p ; - double force[3]; - - - if (transfer_momentum) { - - if (lbpar.resend_halo) { /* first MD step after last LB update */ - - /* exchange halo regions (for fluid-particle coupling) */ - halo_communication(&update_halo_comm, (char*)**lbfluid); -#ifdef ADDITIONAL_CHECKS - lb_check_halo_regions(); -#endif - - /* halo is valid now */ - lbpar.resend_halo = 0; - - /* all fields have to be recalculated */ - for (i=0; ipart ; - np = cell->n ; - for (i=0;ipart ; - np = cell->n ; - - for (i=0;ip.identity==check_id) fprintf(stderr,"%d: OPT: LB f = (%.6e,%.3e,%.3e)\n",this_node,p->f.f[0],p->f.f[1],p->f.f[2])); - - } - - } - - /* ghost cells */ - for (c=0;cpart ; - np = cell->n ; - - for (i=0;i= my_left[0]-0.5*lblattice.agrid && p[i].r.p[0] < my_right[0]+0.5*lblattice.agrid - && p[i].r.p[1] >= my_left[1]-0.5*lblattice.agrid && p[i].r.p[1] < my_right[1]+0.5*lblattice.agrid - && p[i].r.p[2] >= my_left[2]-0.5*lblattice.agrid && p[i].r.p[2] < my_right[2]+0.5*lblattice.agrid) { - - ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: LB coupling of ghost particle:\n",this_node)); - - lb_viscous_coupling(&p[i],force); - - /* ghosts must not have the force added! */ - - ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LB f = (%.6e,%.3e,%.3e)\n",this_node,p->f.f[0],p->f.f[1],p->f.f[2])); - - } - } - } - - } -} - -/***********************************************************************/ - -/** Calculate the average density of the fluid in the system. - * This function has to be called after changing the density of - * a local lattice site in order to set lbpar.rho consistently. */ -void lb_calc_average_rho() { - - index_t index; - int x, y, z; - double rho, local_rho, sum_rho; - - rho = 0.0; - local_rho = 0.0; - index = 0; - for (z=1; z<=lblattice.grid[2]; z++) { - for (y=1; y<=lblattice.grid[1]; y++) { - for (x=1; x<=lblattice.grid[0]; x++) { - - lb_calc_local_rho(index, &rho); - local_rho += rho; - - index++; - } - index += 2; - } - index += 2*lblattice.halo_grid[0]; - } - - MPI_Allreduce(&rho, &sum_rho, 1, MPI_DOUBLE, MPI_SUM, comm_cart); - - /* calculate average density in MD units */ - // TODO!!! - lbpar.rho[0] = sum_rho / (box_l[0]*box_l[1]*box_l[2]); - -} - -/*@}*/ - -#ifdef ADDITIONAL_CHECKS -static int compare_buffers(double *buf1, double *buf2, int size) { - int ret; - if (memcmp(buf1,buf2,size)) { - char *errtxt; - errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt,"{102 Halo buffers are not identical} "); - ret = 1; - } else { - ret = 0; - } - return ret; -} - -/** Checks consistency of the halo regions (ADDITIONAL_CHECKS) - This function can be used as an additional check. It test whether the - halo regions have been exchanged correctly. -*/ -static void lb_check_halo_regions() -{ - - index_t index; - int i,x,y,z, s_node, r_node, count=n_veloc; - double *s_buffer, *r_buffer; - MPI_Status status[2]; - - r_buffer = (double*) malloc(count*sizeof(double)); - s_buffer = (double*) malloc(count*sizeof(double)); - - if (PERIODIC(0)) { - for (z=0;z 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(lblattice.grid[0],y,z,lblattice.halo_grid); - for (i=0;i 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(1,y,z,lblattice.halo_grid); - for (i=0;i 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(x,lblattice.grid[1],z,lblattice.halo_grid); - for (i=0;i 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(x,1,z,lblattice.halo_grid); - for (i=0;i 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(x,y,lblattice.grid[2],lblattice.halo_grid); - for (i=0;i 1) { - MPI_Sendrecv(s_buffer, count, MPI_DOUBLE, r_node, REQ_HALO_CHECK, - r_buffer, count, MPI_DOUBLE, s_node, REQ_HALO_CHECK, - comm_cart, status); - index = get_linear_index(x,y,1,lblattice.halo_grid); - for (i=0;i ROUND_ERROR_PREC) { - count++; fprintf(stderr,"(%d) %f\n",a,sum1); - } - } - - for (a=0; a<3; a++) - for (b=0; b<3; b++) - { - sum2 = 0.0; - for (i=0; i ROUND_ERROR_PREC) { - count++; fprintf(stderr,"(%d,%d,%d,%d) %f\n",a,b,c,d,sum4); - } - } - - for (a=0; a<3; a++) - for (b=0; b<3; b++) - for (c=0; c<3; c++) - for (d=0; d<3; d++) - for (e=0; e<3; e++) - { - sum5 = 0.0; - for (i=0; i ROUND_ERROR_PREC) { - count++; fprintf(stderr,"(%d,%d,%d,%d,%d) %f\n",a,b,c,d,e,sum5); - } - } - - fprintf(stderr,"%d non-null entries\n",count); - -} -#endif /* #ifdef ADDITIONAL_CHECKS */ - -#ifdef ADDITIONAL_CHECKS -static void lb_check_mode_transformation(index_t index, double *mode) { - - /* check if what I think is right */ - - int i; - double *w = lbmodel.w; - double (*e)[19] = d3q19_modebase; - double sum_n=0.0, sum_m=0.0; - double n_eq[19]; - double m_eq[19]; - // unit conversion: mass density - double avg_rho = lbpar.rho*lbpar.agrid*lbpar.agrid*lbpar.agrid; - double (*c)[3] = lbmodel.c; - - m_eq[0] = mode[0]; - m_eq[1] = mode[1]; - m_eq[2] = mode[2]; - m_eq[3] = mode[3]; - - double rho = mode[0] + avg_rho; - double *j = mode+1; - - /* equilibrium part of the stress modes */ - /* remember that the modes have (\todo not?) been normalized! */ - m_eq[4] = /*1./6.*/scalar(j,j)/rho; - m_eq[5] = /*1./4.*/(SQR(j[0])-SQR(j[1]))/rho; - m_eq[6] = /*1./12.*/(scalar(j,j) - 3.0*SQR(j[2]))/rho; - m_eq[7] = j[0]*j[1]/rho; - m_eq[8] = j[0]*j[2]/rho; - m_eq[9] = j[1]*j[2]/rho; - - for (i=10;iROUND_ERROR_PREC) { - fprintf(stderr,"Attention: sum_n=%f sum_m=%f %e\n",sum_n,sum_m,fabs(sum_n-sum_m)); - } - -} - -static void lb_init_mode_transformation() { - -#ifdef D3Q19 - int i, j, k, l; - int n_veloc = 14; - double w[14] = { 7./18., - 1./12., 1./12., 1./12., 1./12., 1./18., - 1./36., 1./36., 1./36., 1./36., - 1./36., 1./36., 1./36., 1./36. }; - double c[14][3] = { { 0., 0., 0. }, - { 1., 0., 0. }, - {-1., 0., 0. }, - { 0., 1., 0. }, - { 0.,-1., 0. }, - { 0., 0., 1. }, - { 1., 1., 0. }, - {-1.,-1., 0. }, - { 1.,-1., 0. }, - {-1., 1., 0. }, - { 1., 0., 1. }, - {-1., 0., 1. }, - { 0., 1., 1. }, - { 0.,-1., 1. } }; - - double b[19][14]; - double e[14][14]; - double proj, norm[14]; - - /* construct polynomials from the discrete velocity vectors */ - for (i=0;i. -*/ - -/** \file lbgpu.cu - * - * Cuda (.cu) file for the Lattice Boltzmann implementation on GPUs. - * Header file for \ref lbgpu.h. - */ - -#include "config.hpp" - -#ifdef LB_GPU -#include -#include -#include - -#include "lbgpu.hpp" -#include "cuda_interface.hpp" -#include "cuda_utils.hpp" - -#ifndef GAUSSRANDOM -#define GAUSSRANDOM -#endif - -int extended_values_flag=0; /* TODO: this has to be set to one by - appropriate functions if there is - the need to compute pi at every - step (e.g. moving boundaries)*/ - -/**defining structures residing in global memory */ - -/** device_rho_v: struct for hydrodynamic fields: this is for internal use - (i.e. stores values in LB units) and should not used for - printing values */ -static LB_rho_v_gpu *device_rho_v= NULL; - -/** device_rho_v_pi: extended struct for hydrodynamic fields: this is the interface - to tcl, and stores values in MD units. It should not used - as an input for any LB calculations. TODO: This structure is not yet - used, and it is here to allow access to the stress tensor at any - timestep, e.g. for future implementations of moving boundary codes */ -static LB_rho_v_gpu *device_rho_v_pi= NULL; - -/** print_rho_v_pi: struct for hydrodynamic fields: this is the interface - to tcl, and stores values in MD units. It should not used - as an input for any LB calculations. TODO: in the future, - one might want to have several structures for printing - separately rho, v, pi without having to compute/store - the complete set. */ -static LB_rho_v_pi_gpu *print_rho_v_pi= NULL; - -/** structs for velocity densities */ -static LB_nodes_gpu nodes_a = {.vd=NULL,.seed=NULL,.boundary=NULL}; -static LB_nodes_gpu nodes_b = {.vd=NULL,.seed=NULL,.boundary=NULL};; -/** struct for node force */ -static LB_node_force_gpu node_f = {.force=NULL} ; - -static LB_extern_nodeforce_gpu *extern_nodeforces = NULL; - -#ifdef LB_BOUNDARIES_GPU -static float* LB_boundary_force = NULL; -static float* LB_boundary_velocity = NULL; -/** pointer for bound index array*/ -static int *boundary_node_list; -static int *boundary_index_list; -static __device__ __constant__ int n_lb_boundaries_gpu = 0; -static size_t size_of_boundindex; -#endif -/** pointers for additional cuda check flag*/ -static int *gpu_check = NULL; -static int *h_gpu_check = NULL; - -static unsigned int intflag = 1; -static LB_nodes_gpu *current_nodes = NULL; -/**defining size values for allocating global memory */ -static size_t size_of_rho_v; -static size_t size_of_rho_v_pi; -static size_t size_of_extern_nodeforces; - -/**parameters residing in constant memory */ -static __device__ __constant__ LB_parameters_gpu para; -static const float c_sound_sq = 1.f/3.f; - -/*-------------------------------------------------------*/ -/*********************************************************/ -/** \name device functions called by kernel functions */ -/*********************************************************/ -/*-------------------------------------------------------*/ - -/*-------------------------------------------------------*/ - -/** atomic add function for sveral cuda architectures -*/ -__device__ inline void atomicadd(float* address, float value){ -#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 // for Fermi, atomicAdd supports floats - atomicAdd(address, value); -#elif __CUDA_ARCH__ >= 110 -#warning Using slower atomicAdd emulation -// float-atomic-add from -// [url="http://forums.nvidia.com/index.php?showtopic=158039&view=findpost&p=991561"] - float old = value; - while ((old = atomicExch(address, atomicExch(address, 0.0f)+old))!=0.0f); -#else -#error I need at least compute capability 1.1 -#endif -} - -/**randomgenerator which generates numbers [0,1] - * @param *rn Pointer to randomnumber array of the local node or particle -*/ -__device__ void random_01(LB_randomnr_gpu *rn){ - - const float mxi = 1.f/(float)(1ul<<31); - unsigned int curr = rn->seed; - - curr = 1103515245 * curr + 12345; - rn->randomnr[0] = (float)(curr & ((1ul<<31)-1))*mxi; - curr = 1103515245 * curr + 12345; - rn->randomnr[1] = (float)(curr & ((1ul<<31)-1))*mxi; - rn->seed = curr; - -} - -/** gaussian random nummber generator for thermalisation - * @param *rn Pointer to randomnumber array of the local node node or particle -*/ -__device__ void gaussian_random(LB_randomnr_gpu *rn){ - - float x1, x2; - float r2, fac; - /** On every second call two gaussian random numbers are calculated - via the Box-Muller transformation.*/ - /** draw two uniform random numbers in the unit circle */ - do { - random_01(rn); - x1 = 2.f*rn->randomnr[0]-1.f; - x2 = 2.f*rn->randomnr[1]-1.f; - r2 = x1*x1 + x2*x2; - } while (r2 >= 1.f || r2 == 0.f); - - /** perform Box-Muller transformation */ - fac = sqrtf(-2.f*__logf(r2)/r2); - rn->randomnr[0] = x2*fac; - rn->randomnr[1] = x1*fac; - -} -/* wrapper */ -__device__ void random_wrapper(LB_randomnr_gpu *rn) { - -#ifdef GAUSSRANDOM - gaussian_random(rn); -#else -#define sqrt12i 0.288675134594813f - random_01(rn); - rn->randomnr[0]-=0.5f; - rn->randomnr[0]*=sqrt12i; - rn->randomnr[1]-=0.5f; - rn->randomnr[1]*=sqrt12i; -#endif -} - - -/**tranformation from 1d array-index to xyz - * @param index node index / thread index (Input) - * @param xyz Pointer to calculated xyz array (Output) - */ -__device__ void index_to_xyz(unsigned int index, unsigned int *xyz){ - - xyz[0] = index%para.dim_x; - index /= para.dim_x; - xyz[1] = index%para.dim_y; - index /= para.dim_y; - xyz[2] = index; -} - -/**calculation of the modes from the velocitydensities (space-transform.) - * @param n_a Pointer to local node residing in array a (Input) - * @param index node index / thread index (Input) - * @param mode Pointer to the local register values mode (Output) -*/ -__device__ void calc_m_from_n(LB_nodes_gpu n_a, unsigned int index, float *mode){ - #pragma unroll - for(int ii=0;iirandomnr[0]; - mode[2 + ii * LBQ] += sqrt((para.mu[ii]*(2.f/3.f)*(1.f-(para.gamma_mobility[0]*para.gamma_mobility[0])))) * (2*ii-1) * rn->randomnr[1]; - } - random_wrapper(rn); - for(int ii=0;iirandomnr[0]; -#endif - - - for(int ii=0;iirandomnr[0]; - mode[5 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.f/9.f)*(1.f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; - random_wrapper(rn); - mode[6 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.f/3.f)*(1.f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[0]; - mode[7 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.f/9.f)*(1.f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; - random_wrapper(rn); - mode[8 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.f/9.f)*(1.f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[0]; - mode[9 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(1.f/9.f)*(1.f-(para.gamma_shear[ii]*para.gamma_shear[ii])))) * rn->randomnr[1]; - /** ghost modes */ - random_wrapper(rn); - mode[10 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/3.f))) * rn->randomnr[0]; - mode[11 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/3.f))) * rn->randomnr[1]; - random_wrapper(rn); - mode[12 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/3.f))) * rn->randomnr[0]; - mode[13 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/9.f))) * rn->randomnr[1]; - random_wrapper(rn); - mode[14 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/9.f))) * rn->randomnr[0]; - mode[15 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f/9.f))) * rn->randomnr[1]; - random_wrapper(rn); - mode[16 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(2.f))) * rn->randomnr[0]; - mode[17 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.f/9.f))) * rn->randomnr[1]; - random_wrapper(rn); - mode[18 + ii * LBQ] += sqrt(Rho*(para.mu[ii]*(4.f/3.f))) * rn->randomnr[0]; - } -} - - -/*-------------------------------------------------------*/ -/**normalization of the modes need befor backtransformation into velocity space - * @param mode Pointer to the local register values mode (Input/Output) -*/ -__device__ void normalize_modes(float* mode){ - #pragma unroll - for(int ii=0;iirandomnr[0]; - viscforce[1+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[1]; - gaussian_random(rn_part); - viscforce[2+ii*3] += para.lb_coupl_pref2[ii]*rn_part->randomnr[0]; -#else - random_01(rn_part); - viscforce[0+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[0]-0.5f); - viscforce[1+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[1]-0.5f); - random_01(rn_part); - viscforce[2+ii*3] += para.lb_coupl_pref[ii]*(rn_part->randomnr[0]-0.5f); -#endif - /** delta_j for transform momentum transfer to lattice units which is done in calc_node_force - (Eq. (12) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) */ - - particle_force[part_index].f[0] += viscforce[0+ii*3]; - particle_force[part_index].f[1] += viscforce[1+ii*3]; - particle_force[part_index].f[2] += viscforce[2+ii*3]; - /* the average force from the particle to surrounding nodes is transmitted back to preserve momentum */ - for(int node=0 ; node < 8 ; node++ ) { - particle_force[part_index].f[0] -= partgrad1[node+ii*8]/8.; - particle_force[part_index].f[1] -= partgrad2[node+ii*8]/8.; - particle_force[part_index].f[2] -= partgrad3[node+ii*8]/8.; - } - /* note that scforce is zero if SHANCHEN is not #defined */ - delta_j[0+3*ii] -= (scforce[0+ii*3]+viscforce[0+ii*3])*para.time_step*para.tau/para.agrid; - delta_j[1+3*ii] -= (scforce[1+ii*3]+viscforce[1+ii*3])*para.time_step*para.tau/para.agrid; - delta_j[2+3*ii] -= (scforce[2+ii*3]+viscforce[2+ii*3])*para.time_step*para.tau/para.agrid; - } -} - -/**calcutlation of the node force caused by the particles, with atomicadd due to avoiding race conditions - (Eq. (14) Ahlrichs and Duenweg, JCP 111(17):8225 (1999)) - * @param *delta Pointer for the weighting of particle position (Input) - * @param *delta_j Pointer for the weighting of particle momentum (Input) - * @param node_index node index around (8) particle (Input) - * @param node_f Pointer to the node force (Output). -*/ -__device__ void calc_node_force(float *delta, float *delta_j, float * partgrad1, float * partgrad2, float * partgrad3, unsigned int *node_index, LB_node_force_gpu node_f){ -/* TODO: should the drag depend on the density?? */ -/* NOTE: partgrad is not zero only if SHANCHEN is defined. It is initialized in calc_node_force. Alternatively one could - specialize this function to the single component LB */ - for(int ii=0; ii < LB_COMPONENTS; ++ii) { - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[0+ii*3] + partgrad1[ii*8+0])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[1+ii*3] + partgrad2[ii*8+0])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[0]]), (delta[0]*delta_j[2+ii*3] + partgrad3[ii*8+0])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[0+ii*3] + partgrad1[ii*8+1])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[1+ii*3] + partgrad2[ii*8+1])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[1]]), (delta[1]*delta_j[2+ii*3] + partgrad3[ii*8+1])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[0+ii*3] + partgrad1[ii*8+2])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[1+ii*3] + partgrad2[ii*8+2])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[2]]), (delta[2]*delta_j[2+ii*3] + partgrad3[ii*8+2])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[0+ii*3] + partgrad1[ii*8+3])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[1+ii*3] + partgrad2[ii*8+3])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[3]]), (delta[3]*delta_j[2+ii*3] + partgrad3[ii*8+3])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[0+ii*3] + partgrad1[ii*8+4])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[1+ii*3] + partgrad2[ii*8+4])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[4]]), (delta[4]*delta_j[2+ii*3] + partgrad3[ii*8+4])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[0+ii*3] + partgrad1[ii*8+5])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[1+ii*3] + partgrad2[ii*8+5])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[5]]), (delta[5]*delta_j[2+ii*3] + partgrad3[ii*8+5])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[0+ii*3] + partgrad1[ii*8+6])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[1+ii*3] + partgrad2[ii*8+6])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[6]]), (delta[6]*delta_j[2+ii*3] + partgrad3[ii*8+6])); - - atomicadd(&(node_f.force[(0+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[0+ii*3] + partgrad1[ii*8+7])); - atomicadd(&(node_f.force[(1+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[1+ii*3] + partgrad2[ii*8+7])); - atomicadd(&(node_f.force[(2+ii*3)*para.number_of_nodes + node_index[7]]), (delta[7]*delta_j[2+ii*3] + partgrad3[ii*8+7])); - } -} - - -/*********************************************************/ -/** \name System setup and Kernel functions */ -/*********************************************************/ - -/**kernel to calculate local populations from hydrodynamic fields given by the tcl values. - * The mapping is given in terms of the equilibrium distribution. - * - * Eq. (2.15) Ladd, J. Fluid Mech. 271, 295-309 (1994) - * Eq. (4) in Berk Usta, Ladd and Butler, JCP 122, 094902 (2005) - * - * @param n_a Pointer to the lattice site (Input). - * @param *gpu_check additional check if gpu kernel are executed(Input). -*/ -__global__ void calc_n_equilibrium(LB_nodes_gpu n_a, LB_rho_v_gpu *d_v, LB_node_force_gpu node_f, int *gpu_check) { - /* TODO: this can handle only a uniform density, somehting similar, but local, - has to be called every time the fields are set by the user ! */ - unsigned int index = blockIdx.y * gridDim.x * blockDim.x + blockDim.x * blockIdx.x + threadIdx.x; - if(indexnumber_of_nodes * sizeof(LB_rho_v_gpu); - size_of_rho_v_pi = lbpar_gpu->number_of_nodes * sizeof(LB_rho_v_pi_gpu); - - - /** Allocate structs in device memory*/ - if(extended_values_flag==0) { - free_and_realloc(device_rho_v, size_of_rho_v); - } else { - /* see the notes to the stucture device_rho_v_pi above...*/ - free_and_realloc(device_rho_v_pi, size_of_rho_v_pi); - } - - - /* TODO: this is a almost a copy copy of device_rho_v thik about eliminating it, and maybe pi can be added to device_rho_v in this case*/ - free_and_realloc(print_rho_v_pi , size_of_rho_v_pi); - free_and_realloc(nodes_a.vd , lbpar_gpu->number_of_nodes * 19 * LB_COMPONENTS * sizeof(float)); - free_and_realloc(nodes_b.vd , lbpar_gpu->number_of_nodes * 19 * LB_COMPONENTS * sizeof(float)); - free_and_realloc(node_f.force , lbpar_gpu->number_of_nodes * 3 * LB_COMPONENTS * sizeof(float)); - - free_and_realloc(nodes_a.seed , lbpar_gpu->number_of_nodes * sizeof( unsigned int)); - free_and_realloc(nodes_a.boundary, lbpar_gpu->number_of_nodes * sizeof( unsigned int)); - free_and_realloc(nodes_b.seed , lbpar_gpu->number_of_nodes * sizeof( unsigned int)); - free_and_realloc(nodes_b.boundary, lbpar_gpu->number_of_nodes * sizeof( unsigned int)); - - - - /**write parameters in const memory*/ - cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); - - /**check flag if lb gpu init works*/ - free_and_realloc(gpu_check, sizeof(int)); - if(h_gpu_check!=NULL) free(h_gpu_check) ; - h_gpu_check = (int*)malloc(sizeof(int)); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - cudaStreamCreate(&stream[0]); - - /** values for the particle kernel */ - int threads_per_block_particles = 64; - int blocks_per_grid_particles_y = 4; - int blocks_per_grid_particles_x = (lbpar_gpu->number_of_particles + threads_per_block_particles * blocks_per_grid_particles_y - 1)/(threads_per_block_particles * blocks_per_grid_particles_y); - dim3 dim_grid_particles = make_uint3(blocks_per_grid_particles_x, blocks_per_grid_particles_y, 1); - - KERNELCALL(reset_boundaries, dim_grid, threads_per_block, (nodes_a, nodes_b)); - - #ifdef SHANCHEN - // TODO FIXME: - /* We must add shan-chen forces, which are zero only if the densities are uniform*/ - #endif - - /** calc of veloctiydensities from given parameters and initialize the Node_Force array with zero */ - KERNELCALL(calc_n_equilibrium, dim_grid, threads_per_block, (nodes_a, device_rho_v ,node_f, gpu_check)); - - - - KERNELCALL(reinit_node_force, dim_grid, threads_per_block, (node_f)); - - - intflag = 1; - current_nodes = &nodes_a; - h_gpu_check[0] = 0; - cuda_safe_mem(cudaMemcpy(h_gpu_check, gpu_check, sizeof(int), cudaMemcpyDeviceToHost)); -//fprintf(stderr, "initialization of lb gpu code %i\n", lbpar_gpu->number_of_nodes); - cudaThreadSynchronize(); - if(!h_gpu_check[0]){ - fprintf(stderr, "initialization of lb gpu code failed! \n"); - errexit(); - } -} -/** reinitialization for the lb gpu fluid called from host - * @param *lbpar_gpu Pointer to parameters to setup the lb field -*/ -void lb_reinit_GPU(LB_parameters_gpu *lbpar_gpu){ - - /**write parameters in const memory*/ - cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - /** calc of veloctiydensities from given parameters and initialize the Node_Force array with zero */ - KERNELCALL(calc_n_equilibrium, dim_grid, threads_per_block, (nodes_a, device_rho_v, node_f, gpu_check)); -} - -/**setup and call particle reallocation from the host - * @param *lbpar_gpu Pointer to parameters to setup the lb field -*/ -void lb_realloc_particle_GPU_leftovers(LB_parameters_gpu *lbpar_gpu){ - - //copy parameters, especially number of parts to gpu mem - cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); -} - -#ifdef LB_BOUNDARIES_GPU -/** setup and call boundaries from the host - * @param host_n_lb_boundaries number of LB boundaries - * @param number_of_boundnodes number of boundnodes - * @param host_boundary_node_list The indices of the boundary nodes - * @param host_boundary_index_list The flag representing the corresponding boundary - * @param host_LB_Boundary_velocity The constant velocity at the boundary, set by the user (Input) -*/ -void lb_init_boundaries_GPU(int host_n_lb_boundaries, int number_of_boundnodes, int *host_boundary_node_list, int* host_boundary_index_list, float* host_LB_Boundary_velocity){ - int temp = host_n_lb_boundaries; - - size_of_boundindex = number_of_boundnodes*sizeof(int); - cuda_safe_mem(cudaMalloc((void**)&boundary_node_list, size_of_boundindex)); - cuda_safe_mem(cudaMalloc((void**)&boundary_index_list, size_of_boundindex)); - cuda_safe_mem(cudaMemcpy(boundary_index_list, host_boundary_index_list, size_of_boundindex, cudaMemcpyHostToDevice)); - cuda_safe_mem(cudaMemcpy(boundary_node_list, host_boundary_node_list, size_of_boundindex, cudaMemcpyHostToDevice)); - - cuda_safe_mem(cudaMalloc((void**)&LB_boundary_force , 3*host_n_lb_boundaries*sizeof(float))); - cuda_safe_mem(cudaMalloc((void**)&LB_boundary_velocity, 3*host_n_lb_boundaries*sizeof(float))); - cuda_safe_mem(cudaMemcpy(LB_boundary_velocity, host_LB_Boundary_velocity, 3*n_lb_boundaries*sizeof(float), cudaMemcpyHostToDevice)); - cuda_safe_mem(cudaMemcpyToSymbol(n_lb_boundaries_gpu, &temp, sizeof(int))); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(reset_boundaries, dim_grid, threads_per_block, (nodes_a, nodes_b)); - - if (n_lb_boundaries == 0) { - cudaThreadSynchronize(); - return; - } - if(number_of_boundnodes == 0){ - fprintf(stderr, "WARNING: boundary cmd executed but no boundary node found!\n"); - } else{ - int threads_per_block_bound = 64; - int blocks_per_grid_bound_y = 4; - int blocks_per_grid_bound_x = (number_of_boundnodes + threads_per_block_bound * blocks_per_grid_bound_y - 1) /(threads_per_block_bound * blocks_per_grid_bound_y); - dim3 dim_grid_bound = make_uint3(blocks_per_grid_bound_x, blocks_per_grid_bound_y, 1); - - KERNELCALL(init_boundaries, dim_grid_bound, threads_per_block_bound, (boundary_node_list, boundary_index_list, number_of_boundnodes, nodes_a, nodes_b)); - } - - cudaThreadSynchronize(); -} -#endif -/**setup and call extern single node force initialization from the host - * @param *lbpar_gpu Pointer to host parameter struct -*/ -void lb_reinit_extern_nodeforce_GPU(LB_parameters_gpu *lbpar_gpu){ - - cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu->number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(reinit_node_force, dim_grid, threads_per_block, (node_f)); - -} -/**setup and call extern single node force initialization from the host - * @param n_extern_nodeforces number of nodes on which the external force has to be applied - * @param *host_extern_nodeforces Pointer to the host extern node forces - * @param *lbpar_gpu Pointer to host parameter struct -*/ -void lb_init_extern_nodeforces_GPU(int n_extern_nodeforces, LB_extern_nodeforce_gpu *host_extern_nodeforces, LB_parameters_gpu *lbpar_gpu){ - - size_of_extern_nodeforces = n_extern_nodeforces*sizeof(LB_extern_nodeforce_gpu); - cuda_safe_mem(cudaMalloc((void**)&extern_nodeforces, size_of_extern_nodeforces)); - cudaMemcpy(extern_nodeforces, host_extern_nodeforces, size_of_extern_nodeforces, cudaMemcpyHostToDevice); - - if(lbpar_gpu->external_force == 0)cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); - - int threads_per_block_exf = 64; - int blocks_per_grid_exf_y = 4; - int blocks_per_grid_exf_x = (n_extern_nodeforces + threads_per_block_exf * blocks_per_grid_exf_y - 1) /(threads_per_block_exf * blocks_per_grid_exf_y); - dim3 dim_grid_exf = make_uint3(blocks_per_grid_exf_x, blocks_per_grid_exf_y, 1); - - KERNELCALL(init_extern_nodeforces, dim_grid_exf, threads_per_block_exf, (n_extern_nodeforces, extern_nodeforces, node_f)); - cudaFree(extern_nodeforces); -} - -/**setup and call particle kernel from the host -*/ -void lb_calc_particle_lattice_ia_gpu(){ - if (lbpar_gpu.number_of_particles) { - /** call of the particle kernel */ - /** values for the particle kernel */ - int threads_per_block_particles = 64; - int blocks_per_grid_particles_y = 4; - int blocks_per_grid_particles_x = (lbpar_gpu.number_of_particles + threads_per_block_particles * blocks_per_grid_particles_y - 1)/(threads_per_block_particles * blocks_per_grid_particles_y); - dim3 dim_grid_particles = make_uint3(blocks_per_grid_particles_x, blocks_per_grid_particles_y, 1); - - KERNELCALL(calc_fluid_particle_ia, dim_grid_particles, threads_per_block_particles, (*current_nodes, gpu_get_particle_pointer(), gpu_get_particle_force_pointer(), node_f, gpu_get_particle_seed_pointer(),device_rho_v)); - } -} - -/** setup and call kernel for getting macroscopic fluid values of all nodes - * @param *host_values struct to save the gpu values -*/ -void lb_get_values_GPU(LB_rho_v_pi_gpu *host_values){ - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(get_mesoscopic_values_in_MD_units, dim_grid, threads_per_block, (nodes_a, print_rho_v_pi, device_rho_v )); - cudaMemcpy(host_values, print_rho_v_pi, size_of_rho_v_pi, cudaMemcpyDeviceToHost); - -} - -/** get all the boundary flags for all nodes - * @param host_bound_array here go the values of the boundary flag - */ -void lb_get_boundary_flags_GPU(unsigned int* host_bound_array){ - - unsigned int* device_bound_array; - cuda_safe_mem(cudaMalloc((void**)&device_bound_array, lbpar_gpu.number_of_nodes*sizeof(unsigned int))); - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) / (threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(lb_get_boundaries, dim_grid, threads_per_block, (*current_nodes, device_bound_array)); - - cudaMemcpy(host_bound_array, device_bound_array, lbpar_gpu.number_of_nodes*sizeof(unsigned int), cudaMemcpyDeviceToHost); - - cudaFree(device_bound_array); - -} - -/** setup and call kernel for getting macroscopic fluid values of a single node*/ -void lb_print_node_GPU(int single_nodeindex, LB_rho_v_pi_gpu *host_print_values){ - - LB_rho_v_pi_gpu *device_print_values; - cuda_safe_mem(cudaMalloc((void**)&device_print_values, sizeof(LB_rho_v_pi_gpu))); - int threads_per_block_print = 1; - int blocks_per_grid_print_y = 1; - int blocks_per_grid_print_x = 1; - dim3 dim_grid_print = make_uint3(blocks_per_grid_print_x, blocks_per_grid_print_y, 1); - - KERNELCALL(lb_print_node, dim_grid_print, threads_per_block_print, (single_nodeindex, device_print_values, *current_nodes, device_rho_v)); - - cudaMemcpy(host_print_values, device_print_values, sizeof(LB_rho_v_pi_gpu), cudaMemcpyDeviceToHost); - cudaFree(device_print_values); - -} - -/** setup and call kernel to calculate the total momentum of the hole fluid - * @param *mass value of the mass calcutated on the GPU -*/ -void lb_calc_fluid_mass_GPU(double* mass){ - - float* tot_mass; - float cpu_mass = 0.f ; - cuda_safe_mem(cudaMalloc((void**)&tot_mass, sizeof(float))); - cudaMemcpy(tot_mass, &cpu_mass, sizeof(float), cudaMemcpyHostToDevice); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(calc_mass, dim_grid, threads_per_block,(*current_nodes, tot_mass)); - - cudaMemcpy(&cpu_mass, tot_mass, sizeof(float), cudaMemcpyDeviceToHost); - - cudaFree(tot_mass); - mass[0] = (double)(cpu_mass); -} - -/** setup and call kernel to calculate the total momentum of the hole fluid - * @param host_mom value of the momentum calcutated on the GPU - */ -void lb_calc_fluid_momentum_GPU(double* host_mom){ - - float* tot_momentum; - float host_momentum[3] = { 0.f, 0.f, 0.f}; - cuda_safe_mem(cudaMalloc((void**)&tot_momentum, 3*sizeof(float))); - cudaMemcpy(tot_momentum, host_momentum, 3*sizeof(float), cudaMemcpyHostToDevice); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(momentum, dim_grid, threads_per_block,(*current_nodes, device_rho_v, node_f, tot_momentum)); - - cudaMemcpy(host_momentum, tot_momentum, 3*sizeof(float), cudaMemcpyDeviceToHost); - - cudaFree(tot_momentum); - host_mom[0] = (double)(host_momentum[0]* lbpar_gpu.agrid/lbpar_gpu.tau); - host_mom[1] = (double)(host_momentum[1]* lbpar_gpu.agrid/lbpar_gpu.tau); - host_mom[2] = (double)(host_momentum[2]* lbpar_gpu.agrid/lbpar_gpu.tau); -} - - -/** setup and call kernel to calculate the temperature of the hole fluid - * @param host_temp value of the temperatur calcutated on the GPU -*/ -void lb_calc_fluid_temperature_GPU(double* host_temp){ - - float host_jsquared = 0.f; - float* device_jsquared; - cuda_safe_mem(cudaMalloc((void**)&device_jsquared, sizeof(float))); - cudaMemcpy(device_jsquared, &host_jsquared, sizeof(float), cudaMemcpyHostToDevice); - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - - KERNELCALL(temperature, dim_grid, threads_per_block,(*current_nodes, device_jsquared)); - - cudaMemcpy(&host_jsquared, device_jsquared, sizeof(float), cudaMemcpyDeviceToHost); - // TODO: check that temperature calculation is properly implemented for shanchen - *host_temp=0; - #pragma unroll - for(int ii=0;iivd, lbpar_gpu.number_of_nodes * 19 * sizeof(float), cudaMemcpyDeviceToHost); - cudaMemcpy(host_checkpoint_seed, current_nodes->seed, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyDeviceToHost); - cudaMemcpy(host_checkpoint_boundary, current_nodes->boundary, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyDeviceToHost); - cudaMemcpy(host_checkpoint_force, node_f.force, lbpar_gpu.number_of_nodes * 3 * sizeof(float), cudaMemcpyDeviceToHost); - -} -/** setup and call kernel for setting macroscopic fluid values of all nodes - * @param *host_values struct to set stored values -*/ -void lb_load_checkpoint_GPU(float *host_checkpoint_vd, unsigned int *host_checkpoint_seed, unsigned int *host_checkpoint_boundary, float *host_checkpoint_force){ - - cudaMemcpy(current_nodes->vd, host_checkpoint_vd, lbpar_gpu.number_of_nodes * 19 * sizeof(float), cudaMemcpyHostToDevice); - intflag = 1; - cudaMemcpy(current_nodes->seed, host_checkpoint_seed, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyHostToDevice); - cudaMemcpy(current_nodes->boundary, host_checkpoint_boundary, lbpar_gpu.number_of_nodes * sizeof(unsigned int), cudaMemcpyHostToDevice); - cudaMemcpy(node_f.force, host_checkpoint_force, lbpar_gpu.number_of_nodes * 3 * sizeof(float), cudaMemcpyHostToDevice); - -} - - -/** setup and call kernel to get the boundary flag of a single node - * @param single_nodeindex number of the node to get the flag for - * @param host_flag her goes the value of the boundary flag - */ -void lb_get_boundary_flag_GPU(int single_nodeindex, unsigned int* host_flag){ - - unsigned int* device_flag; - cuda_safe_mem(cudaMalloc((void**)&device_flag, sizeof(unsigned int))); - int threads_per_block_flag = 1; - int blocks_per_grid_flag_y = 1; - int blocks_per_grid_flag_x = 1; - dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); - - KERNELCALL(lb_get_boundary_flag, dim_grid_flag, threads_per_block_flag, (single_nodeindex, device_flag, *current_nodes)); - - cudaMemcpy(host_flag, device_flag, sizeof(unsigned int), cudaMemcpyDeviceToHost); - - cudaFree(device_flag); - -} - -/** set the density at a single node - * @param single_nodeindex the node to set the velocity for - * @param host_velocity the velocity to set - */ -void lb_set_node_rho_GPU(int single_nodeindex, float* host_rho){ - - float* device_rho; - cuda_safe_mem(cudaMalloc((void**)&device_rho, LB_COMPONENTS*sizeof(float))); - cudaMemcpy(device_rho, host_rho, LB_COMPONENTS*sizeof(float), cudaMemcpyHostToDevice); - int threads_per_block_flag = 1; - int blocks_per_grid_flag_y = 1; - int blocks_per_grid_flag_x = 1; - dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); - KERNELCALL(set_rho, dim_grid_flag, threads_per_block_flag, (*current_nodes, device_rho_v, single_nodeindex, device_rho)); - cudaFree(device_rho); - -} - -/** set the net velocity at a single node - * @param single_nodeindex the node to set the velocity for - * @param host_velocity the velocity to set - */ -void lb_set_node_velocity_GPU(int single_nodeindex, float* host_velocity){ - - float* device_velocity; - cuda_safe_mem(cudaMalloc((void**)&device_velocity, 3*sizeof(float))); - cudaMemcpy(device_velocity, host_velocity, 3*sizeof(float), cudaMemcpyHostToDevice); - int threads_per_block_flag = 1; - int blocks_per_grid_flag_y = 1; - int blocks_per_grid_flag_x = 1; - dim3 dim_grid_flag = make_uint3(blocks_per_grid_flag_x, blocks_per_grid_flag_y, 1); - - KERNELCALL(set_u_equilibrium, dim_grid_flag, threads_per_block_flag, (*current_nodes, single_nodeindex, device_velocity)); - cudaFree(device_velocity); - -} - -/** reinit of params - * @param *lbpar_gpu struct containing the paramters of the fluid -*/ -void reinit_parameters_GPU(LB_parameters_gpu *lbpar_gpu){ - /**write parameters in const memory*/ - cuda_safe_mem(cudaMemcpyToSymbol(para, lbpar_gpu, sizeof(LB_parameters_gpu))); -} - -/**integration kernel for the lb gpu fluid update called from host */ -void lb_integrate_GPU(){ - - /** values for the kernel call */ - int threads_per_block = 64; - int blocks_per_grid_y = 4; - int blocks_per_grid_x = (lbpar_gpu.number_of_nodes + threads_per_block * blocks_per_grid_y - 1) /(threads_per_block * blocks_per_grid_y); - dim3 dim_grid = make_uint3(blocks_per_grid_x, blocks_per_grid_y, 1); - -#ifdef LB_BOUNDARIES_GPU - if (n_lb_boundaries > 0) - cuda_safe_mem(cudaMemset ( LB_boundary_force, 0, 3*n_lb_boundaries*sizeof(float))); -#endif - - - /**call of fluid step*/ - /* NOTE: if pi is needed at every integration step, one should call an extended version - of the integrate kernel, or pass also device_rho_v_pi and make sure that either - it or device_rho_v are NULL depending on extended_values_flag */ - if (intflag == 1){ - KERNELCALL(integrate, dim_grid, threads_per_block, (nodes_a, nodes_b, device_rho_v, node_f)); - current_nodes = &nodes_b; -#ifdef LB_BOUNDARIES_GPU - - if (n_lb_boundaries > 0) { - KERNELCALL(bb_read, dim_grid, threads_per_block, (nodes_a, nodes_b, LB_boundary_velocity, LB_boundary_force)); - } -#endif - intflag = 0; - } - else{ - KERNELCALL(integrate, dim_grid, threads_per_block, (nodes_b, nodes_a, device_rho_v, node_f)); - current_nodes = &nodes_a; -#ifdef LB_BOUNDARIES_GPU - - if (n_lb_boundaries > 0) { - KERNELCALL(bb_read, dim_grid, threads_per_block, (nodes_b, nodes_a, LB_boundary_velocity, LB_boundary_force)); - } -#endif - intflag = 1; - } -} - -void lb_gpu_get_boundary_forces(double* forces) { -#ifdef LB_BOUNDARIES_GPU - float* temp = (float*) malloc(3*n_lb_boundaries*sizeof(float)); - cuda_safe_mem(cudaMemcpy(temp, LB_boundary_force, 3*n_lb_boundaries*sizeof(float), cudaMemcpyDeviceToHost)); - for (int i =0; i<3*n_lb_boundaries; i++) { - forces[i]=(double)temp[i]; - } - free(temp); -#endif -} - -#endif /* LB_GPU */ diff --git a/src/p3m_gpu.hpp b/src/p3m_gpu.hpp deleted file mode 100644 index 90565085d79..00000000000 --- a/src/p3m_gpu.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _P3M_GPU_H -#define _P3M_GPU_H - -//NOTE :if one wants to use doubles it requires cuda compute capability 1.3 -#define _P3M_GPU_FLOAT -//#define _P3M_GPU_REAL_DOUBLE - -#ifdef _P3M_GPU_FLOAT -#define REAL_TYPE float -#define CUFFT_TYPE_COMPLEX cufftComplex -#define CUFFT_FFT cufftExecC2C -#define CUFFT_PLAN_FLAG CUFFT_C2C -#endif - -#ifdef _P3M_GPU_REAL_DOUBLE -#define REAL_TYPE double -#define CUFFT_TYPE_COMPLEX cufftDoubleComplex -#define CUFFT_FFT cufftExecZ2Z -#define CUFFT_PLAN_FLAG CUFFT_Z2Z -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void p3m_gpu_init(int cao, int mesh, REAL_TYPE alpha, REAL_TYPE box); - void p3m_gpu_add_farfield_force(); -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/p3m_gpu_cuda.cu b/src/p3m_gpu_cuda.cu deleted file mode 100644 index f4c676e8425..00000000000 --- a/src/p3m_gpu_cuda.cu +++ /dev/null @@ -1,460 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/** \file lbgpu.cu - * - * Cuda (.cu) file for the Lattice Boltzmann implementation on GPUs. - * Header file for \ref lbgpu.h. - */ - -#include -#include -#include - -#include -#include "cuda_interface.hpp" -#include "cuda_utils.hpp" -#include "config.hpp" -#include "p3m_gpu.hpp" -#include "utils.hpp" - -#ifdef ELECTROSTATICS - -struct dummytypename { - CUFFT_TYPE_COMPLEX *charge_mesh; - CUFFT_TYPE_COMPLEX *force_mesh; - REAL_TYPE *G_hat, *G_hat_host; - cufftHandle fft_plan; - int cao, mesh; - REAL_TYPE alpha; - int npart; - REAL_TYPE box; -} p3m_gpu_data; - - -#define SQR(A) ((A)*(A)) - -void static Aliasing_sums_ik ( int cao, REAL_TYPE box, REAL_TYPE alpha, int mesh, int NX, int NY, int NZ, - REAL_TYPE *Zaehler, REAL_TYPE *Nenner ) { - REAL_TYPE S1,S2,S3; - REAL_TYPE fak1,fak2,zwi; - int MX,MY,MZ; - REAL_TYPE NMX,NMY,NMZ; - REAL_TYPE NM2; - REAL_TYPE expo, TE; - REAL_TYPE Leni = 1.0/box; - - fak1 = 1.0/ ( REAL_TYPE ) mesh; - fak2 = SQR ( PI/ ( alpha ) ); - - Zaehler[0] = Zaehler[1] = Zaehler[2] = *Nenner = 0.0; - - for ( MX = -P3M_BRILLOUIN; MX <= P3M_BRILLOUIN; MX++ ) { - NMX = ( ( NX > mesh/2 ) ? NX - mesh : NX ) + mesh*MX; - S1 = pow ( sinc(fak1*NMX ), 2*cao ); - for ( MY = -P3M_BRILLOUIN; MY <= P3M_BRILLOUIN; MY++ ) { - NMY = ( ( NY > mesh/2 ) ? NY - mesh : NY ) + mesh*MY; - S2 = S1*pow ( sinc (fak1*NMY ), 2*cao ); - for ( MZ = -P3M_BRILLOUIN; MZ <= P3M_BRILLOUIN; MZ++ ) { - NMZ = ( ( NZ > mesh/2 ) ? NZ - mesh : NZ ) + mesh*MZ; - S3 = S2*pow ( sinc( fak1*NMZ ), 2*cao ); - - NM2 = SQR ( NMX*Leni ) + SQR ( NMY*Leni ) + SQR ( NMZ*Leni ); - *Nenner += S3; - - expo = fak2*NM2; - TE = exp ( -expo ); - zwi = S3 * TE/NM2; - Zaehler[0] += NMX*zwi*Leni; - Zaehler[1] += NMY*zwi*Leni; - Zaehler[2] += NMZ*zwi*Leni; - } - } - } -} - -/* Calculate influence function */ -void static calculate_influence_function ( int cao, int mesh, REAL_TYPE box, REAL_TYPE alpha, REAL_TYPE *G_hat ) { - - int NX,NY,NZ; - REAL_TYPE Dnx,Dny,Dnz; - REAL_TYPE Zaehler[3]={0.0,0.0,0.0},Nenner=0.0; - REAL_TYPE zwi; - int ind = 0; - REAL_TYPE Leni = 1.0/box; - - for ( NX=0; NX mesh/2 ) ? NX - mesh : NX; - Dny = ( NY > mesh/2 ) ? NY - mesh : NY; - Dnz = ( NZ > mesh/2 ) ? NZ - mesh : NZ; - - zwi = Dnx*Zaehler[0]*Leni + Dny*Zaehler[1]*Leni + Dnz*Zaehler[2]*Leni; - zwi /= ( ( SQR ( Dnx*Leni ) + SQR ( Dny*Leni ) + SQR ( Dnz*Leni ) ) * SQR ( Nenner ) ); - G_hat[ind] = 2.0 * zwi / PI; - } - } - } - } -} - -//NOTE :if one wants to use the function below it requires cuda compute capability 1.3 -#ifdef _P3M_GPU_REAL_DOUBLE -__device__ double atomicAdd (double* address, double val) -{ - unsigned long long int* address_as_ull = - (unsigned long long int*)address; - unsigned long long int old = *address_as_ull, assumed; - do { - assumed = old; - old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + - __longlong_as_double(assumed))); - } while (assumed != old); - return __longlong_as_double(old); -} -#endif - -/** atomic add function for several cuda architectures -*/ - -#if !defined __CUDA_ARCH__ || __CUDA_ARCH__ >= 200 // for Fermi, atomicAdd supports floats -//atomicAdd supports floats already, do nothing -#elif __CUDA_ARCH__ >= 110 -#warning Using slower atomicAdd emulation -__device__ inline void atomicAdd(float* address, float value){ - // float-atomic-add from -// [url="http://forums.nvidia.com/index.php?showtopic=158039&view=findpost&p=991561"] - float old = value; - while ((old = atomicExch(address, atomicExch(address, 0.0f)+old))!=0.0f); -} -#else -#error I need at least compute capability 1.1 -#endif - - - -__device__ unsigned int getThreadIndexP3M() { //rename is dumb but can't import same fnc from cuda_common - - return blockIdx.y * gridDim.x * blockDim.x + - blockDim.x * blockIdx.x + - threadIdx.x; -} - - -// __global__ void add_p3m_farfield_force_gpu( LB_parameters_gpu* lb_parameters_gpu, -// CUDA_particle_data* lb_particle_gpu, -// CUDA_particle_force* lb_particle_force_gpu -// ) { - -// unsigned int index = getThreadIndex(); - -// if( index < lb_parameters_gpu->number_of_particles ) { - -// lb_particle_force_gpu[ index ].f[0] = 1.0f; -// lb_particle_force_gpu[ index ].f[1] = 2.0f; -// lb_particle_force_gpu[ index ].f[2] = 3.0f; -// } -// } - - -template -__global__ void apply_diff_op( CUFFT_TYPE_COMPLEX *mesh, const int mesh_size, CUFFT_TYPE_COMPLEX *force_mesh, const REAL_TYPE box ) { - int linear_index = mesh_size*mesh_size*blockIdx.x + mesh_size * blockIdx.y + threadIdx.x; - int n; - - switch( dim ) { - case 0: - n = blockIdx.x; - break; - case 1: - n = blockIdx.y; - break; - case 2: - n = threadIdx.x; - break; - } - - n = ( n == mesh_size/2 ) ? 0.0 : n; - n = ( n > mesh_size/2) ? n - mesh_size : n; - - force_mesh[linear_index].x = -2.0 * PI * n * mesh[linear_index].y / box; - force_mesh[linear_index].y = 2.0 * PI * n * mesh[linear_index].x / box; -} - - -__device__ inline int wrap_index(const int ind, const int mesh) { - if(ind < 0) - return ind + mesh; - else if(ind >= mesh) - return ind - mesh; - else - return ind; -} - -__device__ REAL_TYPE caf(int i, REAL_TYPE x, int cao_value) { - switch (cao_value) { - case 1 : return 1.0; - case 2 : { - switch (i) { - case 0: return 0.5-x; - case 1: return 0.5+x; - default: - return 0.0; - } - } - case 3 : { - switch (i) { - case 0: return 0.5*SQR(0.5 - x); - case 1: return 0.75 - SQR(x); - case 2: return 0.5*SQR(0.5 + x); - default: - return 0.0; - } - case 4 : { - switch (i) { - case 0: return ( 1.0+x*( -6.0+x*( 12.0-x* 8.0)))/48.0; - case 1: return (23.0+x*(-30.0+x*(-12.0+x*24.0)))/48.0; - case 2: return (23.0+x*( 30.0+x*(-12.0-x*24.0)))/48.0; - case 3: return ( 1.0+x*( 6.0+x*( 12.0+x* 8.0)))/48.0; - default: - return 0.0; - } - } - case 5 : { - switch (i) { - case 0: return ( 1.0+x*( -8.0+x*( 24.0+x*(-32.0+x*16.0))))/384.0; - case 1: return ( 19.0+x*(-44.0+x*( 24.0+x*( 16.0-x*16.0))))/ 96.0; - case 2: return (115.0+x* x*(-120.0+x* x*48.0)) /192.0; - case 3: return ( 19.0+x*( 44.0+x*( 24.0+x*(-16.0-x*16.0))))/ 96.0; - case 4: return ( 1.0+x*( 8.0+x*( 24.0+x*( 32.0+x*16.0))))/384.0; - default: - return 0.0; - } - } - case 6 : { - switch (i) { - case 0: return ( 1.0+x*( -10.0+x*( 40.0+x*( -80.0+x*( 80.0-x* 32.0)))))/3840.0; - case 1: return (237.0+x*(-750.0+x*( 840.0+x*(-240.0+x*(-240.0+x*160.0)))))/3840.0; - case 2: return (841.0+x*(-770.0+x*(-440.0+x*( 560.0+x*( 80.0-x*160.0)))))/1920.0; - case 3: return (841.0+x*(+770.0+x*(-440.0+x*(-560.0+x*( 80.0+x*160.0)))))/1920.0; - case 4: return (237.0+x*( 750.0+x*( 840.0+x*( 240.0+x*(-240.0-x*160.0)))))/3840.0; - case 5: return ( 1.0+x*( 10.0+x*( 40.0+x*( 80.0+x*( 80.0+x* 32.0)))))/3840.0; - default: - return 0.0; - } - } - case 7 : { - switch (i) { - case 0: return ( 1.0+x*( -12.0+x*( 60.0+x*( -160.0+x*( 240.0+x*(-192.0+x* 64.0))))))/46080.0; - case 1: return ( 361.0+x*( -1416.0+x*( 2220.0+x*(-1600.0+x*( 240.0+x*( 384.0-x*192.0))))))/23040.0; - case 2: return (10543.0+x*(-17340.0+x*( 4740.0+x*( 6880.0+x*(-4080.0+x*(-960.0+x*960.0))))))/46080.0; - case 3: return ( 5887.0+x* x*(-4620.0+x* x*( 1680.0-x* x*320.0))) /11520.0; - case 4: return (10543.0+x*( 17340.0+x*( 4740.0+x*(-6880.0+x*(-4080.0+x*( 960.0+x*960.0))))))/46080.0; - case 5: return ( 361.0+x*( 1416.0+x*( 2220.0+x*( 1600.0+x*( 240.0+x*(-384.0-x*192.0))))))/23040.0; - case 6: return ( 1.0+x*( 12.0+x*( 60.0+x*( 160.0+x*( 240.0+x*( 192.0+x* 64.0))))))/46080.0; - default: - return 0.0; - } - } - }} - return 0.0; -} - -__global__ void apply_influence_function( CUFFT_TYPE_COMPLEX *mesh, int mesh_size, REAL_TYPE *G_hat ) { - int linear_index = mesh_size*mesh_size*blockIdx.x + mesh_size * blockIdx.y + threadIdx.x; - mesh[linear_index].x *= G_hat[linear_index]; - mesh[linear_index].y *= G_hat[linear_index]; -} - -__global__ void assign_charges(const CUDA_particle_data * const pdata, -CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const -REAL_TYPE hi) { - /** id of the particle **/ - int id = blockIdx.x; - /** position relative to the closest gird point **/ - REAL_TYPE m_pos[3]; - /** index of the nearest mesh point **/ - int nmp_x, nmp_y, nmp_z; - - CUDA_particle_data p = pdata[id]; - - m_pos[0] = p.p[0] * hi - pos_shift; - m_pos[1] = p.p[1] * hi - pos_shift; - m_pos[2] = p.p[2] * hi - pos_shift; - - nmp_x = (int) floor(m_pos[0] + 0.5); - nmp_y = (int) floor(m_pos[1] + 0.5); - nmp_z = (int) floor(m_pos[2] + 0.5); - - m_pos[0] -= nmp_x; - m_pos[1] -= nmp_y; - m_pos[2] -= nmp_z; - - nmp_x = wrap_index(nmp_x + threadIdx.x, m_size); - nmp_y = wrap_index(nmp_y + threadIdx.y, m_size); - nmp_z = wrap_index(nmp_z + threadIdx.z, m_size); - - atomicAdd( &(mesh[m_size*m_size*nmp_x + m_size*nmp_y + nmp_z].x), caf(threadIdx.x, m_pos[0], cao)*caf(threadIdx.y, m_pos[1], cao)*caf(threadIdx.z, m_pos[2], cao)*p.q); -} - -__global__ void assign_forces(const CUDA_particle_data * const pdata, CUFFT_TYPE_COMPLEX *mesh, const int m_size, const int cao, const REAL_TYPE pos_shift, const - REAL_TYPE hi, CUDA_particle_force * lb_particle_force_gpu, REAL_TYPE prefactor, int dim) { - /** id of the particle **/ - int id = blockIdx.x; - /** position relative to the closest gird point **/ - REAL_TYPE m_pos[3]; - /** index of the nearest mesh point **/ - int nmp_x, nmp_y, nmp_z; - - CUDA_particle_data p = pdata[id]; - - m_pos[0] = p.p[0] * hi - pos_shift; - m_pos[1] = p.p[1] * hi - pos_shift; - m_pos[2] = p.p[2] * hi - pos_shift; - - nmp_x = (int) floor(m_pos[0] + 0.5); - nmp_y = (int) floor(m_pos[1] + 0.5); - nmp_z = (int) floor(m_pos[2] + 0.5); - - m_pos[0] -= nmp_x; - m_pos[1] -= nmp_y; - m_pos[2] -= nmp_z; - - nmp_x = wrap_index(nmp_x + threadIdx.x, m_size); - nmp_y = wrap_index(nmp_y + threadIdx.y, m_size); - nmp_z = wrap_index(nmp_z + threadIdx.z, m_size); - - atomicAdd( &(lb_particle_force_gpu[id].f[dim]), (float)(-prefactor*mesh[m_size*m_size*nmp_x + m_size*nmp_y + nmp_z].x*caf(threadIdx.x, m_pos[0], cao)*caf(threadIdx.y, m_pos[1], cao)*caf(threadIdx.z, m_pos[2], cao)*p.q)); - -} - -extern "C" { - - /* Init the internal datastructures of the P3M GPU. - * Mainly allocation on the device and influence function calculation. - * Be advised: this needs mesh^3*5*sizeof(REAL_TYPE) of device memory. - */ - - void p3m_gpu_init(int cao, int mesh, REAL_TYPE alpha, REAL_TYPE box) { - gpu_init_particle_comm(); - - - if ( this_node == 0 ) { - p3m_gpu_data.npart = gpu_get_global_particle_vars_pointer_host()->number_of_particles; - p3m_gpu_data.alpha = alpha; - p3m_gpu_data.cao = cao; - p3m_gpu_data.mesh = mesh; - p3m_gpu_data.box = box; - int mesh3 = mesh*mesh*mesh; - - cudaMalloc((void **)&(p3m_gpu_data.charge_mesh), mesh3*sizeof(CUFFT_TYPE_COMPLEX)); - cudaMalloc((void **)&(p3m_gpu_data.force_mesh), mesh3*sizeof(CUFFT_TYPE_COMPLEX)); - cudaMalloc((void **)&(p3m_gpu_data.G_hat), mesh3*sizeof(REAL_TYPE)); - - p3m_gpu_data.G_hat_host = (REAL_TYPE *)malloc(mesh3*sizeof(REAL_TYPE)); - - // Calculate influence function of host. - calculate_influence_function( cao, mesh, box, alpha, p3m_gpu_data.G_hat_host); - - // Copy influence function to device. - cudaMemcpy( p3m_gpu_data.G_hat, p3m_gpu_data.G_hat_host, mesh3*sizeof(REAL_TYPE), cudaMemcpyHostToDevice); - - cufftPlan3d(&(p3m_gpu_data.fft_plan), mesh, mesh, mesh, CUFFT_PLAN_FLAG); - } - } - -void p3m_gpu_add_farfield_force() { - - CUDA_particle_data* lb_particle_gpu; - CUDA_particle_force* lb_particle_force_gpu; - - int mesh = p3m_gpu_data.mesh; - int mesh3 = mesh*mesh*mesh; - int cao = p3m_gpu_data.cao; - REAL_TYPE box = p3m_gpu_data.box; - - lb_particle_gpu = gpu_get_particle_pointer(); - lb_particle_force_gpu = gpu_get_particle_force_pointer(); - - p3m_gpu_data.npart = gpu_get_global_particle_vars_pointer_host()->number_of_particles; - - if(p3m_gpu_data.npart == 0) - return; - - //printf("p3m params: mesh %d npart %d cao %d\n", mesh, p3m_gpu_data.npart, cao); //TODO delete - - dim3 gridAssignment(p3m_gpu_data.npart,1,1); - dim3 threadsAssignment(cao,cao,cao); - - dim3 gridConv(mesh,mesh,1); - dim3 threadsConv(mesh,1,1); - - REAL_TYPE pos_shift = (REAL_TYPE)((cao-1)/2); - REAL_TYPE hi = mesh/box; - REAL_TYPE prefactor = 1.0/(box*box*box*2.0); - - cudaMemset( p3m_gpu_data.charge_mesh, 0, mesh3*sizeof(CUFFT_TYPE_COMPLEX)); - - KERNELCALL(assign_charges, gridAssignment, threadsAssignment, (lb_particle_gpu,p3m_gpu_data.charge_mesh,mesh,cao,pos_shift,hi)); - - cudaThreadSynchronize(); - - if (CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.charge_mesh, p3m_gpu_data.charge_mesh, CUFFT_FORWARD) != CUFFT_SUCCESS){ - fprintf(stderr, "CUFFT error: ExecZ2Z Forward failed\n"); - return; - } - - KERNELCALL( apply_influence_function, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.G_hat)); - - KERNELCALL(apply_diff_op<0>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); - - CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); - - KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 0)); - - KERNELCALL(apply_diff_op<1>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); - - CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); - - KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 1)); - - KERNELCALL(apply_diff_op<2>, gridConv, threadsConv, (p3m_gpu_data.charge_mesh, mesh, p3m_gpu_data.force_mesh, box)); - - CUFFT_FFT(p3m_gpu_data.fft_plan, p3m_gpu_data.force_mesh, p3m_gpu_data.force_mesh, CUFFT_INVERSE); - - KERNELCALL(assign_forces, gridAssignment, threadsAssignment, (lb_particle_gpu, p3m_gpu_data.force_mesh, mesh, cao, pos_shift, hi, lb_particle_force_gpu, prefactor, 2)); - - - // KERNELCALL( add_p3m_farfield_force_gpu, dim_grid, threads_per_block, ( lb_parameters_gpu, lb_particle_gpu, lb_particle_force_gpu ) ); -} - -} - -#endif /* ELECTROSTATICS */ diff --git a/src/python/espressomd/Makefile.am b/src/python/espressomd/Makefile.am new file mode 100644 index 00000000000..047335821bf --- /dev/null +++ b/src/python/espressomd/Makefile.am @@ -0,0 +1,146 @@ +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +AM_DEFAULT_SOURCE_EXT = .cpp + +# Build rules for python libraries +AM_CPPFLAGS = $(PYTHON_CPPFLAGS) \ + -I$(top_srcdir)/src -I$(top_srcdir)/src/core -I$(top_builddir)/src/core +AM_LDFLAGS = $(PYTHON_LDFLAGS) -module -avoid-version -no-undefined +LIBS = $(top_builddir)/src/core/libEspresso.la \ + @LIBS@ + +if MPI_FAKE +AM_CPPFLAGS += -I$(top_srcdir)/src/core/mpifake +endif + +# Build rules for cython +SUFFIXES = .pyx + +EXTRA_DIST = gen_pxiconfig.py +PYFILES = __init__.py \ + system.py \ + highlander.py + +PYXFILES = \ + _init.pyx \ + _system.pyx \ + particle_data.pyx \ + analyze.pyx \ + changeVolume.pyx \ + code_info.pyx \ + cuda_init.pyx \ + debye_hueckel.pyx \ + integrate.pyx \ + interactions.pyx \ + invalidateSystem.pyx \ + thermostat.pyx \ + utils.pyx + +PXDFILES = \ + c_analyze.pxd \ + _espresso.pxd \ + particle_data.pxd \ + analyze.pxd \ + changeVolume.pxd \ + code_info.pxd \ + cuda_init.pxd \ + debye_hueckel.pxd \ + integrate.pxd \ + interactions.pxd \ + invalidateSystem.pxd \ + thermostat.pxd \ + utils.pxd + +if TCL +LIBS += $(top_builddir)/src/tcl/libEspressoTcl4Py.la +PYXFILES += _tcl.pyx +endif + +# Python files have to be copied to the build dir +python-all: + $(AM_V_GEN)for f in $(PYFILES); do \ + if test ! -f $$f || test $(srcdir)/$$f -nt $$f; then \ + $(INSTALL) -D $(srcdir)/$$f $$f; \ + fi ; \ + done +all-local: python-all + +PYCFILES = $(PYFILES:.py=.pyc) +CLEANFILES = $(PYCFILES) +clean-local: + for file in $(PYFILES); do \ + if test -e $$file && test ! $$file -ef $(abs_srcdir)/$$file; then \ + rm -f $$file; \ + fi; \ + done + +EXTRA_DIST += $(PYFILES) $(PYXFILES) $(PXDFILES) + +# Generate the ".cpp" files +CPPFILES = $(PYXFILES:.pyx=.cpp) + +cython_verbose = $(cython_verbose_@AM_V@) +cython_verbose_ = $(cython_verbose_@AM_DEFAULT_V@) +cython_verbose_0 = @echo " CYTHON $@"; + +$(CPPFILES): %.cpp: %.pyx myconfig.pxi + $(cython_verbose)cython \ + -I $(builddir) $< -o $@ + +CLEANFILES += $(CPPFILES) + +# Dummy target to generate libtool rules +noinst_PROGRAMS = dummy +dummy_SOURCES = dummy.cpp + +# Generate the ".la" files. We do not really need these files, but we +# want to use libtool, so we have to give it a corresponding target. +# Also, like this, the .so-files are installed to the right place. +LAFILES = $(PYXFILES:.pyx=.la) +$(LAFILES): %.la: %.lo + $(AM_V_CXXLD)$(CXXLINK) -rpath $(pyexecdir) $< $(LIBS) +CLEANFILES += $(LAFILES) + +# create links to the ./libs/*.so in the dir +SOFILES = $(PYXFILES:.pyx=.so) +all-local: $(SOFILES) +CLEANFILES += $(SOFILES) + +$(SOFILES): %.so: %.la + $(AM_V_GEN)test -L $@ || $(LN_S) @objdir@/$@ $@ + +# build rule for myconfig.pxi +# create gen_pxiconfig.cpp from features.def +gen_pxiconfig.cpp: $(srcdir)/gen_pxiconfig.py $(top_srcdir)/src/features.def + $(AM_V_GEN)$(PYTHON) $(srcdir)/gen_pxiconfig.py \ + $(top_srcdir)/src/features.def gen_pxiconfig.cpp + +gen_pxiconfig_CPPFLAGS=-I$(top_srcdir)/src/core -I$(top_builddir)/src/core -I$(top_builddir)/src +gen_pxiconfig: gen_pxiconfig.cpp $(top_builddir)/src/core/config.hpp $(top_builddir)/src/core/myconfig-final.hpp + $(AM_V_CXXLD)$(CXXLINK) $(gen_pxiconfig_CPPFLAGS) $< + +CLEANFILES += gen_pxiconfig + +# create myconfig.pxi from gen_pxiconfig +myconfig.pxi: gen_pxiconfig + $(AM_V_GEN)./gen_pxiconfig > myconfig.pxi + +CLEANFILES += gen_pxiconfig.cpp myconfig.pxi +BUILT_SOURCES = gen_pxiconfig.cpp myconfig.pxi + diff --git a/doc/doxygen/background_errors.sh b/src/python/espressomd/__init__.py old mode 100755 new mode 100644 similarity index 55% rename from doc/doxygen/background_errors.sh rename to src/python/espressomd/__init__.py index f57d2d06b38..44498710788 --- a/doc/doxygen/background_errors.sh +++ b/src/python/espressomd/__init__.py @@ -1,8 +1,4 @@ -#!/bin/sh -# Parse the background-error lines from the source files -# -# Copyright (C) 2011,2012,2013 The ESPResSo project -# Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010,2011 Axel Arnold +# Copyright (C) 2014 Olaf Lenz # # This file is part of ESPResSo. # @@ -19,23 +15,23 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -AWK_SCRIPT=$SRCDIR/background_errors.awk -UNSORTED=background_errors.unsorted -SORTED=background_errors.sorted -DOC=background_errors.dox +# +# Define the espressomd package +import sys, ctypes + +# OpenMPI magic +sys.setdlopenflags((sys.getdlopenflags() | ctypes.RTLD_GLOBAL )) -$AWK -f $AWK_SCRIPT "$@" > $UNSORTED -sort $UNSORTED > $SORTED +# Initialize MPI, start the main loop on the slaves +import espressomd._init -# OUTPUT -cat < $DOC -/** \\page background_errors background_errors resolved -
      -EOF +# Initialize the Tcl Interpreter if available +try: + import espressomd._tcl + tcl = espressomd._tcl.TclInterpreter() +except ImportError: + pass -cat $SORTED >> $DOC +espressomd._init.setup() -cat <> $DOC -
    -*/ -EOF +from espressomd.system import System diff --git a/src/python/espressomd/_espresso.pxd b/src/python/espressomd/_espresso.pxd new file mode 100644 index 00000000000..dbc8f9ec5f6 --- /dev/null +++ b/src/python/espressomd/_espresso.pxd @@ -0,0 +1,30 @@ +# +# Copyright (C) 2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Common functions needed by all of ESPResSo +# Define no variables here, as all variables should become part of a +# specific class. +# +cdef extern from "tcl.h": + cdef struct Tcl_Interp: + pass + +cdef extern from "communication.hpp": + int mpi_bcast_parameter(int p) + int mpi_gather_runtime_errors(Tcl_Interp *interp, int ret_state) diff --git a/src/python/espressomd/_init.pxd b/src/python/espressomd/_init.pxd new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/python/espressomd/_init.pyx b/src/python/espressomd/_init.pyx new file mode 100644 index 00000000000..9743168c556 --- /dev/null +++ b/src/python/espressomd/_init.pyx @@ -0,0 +1,41 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +import sys + +cdef extern from "communication.hpp": + void mpi_init(int* argc = NULL, char ***argv = NULL) + int this_node + +cdef extern from "initialize.hpp": + void on_program_start() + void mpi_loop() + +### Here we make a minimalistic Tcl_Interp available +# Main code +mpi_init() + +# Main slave loop +if this_node != 0: + on_program_start() + mpi_loop() + sys.exit() + +def setup(): + on_program_start() + diff --git a/src/python/espressomd/_system.pyx b/src/python/espressomd/_system.pyx new file mode 100644 index 00000000000..54b319842d5 --- /dev/null +++ b/src/python/espressomd/_system.pyx @@ -0,0 +1,530 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" + +cimport _espresso + +import numpy as np +cimport cuda_init +import interactions +import particle_data +import cuda_init + +cdef class System +cdef class CellSystem + +cdef extern from "global.hpp": + int FIELD_NPTISO_PISTON + int FIELD_NPTISO_PDIFF + int FIELD_PERIODIC + int FIELD_SIMTIME + int FIELD_SKIN + +cdef extern from "communication.hpp": + extern int n_nodes + void mpi_set_time_step(double time_step) + +cdef extern from "domain_decomposition.hpp": + extern double max_skin + +cdef extern from "integrate.hpp": + double time_step + extern int integ_switch + extern double sim_time + extern double verlet_reuse + +cdef extern from "verlet.hpp": + double skin + +cdef extern from "lattice.hpp": + extern int lattice_switch + +cdef extern from "particle_data.hpp": + extern int n_part + +cdef extern from "interaction_data.hpp": + double dpd_gamma + double dpd_r_cut + extern double max_cut + extern int max_seen_particle + extern int n_particle_types + extern double max_cut_nonbonded + extern double max_cut_bonded + +cdef extern from "thermostat.hpp": + double langevin_gamma + extern double nptiso_gamma0 + extern double nptiso_gammav + extern double temperature + extern int thermo_switch + +cdef extern from "dpd.hpp": + extern int dpd_wf + extern double dpd_tgamma + extern double dpd_tr_cut + extern int dpd_twf + +IF LB: + cdef extern from "lb.hpp": + ctypedef struct LB_Parameters: + double tau + extern LB_Parameters lbpar + +IF LB_GPU: + cdef extern from "lbgpu.hpp": + ctypedef struct LB_parameters_gpu: + double tau + extern LB_parameters_gpu lbpar_gpu + +cdef extern from "cells.hpp": + extern double max_range + +cdef extern from "layered.hpp": + extern int n_layers + +cdef extern from "rattle.hpp": + extern int n_rigidbonds + +cdef extern from "tuning.hpp": + extern int timing_samples + +cdef extern from "imd.hpp": + extern int transfer_rate + +cdef extern from "grid.hpp": + double box_l[3] + double local_box_l[3] + extern int periodic + +cdef extern from "npt.hpp": + ctypedef struct nptiso_struct: + double p_ext + double p_inst + double p_inst_av + double p_diff + double piston + extern nptiso_struct nptiso + +cdef class System: + def __init__(self): + self.part = particle_data.particleList() + self.nonBondedInter = interactions.NonBondedInteractions() + self.bondedInter = interactions.BondedInteractions() + self.cellsystem = CellSystem(self) + + property n_nodes: + def __get__(self): + return n_nodes + + property box_l: + def __set__(self, _box_l): + if len(_box_l) != 3: + raise ValueError("Box length must be of length 3") + for i in range(3): + if _box_l[i] <= 0: + raise ValueError("Box length must be > 0 in all directions") + box_l[i]=_box_l[i] + + _espresso.mpi_bcast_parameter(0) + + def __get__(self): + return np.array([box_l[0], box_l[1], box_l[2]]) + + property dpd_gamma: + def __get__(self): + return dpd_gamma + + property dpd_r_cut: + def __get__(self): + return dpd_r_cut + + property gamma: + def __get__(self): + return langevin_gamma + + property integ_switch: + def __get__(self): + return integ_switch + + property local_box_l: + def __get__(self): + return np.array([local_box_l[0], local_box_l[1], local_box_l[2]]) + + property max_cut: + def __get__(self): + return max_cut + + + property max_part: + def __get__(self): + return max_seen_particle + + property max_range: + def __get__(self): + return max_range + + property max_skin: + def __get__(self): + return max_skin + + property n_layers: + def __get__(self): + return n_layers + + property n_part: + def __get__(self): + return n_part + + property n_part_types: + def __get__(self): + return n_particle_types + + property n_rigidbonds: + def __get__(self): + return n_rigidbonds + + + property nptiso_gamma0: + def __get__(self): + return nptiso_gamma0 + + property nptiso_gammav: + def __get__(self): + return nptiso_gammav + + property npt_p_ext: + def __get__(self): + return nptiso.p_ext + + property npt_p_inst: + def __get__(self): + return nptiso.p_inst + + property npt_p_inst_av: + def __get__(self): + return nptiso.p_inst_av + + property npt_piston: + def __set__(self, _npt_piston): + global npt_piston + if _npt_piston < 0: + raise ValueError("npt_piston must be > 0") + nptiso.piston=_npt_piston + _espresso.mpi_bcast_parameter(FIELD_NPTISO_PISTON) + def __get__(self): + global npt_piston + return nptiso.piston + + property npt_p_diff: + def __set__(self, _npt_p_diff): + global npt_p_diff + nptiso.p_diff=_npt_p_diff + _espresso.mpi_bcast_parameter(FIELD_NPTISO_PDIFF) + def __get__(self): + global npt_p_diff + return nptiso.p_diff + + property periodicity: + def __set__(self, _periodic): + global periodic + if len(_periodic) != 3: + raise ValueError("periodicity must be of length 3, got length "+str(len(_periodic))) + periodicity=np.zeros(3) + for i in range(3): + if _periodic[i] != 1: + raise ValueError("Until we can handle conditional compilation, only periodicity [1,1,1] is supported in python interface") + for i in range(3): + periodicity[i]=_periodic[i] + periodic=4*_periodic[2] + 2*_periodic[1] + _periodic[0] + # first 3 bits of periodic determine the periodicity + # until we can handle contitional compilatio, periodic=7 is the only value which makes sense + _espresso.mpi_bcast_parameter(FIELD_PERIODIC) + def __get__(self): + global periodic + periodicity=np.zeros(3) + periodicity[0]=periodic%2 + periodicity[1]=int(periodic/2)%2 + periodicity[2]=int(periodic/4)%2 + return periodicity + + property skin: + def __set__(self, double _skin): + if _skin <= 0: + raise ValueError("Skin must be >= 0") + global skin + skin=_skin + _espresso.mpi_bcast_parameter(FIELD_SKIN) + def __get__(self): + global skin + return skin + + property temperature: + def __get__(self): + global temperature + return temperature + + property thermo_switch: + def __get__(self): + global thermo_switch + return thermo_switch + + property time: + def __set__(self, double _time): + if _time <= 0: + raise ValueError("Simulation time must be >= 0") + global sim_time + sim_time=_time + _espresso.mpi_bcast_parameter(FIELD_SIMTIME) + def __get__(self): + global sim_time + return sim_time + + property time_step: + def __set__(self, double _time_step): + IF LB: + global lbpar + IF LB_GPU: + global lbpar_gpu + if _time_step <= 0: + raise ValueError("Time Step must be positive") + IF LB: + if lbpar.tau >= 0.0 and _time_step > lbpar.tau: + raise ValueError("Time Step must be > LB_time_step ("+str(lbpar.tau)+")") + IF LB_GPU: + if lbpar_gpu.tau >= 0.0 and _time_step > lbpar_gpu.tau: + raise ValueError("Time Step must be > LB_time_step ("+str(lbpar_gpu.tau)+")") + mpi_set_time_step(_time_step) + def __get__(self): + global time_step + return time_step + + property timings: + def __set__(self, int _timings): + global timing_samples + if _timings <= 0: + timing_samples=0 + else: + timing_samples=_timings + def __get__(self): + global timing_samples + return timing_samples + + property transfer_rate: + def __get__(self): + global transfer_rate + return transfer_rate + + property max_cut_nonbonded: + def __get__(self): + global max_cut_nonbonded + return max_cut_nonbonded + + property verlet_reuse: + def __get__(self): + global verlet_reuse + return verlet_reuse + + + property lattice_switch: + def __get__(self): + global lattice_switch + return lattice_switch + + property dpd_tgamma: + def __get__(self): + global dpd_tgamma + return dpd_tgamma + + property dpd_tr_cut: + def __get__(self): + global dpd_tr_cut + return dpd_tr_cut + + property dpd_twf: + def __get__(self): + global dpd_twf + return dpd_twf + + property dpd_wf: + def __get__(self): + global dpd_wf + return dpd_wf + + property adress_vars: + def __get__(self): + global adress_vars + return np.array( [ \ + adress_vars[0], \ + adress_vars[1], \ + adress_vars[2], \ + adress_vars[3], \ + adress_vars[4], \ + adress_vars[5], \ + adress_vars[6] \ + ]) + + property max_cut_bonded: + def __get__(self): + global max_cut_bonded + return max_cut_bonded + + +cdef extern from "global.hpp": + int FIELD_MAXNUMCELLS + int FIELD_MINNUMCELLS + int FIELD_NODEGRID + +cdef extern from "cells.hpp": + int CELL_STRUCTURE_CURRENT + int CELL_STRUCTURE_DOMDEC + int CELL_STRUCTURE_NSQUARE + int CELL_STRUCTURE_LAYERED + +cdef extern from "layered.hpp": + int determine_n_layers + int n_layers + int determine_n_layers + +cdef extern from "grid.hpp": + int node_grid[3] + +cdef extern from "communication.hpp": + void mpi_bcast_cell_structure(int cs) + +cdef extern from "domain_decomposition.hpp": + ctypedef struct IA_Neighbor: + pass + ctypedef struct IA_Neighbor_List: + pass + ctypedef struct DomainDecomposition: + int use_vList + int cell_grid[3] + double cell_size[3] + + extern DomainDecomposition dd + extern int max_num_cells + extern int min_num_cells + extern double max_skin + int calc_processor_min_num_cells() + +cdef class CellSystem: + cdef System system + + def __init__(self, system): + self.system = system + + property node_grid: + def __set__(self, _node_grid): + global node_grid + if len(_node_grid) != 3: + raise ValueError("node_grid must be of length 3") + for i in range(3): + if _node_grid[i] <= 0: + raise ValueError("node_grid must be > 0 in all directions") + node_grid[i]=_node_grid[i] + n_nodes = self.system.n_nodes + if _node_grid[0]*_node_grid[1]*_node_grid[2] != n_nodes: + raise ValueError("node_grid does not fit n_nodes ("+str(n_nodes)+")") + for i in range(3): + node_grid[i]=_node_grid[i] + _espresso.mpi_bcast_parameter(FIELD_NODEGRID) + def __get__(self): + return np.array([node_grid[0], node_grid[1], node_grid[2]]) + + property cell_grid: + def __get__(self): + return np.array( [ dd.cell_grid[0], dd.cell_grid[1], dd.cell_grid[2] ] ) + + property cell_size: + def __get__(self): + return np.array( [ dd.cell_size[0], dd.cell_size[1], dd.cell_size[2] ] ) + + property max_num_cells: + def __set__(self, int _max_num_cells): + global max_num_cells + if _max_num_cells < min_num_cells: + raise ValueError("max_num_cells must be >= min_num_cells (currently "+str(min_num_cells)+")") + max_num_cells=_max_num_cells + _espresso.mpi_bcast_parameter(FIELD_MAXNUMCELLS) + def __get__(self): + return max_num_cells + + property min_num_cells: + def __set__(self, int _min_num_cells): + global min_num_cells + min = calc_processor_min_num_cells() + if _min_num_cells < min: + raise ValueError("min_num_cells must be >= processor_min_num_cells (currently "+str(min)+")") + if _min_num_cells > max_num_cells: + raise ValueError("min_num_cells must be <= max_num_cells (currently "+str(max_num_cells)+")") + min_num_cells=_min_num_cells + _espresso.mpi_bcast_parameter(FIELD_MINNUMCELLS) + def __get__(self): + return min_num_cells + + def setDomainDecomposition(self, useVerletList=True): + useVerletList=bool(useVerletList) + + ### should work with global_variables.dd + if useVerletList: + dd.use_vList = 1 + else : + dd.use_vList = 0 + + # grid.h::node_grid + mpi_bcast_cell_structure(CELL_STRUCTURE_DOMDEC) + + # @TODO: gathering should be interface independent + # return mpi_gather_runtime_errors(interp, TCL_OK) + return True + + def setNsquare(self): + mpi_bcast_cell_structure(CELL_STRUCTURE_NSQUARE) + # @TODO: gathering should be interface independent + # return mpi_gather_runtime_errors(interp, TCL_OK) + return True + + def setLayered(self, nLayers=""): + if nLayers!="": + if not isinstance(nLayers, int): + raise ValueError("layer height should be positive") + global n_layers + n_layers=int(nLayers) + global determine_n_layers + determine_n_layers=0 + + if (node_grid[0] != 1 or node_grid[1] != 1): + node_grid[0] = node_grid[1] = 1 + node_grid[2] = self.system.n_nodes + err = _espresso.mpi_bcast_parameter(FIELD_NODEGRID) + else: + err = 0 + + if not err: + mpi_bcast_cell_structure(CELL_STRUCTURE_LAYERED) + + # @TODO: gathering should be interface independent + # return mpi_gather_runtime_errors(interp, TCL_OK) + return True + + +#lbfluid=lb.DeviceList() +IF CUDA == 1: + cu=cuda_init.CudaInitHandle() + diff --git a/src/python/espressomd/_tcl.pyx b/src/python/espressomd/_tcl.pyx new file mode 100644 index 00000000000..2930c5f8821 --- /dev/null +++ b/src/python/espressomd/_tcl.pyx @@ -0,0 +1,51 @@ +# +# Copyright (C) 2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "tcl.h": + cdef struct Tcl_Interp: + pass + + Tcl_Interp* Tcl_CreateInterp() + void Tcl_DeleteInterp(Tcl_Interp*) + int Tcl_Eval(Tcl_Interp * interp, char* script) + char* Tcl_GetStringResult(Tcl_Interp * interp) + +cdef extern from "tcl/initialize_interpreter.hpp": + int tcl_appinit(Tcl_Interp *interp) + +# Define Tcl interpreter +cdef class TclInterpreter: + cdef Tcl_Interp* interp + + def __init__(self): + self.interp = Tcl_CreateInterp() + self.eval('global argv; set argv ""') + self.eval('set tcl_interactive 0') + tcl_appinit(self.interp) + + def eval(self, string): + cdef const char* tclresult + result = Tcl_Eval(self.interp, string) + tclresult = Tcl_GetStringResult(self.interp) + if result: + raise Exception("Tcl reports an error", tclresult) + + return tclresult + + def __del__(self): + Tcl_DeleteInterp(self.interp) diff --git a/src/python/espressomd/analyze.pxd b/src/python/espressomd/analyze.pxd new file mode 100644 index 00000000000..76cdb2b522d --- /dev/null +++ b/src/python/espressomd/analyze.pxd @@ -0,0 +1,22 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# For C-extern Analysis + +cimport numpy as np +from utils cimport * diff --git a/src/python/espressomd/analyze.pyx b/src/python/espressomd/analyze.pyx new file mode 100644 index 00000000000..bc5ef625912 --- /dev/null +++ b/src/python/espressomd/analyze.pyx @@ -0,0 +1,173 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# For C-extern Analysis + +cimport c_analyze +cimport utils +cimport particle_data +import utils +import code_info +import particle_data + +# +# Minimal distance between particles +# +def mindist(system, p1 = 'default', p2 = 'default'): + + cdef IntList* set1 + cdef IntList* set2 + + if p1 == 'default' and p2 == 'default': + result = c_analyze.mindist(NULL,NULL) + elif p1 == 'default' and not p2 == 'default': + print 'usage: mindist([typelist],[typelist])' + return 0 + elif not p1 == 'default' and p2 == 'default': + print 'usage: mindist([typelist],[typelist])' + return 0 + else: + for i in range(len(p1)): + if not isinstance(p1[i],int): + print 'usage: mindist([typelist],[typelist])' + return 0 + + for i in range(len(p2)): + if not isinstance(p2[i],int): + print 'usage: mindist([typelist],[typelist])' + return 0 + + set1 = create_IntList_from_python_object(p1) + set2 = create_IntList_from_python_object(p2) + + result = c_analyze.mindist(set1, set2) + + realloc_intlist(set1, 0) + realloc_intlist(set2, 0) + +# The following lines are probably not necessary. +# free (set1) +# free (set2) + + return result + +# +# Distance to particle or point +# +def distto(system, id_or_pos): + cdef double cpos[3] + if system.n_part == 0: + print 'no particles' + return 'no particles' + + # check if id_or_pos is position or particle id + if isinstance(id_or_pos,int): + _id = id_or_pos + _pos = particle_data.ParticleHandle(id_or_pos).pos + for i in range(3): + cpos[i] = _pos[i] + else: + for i in range(3): + cpos[i] = id_or_pos[i] + _id = -1 + return c_analyze.distto(cpos,_id) + +# +# Energy analysis +# +def energy(system, etype = 'all', id1 = 'default', id2 = 'default'): + if system.n_part == 0: + print 'no particles' + return 'no particles' + + if c_analyze.total_energy.init_status == 0: + c_analyze.init_energies(&c_analyze.total_energy) + c_analyze.master_energy_calc() + _value = 0.0 + + if etype == 'all': + _result = energy(system, 'total') + ' ' + energy(system, 'kinetic') + _result += energy(system, 'nonbonded',0,0) + # todo: check for existing particle and bond types + # and add those to _result + return _result + + if etype == 'total': + if id1 != 'default' or id2 != 'default': + print ('warning: energy(\'total\') does not need ' + 'further arguments, ignored.') + for i in range(c_analyze.total_energy.data.n): + _value += c_analyze.total_energy.data.e[i] + return '{ energy: %f }' % _value + + if etype == 'kinetic': + if id1 != 'default' or id2 != 'default': + print ('warning: energy(\'kinetic\') does not need ' + 'further arguments, ignored.') + _value = c_analyze.total_energy.data.e[0] + return '{ kinetic: %f }' % _value + + # coulomb interaction + if etype == 'coulomb': + if(code_info.electrostatics_defined()): + for i in range(c_analyze.total_energy.n_coulomb): + _value += c_analyze.total_energy.coulomb[i] + return '{ coulomb: %f }' % _value + else: + print 'error: ELECTROSTATICS not compiled' + return 'error: ELECTROSTATICS not compiled' + + if etype == 'magnetic': + if(code_info.dipoles_defined()): + for i in range(c_analyze.total_energy.n_dipolar): + _value += c_analyze.total_energy.dipolar[i] + return '{ magnetic: %f }' % _value + else: + print 'error: DIPOLES not compiled' + return 'error: DIPOLES not compiled' + + # bonded interactions + if etype == 'bonded': + if not isinstance(id1, int): + print ('error: analyze.energy(\'bonded\',): ' + ' must be integer') + raise TypeError('analyze.energy(\'bonded\',): ' + ' must be integer') + else: + # todo: check if bond type id1 exist + _value = c_analyze.obsstat_bonded(&c_analyze.total_energy, id1)[0] + return '{ %d bonded: %f }' % (id1,_value) + + # nonbonded interactions + if etype == 'nonbonded': + if not isinstance(id1, int): + print ('error: analyze.energy(\'bonded\',): ' + ' must be integer') + raise TypeError('analyze.energy(\'bonded\',): ' + ' must be integer') + if not isinstance(id2, int): + print ('error: analyze.energy(\'bonded\',): ' + ' must be integer') + raise TypeError('analyze.energy(\'bonded\',): ' + ' must be integer') + else: + # todo: check if particle types id1 and id2 exist + _value = c_analyze.obsstat_nonbonded(&c_analyze.total_energy, id1, id2)[0] + return '{ %d %d nonbonded: %f }' % (id1,id2,_value) + + return 'error: unknown feature of analyze energy: \'%s\'' % etype diff --git a/src/python/espressomd/c_analyze.pxd b/src/python/espressomd/c_analyze.pxd new file mode 100644 index 00000000000..d1cc64b72b9 --- /dev/null +++ b/src/python/espressomd/c_analyze.pxd @@ -0,0 +1,47 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# For C-extern Analysis + +cimport numpy as np +from utils cimport * + +cdef extern from "statistics.hpp": + ctypedef struct Observable_stat: + int init_status + DoubleList data + int n_coulomb + int n_dipolar + int n_non_bonded + double *bonded + double *non_bonded + double *coulomb + double *dipolar + +cdef extern from "statistics.hpp": + cdef double mindist(IntList *set1, IntList *set2) + cdef double distto(double pos[3], int pid) + cdef double *obsstat_bonded(Observable_stat *stat, int j) + cdef double *obsstat_nonbonded(Observable_stat *stat, int i, int j) + +cdef extern from "energy.hpp": + cdef Observable_stat total_energy + +cdef extern from "energy.hpp": + cdef void master_energy_calc() + cdef void init_energies(Observable_stat *stat) diff --git a/src/python/espressomd/changeVolume.pxd b/src/python/espressomd/changeVolume.pxd new file mode 100644 index 00000000000..803b32f6cca --- /dev/null +++ b/src/python/espressomd/changeVolume.pxd @@ -0,0 +1,24 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "config.hpp": + pass + +cdef extern from "grid.hpp": + cdef void rescale_boxl(int dir, double d_new) + diff --git a/src/python/espressomd/changeVolume.pyx b/src/python/espressomd/changeVolume.pyx new file mode 100644 index 00000000000..47fa0044f55 --- /dev/null +++ b/src/python/espressomd/changeVolume.pyx @@ -0,0 +1,36 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +def changeVolume(dNew, dir="xyz"): + if dNew<0: + raise ValueError("No negative lengths") + if dir=="xyz": + dNew=dNew**(1./3.) + rescale_boxl(3, dNew) + elif dir=="x": + rescale_boxl(0, dNew) + elif dir=="y": + rescale_boxl(1, dNew) + elif dir=="z": + rescale_boxl(2, dNew) + else: + raise ValueError('Usage: changeVolume { | { "x" | "y" | "z" | "xyz" } }') + + + diff --git a/src/python/espressomd/code_info.pxd b/src/python/espressomd/code_info.pxd new file mode 100644 index 00000000000..5af4d5e4d58 --- /dev/null +++ b/src/python/espressomd/code_info.pxd @@ -0,0 +1,21 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +cdef extern from "config.hpp": + pass diff --git a/src/python/espressomd/code_info.pyx b/src/python/espressomd/code_info.pyx new file mode 100644 index 00000000000..b3b98eeae68 --- /dev/null +++ b/src/python/espressomd/code_info.pyx @@ -0,0 +1,42 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" + + +def features(): + """Returns list of compiled-in features""" + f=[] + IF ELECTROSTATICS == 1: + f.append("ELECTROSTATICS") + IF DIPOLES == 1: + f.append("DIPOLES") + IF LB_GPU == 1: + f.append("LB_GPU") + IF ROTATION == 1: + f.append("ROTATION") + IF MASS == 1 : + f.append("MASS") + IF VIRTUAL_SITES == 1: + f.append("VIRTUAL_SITES") + IF VIRTUAL_SITES_RELATIVE == 1: + f.append("VIRTUAL_SITES_RELATIVE") + + + return sorted(f) + diff --git a/src/python/espressomd/cuda_init.pxd b/src/python/espressomd/cuda_init.pxd new file mode 100644 index 00000000000..b3642d02aeb --- /dev/null +++ b/src/python/espressomd/cuda_init.pxd @@ -0,0 +1,22 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "cuda_init.hpp": + int cuda_set_device(int dev) + int cuda_get_device() +# int getdevicelist(int* devl, char* devname) diff --git a/src/python/espressomd/cuda_init.pyx b/src/python/espressomd/cuda_init.pyx new file mode 100644 index 00000000000..562ffff6cbc --- /dev/null +++ b/src/python/espressomd/cuda_init.pyx @@ -0,0 +1,49 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" +cimport cuda_init + +cdef class CudaInitHandle: + def __init__(self): + IF CUDA != 1: + raise Exception("Cuda is not compiled in") + + property device: + IF CUDA == 1: + def __set__(self, int _dev): + if cuda_set_device(_dev): + raise Exception("cuda device set error") + def __get__(self): + dev = cuda_get_device() + if dev == -1: + raise Exception("cuda device get error") + return dev + + # property device_list: + # IF CUDA == 1: + # def __set__(self, int _dev): + # raise Exception("cuda device list is read only") + # def __get__(self): + # cdef int _p_devl + # cdef char _devname[4+64] + # if getdevicelist(&_p_devl, _devname): + # raise Exception("cuda devicelist error") + # return _devname + + diff --git a/src/python/espressomd/debye_hueckel.pxd b/src/python/espressomd/debye_hueckel.pxd new file mode 100644 index 00000000000..282650dfb6d --- /dev/null +++ b/src/python/espressomd/debye_hueckel.pxd @@ -0,0 +1,32 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" + +cdef extern from "config.hpp": + pass + +IF ELECTROSTATICS ==1: + cdef extern from "debye_hueckel.hpp": + ctypedef struct Debye_hueckel_params: + double kappa + double r_cut + + Debye_hueckel_params dh_params + int dh_set_params(double kappa, double r_cut) + diff --git a/src/python/espressomd/debye_hueckel.pyx b/src/python/espressomd/debye_hueckel.pyx new file mode 100644 index 00000000000..94c41d61d43 --- /dev/null +++ b/src/python/espressomd/debye_hueckel.pyx @@ -0,0 +1,39 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" +IF ELECTROSTATICS==1: + def setParams(kappa, rCut): + if rCut<0: + raise ValueError("rCut must be > 0") + dh_set_params(kappa, rCut) + + def setRcut(rCut): + if rCut<0: + raise ValueError("rCut must be > 0") + dh_set_params(dh_params.kappa, rCut) + + def setKappa(kappa): + dh_set_params(kappa, dh_params.r_cut) + + def getRcut(): + return dh_params.r_cut + + def getKappa(): + return dh_params.kappa + diff --git a/src/python/espressomd/dummy.cpp b/src/python/espressomd/dummy.cpp new file mode 100644 index 00000000000..3a169db7fca --- /dev/null +++ b/src/python/espressomd/dummy.cpp @@ -0,0 +1,19 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +int main() {} diff --git a/src/python/espressomd/gen_pxiconfig.py b/src/python/espressomd/gen_pxiconfig.py new file mode 100644 index 00000000000..c8fb28548a2 --- /dev/null +++ b/src/python/espressomd/gen_pxiconfig.py @@ -0,0 +1,69 @@ +# Copyright (C) 2014 Olaf Lenz +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# This script generates gen_pxiconfig.cpp, which in turn generates myconfig.pxi. +# +from __future__ import print_function +import inspect, sys, os +# find featuredefs.py +moduledir = os.path.dirname(inspect.getfile(inspect.currentframe())) +sys.path.append(os.path.join(moduledir, '..', '..')) +import featuredefs + +if len(sys.argv) != 3: + print("Usage: {} DEFFILE CPPFILE".format(sys.argv[0]), file=sys.stderr) + exit(2) + +deffilename, cfilename = sys.argv[1:3] + +print("Reading definitions from " + deffilename + "...") +defs = featuredefs.defs(deffilename) +print("Done.") + +# generate cpp-file +print("Writing " + cfilename + "...") +cfile = open(cfilename, 'w'); + +cfile.write(""" +#include "config.hpp" +#include +using namespace std; +int main() { + +cout << "# This file was autogenerated." << endl + << "# Do not modify it or your changes will be overwritten!" << endl; + +""") + +template=""" +#ifdef {0} +cout << "DEF {0} = 1" << endl; +#else +cout << "DEF {0} = 0" << endl; +#endif +""" + +for feature in defs.allfeatures: + cfile.write(template.format(feature)) + +cfile.write(""" +} +""") + +cfile.close() +print("Done.") + diff --git a/src/python/espressomd/highlander.py b/src/python/espressomd/highlander.py new file mode 100644 index 00000000000..0e5635e8ebd --- /dev/null +++ b/src/python/espressomd/highlander.py @@ -0,0 +1,67 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +from functools import update_wrapper + +class ThereCanOnlyBeOne(BaseException): + def __init__(self, cls): + self._cls = cls + def __str__(self): + return "There can only be one instance of '{}' at any time.".format(self._cls) + +def highlander(klass): + klass.highlander_created = False + + def cls_init(self, *args, **kwargs): + "__init__ method by the highlander decorator." + if self.__class__.highlander_created: + raise ThereCanOnlyBeOne(self.__class__) + self.__class__.highlander_created = True + def cls_init_call_orig(self, *args, **kwargs): + if self.__class__.highlander_created: + raise ThereCanOnlyBeOne(self.__class__) + self.__class__.highlander_created = True + self.__class__.__init_orig__(self, *args, **kwargs) + + # override the __init__ method of the class to store the bool + # "highlander_created" + if hasattr(klass, '__init__'): + klass.__init_orig__ = klass.__init__ + klass.__init__ = cls_init_call_orig + update_wrapper(cls_init_call_orig, klass.__init_orig__) + else: + klass.__init__ = cls_init + + # override the __del__ method of the class + def cls_del(self): + "__del__ method by the highlander decorator." + self.__class__.highlander_created = False + def cls_del_call_orig(self): + cls_del(self) + self.__class__.__del_orig__(self) + + if hasattr(klass, '__del__'): + klass.__del_orig__ = klass.__del__ + klass.__del__ = cls_del_call_orig + update_wrapper(cls_del_call_orig, klass.__del_orig__) + else: + klass.__del__ = cls_del + + return klass + + diff --git a/src/python/espressomd/integrate.pxd b/src/python/espressomd/integrate.pxd new file mode 100644 index 00000000000..3d4721d9f69 --- /dev/null +++ b/src/python/espressomd/integrate.pxd @@ -0,0 +1,23 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "config.hpp": + pass + +cdef extern from "integrate.hpp": + cdef void integrate_vv(int n_steps, int reuse_forces) diff --git a/src/python/espressomd/integrate.pyx b/src/python/espressomd/integrate.pyx new file mode 100644 index 00000000000..9e4baf1a073 --- /dev/null +++ b/src/python/espressomd/integrate.pyx @@ -0,0 +1,21 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +def integrate(nSteps): + integrate_vv(nSteps, 0) + diff --git a/src/python/espressomd/interactions.pxd b/src/python/espressomd/interactions.pxd new file mode 100644 index 00000000000..223efb79b5f --- /dev/null +++ b/src/python/espressomd/interactions.pxd @@ -0,0 +1,242 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Handling of interactions + +cimport numpy as np +from utils cimport * + +cdef extern from "interaction_data.hpp": + ctypedef struct IA_parameters: + double LJ_eps + double LJ_sig + double LJ_cut + double LJ_shift + double LJ_offset + double LJ_capradius + double LJ_min + + cdef IA_parameters *get_ia_param(int i, int j) + +cdef extern from "lj.hpp": + cdef int lennard_jones_set_params(int part_type_a, int part_type_b, + double eps, double sig, double cut, + double shift, double offset, + double cap_radius, double min) + + + + +cdef extern from "forcecap.hpp": + double force_cap + int forcecap_set_params(double forcecap) + + + + +cdef extern from "interaction_data.hpp": + ctypedef struct Fene_bond_parameters: + double k + double drmax + double r0 + double drmax2 + double drmax2i + + + +#* Parameters for hyperelastic stretching_force */ + ctypedef struct Stretching_force_bond_parameters: + double r0 + double ks + + +#* Parameters for linear stretching_force */ + ctypedef struct Stretchlin_force_bond_parameters: + double r0 + double kslin + + +#* Parameters for area_force_local */ + ctypedef struct Area_force_local_bond_parameters: + double A0_l + double ka_l + + +#* Parameters for area_force_global */ + ctypedef struct Area_force_global_bond_parameters: + double A0_g + double ka_g + + +#* Parameters for bending_force */ + ctypedef struct Bending_force_bond_parameters: + double phi0 + double kb + + +#* Parameters for volume_force */ + ctypedef struct Volume_force_bond_parameters: + double V0 + double kv + + + +#* Parameters for harmonic bond Potential */ + ctypedef struct Harmonic_bond_parameters: + double k + double r + double r_cut + +#* Parameters for three body angular potential (bond-angle potentials). + ctypedef struct Angle_bond_parameters: + double bend + double phi0 + double cos_phi0 + double sin_phi0 + +#* Parameters for three body angular potential (bond_angle_harmonic). + ctypedef struct Angle_harmonic_bond_parameters: + double bend + double phi0 + + + + + +#* Parameters for three body angular potential (bond_angle_cosine). + ctypedef struct Angle_cosine_bond_parameters: + double bend + double phi0 + double cos_phi0 + double sin_phi0 + + + +#* Parameters for three body angular potential (bond_angle_cossquare). + ctypedef struct Angle_cossquare_bond_parameters: + double bend + double phi0 + double cos_phi0 + +#* Parameters for four body angular potential (dihedral-angle potentials). */ + ctypedef struct Dihedral_bond_parameters: + double mult + double bend + double phase + + +#* Parameters for n-body tabulated potential (n=2,3,4). */ + ctypedef struct Tabulated_bond_parameters: + char *filename + int type + int npoints + double minval + double maxval + double invstepsize + double *f + double *e + +#* Parameters for n-body overlapped potential (n=2,3,4). */ + ctypedef struct Overlap_bond_parameters: + char *filename + int type + double maxval + int noverlaps + double *para_a + double *para_b + double *para_c + + +#* Dummy parameters for -LJ Potential */ + ctypedef struct Subt_lj_bond_parameters: + double k + double r + double r2 + + + +#*Parameters for the rigid_bond/SHAKE/RATTLE ALGORITHM*/ + ctypedef struct Rigid_bond_parameters: + #*Length of rigid bond/Constrained Bond*/ + #double d + #*Square of the length of Constrained Bond*/ + double d2 + #*Positional Tolerance/Accuracy value for termination of RATTLE/SHAKE iterations during position corrections*/ + double p_tol + #*Velocity Tolerance/Accuracy for termination of RATTLE/SHAKE iterations during velocity corrections */ + double v_tol + + + +#* Parameters for three body angular potential (bond-angle potentials) that + ctypedef struct Angledist_bond_parameters: + double bend + double phimin + double distmin + double phimax + double distmax + double cos_phi0 + double sin_phi0 + + + +#* Parameters for chainend angular potential with wall */ + ctypedef struct Endangledist_bond_parameters: + double bend + double phi0 + double distmin + double distmax + +#* Union in which to store the parameters of an individual bonded interaction */ + ctypedef union Bond_parameters: + Fene_bond_parameters fene + Stretchlin_force_bond_parameters stretchlin_force + Stretching_force_bond_parameters stretching_force + Area_force_local_bond_parameters area_force_local + Area_force_global_bond_parameters area_force_global + Bending_force_bond_parameters bending_force + Volume_force_bond_parameters volume_force + Harmonic_bond_parameters harmonic + Angle_bond_parameters angle + Angle_harmonic_bond_parameters angle_harmonic + Angle_cosine_bond_parameters angle_cosine + Angle_cossquare_bond_parameters angle_cossquare + Dihedral_bond_parameters dihedral + Tabulated_bond_parameters tab + Overlap_bond_parameters overlap + Subt_lj_bond_parameters subt_lj + Rigid_bond_parameters rigid_bond + Angledist_bond_parameters angledist + Endangledist_bond_parameters endangledist + + + + + ctypedef struct Bonded_ia_parameters: + int type + int num + #* union to store the different bonded interaction parameters. */ + Bond_parameters p + + Bonded_ia_parameters* bonded_ia_params + cdef int n_bonded_ia + +cdef extern from "fene.hpp": + int fene_set_params(int bond_type, double k, double drmax, double r0) +cdef extern from "harmonic.hpp": + int harmonic_set_params(int bond_type, double k, double r,double r_cut) diff --git a/src/python/espressomd/interactions.pyx b/src/python/espressomd/interactions.pyx new file mode 100644 index 00000000000..f9fd77971be --- /dev/null +++ b/src/python/espressomd/interactions.pyx @@ -0,0 +1,455 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" +# Non-bonded interactions + +cdef class NonBondedInteraction(object): + + cdef public object _partTypes + cdef object _params + + def __init__(self, *args, **kwargs): + """Represents an instance of a non-bonded interaction, such as lennard jones + Either called with two particle type id, in which case, the interaction + will represent the bonded interaction as it is defined in Espresso core + Or called with keyword arguments describing a new interaction.""" + + + # Interaction id as argument + if len(args)==2 and isinstance(args[0],int) and isinstance(args[1],int): + self._partTypes=args + + # Load the parameters currently set in the Espresso core + self._params=self._getParamsFromEsCore() + + # Or have we been called with keyword args describing the interaction + elif len(args)==0: + # Initialize default values + self._params=self.defaultParams() + self._partTypes=[-1,-1] + + # Check if all required keys are given + for k in self.requiredKeys(): + if k not in kwargs: + raise ValueError("At least the following keys have to be given as keyword arguments: "+self.requiredKeys().__str__()) + + self._params = kwargs + + # Validation of parameters + self.validateParams() + + else: + raise Exception("The constructor has to be called either with two particle type ids (as interger), or with a set of keyword arguments describing a new interaction") + + + + + + + def isValid(self): + """Check, if the data stored in the instance still matches what is in Espresso""" + + # check, if the bond parameters saved in the class still match those saved in Espresso + tempParams =self._getParamsFromEsCore() + if self._params != tempParams: + return False + + # If we're still here, the instance is valid + return True + + + def getParams(self): + """Get interaction parameters""" + # If this instance refers to an actual interaction defined in the es core, load + # current parameters from there + if self._partTypes[0]>=0 and self._partTypes[1]>=0: + self._params=self._getParamsFromEsCore() + + return self._params + + def setParams(self,**p): + """Update parameters. Only given """ + # Check, if any key was passed, which is not known + for k in p.keys(): + if k not in self.validKeys(): + raise ValueError("Only the following keys are supported: "+self.validKeys().__str__()) + + # When an interaction is newly activated, all required keys must be given + if not self.isActive(): + for k in self.requiredKeys(): + if k not in p: + raise ValueError("At least the following keys have to be given as keyword arguments: "+self.requiredKeys().__str__()) + + # If this instance refers to an interaction defined in the espresso core, + # load the parameters from there + + if self._partTypes[0]>=0 and self._partTypes[1]>=0: + self._params=self._getParamsFromEsCore() + + # Put in values given by the user + self._params.update(p) + + if self._partTypes[0]>=0 and self._partTypes[1]>=0: + self._setParamsInEsCore() + + def validateParams(self): + return True + + def _getParamsFromEsCore(self): + raise Exception("Subclasses of NonBondedInteraction must define the _getParamsFromEsCore() method.") + + def _setParamsInEsCore(self): + raise Exception("Subclasses of NonBondedInteraction must define the setParamsFromEsCore() method.") + + def defaultParams(self): + raise Exception("Subclasses of NonBondedInteraction must define the defaultParams() method.") + + def isActive(self): + # If this instance refers to an actual interaction defined in the es core, load + # current parameters from there + if self._partTypes[0]>=0 and self._partTypes[1]>=0: + self._params=self._getParamsFromEsCore() + raise Exception("Subclasses of NonBondedInteraction must define the isActive() method.") + + + def typeName(self): + raise Exception("Subclasses of NonBondedInteraction must define the typeName() method.") + + def validKeys(self): + raise Exception("Subclasses of NonBondedInteraction must define the validKeys() method.") + + def requiredKeys(self): + raise Exception("Subclasses of NonBondedInteraction must define the requiredKeys() method.") + +# Lennard Jones + +cdef class LennardJonesInteraction(NonBondedInteraction): + if LENNARD_JONES == 1: + def validateParams(self): + if self._params["epsilon"]<0: + raise ValueError("Lennard-Jones eps has to be >=0") + if self._params["sigma"]<0: + raise ValueError("Lennard-Jones sigma has to be >=0") + if self._params["cutoff"]<0: + raise ValueError("Lennard-Jones cutoff has to be >=0") + return True + + def _getParamsFromEsCore(self): + cdef IA_parameters* iaParams + iaParams = get_ia_param(self._partTypes[0],self._partTypes[1]) + return { \ + "epsilon": iaParams.LJ_eps, \ + "sigma": iaParams.LJ_sig, \ + "cutoff": iaParams.LJ_cut, \ + "shift": iaParams.LJ_shift, \ + "offset": iaParams.LJ_offset, \ + "min": iaParams.LJ_min } + + + def isActive(self): + return (self._params["epsilon"] >0) + + def _setParamsInEsCore(self): + # Handle the case of shift="auto" + if self._params["shift"]=="auto": + # Calc shift + self._params["shift"]= -( (self._params["sigma"]/self._params["cutoff"])**12 - (self._params["sigma"]/self._params["cutoff"])**6 ) + + if lennard_jones_set_params(self._partTypes[0],self._partTypes[1],\ + self._params["epsilon"], \ + self._params["sigma"], \ + self._params["cutoff"], \ + self._params["shift"], \ + self._params["offset"], \ + 0.0, \ + self._params["min"]): + raise Exception("Could not set Lennard Jones parameters") + + def defaultParams(self): + self._params={\ + "epsilon":0.,\ + "sigma":0.,\ + "cutoff":0.,\ + "shift":0.,\ + "offset":0.,\ + "min":0.} + + def typeName(self): + return "LennardJones" + + def validKeys(self): + return "epsilon","sigma","cutoff","shift","offset","min" + + def requiredKeys(self): + return "epsilon","sigma","cutoff","shift" + + +class NonBondedInteractionHandle(object): + """Provides access to all Non-bonded interactions between + two particle types.""" + + type1=-1 + type2=-1 + + # Here, one line per non-bonded ia + lennardJones=None + + + def __init__(self, _type1, _type2): + """Takes two particle types as argument""" + if not (isinstance(_type1,int) and isinstance(_type2,int)): + raise TypeError("The particle types have to be of type integer.") + self.type1=_type1 + self.type2=_type2 + + + # Here, add one line for each nonbonded ia + self.lennardJones =LennardJonesInteraction(_type1,_type2) + + + + + +cdef class NonBondedInteractions: + """Access to non-bonded interaction parameters via [i,j], where i,j are particle + types. Returns NonBondedInteractionHandle. + Also: access to force capping + """ + def __getitem__(self,key): + if not isinstance(key,tuple): + raise ValueError("NonBondedInteractions[] expects two particle types as indices.") + if len(key) != 2 or (not isinstance(key[0],int)) or (not isinstance(key[1],int)): + raise ValueError("NonBondedInteractions[] expects two particle types as indices.") + return NonBondedInteractionHandle(key[0],key[1]) + + def setForceCap(self,cap): + if forcecap_set_params(cap): + raise Exception("Could not set forcecap") + + def getForceCap(self): + return force_cap + + + + + + +cdef class BondedInteraction(object): + def __init__(self, *args, **kwargs): + """Either called with an interaction id, in which case, the interaction will represent + the bonded interaction as it is defined in Espresso core + Or called with keyword arguments describing a new interaction.""" + # Interaction id as argument + if len(args)==1 and isinstance(args[0],int): + bondId=args[0] + # Check, if the bond in Espresso core is really defined as a FENE bond + if bonded_ia_params[bondId].type != self.typeNumber(): + raise Exception("The bond with this id is not defined as a "+self.typeName()+" bond in the Espresso core.") + + self._bondId=bondId + # Load the parameters currently set in the Espresso core + self._params=self._getParamsFromEsCore() + self._bondId=bondId + + # Or have we been called with keyword args describing the interaction + elif len(args)==0: + # Check if all required keys are given + for k in self.requiredKeys(): + if k not in kwargs: + raise ValueError("At least the following keys have to be given as keyword arguments: "+self.requiredKeys().__str__()) + + self.params = kwargs + + # Validation of parameters + self.validateParams() + + else: + raise Exception("The constructor has to be called either with a bond id (as interger), or with a set of keyword arguments describing a new interaction") + + + + + + + def isValid(self): + """Check, if the data stored in the instance still matches what is in Espresso""" + # Check if the bond type in Espresso still matches the bond type saved in this class + if bonded_ia_params[self._bondId].type != self.typeNumber(): + return False + + # check, if the bond parameters saved in the class still match those saved in Espresso + tempParams =self._getParamsFromEsCore() + if self._params != tempParams: + return False + + # If we're still here, the instance is valid + return True + + + property params: + def __get__(self): + return self._params + + def __set__(self,p): + # Check, if any key was passed, which is not known + for k in p.keys(): + if k not in self.validKeys(): + raise ValueError("Only the following keys are supported: "+self.validKeys().__str__) + + # Initialize default values + self.setDefaultParams() + # Put in values given by the user + self._params.update(p) + + def validateParams(self): + return True + + def _getParamsFromEsCore(self): + raise Exception("Subclasses of BondedInteraction must define the _getParamsFromEsCore() method.") + + def _setParamsInEsCore(self): + raise Exception("Subclasses of BondedInteraction must define the setParamsFromEsCore() method.") + + def setDefaultParams(self): + raise Exception("Subclasses of BondedInteraction must define the setDefaultParams() method.") + + def typeNumber(self): + raise Exception("Subclasses of BondedInteraction must define the typeNumber() method.") + + + def typeName(self): + raise Exception("Subclasses of BondedInteraction must define the typeName() method.") + + def validKeys(self): + raise Exception("Subclasses of BondedInteraction must define the validKeys() method.") + + def requiredKeys(self): + raise Exception("Subclasses of BondedInteraction must define the requiredKeys() method.") + + + + + +# Fene bond + +class FeneBond(BondedInteraction): + + def typeNumber(self): + return 0 + + def typeName(self): + return "FENE" + + def validKeys(self): + return "k","d_r_max","r_0" + + def requiredKeys(self): + return "k","d_r_max" + + def setDefaultParams(self): + self._params = {"r_0":0.} + # Everything else has to be supplied by the user, anyway + + def _getParamsFromEsCore(self): + return \ + {"k":bonded_ia_params[self._bondId].p.fene.k,\ + "d_r_max":bonded_ia_params[self._bondId].p.fene.drmax,\ + "r_0":bonded_ia_params[self._bondId].p.fene.r0} + + def _setParamsInEsCore(self): + fene_set_params(self._bondId,self._params["k"],self._params["d_r_max"],self._params["r_0"]) + +class HarmonicBond(BondedInteraction): + def typeNumber(self): + return 1 + + def typeName(self): + return "HARMONIC" + + def validKeys(self): + return "k","r_0","r_cut" + + def requiredKeys(self): + return "k","r_0" + + def setDefaultParams(self): + self._params = {"k'":0.,"r_0":0.,"r_cut":0.} + + def _getParamsFromEsCore(self): + return \ + {"k":bonded_ia_params[self._bondId].p.harmonic.k,\ + "r_0":bonded_ia_params[self._bondId].p.harmonic.r,\ + "r_cut":bonded_ia_params[self._bondId].p.harmonic.r_cut} + + def _setParamsInEsCore(self): + harmonic_set_params(self._bondId,self._params["k"],self._params["r_0"],self._params["r_cut"]) + + + + +bondedInteractionClasses = {0:FeneBond, 1:HarmonicBond} + + + + + + +class BondedInteractions: + """Represents the non-bonded interactions. Individual interactions can be accessed using + NonBondedInteractions[i], where i is the bond id. Will return an instance o + BondedInteractionHandle""" + def __getitem__(self, key): + if not isinstance(key,int): + raise ValueError("Index to BondedInteractions[] hast to ba an integer referring to a bond id") + + # Find out the type of the interaction from Espresso + bondType = bonded_ia_params[key].type + + # Check if the bonded interaction exists in Espresso core + if bondType == -1: + raise ValueError("The bonded interaction with the id "+str(key)+" is not yet defined.") + + # Find the appropriate class representing such a bond + bondClass =bondedInteractionClasses[bondType] + + # And return an instance of it, which refers to the bonded interaction id in Espresso + return bondClass(key) + + def __setitem__(self,key,value): + # Validate arguments + + # type of key must be int + if not isinstance(key,int): + raise ValueError("Index to BondedInteractions[] has to ba an integer referring to a bond id") + + # Value must be subclass off BondedInteraction + if not isinstance(value,BondedInteraction): + raise ValueError("Only subclasses of BondedInteraction can be assigned.") + + # Save the bond id in the BondedInteraction instance + value._bondId=key + + # Set the parameters of the BondedInteraction instance in the Es core + value._setParamsInEsCore() + + + + + + diff --git a/src/python/espressomd/invalidateSystem.pxd b/src/python/espressomd/invalidateSystem.pxd new file mode 100644 index 00000000000..eacb0ddc8d5 --- /dev/null +++ b/src/python/espressomd/invalidateSystem.pxd @@ -0,0 +1,20 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "config.hpp": + pass diff --git a/src/python/espressomd/invalidateSystem.pyx b/src/python/espressomd/invalidateSystem.pyx new file mode 100644 index 00000000000..5f3f914206e --- /dev/null +++ b/src/python/espressomd/invalidateSystem.pyx @@ -0,0 +1,20 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +def invalidateSystem(): + pass diff --git a/src/python/espressomd/lb.pxd b/src/python/espressomd/lb.pxd new file mode 100644 index 00000000000..8c23c9f94b0 --- /dev/null +++ b/src/python/espressomd/lb.pxd @@ -0,0 +1,56 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" + + + +IF LB_GPU==1: + + + cdef extern from "../src/config.hpp": + pass + + #cdef extern from "../src/lattice.hpp": + # int lattice_switch + + cdef extern from "lb.hpp": + int lb_lbfluid_set_tau(double p_tau) + int lb_lbfluid_set_density(double p_dens) + int lb_lbfluid_get_density(double* p_dens) + int lb_lbfluid_set_visc(double p_visc) + int lb_lbfluid_get_visc(double* p_visc) + int lb_lbfluid_set_agrid(double p_agrid) + int lb_lbfluid_get_agrid(double* p_agrid) + int lb_lbfluid_set_friction(double friction) + int lb_lbfluid_get_friction(double* p_friction) + int lb_lbfluid_set_gamma_odd(double p_gamma_odd) + int lb_lbfluid_get_gamma_odd(double* p_gamma_odd) + int lb_lbfluid_set_gamma_even(double p_gamma_even) + int lb_lbfluid_get_gamma_even(double* p_gamma_even) + int lb_lbfluid_set_ext_force(double p_fx, double p_fy, double p_fz) + int lb_lbfluid_get_ext_force(double* p_fx, double* p_fy, double* p_fz) + int lb_lbfluid_set_bulk_visc(double p_bulk_visc) + int lb_lbfluid_get_bulk_visc(double* p_bulk_visc) + int lb_lbfluid_print_vtk_velocity(char* filename) + int lb_lbfluid_print_vtk_boundary(char* filename) + int lb_lbfluid_print_velocity(char* filename) + int lb_lbfluid_print_boundary(char* filename) + int lb_lbfluid_save_checkpoint(char* filename, int binary) + int lb_lbfluid_load_checkpoint(char* filename, int binary) + void cython_lb_init(int switch) diff --git a/src/python/espressomd/lb.pyx b/src/python/espressomd/lb.pyx new file mode 100644 index 00000000000..9f43f193575 --- /dev/null +++ b/src/python/espressomd/lb.pyx @@ -0,0 +1,167 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" + +IF LB_GPU ==1: + #cimport global_variables + import numpy as np + cimport lb + + cdef class LBparaHandle: + cdef int switch + cdef int checkpoint_binary + cdef char* checkpoint_filename + + def __init__(self, _dev): + if _dev == "gpu" : + switch=1 + cython_lb_init(switch) + else: + switch=0 + cython_lb_init(switch) + + property tau: + def __set__(self, double p_tau): + if lb_lbfluid_set_tau(p_tau): + raise Exception("lb_lbfluid_set_tau error") + def __get__(self): + raise Exception("get friction c function not implemented in lb.c") + + property dens: + def __set__(self, double p_dens): + if lb_lbfluid_set_density(p_dens): + raise Exception("lb_lbfluid_set_density error") + def __get__(self): + cdef double _p_dens + if lb_lbfluid_get_density(&_p_dens): + raise Exception("lb_lbfluid_get_density error") + return _p_dens + + property visc: + def __set__(self, _visc): + if lb_lbfluid_set_visc(_visc): + raise Exception("lb_lbfluid_set_visc error") + def __get__(self): + cdef double _p_visc + if lb_lbfluid_get_visc(&_p_visc): + raise Exception("lb_lbfluid_get_visc error") + return _p_visc + + property agrid: + def __set__(self, double _agrid): + if lb_lbfluid_set_agrid(_agrid): + raise Exception("lb_lbfluid_set_agrid error") + def __get__(self): + cdef double _p_agrid + if lb_lbfluid_get_agrid(&_p_agrid): + raise Exception("lb_lbfluid_get_agrid error") + return _p_agrid + + property friction: + def __set__(self, double _friction): + IF LB == 1: + if lb_lbfluid_set_friction(_friction): + raise Exception("lb_lbfluid_set_friction error") + ELSE: + pass + def __get__(self): + cdef double _p_friction + raise Exception("get friction c function not implemented in lb.c") + #return lb_lbfluid_get_friction(&_p_friction) + + property gamma_odd: + def __set__(self, double _gamma_odd): + if lb_lbfluid_set_gamma_odd(_gamma_odd): + raise Exception("lb_lbfluid_set_gamma_odd error") + def __get__(self): + cdef double _p_gamma_odd + if lb_lbfluid_get_gamma_odd(&_p_gamma_odd): + raise Exception("lb_lbfluid_get_gamma_odd error") + return _p_gamma_odd + + property gamma_even: + def __set__(self, double _gamma_even): + if lb_lbfluid_set_gamma_even(_gamma_even): + raise Exception("lb_lbfluid_set_gamma_even error") + def __get__(self): + cdef double _p_gamma_even + if lb_lbfluid_get_gamma_even(&_p_gamma_even): + raise Exception("lb_lbfluid_get_gamma_even error") + return _p_gamma_even + + property ext_force: + def __set__(self, _ext_force): + if lb_lbfluid_set_ext_force(_ext_force[0], _ext_force[1], _ext_force[2]): + raise Exception("lb_lbfluid_set_ext_force error") + def __get__(self): + cdef double _p_ext_force[3] + if lb_lbfluid_get_ext_force(&_p_ext_force[0], &_p_ext_force[1], &_p_ext_force[2]): + raise Exception("lb_lbfluid_get_ext_force error") + return np.array([_p_ext_force[0], _p_ext_force[1], _p_ext_force[2]]) + + property bulk_visc: + def __set__(self, double _bulk_visc): + if lb_lbfluid_set_bulk_visc(_bulk_visc): + raise Exception("lb_lbfluid_set_bulk_visc error") + def __get__(self): + cdef double _p_bulk_visc + if lb_lbfluid_get_bulk_visc(&_p_bulk_visc): + raise Exception("lb_lbfluid_get_bulk_visc error") + return _p_bulk_visc + + property print_vtk_velocity: + def __set__(self, char* _filename): + if lb_lbfluid_print_vtk_velocity(_filename): + raise Exception("lb_lbfluid_print_vtk_velocity error") + + property print_vtk_boundary: + def __set__(self, char* _filename): + if lb_lbfluid_print_vtk_boundary(_filename): + raise Exception("lb_lbfluid_print_vtk_boundary error") + + property print_velocity: + def __set__(self, char* _filename): + if lb_lbfluid_print_velocity(_filename): + raise Exception("lb_lbfluid_print_vtk_velocity error") + + property print_boundary: + def __set__(self, char* _filename): + if lb_lbfluid_print_boundary(_filename): + raise Exception("lb_lbfluid_print_vtk_boundary error") + + property checkpoint: + def __set__(self, char* checkpoint_filename): + self.checkpoint_filename=checkpoint_filename + if lb_lbfluid_save_checkpoint(checkpoint_filename, self.checkpoint_binary): + raise Exception("lb_lbfluid_save_checkpoint error") + def __get__(self): + if lb_lbfluid_load_checkpoint(self.checkpoint_filename, self.checkpoint_binary): + raise Exception("lb_lbfluid_load_checkpoint error") + + property checkpoint_style: + def __set__(self, int _binary): + self.checkpoint_binary=_binary + def __get__(self): + return self.checkpoint_binary + + class DeviceList: + def __getitem__(self, _dev): + return LBparaHandle(_dev) + + diff --git a/src/python/espressomd/particle_data.pxd b/src/python/espressomd/particle_data.pxd new file mode 100644 index 00000000000..b67af8355fc --- /dev/null +++ b/src/python/espressomd/particle_data.pxd @@ -0,0 +1,186 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +## Here we create something to handle particles +cimport numpy as np +from utils cimport * + +include "myconfig.pxi" + +# Import particle data structures and setter functions from particle_data.hpp + +cdef extern from "particle_data.hpp": + + # DATA STRUCTURES + + # Note: Conditional compilation is not possible within ctypedef blocks. + # Therefore, only member variables are imported here, which are always compiled into Espresso. + # For all other properties, getter-funcionts have to be used on the c level. + + ctypedef struct ParticleProperties: + int identity + int mol_id + int type + + ctypedef struct ParticlePosition: + double p[3] + + + ctypedef struct ParticleForce: + double f[3] + + ctypedef struct ParticleMomentum: + double v[3] + + ctypedef struct ParticleLocal: + pass + + + ctypedef struct Particle: + ParticleProperties p + ParticlePosition r + ParticleMomentum m + ParticleForce f + ParticleLocal l + IntList bl + + + # Setter/getter/modifier functions functions + + int get_particle_data(int part, Particle *data) + + int place_particle(int part, double p[3]) + + int set_particle_v(int part, double v[3]) + + + int set_particle_f(int part, double F[3]) + + int set_particle_mass(int part, double mass) + + int set_particle_solvation(int part, double* solvation) + + + IF ROTATIONAL_INERTIA == 1: + int set_particle_rotational_inertia(int part, double rinertia[3]) + + IF ROTATION_PER_PARTICLE == 1: + int set_particle_rotation(int part, int rot) + + + int set_particle_q(int part, double q) + + int set_particle_mu_E(int part, double mu_E[3]) + + int set_particle_type(int part, int type) + + int set_particle_mol_id(int part, int mid) + + IF ROTATION == 1: + int set_particle_quat(int part, double quat[4]) + +# int set_particle_quatu(int part, double quat[4]) + + int set_particle_omega_lab(int part, double omega[3]) + + int set_particle_omega_body(int part, double omega[3]) + + int set_particle_torque_lab(int part, double torque[3]) + + int set_particle_torque_body(int part, double torque[3]) + + void pointer_to_omega_body(Particle* p, double*& res) + + void pointer_to_torque_lab(Particle* p, double*& res) + + + void pointer_to_quatu(Particle* p, double*& res) + void pointer_to_quat(Particle* p, double*& res) + + IF MASS == 1: + void pointer_to_mass(Particle* p, double*& res) + + IF DIPOLES == 1: + int set_particle_dip(int part, double dip[3]) + + int set_particle_dipm(int part, double dipm) + + IF VIRTUAL_SITES == 1: + int set_particle_virtual(int part,int isVirtual) + + IF LANGEVIN_PER_PARTICLE == 1: + int set_particle_temperature(int part, double T) + + int set_particle_gamma(int part, double gamma) + IF DIPOLES ==1: + void pointer_to_dip(Particle* P, double*& res) + void pointer_to_dipm(Particle* P, double*& res) + + IF VIRTUAL_SITES == 1: + void pointer_to_virtual(Particle* P, int*& res) + + IF VIRTUAL_SITES_RELATIVE == 1: + void pointer_to_vs_relative(Particle* P, int*& res1, double*& res2) + + IF ELECTROSTATICS == 1: + void pointer_to_q(Particle* P, double*& res) + + IF EXTERNAL_FORCES == 1: + IF ROTATION == 1: + int set_particle_ext_torque(int part, int flag, double torque[3]) + int set_particle_ext_force(int part, int flag, double force[3]) + int set_particle_fix(int part, int flag) + + int change_particle_bond(int part, int *bond, int _delete) + + IF EXCLUSIONS == 1: + int change_exclusion(int part, int part2, int _delete) + + void remove_all_exclusions() + + + int remove_particle(int part) + + void remove_all_particles() + + void remove_all_bonds_to(int part) + +cdef extern from "virtual_sites_relative.hpp": + IF VIRTUAL_SITES_RELATIVE == 1: + int vs_relate_to(int part_num, int relate_to) + int set_particle_vs_relative(int part, int vs_relative_to, double vs_distance) + +cdef extern from "rotation.hpp": + void convert_omega_body_to_space(Particle *p, double *omega) + void convert_torques_body_to_space(Particle *p, double *torque) + +# The bonded_ia_params stuff has to be included here, because the setter/getter +# of the particles' bond property needs to now about the correct number of bond partners +cdef extern from "interaction_data.hpp": + ctypedef struct Bonded_ia_parameters: + int num + pass + Bonded_ia_parameters* bonded_ia_params + cdef int n_bonded_ia + +cdef class ParticleHandle(object): + cdef public int id + cdef bint valid + cdef Particle particleData + cdef int updateParticleData(self) + diff --git a/src/python/espressomd/particle_data.pyx b/src/python/espressomd/particle_data.pyx new file mode 100644 index 00000000000..94b5cfe367d --- /dev/null +++ b/src/python/espressomd/particle_data.pyx @@ -0,0 +1,431 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +include "myconfig.pxi" +cimport numpy as np +import numpy as np +cimport utils +from utils cimport * +cimport particle_data + +cdef class ParticleHandle: + def __cinit__(self, _id): +# utils.init_intlist(self.particleData.el) + utils.init_intlist(&(self.particleData.bl)) + self.id=_id + + cdef int updateParticleData(self) except -1: +# utils.realloc_intlist(self.particleData.el, 0) + utils.realloc_intlist(&(self.particleData.bl), 0) + + if get_particle_data(self.id, &self.particleData): + raise Exception("Error updating particle data") + else: + return 0 + + + # The individual attributes of a particle are implemented as properties. + + # Particle Type + property type: + """Particle type""" + def __set__(self, _type): + if isinstance(_type, int) and _type >=0: + if set_particle_type(self.id, _type) == 1: + raise Exception("set particle position first") + else: + raise ValueError("type must be an integer >= 0") + + def __get__(self): + self.updateParticleData() + return self.particleData.p.type + + # Position + property pos: + """Particle position (not folded into central image).""" + def __set__(self, _pos): + cdef double mypos[3] + checkTypeOrExcept(_pos, 3,float,"Postion must be 3 floats") + for i in range(3): mypos[i]=_pos[i] + if place_particle(self.id, mypos) == -1: + raise Exception("particle could not be set") + + def __get__(self): + self.updateParticleData() + return np.array([self.particleData.r.p[0],\ + self.particleData.r.p[1],\ + self.particleData.r.p[2]]) + + # Velocity + property v: + """Particle velocity""" + def __set__(self, _v): + cdef double myv[3] + checkTypeOrExcept(_v,3,float,"Velocity has to be floats") + for i in range(3): + myv[i]=_v[i] + if set_particle_v(self.id, myv) == 1: + raise Exception("set particle position first") + def __get__(self): + self.updateParticleData() + return np.array([ self.particleData.m.v[0],\ + self.particleData.m.v[1],\ + self.particleData.m.v[2]]) + + # Force + property f: + """Particle force""" + def __set__(self, _f): + cdef double myf[3] + checkTypeOrExcept(_f,3,float, "Force has to be floats") + for i in range(3): + myf[i]=_f[i] + if set_particle_f(self.id, myf) == 1: + raise Exception("set particle position first") + def __get__(self): + self.updateParticleData() + return np.array([ self.particleData.f.f[0],\ + self.particleData.f.f[1],\ + self.particleData.f.f[2]]) + + # Bonds + property bonds: + """Bond partners with respect to bonded interactions.""" + + def __set__(self,_bonds): + # First, we check that we got a list/tuple. + if not hasattr(_bonds, "__getitem__"): + raise ValueError("bonds have to specified as a tuple of tuples. (Lists can also be used)") + # Check individual bonds + for bond in _bonds: + self.checkBondOrThrowException(bond) + + # Assigning to the bond property means replacing the existing value + # i.e., we delete all existing bonds + if change_particle_bond(self.id,NULL,1): + raise Exception("Deleting existing bonds failed.") + + # And add the new ones + for bond in _bonds: + self.addVerifiedBond(bond) + + + def __get__(self): + self.updateParticleData() + bonds =[] + # Go through the bond list of the particle + i=0 + while i= 0") + def __get__(self): + self.updateParticleData() + cdef int* x = NULL + pointer_to_virtual(&(self.particleData),x) + return x[0] + + IF VIRTUAL_SITES_RELATIVE == 1: + # Virtual sites relative parameters + property vs_relative: + """virtual sites relative parameters""" + def __set__(self,x): + if len(x) !=2: + raise ValueError("vs_relative needs two args") + _relto=x[0] + _dist=x[1] + if isinstance(_relto, int) and isinstance(_dist,float): + if set_particle_vs_relative(self.id, _relto,_dist) == 1: + raise Exception("set particle position first") + else: + raise ValueError("vs_relative takes one int and one float as parameters.") + def __get__(self): + self.updateParticleData() + cdef int* rel_to = NULL + cdef double* dist = NULL + pointer_to_vs_relative(&(self.particleData),rel_to,dist) + return (rel_to[0],dist[0]) + + # vs_auto_relate_to + def vs_auto_relate_to(self,_relto): + """Setup this particle as virtual site relative to the particle with the given id""" + if isinstance(_relto,int): + if vs_relate_to(self.id,_relto): + raise Exception("Vs_relative setup failed.") + else: + raise ValueError("Argument of vs_auto_relate_to has to be of type int") + + + IF DIPOLES == 1: + # Vector dipole moment + property dip: + """Dipole moment as vector""" + def __set__(self, _q): + cdef double myq[3] + checkTypeOrExcept(_q,3,float,"Dipole moment vector has to be 3 floats") + for i in range(3): + myq[i]=_q[i] + if set_particle_dip(self.id, myq) == 1: + raise Exception("set particle position first") + def __get__(self): + self.updateParticleData() + cdef double* x + pointer_to_dip(&(self.particleData),x) + return np.array([x[0],x[1],x[2]]) + + # Scalar magnitude of dipole moment + property dipm: + """Dipole moment (magnitude)""" + def __set__(self, _q): + checkTypeOrExcept(_q,1,float,"Magnitude of dipole moment has to be 1 floats") + if set_particle_dipm(self.id, _q) == 1: + raise Exception("set particle position first") + def __get__(self): + self.updateParticleData() + cdef double* x + pointer_to_dipm(&(self.particleData),x) + return x[0] + + + def delete(self): + """Delete the particle""" + if remove_particle(self.id): + raise Exception("Could not delete particle") + del self + + + IF VIRTUAL_SITES_RELATIVE == 1: + # vs_auto_relate_to + def vs_auto_relate_to(self,_relto): + """Setup this particle as virtual site relative to the particle with the given id""" + if isinstance(_relto,int): + if vs_relate_to(self.id,_relto): + raise Exception("Vs_relative setup failed.") + else: + raise ValueError("Argument of vs_auto_relate_to has to be of type int") + + # Bond related methods + def addVerifiedBond(self,bond): + """Add a bond, the validity of which has already been verified""" + # If someone adds bond types with more than four partners, this has to be changed + cdef int bondInfo[5] + for i in range(len(bond)): + bondInfo[i]=bond[i] + if change_particle_bond(self.id,bondInfo,0): + raise Exception("Adding the bond failed.") + + def deleteVerifiedBond(self,bond): + """Delete a bond, the validity of which has already been verified""" + # If someone adds bond types with more than four partners, this has to be changed + cdef int bondInfo[5] + for i in range(len(bond)): + bondInfo[i]=bond[i] + if change_particle_bond(self.id,bondInfo,1): + raise Exception("Deleting the bond failed.") + + def checkBondOrThrowException(self,bond) : + """Checks the validity of the given bond: + * if the bond is given as a tuple + * if it contains at least two values. + * if all elements are of type int + * If the bond type used exists (is lower than n_bonded_ia) + * If the number of bond partners fits the bond type + Throw an exception if any of these are not met""" + if not hasattr(bond,"__getitem__"): + raise ValueError("Elements of the bond list have to be tuples of the form (bondType,bondPartner)") + if len(bond) <2: + raise ValueError("Elements of the bond list have to be tuples of the form (bondType,bondPartner)") + + for y in bond: + if not isinstance(y,int): + raise ValueError("The bond type and bond partners have to be integers.") + if bond[0] >= n_bonded_ia: + raise ValueError("The bond type",bond[0], "does not exist.") + + if bonded_ia_params[bond[0]].num != len(bond)-1: + raise ValueError("Bond of type",bond[0],"needs",bonded_ia_params[bond[0]],"partners.") + + def addBond(self,bond): + """Add a single bond to the particle""" + self.checkBondOrThrowException(bond) + self.addVerifiedBond(bond) + + def deleteBond(self, bond): + """Delete a single bond from the particle""" + self.checkBondOrThrowException(bond) + self.deleteVerifiedBond(bond) + + def deleteAllBonds(self): + if change_particle_bond(self.id,NULL,1): + raise Exception("Deleting all bonds failed.") + + +cdef class particleList: + """Provides access to the particles via [i], where i is the particle id. Returns a ParticleHandle object """ + def __getitem__(self, key): + return ParticleHandle(key) + + diff --git a/src/python/espressomd/system.py b/src/python/espressomd/system.py new file mode 100644 index 00000000000..f9e052a72b5 --- /dev/null +++ b/src/python/espressomd/system.py @@ -0,0 +1,8 @@ +from __future__ import print_function +from espressomd.highlander import highlander +from espressomd import _system + +@highlander +class System(_system.System): + def __init__(self): + _system.System.__init__(self) diff --git a/src/python/espressomd/thermostat.pxd b/src/python/espressomd/thermostat.pxd new file mode 100644 index 00000000000..a7f354558e5 --- /dev/null +++ b/src/python/espressomd/thermostat.pxd @@ -0,0 +1,33 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "communication.hpp": + void mpi_bcast_parameter(int p) + +cdef extern from "global.hpp": + int FIELD_TEMPERATURE + int FIELD_THERMO_SWITCH + int FIELD_TEMPERATURE + int FIELD_LANGEVIN_GAMMA + +cdef extern from "thermostat.hpp": + double temperature + int thermo_switch + double langevin_gamma + int THERMO_OFF + int THERMO_LANGEVIN diff --git a/src/python/espressomd/thermostat.pyx b/src/python/espressomd/thermostat.pyx new file mode 100644 index 00000000000..0c65b80eda5 --- /dev/null +++ b/src/python/espressomd/thermostat.pyx @@ -0,0 +1,66 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cimport thermostat + +cdef class Thermostat: + def __init__(self): + pass + + def getStatus(self): + """Returns the thermostat status. Equivalent to the tcl command 'thermostat' with no arguments""" + + if temperature == -1: + return "{ not initialized }" + if thermo_switch == THERMO_OFF: + return "{ off }" + if thermo_switch and THERMO_LANGEVIN : + return "{ langevin "+str(temperature)+" "+str(langevin_gamma)+" }" + + def turnOff(self): + """Turns off all the thermostat and sets all the thermostat variables to zero""" + + global temperature + temperature=0. + mpi_bcast_parameter(FIELD_TEMPERATURE) + global langevin_gamma + langevin_gamma=0. + mpi_bcast_parameter(FIELD_LANGEVIN_GAMMA) + global thermo_switch + thermo_switch = THERMO_OFF + mpi_bcast_parameter(FIELD_THERMO_SWITCH) + # here other thermostats stuff + return True + + def setLangevin(self, _temperature="", _gamma=""): + """Sets the Langevin thermostat with required parameters 'temperature' 'gamma'""" + + if _temperature=="" or _gamma=="": + raise ValueError("wrong # args: should be\n\"thermostat langevin \"") + if not isinstance(_temperature, float) or not isinstance(_gamma, float) or float(_temperature)<0. or float(_gamma)<0.: + raise ValueError("temperature and gamma must be positive numbers") + global temperature + temperature=float(_temperature) + global langevin_gamma + langevin_gamma=float(_gamma) + global thermo_switch + thermo_switch = ( thermo_switch or THERMO_LANGEVIN ) + mpi_bcast_parameter(FIELD_THERMO_SWITCH) + mpi_bcast_parameter(FIELD_TEMPERATURE) + mpi_bcast_parameter(FIELD_LANGEVIN_GAMMA) + return True diff --git a/src/python/espressomd/utils.pxd b/src/python/espressomd/utils.pxd new file mode 100644 index 00000000000..2b5278d6cfb --- /dev/null +++ b/src/python/espressomd/utils.pxd @@ -0,0 +1,42 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +from utils cimport * + +cdef extern from "stdlib.h": + void free(void* ptr) + void* malloc(size_t size) + void* realloc(void* ptr, size_t size) + +cdef extern from "utils.hpp": + ctypedef struct IntList: + int *e + int n + cdef void init_intlist(IntList *il) + cdef void alloc_intlist(IntList *il, int size) + cdef void realloc_intlist(IntList *il, int size) + + ctypedef struct DoubleList: + int *e + int n + cdef void init_intlist(IntList *il) + cdef void alloc_intlist(IntList *il, int size) + cdef void realloc_intlist(IntList *il, int size) + +cdef IntList* create_IntList_from_python_object(obj) +cdef checkTypeOrExcept(x,n,t,msg) diff --git a/src/python/espressomd/utils.pyx b/src/python/espressomd/utils.pyx new file mode 100644 index 00000000000..b1ad5ee7776 --- /dev/null +++ b/src/python/espressomd/utils.pyx @@ -0,0 +1,58 @@ +# +# Copyright (C) 2013,2014 The ESPResSo project +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +cdef extern from "stdlib.h": + void free(void* ptr) + void* malloc(size_t size) + void* realloc(void* ptr, size_t size) + + +cdef IntList* create_IntList_from_python_object(obj): + cdef IntList* il + il= malloc(sizeof(IntList)) + init_intlist(il) + + alloc_intlist(il, len(obj)) + for i in range(len(obj)): + il.e[i] = obj[i] + print il.e[i] + + return il + +cdef checkTypeOrExcept(x,n,t,msg): + """Checks that x is of type t and that n values are given, otherwise throws ValueError with the message msg. + If x is an array/list/tuple, the type checking is done on the elements, and + all elements are checked. + Integers are accepted when a float was asked for. + """ + # Check whether x is an array/list/tuple or a single value + if n>1: + if hasattr(x, "__getitem__"): + for i in range(len(x)): + if not isinstance(x[i], t): + if not (t==float and isinstance(x[i],int)): + raise ValueError(msg + " -- Item "+str(i)+" was of type "+type(x[i]).__name__) + else: + # if n>1, but the user passed a single value, also throw exception + raise ValueError(msg+" -- A single value was given but "+str(n)+" were expected.") + else: + # N=1 and a single value + if not isinstance(x, t): + if not (t==float and isinstance(x,int)): + raise ValueError(msg+" -- Got an "+type(x).__name__) + diff --git a/src/python/pypresso.in b/src/python/pypresso.in new file mode 100644 index 00000000000..f5d0b7a7ac4 --- /dev/null +++ b/src/python/pypresso.in @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright (C) 2010,2011,2014 The ESPResSo project +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. This file is offered as-is, +# without any warranty. +# +if test -n "$PYTHONPATH"; then + PYTHONPATH=$PYTHONPATH:@abs_top_builddir@ +else + PYTHONPATH=@abs_top_builddir@ +fi +export PYTHONPATH +exec @PYTHON@ $@ diff --git a/src/statistics_observable.hpp b/src/statistics_observable.hpp deleted file mode 100644 index 47e0d4d9330..00000000000 --- a/src/statistics_observable.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef _STATISTICS_OBSERVABLE_H -#define _STATISTICS_OBSERVABLE_H - -#include "config.hpp" -#include "utils.hpp" -#include -#include -#include - - -typedef struct { - char* obs_name; - void* args; - int n; - int (*fun) ( void* A_args, double* A, unsigned int dim_A); - double* last_value; - int last_update; -} observable; - -extern observable** observables; -extern int n_observables; - -int* observable_calc(observable* self, double* A); - -/* Here we have the particular observables listed */ -int observable_particle_velocities(void* idlist, double* A, unsigned int n_A); -int observable_particle_angular_momentum(void* idlist, double* A, unsigned int n_A); -int observable_com_velocity(void* idlist, double* A, unsigned int n_A); -int observable_blocked_com_velocity(void* idlist, double* A, unsigned int n_A); -/** Obtain the particle positions. - * TODO: Folded or unfolded? - */ -int observable_particle_positions(void* typelist, double* A, unsigned int n_A); -int observable_particle_forces(void* typelist, double* A, unsigned int n_A); -int observable_com_force(void* typelist, double* A, unsigned int n_A); -int observable_blocked_com_force(void* typelist, double* A, unsigned int n_A); -int observable_stress_tensor(void* typelist, double* A, unsigned int n_A); -int observable_stress_tensor_acf_obs(void* typelist, double* A, unsigned int n_A); -int observable_com_position(void* idlist, double* A, unsigned int n_A); -int observable_blocked_com_position(void* idlist, double* A, unsigned int n_A); - -#ifdef ELECTROSTATICS -int observable_particle_currents(void* typelist, double* A, unsigned int n_A); -int observable_currents(void* typelist, double* A, unsigned int n_A); -int observable_dipole_moment(void* typelist, double* A, unsigned int n_A); -#endif - - -/** Calculate structure factor from positions and scattering length */ -int observable_structure_factor(void* params, double* A, unsigned int n_A); -typedef struct { -// FIXME finish the implementation of scattering length - IntList* id_list; - DoubleList *scattering_length; // Scattering lengths of particles - int order; - int dim_sf; // number of q vectors - int *q_vals; // values of q vectors - double *q_density; // number of q vectors per bin - // entries for spherical averaging -} observable_sf_params; - -/** See if particles from idList1 interact with any of the particles in idList2 -input parameters are passed via struct iw_params -*/ -int observable_interacts_with(void* params, double* A, unsigned int n_A); -typedef struct { - double cutoff; - IntList *ids1; - IntList *ids2; -} iw_params; - - -/** Do nothing */ -int observable_obs_nothing (void* params, double* A, unsigned int n_A); - -int observable_flux_density_profile(void* params, double* A, unsigned int n_A); -typedef struct { - IntList* id_list; - double minx; - double maxx; - double miny; - double maxy; - double minz; - double maxz; - int xbins; - int ybins; - int zbins; -} profile_data; - -int observable_density_profile(void* params, double* A, unsigned int n_A); - -int observable_lb_velocity_profile(void* params, double* A, unsigned int n_A); - -int observable_radial_density_profile(void* params, double* A, unsigned int n_A); -int observable_radial_flux_density_profile(void* params, double* A, unsigned int n_A); -int observable_lb_radial_velocity_profile(void* params, double* A, unsigned int n_A); -typedef struct { - IntList* id_list; - double minr; - double maxr; - double minphi; - double maxphi; - double minz; - double maxz; - double center[3]; - double axis[3]; - int phibins; - int rbins; - int zbins; -} radial_profile_data; - - - -#endif diff --git a/src/tcl/Makefile.am b/src/tcl/Makefile.am new file mode 100644 index 00000000000..08860340110 --- /dev/null +++ b/src/tcl/Makefile.am @@ -0,0 +1,213 @@ +# Copyright (C) 2013,2014 Olaf Lenz +# +# This file is part of ESPResSo. +# +# ESPResSo is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ESPResSo is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +EXTRA_DIST = +CLEANFILES = +AM_CPPFLAGS = -I$(top_srcdir)/src/core -I$(top_srcdir)/src -I$(builddir)/../core +if MPI_FAKE +AM_CPPFLAGS += -I$(top_srcdir)/src/core/mpifake +endif +AM_DEFAULT_SOURCE_EXT = .cpp + +noinst_LTLIBRARIES = libEspressoTcl.la +libEspressoTcl_la_SOURCES = \ + TclOutputHelper.hpp \ + bin_tcl.cpp \ + binary_file_tcl.cpp binary_file_tcl.hpp \ + blockfile_tcl.cpp \ + cells_tcl.cpp \ + cells_tcl.hpp \ + channels_tcl.cpp \ + collision_tcl.cpp \ + comfixed_tcl.cpp comfixed_tcl.hpp \ + comforce_tcl.cpp comforce_tcl.hpp \ + config_tcl.cpp \ + constraint_tcl.cpp constraint_tcl.hpp \ + domain_decomposition_tcl.cpp domain_decomposition_tcl.hpp \ + electrokinetics_tcl.cpp electrokinetics_tcl.hpp \ + external_potential_tcl.cpp external_potential_tcl.hpp \ + energy_tcl.cpp \ + galilei_tcl.cpp galilei_tcl.hpp \ + global_tcl.cpp global_tcl.hpp \ + grid_tcl.cpp grid_tcl.hpp \ + iccp3m_tcl.cpp iccp3m_tcl.hpp \ + imd_tcl.cpp \ + initialize_interpreter.cpp initialize_interpreter.hpp \ + integrate_tcl.cpp integrate_tcl.hpp \ + interaction_data_tcl.cpp interaction_data_tcl.hpp \ + lb-boundaries_tcl.cpp lb-boundaries_tcl.hpp \ + lb_tcl.cpp lb_tcl.hpp \ + lees_edwards_tcl.cpp lees_edwards_tcl.hpp \ + metadynamics_tcl.cpp metadynamics_tcl.hpp \ + nemd_tcl.cpp \ + mol_cut_tcl.cpp mol_cut_tcl.hpp \ + parser.cpp parser.hpp \ + particle_data_tcl.cpp \ + polymer_tcl.cpp polymer_tcl.hpp \ + pressure_tcl.cpp pressure_tcl.hpp \ + random_tcl.cpp random_tcl.hpp \ + reaction_tcl.cpp reaction_tcl.hpp \ + rattle_tcl.cpp rattle_tcl.hpp \ + statistics_chain_tcl.cpp statistics_chain_tcl.hpp \ + statistics_cluster_tcl.cpp statistics_cluster_tcl.hpp \ + statistics_correlation_tcl.cpp statistics_correlation_tcl.hpp \ + statistics_fluid_tcl.cpp statistics_fluid_tcl.hpp \ + statistics_observable_tcl.cpp statistics_observable_tcl.hpp \ + statistics_wallstuff_tcl.cpp statistics_wallstuff_tcl.hpp \ + statistics_tcl.cpp statistics_tcl.hpp \ + thermostat_tcl.cpp thermostat_tcl.hpp \ + topology_tcl.cpp \ + tuning_tcl.cpp \ + uwerr_tcl.cpp \ + virtual_sites_com_tcl.cpp virtual_sites_com_tcl.hpp \ + ghmc_tcl.cpp ghmc_tcl.hpp + +# nonbonded potentials and forces +libEspressoTcl_la_SOURCES += \ + bmhtf-nacl_tcl.cpp bmhtf-nacl_tcl.hpp \ + buckingham_tcl.cpp buckingham_tcl.hpp \ + dpd_tcl.cpp dpd_tcl.hpp \ + forcecap_tcl.cpp forcecap_tcl.hpp \ + gaussian_tcl.cpp gaussian_tcl.hpp \ + gb_tcl.cpp gb_tcl.hpp \ + hat_tcl.cpp hat_tcl.hpp \ + hertzian_tcl.cpp hertzian_tcl.hpp \ + lj_tcl.cpp lj_tcl.hpp \ + ljangle_tcl.cpp ljangle_tcl.hpp \ + ljcos2_tcl.cpp ljcos2_tcl.hpp \ + ljcos_tcl.cpp ljcos_tcl.hpp \ + ljgen_tcl.cpp ljgen_tcl.hpp \ + morse_tcl.cpp morse_tcl.hpp \ + soft_sphere_tcl.cpp soft_sphere_tcl.hpp \ + steppot_tcl.cpp steppot_tcl.hpp \ + tab_tcl.cpp tab_tcl.hpp \ + tunable_slip_tcl.cpp tunable_slip_tcl.hpp + +# bonded potentials and forces +libEspressoTcl_la_SOURCES += \ + angle_tcl.cpp angle_tcl.hpp \ + angle_harmonic_tcl.cpp angle_harmonic_tcl.hpp \ + angle_cosine_tcl.cpp angle_cosine_tcl.hpp \ + angle_cossquare_tcl.cpp angle_cossquare_tcl.hpp \ + angledist_tcl.cpp angledist_tcl.hpp \ + dihedral_tcl.cpp dihedral_tcl.hpp \ + endangledist_tcl.cpp endangledist_tcl.hpp \ + fene_tcl.cpp fene_tcl.hpp \ + harmonic_tcl.cpp harmonic_tcl.hpp \ + quartic_tcl.cpp quartic_tcl.hpp \ + bonded_coulomb_tcl.cpp bonded_coulomb_tcl.hpp \ + overlap_tcl.cpp overlap_tcl.hpp \ + subt_lj_tcl.cpp subt_lj_tcl.hpp \ + object-in-fluid/area_force_local_tcl.cpp \ + object-in-fluid/area_force_local_tcl.hpp \ + object-in-fluid/area_force_global_tcl.cpp \ + object-in-fluid/area_force_global_tcl.hpp \ + object-in-fluid/bending_force_tcl.cpp \ + object-in-fluid/bending_force_tcl.hpp \ + object-in-fluid/stretching_force_tcl.cpp \ + object-in-fluid/stretching_force_tcl.hpp \ + object-in-fluid/stretchlin_force_tcl.cpp \ + object-in-fluid/stretchlin_force_tcl.hpp \ + object-in-fluid/volume_force_tcl.cpp \ + object-in-fluid/volume_force_tcl.hpp + +# Coulomb methods +libEspressoTcl_la_SOURCES += \ + debye_hueckel_tcl.cpp debye_hueckel_tcl.hpp \ + elc_tcl.cpp elc_tcl.hpp \ + magnetic_non_p3m_methods_tcl.cpp magnetic_non_p3m_methods_tcl.hpp \ + maggs_tcl.cpp maggs_tcl.hpp \ + mmm1d_tcl.cpp mmm1d_tcl.hpp \ + mmm2d_tcl.cpp mmm2d_tcl.hpp \ + p3m-dipolar_tcl.cpp p3m-dipolar_tcl.hpp \ + p3m_tcl.cpp p3m_tcl.hpp \ + reaction_field_tcl.cpp reaction_field_tcl.hpp \ + mdlc_correction_tcl.cpp mdlc_correction_tcl.hpp + +# Generic actors +libEspressoTcl_la_SOURCES += \ + actor/Mmm1dgpu_tcl.cpp actor/Mmm1dgpu_tcl.hpp \ + actor/Ewaldgpu_tcl.cpp actor/Ewaldgpu_tcl.hpp \ + actor/HarmonicWell_tcl.cpp actor/HarmonicWell_tcl.hpp + +if CUDA +libEspressoTcl_la_SOURCES += cuda_init_tcl.cpp +endif + +################################################################# +# Compile the (TCL) main program +################################################################# + +# Two binaries are generated: Espresso for the build dir, +# Espresso.install for the installation dir. +# The ".install" suffix is removed upon installation. +noinst_PROGRAMS = Espresso +Espresso_CPPFLAGS = -D ESPRESSO_SCRIPTS_DEFAULT=\"$(buildscriptsdir)\" $(AM_CPPFLAGS) +Espresso_SOURCES = scriptsdir.cpp main.cpp +Espresso_LDADD = libEspressoTcl.la ../core/libEspresso.la + +bin_PROGRAMS = Espresso.install +Espresso_install_CPPFLAGS = -D ESPRESSO_SCRIPTS_DEFAULT=\"$(scriptsdir)\" $(AM_CPPFLAGS) +Espresso_install_SOURCES = scriptsdir.cpp main.cpp +Espresso_install_LDADD = libEspressoTcl.la ../core/libEspresso.la + +# generate the Tcl library for the python interpreter +if PYTHON_INTERFACE +noinst_LTLIBRARIES += libEspressoTcl4Py.la +libEspressoTcl4Py_la_CPPFLAGS = -D ESPRESSO_SCRIPTS_DEFAULT=\"$(buildscriptsdir)\" $(AM_CPPFLAGS) +libEspressoTcl4Py_la_SOURCES = scriptsdir.cpp +libEspressoTcl4Py_la_LIBADD = libEspressoTcl.la +endif + +ESPRESSO = `echo Espresso | sed '$(transform)'`$(EXEEXT) +ESPRESSO_INSTALL = `echo Espresso.install | sed '$(transform)'`$(EXEEXT) +# rename Espresso after installation +install-exec-hook: + $(am__mv) \ + $(DESTDIR)$(bindir)/$(ESPRESSO_INSTALL) \ + $(DESTDIR)$(bindir)/$(ESPRESSO) + +uninstall-local: + -rm -f $(DESTDIR)$(bindir)/$(ESPRESSO) + +################################################################# +# Build an empty CUDA object +################################################################# +# this is necessary since Xcode 4.3 otherwise builds binaries +# with a broken dyld relocation table +if CUDA + +SUFFIXES=.cu + +cuda_verbose = $(cuda_verbose_@AM_V@) +cuda_verbose_ = $(cuda_verbose_@AM_DEFAULT_V@) +cuda_verbose_0 = @echo " NVCC $@"; + +# nvcc does not allow for option MF for dependency generation, +# therefore make a separate run to generate dependencies +# putting them into DEPDIR ensures configure creates empties dummies +cuda_workaround.o: cuda_workaround.cu + $(cuda_verbose)$(NVCC) \ + $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_NVCCFLAGS) $(NVCCFLAGS) -c -o $@ $< + +Espresso_LDADD += cuda_workaround.o +Espresso_install_LDADD += cuda_workaround.o +EXTRA_DIST += cuda_workaround.cu + +endif diff --git a/src/tcl/TclOutputHelper.hpp b/src/tcl/TclOutputHelper.hpp new file mode 100644 index 00000000000..818c443a913 --- /dev/null +++ b/src/tcl/TclOutputHelper.hpp @@ -0,0 +1,157 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef CPP_CONVERSIONS_H +#define CPP_CONVERSIONS_H + +#include "tcl.h" +#include +#include +#include +//#include "Eigen/Core" + +/** + * In this file we define a few generic functions to make returning + * complex c++ data easy. The idea is as follows: + * + * We provide a set of functions + * void Tcl_Append(Tcl_Interp* interp, const T& what, bool is_in_list=0) + * that append what to the current result stored in the TCL interpreter. + * + * We provide a generic Tcl_Append function that uses the << operator + * in combination with a stringstream. Any class that has an implentation + * of <<(ostream) can be converted into a TCL result. + * + * For certain data types we have special implementation: E.G. For + * double we use Tcl_PrintDouble, and a Vector3d from Eigen creates + * a list with 3 entries. std::vector is converted into a TCL list etc. + * + * The usage of lists is particularly interesting as this generic + * programming technique allows us also to use lists of lists, without + * actually changing anything. One difficulty requires using a is_in_list + * flag: TCL lists require having no braces {} when on "top level", but + * lists in lists, need braces {}. Thus a simple list of list of integers + * looks like: + * "{ 1 2 } { 3 4 }", without outer braces. + * + * Thus we pass the flag is_in_list to every Tcl_Append call, so that + * inside the function is is possible to decide weather braces are necessary: + * If is_in_list is set, outer braces are added, if the type itself + * is a list. + */ + +/** + * Generic implementation for types that support << (ostream) + * + * The is_in_list flag can not be used, as we can not know if + * the object passed is actually a list-type object or a simple object. + */ +template +void Tcl_Append(Tcl_Interp* interp, const T& what, bool is_in_list=0) { + std::stringstream ss; + ss << what; + Tcl_AppendResult(interp, ss.str().c_str(), (char *)NULL); +} + +/** + * Implementation for double, using TCL_PrintDouble, to make sure + * TCL is happy with the float representation. + */ +void Tcl_Append(Tcl_Interp* interp, const double& what, bool is_in_list=0) { + char buffer[TCL_DOUBLE_SPACE]; + Tcl_PrintDouble(interp, what, buffer); + Tcl_AppendResult(interp, buffer, (char *)NULL); +} + +/** + * Implementation for fixed width char arrays: + * Usage Tcl_Append("Message for user") + * + */ +template +void Tcl_Append(Tcl_Interp* interp, const char (&what)[N], bool is_in_list=0) { + Tcl_AppendResult(interp, what, (char *)NULL); +} + +/** + * Implementation for Eigen::Vector3d + * + * Appends a result that can be interpreted as TCL list. + * + */ +//void Tcl_Append(Tcl_Interp* interp, const Eigen::Vector3d &what, bool is_in_list=0) { +// if (is_in_list) +// Tcl_Append(interp, "{"); +// char buffer[TCL_DOUBLE_SPACE]; +// Tcl_PrintDouble(interp, what[0], buffer); +// Tcl_AppendResult(interp, buffer, " ", (char *)NULL); +// Tcl_PrintDouble(interp, what[1], buffer); +// Tcl_AppendResult(interp, buffer, " ", (char *)NULL); +// Tcl_PrintDouble(interp, what[2], buffer); +// Tcl_AppendResult(interp, buffer, (char *)NULL); +// if (is_in_list) +// Tcl_Append(interp, "}"); +//} + +/** + * Implementation for std::vector + * + * Simply calls the generic function Tcl_Append_Iterable. + * This then calls Tcl_Append for every member of the vector. + * + */ +template +void Tcl_Append(Tcl_Interp* interp, const std::vector what, bool is_in_list=0) { + Tcl_Append_Iterable(interp, what, is_in_list); +} + +/** + * Generic implemtation that supports everything which can be iterated over. + * This requires + * typedef const_iterator + * const_reference begin() + * const_reference end() + * + * Calls the Tcl_Append for every member of the iterable object. + * + */ +template +void Tcl_Append_Iterable(Tcl_Interp* interp, const C& what, bool is_in_list=0) { + + typename C::const_iterator it=what.begin(); + + if (is_in_list) + Tcl_Append(interp, "{"); + if (it!=what.end()) { + Tcl_Append(interp, *it, true); + ++it; + } + while (it!=what.end()) { + Tcl_Append(interp, " "); + Tcl_Append(interp, *it, true); + ++it; + } + if (is_in_list) + Tcl_Append(interp, "}"); +} + + +#endif diff --git a/src/tcl/actor/Ewaldgpu_tcl.cpp b/src/tcl/actor/Ewaldgpu_tcl.cpp new file mode 100644 index 00000000000..a6dadd246ed --- /dev/null +++ b/src/tcl/actor/Ewaldgpu_tcl.cpp @@ -0,0 +1,273 @@ +#include "Ewaldgpu_tcl.hpp" +#include "forces.hpp" +#include "energy.hpp" +#include "actor/EwaldgpuForce.hpp" +#include "EspressoSystemInterface.hpp" + +#ifdef EWALD_GPU + +EwaldgpuForce *ewaldgpuForce; + +int tclprint_to_result_ewaldgpu(Tcl_Interp *interp) +{ + //Used in tcl-script output + char buffer[TCL_DOUBLE_SPACE]; + Tcl_PrintDouble(interp, ewaldgpu_params.rcut, buffer); + Tcl_AppendResult(interp, "ewaldgpu ", buffer, " ", (char *) NULL); + sprintf(buffer,"%d",ewaldgpu_params.num_kx); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + sprintf(buffer,"%d",ewaldgpu_params.num_ky); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + sprintf(buffer,"%d",ewaldgpu_params.num_kz); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, ewaldgpu_params.alpha, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, ewaldgpu_params.accuracy, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + return TCL_OK; +} +int tclcommand_inter_coulomb_parse_ewaldgpu(Tcl_Interp * interp, int argc, char ** argv) +{ + //PARSE EWALD COMMAND LINE + if (argc < 1) + { + Tcl_AppendResult(interp, "\nExpected: inter coulomb ewaldgpu ( | { }) \nExpected: inter coulomb ewaldgpu tune [] \nExpected: inter coulomb ewaldgpu tunealpha []",(char *) NULL); + return TCL_ERROR; + } + + //Tune + if (ARG0_IS_S("tune")) + { + return tclcommand_inter_coulomb_parse_ewaldgpu_tune(interp, argc-1, argv+1, 0); + } + //Tune alpha + else if (ARG0_IS_S("tunealpha")) + { + return tclcommand_inter_coulomb_parse_ewaldgpu_tunealpha(interp, argc-1, argv+1); + } + //No tuning + else + { + return tclcommand_inter_coulomb_parse_ewaldgpu_notune(interp, argc, argv); + } +} + +int tclcommand_inter_coulomb_parse_ewaldgpu_notune(Tcl_Interp * interp, int argc, char ** argv) +{ + double r_cut=-1; + int num_kx=-1; + int num_ky=-1; + int num_kz=-1; + double alpha=-1; + IntList il; + init_intlist(&il); + + if(argc < 3 || argc > 5) { + Tcl_AppendResult(interp, "\nExpected: inter coulomb ewaldgpu ( | { }) ",(char *) NULL); + return TCL_ERROR; + } + if(! ARG_IS_D(0,r_cut)) + { + Tcl_AppendResult(interp, "\n double expected", (char *) NULL); + return TCL_ERROR; + } + if(! ARG_IS_I(1, num_kx)) + { + if( ! ARG_IS_INTLIST(1, il) || !(il.n == 3) ) + { + Tcl_AppendResult(interp, "\n( | { }) integer or integer list of length 3 expected", (char *) NULL); + return TCL_ERROR; + } + else + { + num_kx = il.e[0]; + num_ky = il.e[1]; + num_kz = il.e[2]; + } + } + else + { + num_kz = num_ky = num_kx; + } + if(argc > 2) + { + if(! ARG_IS_D(2, alpha)) + { + Tcl_AppendResult(interp, "\n double expected", (char *) NULL); + return TCL_ERROR; + } + } + else + { + Tcl_AppendResult(interp, "\nAutomatic ewaldgpu tuning not implemented.", + (char *) NULL); + return TCL_ERROR; + } + + //Turn on ewaldgpu + if (!ewaldgpuForce) // inter coulomb ewaldgpu was never called before + { + ewaldgpuForce = new EwaldgpuForce(espressoSystemInterface, r_cut, num_kx, num_ky, num_kz, alpha); + forceActors.add(ewaldgpuForce); + energyActors.add(ewaldgpuForce); + } + //Broadcast parameters + ewaldgpuForce->set_params(r_cut, num_kx, num_ky, num_kz, alpha); + coulomb.method = COULOMB_EWALD_GPU; + ewaldgpu_params.isTunedFlag = false; + ewaldgpu_params.isTuned = true; + rebuild_verletlist = 1; + mpi_bcast_coulomb_params(); + return TCL_OK; +} +int tclcommand_inter_coulomb_parse_ewaldgpu_tune(Tcl_Interp * interp, int argc, char ** argv, int adaptive) +{ + double r_cut=-1; + double alpha=-1; + int num_kx=-1; + int num_ky=-1; + int num_kz=-1; + int K_max = 30; + int time_calc_steps = -1; + double accuracy = 0.0001; + double precision = 0.000001; + + //PARSE EWALD COMMAND LINE + while(argc > 0) + { + if(ARG0_IS_S("accuracy")) + { + if(! (argc > 1 && ARG1_IS_D(accuracy) && accuracy > 0)) + { + Tcl_AppendResult(interp, "\n expects a positive double ",(char *) NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("precision")) + { + if(! (argc > 1 && ARG1_IS_D(precision) && precision > 0)) + { + Tcl_AppendResult(interp, "\n expects a positive double ",(char *) NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("K_max")) + { + if(! (argc > 1 && ARG1_IS_I(K_max) && K_max > 0)) + { + Tcl_AppendResult(interp, "\n expects a positive integer ",(char *) NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("time_calc_steps")) + { + if(! (argc > 1 && ARG1_IS_I(time_calc_steps) && time_calc_steps > 0)) + { + Tcl_AppendResult(interp, "\n expects a positive integer ",(char *) NULL); + return TCL_ERROR; + } + } + else break; + + argc -= 2; + argv += 2; + } + + //Turn on ewaldgpu + ewaldgpuForce->set_params_tune(accuracy, precision, K_max, time_calc_steps); + if (!ewaldgpuForce) // inter coulomb ewaldgpu was never called before + { + ewaldgpuForce = new EwaldgpuForce(espressoSystemInterface, r_cut, num_kx, num_ky, num_kz, alpha); + forceActors.add(ewaldgpuForce); + energyActors.add(ewaldgpuForce); + } + + //Broadcast parameters + coulomb.method = COULOMB_EWALD_GPU; + ewaldgpu_params.isTunedFlag = false; + rebuild_verletlist = 1; + mpi_bcast_coulomb_params(); + //Tuning + char *log = NULL; + if (ewaldgpuForce->adaptive_tune(&log,espressoSystemInterface) == ES_ERROR) + { + Tcl_AppendResult(interp, "\nAccuracy could not been reached. Choose higher K_max or lower accuracy", (char *) NULL); + return TCL_ERROR; + } + //Tell the user about the tuning outcome + Tcl_AppendResult(interp, log, (char *) NULL); + if (log) free(log); + + return TCL_OK; +} +int tclcommand_inter_coulomb_parse_ewaldgpu_tunealpha(Tcl_Interp * interp, int argc, char ** argv) +{ + double r_cut; + double alpha; + int num_kx; + int num_ky; + int num_kz; + double precision=0.000001; + IntList il; + init_intlist(&il); + + //PARSE EWALD COMMAND LINE + if (argc < 3) + { + Tcl_AppendResult(interp, "\nWrong # arguments: ( | { }) ", (char *) NULL); + return TCL_ERROR; + } + if (! ARG0_IS_D(r_cut)) + { + Tcl_AppendResult(interp, "\n should be a double",(char *) NULL); + return TCL_ERROR; + } + if(! ARG_IS_I(1, num_kx)) + { + if( ! ARG_IS_INTLIST(1, il) || !(il.n == 3) ) + { + Tcl_AppendResult(interp, "\n( | { }) integer or integer list of length 3 expected", (char *) NULL); + return TCL_ERROR; + } + else + { + num_kx = il.e[0]; + num_ky = il.e[1]; + num_kz = il.e[2]; + } + } + else + { + num_kz = num_ky = num_kx; + } + if (! ARG_IS_D(2, precision)) + { + Tcl_AppendResult(interp, "\n should be a double", (char *) NULL); + return TCL_ERROR; + } + + //Compute alpha + Particle *particle; + particle = (Particle*)malloc(n_part*sizeof(Particle)); + mpi_get_particles(particle, NULL); + double q_sqr = ewaldgpuForce->compute_q_sqare(particle); + alpha = ewaldgpuForce->compute_optimal_alpha(r_cut, num_kx, num_ky, num_kz, q_sqr, box_l, precision); + + //Turn on ewaldgpu + if (!ewaldgpuForce) // inter coulomb ewaldgpu was never called before + { + ewaldgpuForce = new EwaldgpuForce(espressoSystemInterface, r_cut, num_kx, num_ky, num_kz, alpha); + forceActors.add(ewaldgpuForce); + energyActors.add(ewaldgpuForce); + } + //Broadcast parameters + coulomb.method = COULOMB_EWALD_GPU; + ewaldgpu_params.isTunedFlag = false; + ewaldgpu_params.isTuned = true; + rebuild_verletlist = 1; + mpi_bcast_coulomb_params(); + return TCL_OK; +} + +#endif + diff --git a/src/tcl/actor/Ewaldgpu_tcl.hpp b/src/tcl/actor/Ewaldgpu_tcl.hpp new file mode 100644 index 00000000000..9d09b14c0d0 --- /dev/null +++ b/src/tcl/actor/Ewaldgpu_tcl.hpp @@ -0,0 +1,21 @@ +#ifndef EWALDGPU_TCL_H +#define EWALDGPU_TCL_H + +#include "parser.hpp" +#include "config.hpp" + +#ifdef EWALD_GPU + +#ifndef ELECTROSTATICS +#error EWALD_GPU requires ELECTROSTATICS +#endif + +int tclprint_to_result_ewaldgpu(Tcl_Interp *interp); +int tclcommand_inter_coulomb_parse_ewaldgpu(Tcl_Interp *interp, int argc, char **argv); +int tclcommand_inter_coulomb_parse_ewaldgpu_notune(Tcl_Interp * interp, int argc, char ** argv); +int tclcommand_inter_coulomb_parse_ewaldgpu_tune(Tcl_Interp * interp, int argc, char ** argv, int adaptive); +int tclcommand_inter_coulomb_parse_ewaldgpu_tunealpha(Tcl_Interp * interp, int argc, char ** argv); +#endif +#endif + + diff --git a/src/tcl/actor/HarmonicWell_tcl.cpp b/src/tcl/actor/HarmonicWell_tcl.cpp new file mode 100644 index 00000000000..378470a0a66 --- /dev/null +++ b/src/tcl/actor/HarmonicWell_tcl.cpp @@ -0,0 +1,61 @@ +/* + Copyright (C) 2012,2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "actor/HarmonicWell_tcl.hpp" + +#ifdef CUDA + +#include "forces.hpp" +#include "actor/HarmonicWell.hpp" +#include "EspressoSystemInterface.hpp" + +HarmonicWell *harmonicWell; + +int tclcommand_HarmonicWell(ClientData data, Tcl_Interp *interp, int argc, char **argv) { + DoubleList dl; + + init_doublelist(&dl); + + if(!ARG1_IS_DOUBLELIST(dl)) { + puts("Expected double list"); + return TCL_ERROR; + } + + if(dl.n != 4) { + puts("Wrong # of args"); + for(int i = 0; i < dl.n; i++) + printf("%d %e\n", i, dl.e[i]); + + return TCL_ERROR; + } + + // printf("x %e %e %e, k %e\n", dl.e[0], dl.e[1],dl.e[2],dl.e[3]); + + if (harmonicWell != NULL) + delete harmonicWell; + + harmonicWell = new HarmonicWell(dl.e[0], dl.e[1], dl.e[2], dl.e[3], + espressoSystemInterface); + + forceActors.push_back(harmonicWell); + return TCL_OK; +} + + +#endif diff --git a/src/tcl/actor/HarmonicWell_tcl.hpp b/src/tcl/actor/HarmonicWell_tcl.hpp new file mode 100644 index 00000000000..87d31d7a1e8 --- /dev/null +++ b/src/tcl/actor/HarmonicWell_tcl.hpp @@ -0,0 +1,31 @@ +/* + Copyright (C) 2012,2013,2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _ACTOR_HARMONICWELL_TCL_HPP +#define _ACTOR_HARMONICWELL_TCL_HPP + +#include "parser.hpp" + +#ifdef CUDA + +int tclcommand_HarmonicWell(ClientData data, Tcl_Interp *interp, int argc, char **argv); + +#endif + +#endif diff --git a/src/tcl/actor/Mmm1dgpu_tcl.cpp b/src/tcl/actor/Mmm1dgpu_tcl.cpp new file mode 100644 index 00000000000..0df775cba6b --- /dev/null +++ b/src/tcl/actor/Mmm1dgpu_tcl.cpp @@ -0,0 +1,129 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "Mmm1dgpu_tcl.hpp" +#include "forces.hpp" +#include "energy.hpp" +#include "actor/Mmm1dgpuForce.hpp" +#include "mmm1d.hpp" +#include "EspressoSystemInterface.hpp" + +#ifdef MMM1D_GPU + +Mmm1dgpuForce *mmm1dgpuForce; + +int tclprint_to_result_MMM1DGPU (Tcl_Interp * interp) +{ + char buffer[TCL_DOUBLE_SPACE]; + + Tcl_PrintDouble (interp, sqrt (mmm1d_params.far_switch_radius_2), buffer); + Tcl_AppendResult (interp, "mmm1dgpu ", buffer, " ", (char *) NULL); + sprintf (buffer, "%d", mmm1d_params.bessel_cutoff); + Tcl_AppendResult (interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble (interp, mmm1d_params.maxPWerror, buffer); + Tcl_AppendResult (interp, buffer, (char *) NULL); + + return TCL_OK; +} + +//void Mmm1dgpuForce::disable() +//{ +// if (!mmm1dgpuForce) { +// forceActors.remove(mmm1dgpuForce); +// if (coulomb.method == COULOMB_MMM1D_GPU) { +// coulomb.method = COULOMB_NONE; +// mpi_bcast_coulomb_params(); +// } +// } +//} + +int tclcommand_inter_coulomb_parse_mmm1dgpu (Tcl_Interp * interp, int argc, char **argv) +{ + double switch_rad, maxPWerror; + int bessel_cutoff; + + if (argc < 2) + { + Tcl_AppendResult (interp, "wrong # arguments: inter coulomb mmm1dgpu " + "{} | tune ", (char *) NULL); + return TCL_ERROR; + } + + if (ARG0_IS_S ("tune")) + { + /* autodetermine bessel cutoff AND switching radius */ + if (!ARG_IS_D (1, maxPWerror)) + return TCL_ERROR; + bessel_cutoff = -1; + switch_rad = -1; + } + else + { + if (argc == 2) + { + /* autodetermine bessel cutoff */ + if ((!ARG_IS_D (0, switch_rad)) || (!ARG_IS_D (1, maxPWerror))) + return TCL_ERROR; + bessel_cutoff = -1; + } + else if (argc == 3) + { + /* fully manual */ + if ((!ARG_IS_D (0, switch_rad)) || (!ARG_IS_I (1, bessel_cutoff)) || (!ARG_IS_D (2, maxPWerror))) + return TCL_ERROR; + + if (bessel_cutoff <= 0) + { + Tcl_AppendResult (interp, "bessel cutoff too small", (char *) NULL); + return TCL_ERROR; + } + } + else + { + Tcl_AppendResult (interp, "wrong # arguments: inter coulomb mmm1dgpu " "{} | tune ", (char *) NULL); + return TCL_ERROR; + } + + if (switch_rad <= 0 || switch_rad > box_l[2]) + { + Tcl_AppendResult (interp, "switching radius is not between 0 and box_l[2]", (char *) NULL); + return TCL_ERROR; + } + } + + // turn on MMM1DGPU + + /* coulomb.prefactor apparently is not available yet at this point */ + if (!mmm1dgpuForce) // inter coulomb mmm1dgpu was never called before + { + mmm1dgpuForce = new Mmm1dgpuForce(espressoSystemInterface, 0, maxPWerror, + switch_rad, bessel_cutoff); + forceActors.add(mmm1dgpuForce); + energyActors.add(mmm1dgpuForce); + } + /* set_params needs to be called both upon create and upon update because it is responsible for writing + to the struct from which the TCL command "inter coulomb" retrieves the current parameter set */ + mmm1dgpuForce->set_params(0, 0, maxPWerror, switch_rad, bessel_cutoff, true); + + coulomb.method = COULOMB_MMM1D_GPU; + mpi_bcast_coulomb_params(); + + return TCL_OK; +} + +#endif diff --git a/src/tcl/actor/Mmm1dgpu_tcl.hpp b/src/tcl/actor/Mmm1dgpu_tcl.hpp new file mode 100644 index 00000000000..de8d2ef3c7b --- /dev/null +++ b/src/tcl/actor/Mmm1dgpu_tcl.hpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef MMM1D_GPU_TCL_H +#define MMM1D_GPU_TCL_H + +#include "parser.hpp" +#include "config.hpp" + +#ifdef MMM1D_GPU + +#ifndef ELECTROSTATICS +#error MMM1D_GPU requires ELECTROSTATICS +#endif + +/// print the mmm1d parameters to the interpreters result +int tclprint_to_result_MMM1DGPU (Tcl_Interp * interp); + +/// parse the mmm1d parameters +int tclcommand_inter_coulomb_parse_mmm1dgpu (Tcl_Interp * interp, int argc, char **argv); + +#endif +#endif diff --git a/src/tcl/adresso_tcl.cpp b/src/tcl/adresso_tcl.cpp deleted file mode 100644 index b01a3c4e4a4..00000000000 --- a/src/tcl/adresso_tcl.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project - Copyright (C) 2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -/** \file adresso.c - This is the place for adaptive resolution scheme - Implementation of adresso.h -*/ - -#include "adresso_tcl.hpp" -#include "communication.hpp" -#include "parser.hpp" -#include "cells.hpp" -#include "adresso.hpp" -#include -#include "virtual_sites.hpp" -#include "interaction_data.hpp" - - -/** \name Privat Functions */ -/************************************************************/ -/*@{*/ -#ifdef ADRESS -/** prints adress settings */ -int tclcommand_adress_parse_print(Tcl_Interp *interp,int argc, char **argv); - -/** prints adress settings */ -int tclcommand_adress_parse_set(Tcl_Interp *interp,int argc, char **argv); - -#endif - -/*@}*/ - -int tclcommand_adress(ClientData data, Tcl_Interp *interp, int argc, char **argv){ - int err = TCL_OK; -#ifndef ADRESS - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "Adress is not compiled in (change config.h).", (char *)NULL); - err = (TCL_ERROR); -#else - if (argc < 2) { - Tcl_AppendResult(interp, "Wrong # of args! Usage: adress (set|print)", (char *)NULL); - err = (TCL_ERROR); - } - else{ - if (ARG1_IS_S("print")) err=tclcommand_adress_parse_print(interp,argc,argv); - else if (ARG1_IS_S("set")) err=tclcommand_adress_parse_set(interp,argc,argv); - else { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "The operation \"", argv[1],"\" you requested is not implemented.", (char *)NULL); - err = (TCL_ERROR); - } - } -#endif - return gather_runtime_errors(interp, err); -} - -#ifdef ADRESS -int tclcommand_adress_parse_print(Tcl_Interp *interp,int argc, char **argv){ - int topo=(int)adress_vars[0],dim; - char buffer[3*TCL_DOUBLE_SPACE]; - argv+=2;argc-=2; - Tcl_ResetResult(interp); - if (topo == 0) { - Tcl_AppendResult(interp,"adress topo 0", (char *)NULL); - return TCL_OK; - } - else if (topo == 1) { - Tcl_PrintDouble(interp, adress_vars[1], buffer); - Tcl_AppendResult(interp,"adress topo 1 width ",buffer, (char *)NULL); - return TCL_OK; - } - //topo 2 and 3 - sprintf(buffer,"%i",topo); - Tcl_AppendResult(interp,"adress topo ",buffer," width ",(char *)NULL); - Tcl_PrintDouble(interp, adress_vars[1], buffer); - Tcl_AppendResult(interp,buffer, " ", (char *)NULL); - Tcl_PrintDouble(interp, adress_vars[2], buffer); - Tcl_AppendResult(interp,buffer, " center ", (char *)NULL); - - if (topo==2) { - dim=(int)adress_vars[3]; - if (dim==0) sprintf(buffer,"x"); - else if (dim==1) sprintf(buffer,"y"); - else sprintf(buffer,"z"); - Tcl_AppendResult(interp,buffer," ", (char *)NULL); - Tcl_PrintDouble(interp, adress_vars[4], buffer); - } - else{ // topo == 3 - Tcl_PrintDouble(interp, adress_vars[3], buffer); - Tcl_AppendResult(interp,buffer," ", (char *)NULL); - Tcl_PrintDouble(interp, adress_vars[4], buffer); - Tcl_AppendResult(interp,buffer," ", (char *)NULL); - Tcl_PrintDouble(interp, adress_vars[5], buffer); - } - Tcl_AppendResult(interp,buffer, " wf ", (char *)NULL); - sprintf(buffer,"%i",(int)adress_vars[6]); - Tcl_AppendResult(interp,buffer, (char *)NULL); - - return TCL_OK; -} - -int tclcommand_adress_parse_set(Tcl_Interp *interp,int argc, char **argv){ - int topo=-1,i,wf=0,set_center=0; - double width[2],center[3]; - char buffer[3*TCL_DOUBLE_SPACE]; - argv+=2;argc-=2; - - for(i=0;i<3;i++) center[i]=box_l[i]/2; - - if (argc < 2) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "Wrong # of args! adress set needs at least 2 arguments\n", (char *)NULL); - Tcl_AppendResult(interp, "Usage: adress set topo [0|1|2|3] width X.X Y.Y (center X.X Y.Y Z.Z) (wf [0|1])\n", (char *)NULL); - Tcl_AppendResult(interp, "topo: 0 - switched off (no more values needed)\n", (char *)NULL); - Tcl_AppendResult(interp, " 1 - constant (weight will be first value of width)\n", (char *)NULL); - Tcl_AppendResult(interp, " 2 - divided in one direction (default x, or give a negative center coordinate\n", (char *)NULL); - Tcl_AppendResult(interp, " 3 - spherical topology\n", (char *)NULL); - Tcl_AppendResult(interp, "width: X.X - half of size of ex zone(r0/2 in the papers)\n", (char *)NULL); - Tcl_AppendResult(interp, " Y.Y - size of hybrid zone (d in the papers)\n", (char *)NULL); - Tcl_AppendResult(interp, " Note: Only one value need for topo 1 \n", (char *)NULL); - Tcl_AppendResult(interp, "center: center of the ex zone (default middle of the box) \n", (char *)NULL); - Tcl_AppendResult(interp, " Note: x|y|x X.X for topo 2 \n", (char *)NULL); - Tcl_AppendResult(interp, " Note: X.X Y.Y Z.Z for topo 3 \n", (char *)NULL); - Tcl_AppendResult(interp, "wf: 0 - cos weighting function (default)\n", (char *)NULL); - Tcl_AppendResult(interp, " 1 - polynom weighting function\n", (char *)NULL); - Tcl_AppendResult(interp, "ALWAYS set box_l first !!!", (char *)NULL); - return (TCL_ERROR); - } - - //parse topo - if ( (argc<2) || (!ARG0_IS_S("topo")) || (!ARG1_IS_I(topo)) || (topo < 0) || (topo > 3) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'topo 0|1|2|3\'\n", (char *)NULL); - return (TCL_ERROR); - } - argv+=2;argc-=2; - - //stop if topo is 0 - if (topo==0) { - adress_vars[0]=0.0; - mpi_bcast_parameter(FIELD_ADRESS); - return TCL_OK; - } - - //parse width - if ( (argc>1) && (ARG0_IS_S("width")) ) { - if (topo==1) { - if ( (!ARG1_IS_D(width[0])) || (width[0]<0) ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'width X.X (X.X non-negative)\'", (char *)NULL); - return (TCL_ERROR); - } - if ((width[0]> 1.0) || (width[0]< 0.0)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "for constant topo, first width must be between 0 and 1", (char *)NULL); - return (TCL_ERROR); - } - //stop if topo is 1 - adress_vars[0]=1; - adress_vars[1]=width[0]; - mpi_bcast_parameter(FIELD_ADRESS); - return TCL_OK; - } - else {//topo 2 and 3 are left over - if ( (argc<3) || (!ARG1_IS_D(width[0])) || (width[0]<0) ||(!ARG_IS_D(2,width[1])) || (width[1]<0) ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'width X.X Y.Y (both non-negative)\'", (char *)NULL); - return (TCL_ERROR); - } - argv+=3;argc-=3; - } - } - else{ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'width\'", (char *)NULL); - return (TCL_ERROR); - } - - while (argc!=0){ - if (ARG0_IS_S("wf")){ - if ( (argc<2) || (!ARG1_IS_I(wf)) || (wf < 0) || (wf > 1) ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'wf 0|1\'", (char *)NULL); - return (TCL_ERROR); - } - else{ - argv+=2;argc-=2; - } - } - else if (ARG0_IS_S("center")){ - if (topo == 2) { - if ( (argc<3) || ( (!ARG1_IS_S("x"))&&(!ARG1_IS_S("y"))&&(!ARG1_IS_S("z")) ) || (!ARG_IS_D(2,center[1])) ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'center x|y|z X.X\'", (char *)NULL); - return (TCL_ERROR); - } - if (ARG1_IS_S("x")) center[0]=0; - else if (ARG1_IS_S("y")) center[0]=1; - else center[0]=2; - if ( (center[1]<0) || (center[1]>box_l[(int)center[0]]) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "The center component is outside the box", (char *)NULL); - return (TCL_ERROR); - } - set_center=1; - argv+=3;argc-=3; - } - else { //topo 3 - if ( (argc<4) || (!ARG_IS_D(1,center[0])) || (!ARG_IS_D(2,center[1])) || (!ARG_IS_D(3,center[2])) ){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "expected \'center X.X Y.Y Z.Z\'", (char *)NULL); - return (TCL_ERROR); - } - argv+=4;argc-=4; - //check components of center - for (i=0;i<3;i++){ - if ( (center[i]<0)||(center[i]>box_l[i]) ){ - Tcl_ResetResult(interp); - sprintf(buffer,"%i",i); - Tcl_AppendResult(interp, "The ",buffer," th component of center is outside the box\n", (char *)NULL); - return (TCL_ERROR); - } - } - } - } - else{ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "The unknown operation \"", argv[0],"\".", (char *)NULL); - return (TCL_ERROR); - } - } - - //set standard center value for topo 2 - if ((topo==2) && (set_center==0) ) center[0]=0; - - //width check - if (topo==2){ - if (width[0]+width[1]>box_l[(int)center[0]]/2){ - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "The width of ex+hy must smaller than box_l/2\n", (char *)NULL); - return (TCL_ERROR); - } - } - else if (topo==3){ - for (i=0;i<3;i++){ - if (width[0]+width[1]>box_l[i]/2){ - Tcl_ResetResult(interp); - sprintf(buffer,"%i",i); - Tcl_AppendResult(interp, "The width of ex+hy must smaller than box_l/2 in dim " ,buffer,"\n", (char *)NULL); - return (TCL_ERROR); - } - } - } - - adress_vars[0]=topo; - adress_vars[1]=width[0]; - adress_vars[2]=width[1]; - adress_vars[3]=center[0]; - adress_vars[4]=center[1]; - adress_vars[5]=center[2]; - adress_vars[6]=wf; - - mpi_bcast_parameter(FIELD_ADRESS); - - return TCL_OK; -} - -/* #ifdef THERMODYNAMIC_FORCE */ -int tclcommand_thermodynamic_force(ClientData _data, Tcl_Interp * interp, int argc, char ** argv) -{ - int i, part_type, err_code; - double j, prefactor; - - Tcl_ResetResult(interp); - - if(argc != 4){ - Tcl_AppendResult(interp, "wrong # args: should be \"", - "thermodynamic_force \"", - (char *) NULL); - err_code = TCL_ERROR; - } - else { - i=ARG_IS_I(1, part_type); - j=ARG_IS_D(3,prefactor); - if(i && j) - err_code = tclcommand_thermodynamic_force_parse_opt(interp, part_type, prefactor, argc-2, argv+2); - else - err_code = TCL_ERROR; - } - - return err_code; -} - - -int tclcommand_thermodynamic_force_parse_opt(Tcl_Interp * interp, int type, double prefactor, int argc, char ** argv){ - char * filename = NULL; - - filename = argv[0]; - - switch(tf_set_params(type, prefactor, filename)){ - case 1: - Tcl_AppendResult(interp, "particle type must be non-negative", (char *) NULL); - return 0; - case 2: - Tcl_AppendResult(interp, "the length of the filename must be less than 256 characters," - "but is \"", filename, "\"", (char *)NULL); - return 0; - case 3: - Tcl_AppendResult(interp, "cannot open \"", filename, "\"", (char *)NULL); - return 0; - case 4: - Tcl_AppendResult(interp, "attempt to read file \"", filename, - "\" failed, could not find start the start token <#>", (char *)NULL); - return 0; - case 5: - Tcl_AppendResult(interp, "number of data points does not match the existing table", (char *)NULL); - return 0; - } - return TCL_OK; -} -/* #endif */ - -int tclcommand_update_adress_weights(ClientData _data, Tcl_Interp * interp, int argc, char ** argv) -{ - int err_code = TCL_OK; - - adress_update_weights(); - - return err_code; -} - -#ifdef INTERFACE_CORRECTION - -int adress_tab_parser(Tcl_Interp * interp, - int part_type_a, int part_type_b, - int argc, char ** argv) -{ - char *filename = NULL; - - /* adress_tab interactions should supply a file name for a file containing - both force and energy profiles as well as number of points, max - values etc. - */ - if (argc < 2) { - Tcl_AppendResult(interp, "tabulated potentials require a filename: " - "", - (char *) NULL); - return 0; - } - - /* copy tabulated parameters */ - filename = argv[1]; - - switch (adress_tab_set_params(part_type_a, part_type_b, filename)) { - case 1: - Tcl_AppendResult(interp, "particle types must be non-negative", (char *) NULL); - return 0; - case 2: - Tcl_AppendResult(interp, "the length of the filename must be less than 256 characters," - "but is \"", filename, "\"", (char *)NULL); - return 0; - case 3: - Tcl_AppendResult(interp, "cannot open \"", filename, "\"", (char *)NULL); - return 0; - case 4: - Tcl_AppendResult(interp, "attempt to read file \"", filename, - "\" failed, could not find start the start token <#>", (char *)NULL); - return 0; - } - return 2; -} - -#endif - -#endif diff --git a/src/tcl/adresso_tcl.hpp b/src/tcl/adresso_tcl.hpp deleted file mode 100644 index 85ae34e6820..00000000000 --- a/src/tcl/adresso_tcl.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (C) 2010,2012,2013 The ESPResSo project - Copyright (C) 2008,2009,2010 - Max-Planck-Institute for Polymer Research, Theory Group - - This file is part of ESPResSo. - - ESPResSo is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ESPResSo is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef ADRESSO_TCL_H -#define ADRESSO_TCL_H -/** \file adresso.h - This is the place for adaptive resolution scheme (adress) - Implementation of adresso.h - - For more details about adress see: - - M. Praprotnik, L. Delle Site and K. Kremer, JCP 123, 224106, 2005. - - M. Praprotnik, L. Delle Site and K. Kremer, Annu. Rev. Phys. Chem. 59, 545-571, 2008. - - S. Poblete, M. Praprotnik, K. Kremer and L. Delle Site, J. Chem. Phys. 132, 114101, 2010. - - For more detail about the implementation here see: - - C. Junghans and S. Poblete, Comp. Phys. Comm. 181, 1449, 2010. -*/ -#include "parser.hpp" - -/** \name Exported Functions */ -/************************************************************/ -/*@{*/ -/** Implements the Tcl command "adress". This allows for seetings for adress -*/ -int tclcommand_adress(ClientData data, Tcl_Interp *interp, int argc, char **argv); - -int tclcommand_update_adress_weights(ClientData _data, Tcl_Interp * interp, int argc, char ** argv); - -#ifdef ADRESS - -/* #ifdef THERMODYNAMIC_FORCE */ -int tclcommand_thermodynamic_force_parse_opt(Tcl_Interp * interp, int type, double prefactor, int argc, char ** argv); -int tclcommand_thermodynamic_force(ClientData _data, Tcl_Interp * interp, int argc, char ** argv); -/* #endif */ - -/// -int adress_tab_parser(Tcl_Interp * interp, - int part_type_a, int part_type_b, - int argc, char ** argv); -#endif -/*@}*/ -#endif diff --git a/src/tcl/angle_cosine_tcl.cpp b/src/tcl/angle_cosine_tcl.cpp index cb04820c6dd..5d76671ce3c 100644 --- a/src/tcl/angle_cosine_tcl.cpp +++ b/src/tcl/angle_cosine_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_cosine_tcl.c +/** \file angle_cosine_tcl.cpp * * Implementation of \ref angle_cosine_tcl.hpp */ diff --git a/src/tcl/angle_cosine_tcl.hpp b/src/tcl/angle_cosine_tcl.hpp index 70b63dc309f..03a5174763c 100644 --- a/src/tcl/angle_cosine_tcl.hpp +++ b/src/tcl/angle_cosine_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _ANGLE_COSINE_TCL_H #define _ANGLE_COSINE_TCL_H /** \file angle_cosine_tcl.hpp - * Tcl interface for \ref angle_cosine.h + * Tcl interface for \ref angle_cosine.hpp */ #include "parser.hpp" diff --git a/src/tcl/angle_cossquare_tcl.cpp b/src/tcl/angle_cossquare_tcl.cpp index 374623322e6..478715b5201 100644 --- a/src/tcl/angle_cossquare_tcl.cpp +++ b/src/tcl/angle_cossquare_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_cossquare_tcl.c +/** \file angle_cossquare_tcl.cpp * * Implementation of \ref angle_cossquare_tcl.hpp */ diff --git a/src/tcl/angle_cossquare_tcl.hpp b/src/tcl/angle_cossquare_tcl.hpp index a31ae0f28cf..91ad8b04271 100644 --- a/src/tcl/angle_cossquare_tcl.hpp +++ b/src/tcl/angle_cossquare_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _ANGLE_COSSQUARE_TCL_H #define _ANGLE_COSSQUARE_TCL_H /** \file angle_cossquare_tcl.hpp - * Tcl interface for \ref angle_cossquare.h + * Tcl interface for \ref angle_cossquare.hpp */ #include "parser.hpp" diff --git a/src/tcl/angle_harmonic_tcl.cpp b/src/tcl/angle_harmonic_tcl.cpp index 81d0e5228c2..114deca608d 100644 --- a/src/tcl/angle_harmonic_tcl.cpp +++ b/src/tcl/angle_harmonic_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_harmonic_tcl.c +/** \file angle_harmonic_tcl.cpp * * Implementation of \ref angle_harmonic_tcl.hpp */ diff --git a/src/tcl/angle_harmonic_tcl.hpp b/src/tcl/angle_harmonic_tcl.hpp index cbdb1909a26..6e07fbd514d 100644 --- a/src/tcl/angle_harmonic_tcl.hpp +++ b/src/tcl/angle_harmonic_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _ANGLE_HARMONIC_TCL_H #define _ANGLE_HARMONIC_TCL_H /** \file angle_harmonic_tcl.hpp - * Tcl interface for \ref angle_harmonic.h + * Tcl interface for \ref angle_harmonic.hpp */ #include "config.hpp" diff --git a/src/tcl/angle_tcl.cpp b/src/tcl/angle_tcl.cpp index ab1918c68b7..ac7d0f4c4e3 100644 --- a/src/tcl/angle_tcl.cpp +++ b/src/tcl/angle_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angle_tcl.c +/** \file angle_tcl.cpp * * Implementation of \ref angle_tcl.hpp */ diff --git a/src/tcl/angle_tcl.hpp b/src/tcl/angle_tcl.hpp index e13f17dbbbd..7472ba6d8e8 100644 --- a/src/tcl/angle_tcl.hpp +++ b/src/tcl/angle_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _ANGLE_TCL_H #define _ANGLE_TCL_H /** \file angle_tcl.hpp - * Tcl interface for \ref angle.h + * Tcl interface for \ref angle.hpp */ #include "parser.hpp" diff --git a/src/tcl/angledist_tcl.cpp b/src/tcl/angledist_tcl.cpp index 360fb882a7f..3643755af94 100644 --- a/src/tcl/angledist_tcl.cpp +++ b/src/tcl/angledist_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file angledist_tcl.c +/** \file angledist_tcl.cpp * * Implementation of \ref angledist_tcl.hpp */ diff --git a/src/tcl/angledist_tcl.hpp b/src/tcl/angledist_tcl.hpp index 797604394c3..14c01fe57a9 100644 --- a/src/tcl/angledist_tcl.hpp +++ b/src/tcl/angledist_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef ANGLEDIST_TCL_H #define ANGLEDIST_TCL_H /** \file angledist_tcl.hpp - * Tcl interface for \ref angledist.h + * Tcl interface for \ref angledist.hpp */ #include "parser.hpp" diff --git a/src/tcl/bin_tcl.cpp b/src/tcl/bin_tcl.cpp index bbb4156011b..f0107d5ed86 100644 --- a/src/tcl/bin_tcl.cpp +++ b/src/tcl/bin_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/binary_file_tcl.cpp b/src/tcl/binary_file_tcl.cpp index 2b0a9fcf3fe..3bcec58c441 100644 --- a/src/tcl/binary_file_tcl.cpp +++ b/src/tcl/binary_file_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file binary_file_tcl.c +/** \file binary_file_tcl.cpp Implementation of \ref binary_file_tcl.hpp "binary_file_tcl.h". */ #include @@ -148,8 +148,12 @@ int tclcommand_writemd(ClientData data, Tcl_Interp *interp, for (p = 0; p <= max_seen_particle; p++) { Particle data; - if (get_particle_data(p, &data)) { + if (get_particle_data(p, &data) == ES_OK) { +#ifdef LEES_EDWARDS + unfold_position(data.r.p, data.m.v, data.l.i); +#else unfold_position(data.r.p, data.l.i); +#endif /* write particle index */ Tcl_Write(channel, (char *)&p, sizeof(int)); diff --git a/src/tcl/binary_file_tcl.hpp b/src/tcl/binary_file_tcl.hpp index 48ecb4dc278..a9e722217fa 100644 --- a/src/tcl/binary_file_tcl.hpp +++ b/src/tcl/binary_file_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -26,7 +26,7 @@ The functions in this file are no longer supported by the Espresso team. Use them at your own risk! - It is the header file for \ref binary_file_tcl.c "binary_file_tcl.c" and provides + It is the header file for \ref binary_file_tcl.cpp "binary_file_tcl.c" and provides functions to read and write binary particle data to Tcl channels. It also defines the structures and constants necessary to interprete/ generate particle data files in this format. THE FILE FORMAT IS HARDWARE diff --git a/src/tcl/blockfile_tcl.cpp b/src/tcl/blockfile_tcl.cpp index 6ac72000ca3..62cb4138662 100644 --- a/src/tcl/blockfile_tcl.cpp +++ b/src/tcl/blockfile_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file blockfile_tcl.c +/** \file blockfile_tcl.cpp Implements the blockfile command for writing Tcl-formatted data files. */ diff --git a/src/tcl/bmhtf-nacl_tcl.cpp b/src/tcl/bmhtf-nacl_tcl.cpp index 0f72ccb0eb0..31c3ed9b7c6 100644 --- a/src/tcl/bmhtf-nacl_tcl.cpp +++ b/src/tcl/bmhtf-nacl_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file bmhtf-nacl_tcl.c +/** \file bmhtf-nacl_tcl.cpp * * Implementation of \ref bmhtf-nacl_tcl.hpp */ diff --git a/src/tcl/bmhtf-nacl_tcl.hpp b/src/tcl/bmhtf-nacl_tcl.hpp index e24e1288fff..a209d4f0c67 100644 --- a/src/tcl/bmhtf-nacl_tcl.hpp +++ b/src/tcl/bmhtf-nacl_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef BMHTF_NACL_TCL_H #define BMHTF_NACL_TCL_H /** \file bmhtf-nacl_tcl.hpp - * Tcl interface for \ref bmhtf-nacl.h + * Tcl interface for \ref bmhtf-nacl.hpp */ #include "parser.hpp" diff --git a/src/tcl/bonded_coulomb_tcl.cpp b/src/tcl/bonded_coulomb_tcl.cpp new file mode 100644 index 00000000000..553dd47ea9e --- /dev/null +++ b/src/tcl/bonded_coulomb_tcl.cpp @@ -0,0 +1,59 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file bonded_coulomb_tcl.cpp + * + * Implementation of \ref bonded_coulomb_tcl.hpp + */ +#include "bonded_coulomb_tcl.hpp" +#include "bonded_coulomb.hpp" + +#ifdef ELECTROSTATICS + +int tclcommand_inter_parse_bonded_coulomb(Tcl_Interp *interp, int bond_type, int argc, char **argv) +{ + double prefactor; + + if (argc != 2) { + Tcl_AppendResult(interp, "bonded_coulomb exactly one parameter: " + "", (char *) NULL); + return TCL_ERROR; + } + + if (! ARG_IS_D(1, prefactor)) { + Tcl_AppendResult(interp, "bonded_coulomb needs 1 DOUBLE parameters: " + "", (char *) NULL); + return TCL_ERROR; + } + + CHECK_VALUE(bonded_coulomb_set_params(bond_type, prefactor), "bond type must be nonnegative"); +} + +int tclprint_to_result_bonded_coulombIA(Tcl_Interp *interp, Bonded_ia_parameters *params) +{ + char buffer[TCL_DOUBLE_SPACE]; + + Tcl_PrintDouble(interp, params->p.bonded_coulomb.prefactor, buffer); + Tcl_AppendResult(interp, "BONDED_COULOMB ", buffer, " ", (char *) NULL); + + return TCL_OK; +} + +#endif diff --git a/src/tcl/bonded_coulomb_tcl.hpp b/src/tcl/bonded_coulomb_tcl.hpp new file mode 100644 index 00000000000..b153a49eaa8 --- /dev/null +++ b/src/tcl/bonded_coulomb_tcl.hpp @@ -0,0 +1,40 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef BONDED_COULOMB_TCL_H +#define BONDED_COULOMB_TCL_H +/** \file bonded_coulomb_tcl.hpp + * Tcl interface for \ref bonded_coulomb.hpp + */ + +#include "parser.hpp" +#include "interaction_data.hpp" + +#ifdef ELECTROSTATICS + +/// parse parameters for the bonded_coulomb potential +int tclcommand_inter_parse_bonded_coulomb(Tcl_Interp *interp, int bond_type, int argc, char **argv); + +/// +int tclprint_to_result_bonded_coulombIA(Tcl_Interp *interp, Bonded_ia_parameters *params); + +#endif + +#endif diff --git a/src/tcl/buckingham_tcl.cpp b/src/tcl/buckingham_tcl.cpp index 62767d863fd..fac59e8c091 100644 --- a/src/tcl/buckingham_tcl.cpp +++ b/src/tcl/buckingham_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file buckingham_tcl.c +/** \file buckingham_tcl.cpp * * Implementation of \ref buckingham_tcl.hpp */ diff --git a/src/tcl/buckingham_tcl.hpp b/src/tcl/buckingham_tcl.hpp index 8f30fc830ea..58001681d27 100644 --- a/src/tcl/buckingham_tcl.hpp +++ b/src/tcl/buckingham_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef BUCKINGHAM_TCL_H #define BUCKINGHAM_TCL_H /** \file buckingham_tcl.hpp - * Tcl interface for \ref buckingham.h + * Tcl interface for \ref buckingham.hpp */ #include "parser.hpp" diff --git a/src/tcl/cells_tcl.cpp b/src/tcl/cells_tcl.cpp index df869506f58..893a1e45a3d 100644 --- a/src/tcl/cells_tcl.cpp +++ b/src/tcl/cells_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,11 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file cells.c +/** \file cells.cpp * * This file contains functions for the cell system. * - * For more information on cells, see cells.h + * For more information on cells, see cells.hpp * */ #include "parser.hpp" #include "domain_decomposition.hpp" @@ -30,11 +30,15 @@ #include "ghosts.hpp" #include "verlet.hpp" - /************************************************************ * Exported Functions * ************************************************************/ +int tclcommand_sort_particles(ClientData data, Tcl_Interp *interp, int argc, char **argv) { + mpi_bcast_event(SORT_PARTICLES); + return TCL_OK; +} + int tclcommand_cellsystem(ClientData data, Tcl_Interp *interp, int argc, char **argv) { diff --git a/src/tcl/cells_tcl.hpp b/src/tcl/cells_tcl.hpp new file mode 100644 index 00000000000..95847719321 --- /dev/null +++ b/src/tcl/cells_tcl.hpp @@ -0,0 +1,39 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _CELLS_TCL_H +#define _CELLS_TCL_H +#include "parser.hpp" + +/** \name Exported Functions */ +/************************************************************/ +/*@{*/ + +/** implementation of the Tcl command cellsystem. See \ref cells_tcl.cpp */ +int tclcommand_cellsystem(ClientData data, Tcl_Interp *interp, + int argc, char **argv); + +/** implementation of the Tcl command sort_particles. See \ref cells_tcl.cpp */ +int tclcommand_sort_particles(ClientData data, Tcl_Interp *interp, + int argc, char **argv); + +/*@}*/ + +#endif diff --git a/src/tcl/channels_tcl.cpp b/src/tcl/channels_tcl.cpp index 0f9e6dcb5cd..5b3c8a099a6 100644 --- a/src/tcl/channels_tcl.cpp +++ b/src/tcl/channels_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/collision_tcl.cpp b/src/tcl/collision_tcl.cpp index 0a84f887287..1fa1ac78d59 100644 --- a/src/tcl/collision_tcl.cpp +++ b/src/tcl/collision_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2011,2012,2013 The ESPResSo project + Copyright (C) 2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/src/tcl/comfixed_tcl.cpp b/src/tcl/comfixed_tcl.cpp index eebc950f4ab..db8159b16f1 100644 --- a/src/tcl/comfixed_tcl.cpp +++ b/src/tcl/comfixed_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file comfixed_tcl.c +/** \file comfixed_tcl.cpp * * Implementation of \ref comfixed_tcl.hpp */ @@ -71,9 +71,6 @@ int tclcommand_inter_parse_comfixed(Tcl_Interp * interp, case 2: Tcl_AppendResult(interp, "works only with a single CPU", (char *) NULL); return 0; - case 3: - Tcl_AppendResult(interp, "works only with non periodic BC", (char *) NULL); - return 0; } return 2; diff --git a/src/tcl/comfixed_tcl.hpp b/src/tcl/comfixed_tcl.hpp index 2e2b87e2344..f1705abf643 100644 --- a/src/tcl/comfixed_tcl.hpp +++ b/src/tcl/comfixed_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef COMFIXED_TCL_H #define COMFIXED_TCL_H /** \file comfixed_tcl.hpp - * Tcl interface for \ref comfixed.h + * Tcl interface for \ref comfixed.hpp */ #include "parser.hpp" diff --git a/src/tcl/comforce_tcl.cpp b/src/tcl/comforce_tcl.cpp index 2b164485dfd..ff8150cfb86 100644 --- a/src/tcl/comforce_tcl.cpp +++ b/src/tcl/comforce_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file comforce_tcl.c +/** \file comforce_tcl.cpp * * Implementation of \ref comforce_tcl.hpp. */ diff --git a/src/tcl/comforce_tcl.hpp b/src/tcl/comforce_tcl.hpp index 799121c1e8f..8ed417f6fdb 100644 --- a/src/tcl/comforce_tcl.hpp +++ b/src/tcl/comforce_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef COMFORCE_TCL_H #define COMFORCE_TCL_H /** \file comforce_tcl.hpp - Tcl interface for \ref comforce.h. + Tcl interface for \ref comforce.hpp. */ #include "parser.hpp" diff --git a/src/tcl/config_tcl.cpp b/src/tcl/config_tcl.cpp index 4de91eb8982..c03182bbea8 100644 --- a/src/tcl/config_tcl.cpp +++ b/src/tcl/config_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file config_tcl.c +/** \file config_tcl.cpp * * contains code_info and version stuff. */ diff --git a/src/tcl/constraint_tcl.cpp b/src/tcl/constraint_tcl.cpp index fedd7acf315..85845af71de 100644 --- a/src/tcl/constraint_tcl.cpp +++ b/src/tcl/constraint_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file constraint.c - Implementation of \ref constraint.h "constraint.h", here it's just the parsing stuff. +/** \file constraint.cpp + Implementation of \ref constraint.hpp "constraint.h", here it's just the parsing stuff. */ +#include #include "constraint.hpp" #include "communication.hpp" #include "parser.hpp" +#include "TclOutputHelper.hpp" #ifdef CONSTRAINTS static int tclprint_to_result_Constraint(Tcl_Interp *interp, int i) @@ -47,6 +49,8 @@ static int tclprint_to_result_Constraint(Tcl_Interp *interp, int i) Tcl_AppendResult(interp, " type ", buffer, (char *) NULL); sprintf(buffer, "%d", con->c.wal.penetrable); Tcl_AppendResult(interp, " penetrable ", buffer, (char *) NULL); + sprintf(buffer, "%d", con->c.wal.only_positive); + Tcl_AppendResult(interp, " only_positive ", buffer, (char *) NULL); break; case CONSTRAINT_SPH: Tcl_PrintDouble(interp, con->c.sph.pos[0], buffer); @@ -169,7 +173,6 @@ static int tclprint_to_result_Constraint(Tcl_Interp *interp, int i) Tcl_AppendResult(interp, " type ", buffer, (char *) NULL); break; case CONSTRAINT_STOMATOCYTE: - Tcl_PrintDouble(interp, con->c.stomatocyte.position_x, buffer); Tcl_AppendResult(interp, "stomatocyte center ", buffer, " ", (char *) NULL); Tcl_PrintDouble(interp, con->c.stomatocyte.position_y, buffer); @@ -197,6 +200,36 @@ static int tclprint_to_result_Constraint(Tcl_Interp *interp, int i) Tcl_PrintDouble(interp, con->c.stomatocyte.reflecting, buffer); Tcl_AppendResult(interp, " reflecting ", buffer, (char *) NULL); break; + case CONSTRAINT_HOLLOW_CONE: + Tcl_PrintDouble(interp, con->c.hollow_cone.position_x, buffer); + Tcl_AppendResult(interp, "hollow_cone center ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.position_y, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.position_z, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.orientation_x, buffer); + Tcl_AppendResult(interp, " orientation ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.orientation_y, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.orientation_z, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.outer_radius, buffer); + Tcl_AppendResult(interp, " outer radius ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.inner_radius, buffer); + Tcl_AppendResult(interp, " inner radius ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.width, buffer); + Tcl_AppendResult(interp, " width ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.opening_angle, buffer); + Tcl_AppendResult(interp, " opening angle ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.direction, buffer); + Tcl_AppendResult(interp, " direction ", buffer, (char *) NULL); + sprintf(buffer, "%d", con->part_rep.p.type); + Tcl_AppendResult(interp, " type ", buffer, (char *) NULL); + sprintf(buffer, "%d", con->c.hollow_cone.penetrable); + Tcl_AppendResult(interp, " penetrable ", buffer, (char *) NULL); + Tcl_PrintDouble(interp, con->c.hollow_cone.reflecting, buffer); + Tcl_AppendResult(interp, " reflecting ", buffer, (char *) NULL); + break; //ER case CONSTRAINT_EXT_MAGN_FIELD: Tcl_PrintDouble(interp, con->c.emfield.ext_magn_field[0], buffer); @@ -254,6 +287,14 @@ static void tclprint_to_result_ConstraintForce(Tcl_Interp *interp, int con) Tcl_AppendResult(interp, buffer, (char *) NULL); } + +static void tclprint_to_result_n_constraints(Tcl_Interp *interp) +{ + char buffer[TCL_INTEGER_SPACE]; + sprintf(buffer, "%d", n_constraints); + Tcl_AppendResult(interp, buffer, (char *) NULL); +} + static int tclcommand_constraint_parse_wall(Constraint *con, Tcl_Interp *interp, int argc, char **argv) { @@ -266,6 +307,7 @@ static int tclcommand_constraint_parse_wall(Constraint *con, Tcl_Interp *interp, con->c.wal.n[2] = 0; con->c.wal.d = 0; con->c.wal.penetrable = 0; + con->c.wal.only_positive = 0; con->part_rep.p.type = -1; while (argc > 0) { if(!strncmp(argv[0], "normal", strlen(argv[0]))) { @@ -315,6 +357,15 @@ static int tclcommand_constraint_parse_wall(Constraint *con, Tcl_Interp *interp, return (TCL_ERROR); argc -= 2; argv += 2; } + else if(!strncmp(argv[0], "only_positive", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint wall only_positive {0|1} expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetInt(interp, argv[1], &(con->c.wal.only_positive)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } else break; } @@ -741,10 +792,15 @@ static int tclcommand_constraint_parse_pore(Constraint *con, Tcl_Interp *interp, con->c.pore.axis[2] = 0; con->c.pore.rad_left = 0; con->c.pore.rad_right = 0; + con->c.pore.outer_rad_left = 1e99; + con->c.pore.outer_rad_right = 1e99; con->c.pore.length = 0; con->c.pore.reflecting = 0; con->part_rep.p.type = -1; con->c.pore.smoothing_radius = 1.; + con->c.pore.outer_rad_left = std::numeric_limits::max(); + con->c.pore.outer_rad_right = std::numeric_limits::max(); + while (argc > 0) { if(!strncmp(argv[0], "center", strlen(argv[0]))) { if(argc < 4) { @@ -779,6 +835,16 @@ static int tclcommand_constraint_parse_pore(Constraint *con, Tcl_Interp *interp, con->c.pore.rad_right = con->c.pore.rad_left; argc -= 2; argv += 2; } + else if(!strncmp(argv[0], "outer_radius", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint pore outer_radius expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.pore.outer_rad_left)) == TCL_ERROR) + return (TCL_ERROR); + con->c.pore.outer_rad_right = con->c.pore.outer_rad_left; + argc -= 2; argv += 2; + } else if(!strncmp(argv[0], "smoothing_radius", strlen(argv[0]))) { if (argc < 1) { Tcl_AppendResult(interp, "constraint pore smoothing_radius expected", (char *) NULL); @@ -799,6 +865,17 @@ static int tclcommand_constraint_parse_pore(Constraint *con, Tcl_Interp *interp, return (TCL_ERROR); argc -= 3; argv += 3; } + else if(!strncmp(argv[0], "outer_radii", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint pore outer_radii expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.pore.outer_rad_left)) == TCL_ERROR) + return (TCL_ERROR); + if (Tcl_GetDouble(interp, argv[2], &(con->c.pore.outer_rad_right)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 3; argv += 3; + } else if(!strncmp(argv[0], "length", strlen(argv[0]))) { if (argc < 1) { Tcl_AppendResult(interp, "constraint pore length expected", (char *) NULL); @@ -853,6 +930,125 @@ static int tclcommand_constraint_parse_pore(Constraint *con, Tcl_Interp *interp, return (TCL_OK); } + +static int tclcommand_constraint_parse_slitpore(Constraint *con, Tcl_Interp *interp, + int argc, char **argv) +{ + + con->type = CONSTRAINT_SLITPORE; + /* invalid entries to start of */ + con->c.slitpore.pore_mouth = 0; + con->c.slitpore.channel_width = 0; + con->c.slitpore.pore_width = 0; + con->c.slitpore.pore_length = 0; + con->c.slitpore.upper_smoothing_radius = 0; + con->c.slitpore.lower_smoothing_radius = 0; + con->c.slitpore.reflecting = 0; + con->part_rep.p.type = -1; + while (argc > 0) { + if(!strncmp(argv[0], "pore_mouth", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore mouth expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.pore_mouth)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "pore_width", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore pore_width expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.pore_width)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "pore_length", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore pore_width expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.pore_length)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "channel_width", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore channel_width expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.channel_width)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "upper_smoothing_radius", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore upper_smoothing_radius expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.upper_smoothing_radius)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "lower_smoothing_radius", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint slitpore lower_smoothing_radius expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetDouble(interp, argv[1], &(con->c.slitpore.lower_smoothing_radius)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "type", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint pore type expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetInt(interp, argv[1], &(con->part_rep.p.type)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "reflecting", strlen(argv[0]))) { + if (argc < 1) { + Tcl_AppendResult(interp, "constraint pore reflecting {0|1} expected", (char *) NULL); + return (TCL_ERROR); + } + if (Tcl_GetInt(interp, argv[1], &(con->c.slitpore.reflecting)) == TCL_ERROR) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else + break; + } + + int error = 0; + if (con->c.slitpore.channel_width <= 0.) { + Tcl_AppendResult(interp, "Error in contraint slitpore: Channel with must be > 0", (char *) NULL); + error=1; + } + if ( con->c.slitpore.pore_width <= 0. ) { + Tcl_AppendResult(interp, "Error in contraint slitpore: Pore width must be > 0", (char *) NULL); + error=1; + } + if ( con->c.slitpore.pore_length < 0. ) { + Tcl_AppendResult(interp, "Error in contraint slitpore: Pore length must be > 0", (char *) NULL); + error=1; + } + if ( con->part_rep.p.type < 0 ) { + Tcl_AppendResult(interp, "Error in contraint slitpore: Type not set", (char *) NULL); + error=1; + } + + if (error) + return (TCL_ERROR); + + make_particle_type_exist(con->part_rep.p.type); + + return (TCL_OK); +} + + static int tclcommand_constraint_parse_rod(Constraint *con, Tcl_Interp *interp, int argc, char **argv) { @@ -1110,6 +1306,200 @@ static int tclcommand_constraint_parse_stomatocyte(Constraint *con, Tcl_Interp * return (TCL_OK); } +static int tclcommand_constraint_parse_hollow_cone(Constraint *con, Tcl_Interp *interp, + int argc, char **argv) +{ + con->type = CONSTRAINT_HOLLOW_CONE; + + /* invalid entries to start of */ + + con->c.hollow_cone.position_x = -M_PI; + con->c.hollow_cone.position_y = -M_PI; + con->c.hollow_cone.position_z = -M_PI; + con->c.hollow_cone.orientation_x = -M_PI; + con->c.hollow_cone.orientation_y = -M_PI; + con->c.hollow_cone.orientation_z = -M_PI; + con->c.hollow_cone.outer_radius = -1.0; + con->c.hollow_cone.inner_radius = -1.0; + con->c.hollow_cone.width = -1.0; + con->c.hollow_cone.opening_angle = -1.0; + con->c.hollow_cone.direction = 0; + con->c.hollow_cone.penetrable = 0; + con->c.hollow_cone.reflecting = 0; + con->part_rep.p.type = -1; + + /* read the data */ + + while ( argc > 0 ) + { + if ( ARG_IS_S( 0, "center" ) ) + { + if(argc < 4) + { + Tcl_AppendResult(interp, "constraint hollow_cone center expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, con->c.hollow_cone.position_x ) || + !ARG_IS_D( 2, con->c.hollow_cone.position_y ) || + !ARG_IS_D( 3, con->c.hollow_cone.position_z ) ) + { + return (TCL_ERROR); + } + + argc -= 4; argv += 4; + } + else if ( ARG_IS_S( 0, "orientation" ) ) + { + if(argc < 4) + { + Tcl_AppendResult(interp, "constraint hollow_cone orientation expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, con->c.hollow_cone.orientation_x ) || + !ARG_IS_D( 2, con->c.hollow_cone.orientation_y ) || + !ARG_IS_D( 3, con->c.hollow_cone.orientation_z ) ) + { + return (TCL_ERROR); + } + + argc -= 4; argv += 4; + } + else if ( ARG_IS_S( 0, "outer_radius" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "constraint hollow_cone outer_radius expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D(1, con->c.hollow_cone.outer_radius ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "inner_radius" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "constraint hollow_cone inner_radius expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, con->c.hollow_cone.inner_radius ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "width" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "constraint hollow_cone width expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, con->c.hollow_cone.width ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "opening_angle" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "constraint hollow_cone opening_angle expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, con->c.hollow_cone.opening_angle ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "direction" ) ) + { + if ( argc < 2 ) + { + Tcl_AppendResult(interp, "constraint hollow_cone direction {-1|1} or {inside|outside} is expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( ARG_IS_S( 1, "inside" ) ) + con->c.hollow_cone.direction = -1; + else if ( ARG_IS_S( 1, "outside" ) ) + con->c.hollow_cone.direction = 1; + else if ( !ARG_IS_D( 1, con->c.hollow_cone.direction ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "type" ) ) + { + if ( argc < 2 ) + { + Tcl_AppendResult(interp, "constraint hollow_cone type expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_I( 1, con->part_rep.p.type ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "penetrable" ) ) + { + if ( argc < 2 ) + { + Tcl_AppendResult(interp, "constraint hollow_cone penetrable {0|1} expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_I( 1, con->c.hollow_cone.penetrable ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "reflecting" ) ) + { + if (argc < 1) + { + Tcl_AppendResult(interp, "constraint hollow_cone reflecting {0|1} expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_I( 1, con->c.hollow_cone.reflecting ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else + break; + } + + if ( con->c.hollow_cone.outer_radius < 0.0 || + con->c.hollow_cone.inner_radius < 0.0 || + con->c.hollow_cone.width < 0.0 ) + { + Tcl_AppendResult(interp, "hollow_cone radii and width have to be greater than zero", + (char *) NULL); + return (TCL_ERROR); + } + + if ( con->c.hollow_cone.opening_angle < 0.0 || + con->c.hollow_cone.opening_angle > M_PI ) + { + Tcl_AppendResult(interp, "hollow_cone requires 0.0 <= opening_angle <= Pi", + (char *) NULL); + return (TCL_ERROR); + } + + make_particle_type_exist(con->part_rep.p.type); + + return (TCL_OK); +} + static int tclcommand_constraint_parse_maze(Constraint *con, Tcl_Interp *interp, int argc, char **argv) { @@ -1317,12 +1707,23 @@ static int tclcommand_constraint_mindist_position(Tcl_Interp *interp, int argc, else dist=1e100; break; + case CONSTRAINT_HOLLOW_CONE: + if ( !constraints[n].c.hollow_cone.penetrable ) + calculate_hollow_cone_dist(p1, pos, &constraints[n].part_rep, &constraints[n].c.hollow_cone, &dist, vec); + else + dist=1e100; + break; case CONSTRAINT_PORE: calculate_pore_dist(p1, pos, &constraints[n].part_rep, &constraints[n].c.pore, &dist, vec); break; + case CONSTRAINT_SLITPORE: + calculate_slitpore_dist(p1, pos, &constraints[n].part_rep, &constraints[n].c.slitpore, &dist, vec); + break; case CONSTRAINT_PLANE: calculate_plane_dist(p1, pos, &constraints[n].part_rep, &constraints[n].c.plane, &dist, vec); break; + default: // rest of constraints just don't have associated distances + break; } mindist = dist. +*/ +/* Just an empty file that is compiled as workaround for CUDA with Xcode 4.3 and openmpi. + If CUDA files are only included via archives, the linking breaks and creates unstartable binaries. + */ diff --git a/src/tcl/debye_hueckel_tcl.cpp b/src/tcl/debye_hueckel_tcl.cpp index e8e1143e9dc..75e6580bd53 100644 --- a/src/tcl/debye_hueckel_tcl.cpp +++ b/src/tcl/debye_hueckel_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file debye_hueckel_tcl.c +/** \file debye_hueckel_tcl.cpp * * Implementation of \ref debye_hueckel_tcl.hpp */ diff --git a/src/tcl/debye_hueckel_tcl.hpp b/src/tcl/debye_hueckel_tcl.hpp index b65cee09638..067abc24214 100644 --- a/src/tcl/debye_hueckel_tcl.hpp +++ b/src/tcl/debye_hueckel_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef DEBYE_HUECKEL_TCL_H #define DEBYE_HUECKEL_TCL_H /** \file debye_hueckel_tcl.hpp - * Tcl interface for \ref debye_hueckel.h + * Tcl interface for \ref debye_hueckel.hpp */ #include "parser.hpp" diff --git a/src/tcl/dihedral_tcl.cpp b/src/tcl/dihedral_tcl.cpp index 402388e5b0b..1cf461e834a 100644 --- a/src/tcl/dihedral_tcl.cpp +++ b/src/tcl/dihedral_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file dihedral_tcl.c +/** \file dihedral_tcl.cpp * * Parser for the dihedral potential */ diff --git a/src/tcl/dihedral_tcl.hpp b/src/tcl/dihedral_tcl.hpp index fb7d7ef5632..711017ea29e 100644 --- a/src/tcl/dihedral_tcl.hpp +++ b/src/tcl/dihedral_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,13 +21,13 @@ #ifndef DIHEDRAL_TCL_H #define DIHEDRAL_TCL_H /** \file dihedral_tcl.hpp - * Tcl interface for \ref dihedral.h + * Tcl interface for \ref dihedral.hpp */ #include "parser.hpp" #include "interaction_data.hpp" -/// parse parameters for the dihedral potential, dihedral_tcl.c +/// parse parameters for the dihedral potential, dihedral_tcl.cpp int tclcommand_inter_parse_dihedral(Tcl_Interp *interp, int bond_type, int argc, char **argv); /// diff --git a/src/tcl/domain_decomposition_tcl.cpp b/src/tcl/domain_decomposition_tcl.cpp index a11c9cba314..b94344599a9 100644 --- a/src/tcl/domain_decomposition_tcl.cpp +++ b/src/tcl/domain_decomposition_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file domain_decomposition.c +/** \file domain_decomposition.cpp * * This file contains everything related to the cell system: domain decomposition. - * See also \ref domain_decomposition.h + * See also \ref domain_decomposition.hpp */ #include "utils.hpp" #include "parser.hpp" diff --git a/src/tcl/domain_decomposition_tcl.hpp b/src/tcl/domain_decomposition_tcl.hpp index 24f5e4c419b..0c289e81839 100644 --- a/src/tcl/domain_decomposition_tcl.hpp +++ b/src/tcl/domain_decomposition_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/dpd_tcl.cpp b/src/tcl/dpd_tcl.cpp index 80f07264da7..28f59deb778 100644 --- a/src/tcl/dpd_tcl.cpp +++ b/src/tcl/dpd_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file dpd.c +/** \file dpd.cpp Implementation of \ref dpd_tcl.hpp "dpd_tcl.h" */ #include "dpd_tcl.hpp" @@ -259,6 +259,15 @@ int tclcommand_thermostat_parse_inter_dpd(Tcl_Interp *interp, int argc, char ** return TCL_ERROR; } + if (argc>2 && ARG_IS_S(2, "ignore_fixed_particles")) { + if (argc == 3) + dpd_ignore_fixed_particles=1; + else if (argc!= 4 || (!ARG_IS_I(3, dpd_ignore_fixed_particles))) + return TCL_ERROR; + mpi_bcast_parameter(FIELD_DPD_IGNORE_FIXED_PARTICLES); + return TCL_OK; + } + /* copy lattice-boltzmann parameters */ if (! ARG_IS_D(2, temp)) { return TCL_ERROR; } diff --git a/src/tcl/dpd_tcl.hpp b/src/tcl/dpd_tcl.hpp index 155dd204fc1..6670485906c 100644 --- a/src/tcl/dpd_tcl.hpp +++ b/src/tcl/dpd_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/elc_tcl.cpp b/src/tcl/elc_tcl.cpp index bc3b111ff8b..5d7351ef7a7 100644 --- a/src/tcl/elc_tcl.cpp +++ b/src/tcl/elc_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file elc_tcl.c +/** \file elc_tcl.cpp * * Implementation of \ref elc_tcl.hpp */ @@ -39,14 +39,14 @@ int tclprint_to_result_ELC(Tcl_Interp *interp) Tcl_AppendResult(interp, " ", buffer, (char *) NULL); if (!elc_params.neutralize) Tcl_AppendResult(interp, " noneutralization", (char *) NULL); - if (elc_params.dielectric_contrast_on) { - Tcl_PrintDouble(interp, elc_params.di_top, buffer); - Tcl_AppendResult(interp, " dielectric ", buffer, (char *) NULL); - Tcl_PrintDouble(interp, elc_params.di_mid, buffer); - Tcl_AppendResult(interp, " ", buffer, (char *) NULL); - Tcl_PrintDouble(interp, elc_params.di_bot, buffer); - Tcl_AppendResult(interp, " ", buffer, (char *) NULL); - Tcl_PrintDouble(interp, elc_params.space_layer, buffer); + if (elc_params.const_pot_on) { + Tcl_PrintDouble(interp, elc_params.pot_diff, buffer); + Tcl_AppendResult(interp, " capacitor ", buffer, (char *) NULL); + } + else if (elc_params.dielectric_contrast_on) { + Tcl_PrintDouble(interp, elc_params.di_mid_top, buffer); + Tcl_AppendResult(interp, " dielectric-contrasts ", buffer, (char *) NULL); + Tcl_PrintDouble(interp, elc_params.di_mid_bot, buffer); Tcl_AppendResult(interp, " ", buffer, (char *) NULL); } return TCL_OK; @@ -58,10 +58,13 @@ int tclcommand_inter_coulomb_parse_elc_params(Tcl_Interp * interp, int argc, cha double gap_size; double far_cut = -1; double top = 1, mid = 1, bot = 1; + double delta_top = 0, delta_bot = 0; int neutralize = 1; + double pot_diff = 0; + int const_pot_on = 0; if (argc < 2) { - Tcl_AppendResult(interp, "either nothing or elc {} {dielectric } {noneutralization} expected, not \"", + Tcl_AppendResult(interp, "either nothing or elc {} <{dielectric } | {dielectric-contrasts } | {capacitor }> {noneutralization} expected, not \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } @@ -86,26 +89,47 @@ int tclcommand_inter_coulomb_parse_elc_params(Tcl_Interp * interp, int argc, cha argc--; argv++; } else if (argc >= 4 && ARG0_IS_S("dielectric")) { + Tcl_AppendResult(interp, "There seems to be an error when using ELC with dielectric constrasts. If you are sure you want to use it, you have to deactivate this message manually. ", (char *)NULL); + return TCL_ERROR; // just a dummy, not used, as it is only printed for information // purposes. We need to calculate it double space_layer_dummy; if (!ARG_IS_D(1,top) || !ARG_IS_D(2,mid) || !ARG_IS_D(3,bot)) return TCL_ERROR; + delta_top = (mid - top)/(mid + top); + delta_bot = (mid - bot)/(mid + bot); argc -= 4; argv += 4; if (argc > 0 && ARG_IS_D(4, space_layer_dummy)) { argc--; argv++; } } + else if (argc >= 3 && ARG0_IS_S("dielectric-contrasts")) { + Tcl_AppendResult(interp, "There seems to be an error when using ELC with dielectric constrasts. If you are sure you want to use it, you have to deactivate this message manually. ", (char *)NULL); + return TCL_ERROR; + + if (!ARG_IS_D(1,delta_top) || !ARG_IS_D(2,delta_bot)) + return TCL_ERROR; + argc -= 3; argv += 3; + } + else if (argc >= 1 && ARG0_IS_S("capacitor")) { + Tcl_AppendResult(interp, "There seems to be an error when using ELC with dielectric constrasts. If you are sure you want to use it, you have to deactivate this message manually. ", (char *)NULL); + return TCL_ERROR; + if (!ARG_IS_D(1,pot_diff)) + return TCL_ERROR; + argc -= 2; argv += 2; + const_pot_on = 1; + delta_top = -1; delta_bot = -1; + } else { - Tcl_AppendResult(interp, "either nothing or elc {} {dielectric } {noneutralization} expected, not \"", - argv[0], "\"", (char *)NULL); + Tcl_AppendResult(interp, "either nothing or elc {} <{dielectric } | {dielectric-contrasts } | {capacitor }> {noneutralization} expected, not \"", argv[0], "\"", (char *)NULL); return TCL_ERROR; } } } - CHECK_VALUE(ELC_set_params(pwerror, gap_size, far_cut, neutralize, top, mid, bot), "choose a 3d electrostatics method prior to ELC"); + CHECK_VALUE(ELC_set_params(pwerror, gap_size, far_cut, neutralize, delta_top, delta_bot, const_pot_on, pot_diff), + "choose a 3d electrostatics method prior to ELC"); } #endif diff --git a/src/tcl/elc_tcl.hpp b/src/tcl/elc_tcl.hpp index 6c158333d0b..c8b47728ab3 100644 --- a/src/tcl/elc_tcl.hpp +++ b/src/tcl/elc_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef ELC_TCL_H #define ELC_TCL_H /** \file elc_tcl.hpp - * Tcl interface for \ref elc.h + * Tcl interface for \ref elc.hpp */ #include "parser.hpp" diff --git a/src/tcl/electrokinetics_tcl.cpp b/src/tcl/electrokinetics_tcl.cpp new file mode 100644 index 00000000000..429ad1ef0ea --- /dev/null +++ b/src/tcl/electrokinetics_tcl.cpp @@ -0,0 +1,1344 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "config.hpp" +#include "electrokinetics_tcl.hpp" +#include "electrokinetics.hpp" +#include "lb.hpp" +#include "lb-boundaries.hpp" +#include "lb-boundaries_tcl.hpp" +#include "initialize.hpp" +#include "electrokinetics_pdb_parse.hpp" + +#ifdef ELECTROKINETICS +extern int ek_initialized; +#endif + +int tclcommand_electrokinetics(ClientData data, Tcl_Interp *interp, int argc, char **argv) { +#ifndef ELECTROKINETICS + Tcl_AppendResult(interp, "Feature ELECTROKINETICS required", NULL); + return TCL_ERROR; +#else + + argc--; + argv++; + + int err = TCL_OK; + int species; + double floatarg; + double vectarg[3]; + int coord[3]; + char int_buffer[TCL_INTEGER_SPACE]; + char double_buffer[TCL_DOUBLE_SPACE]; + +#ifdef EK_REACTION + int reactant, + product0, + product1; + double ct_rate, + rho_reactant_reservoir, + rho_product0_reservoir, + rho_product1_reservoir, + fraction0, + fraction1, + mass_reactant, + mass_product0, + mass_product1; +#endif + + if(argc < 2) + { + Tcl_AppendResult(interp, "Usage of \"electrokinetics\":\n\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics [agrid #float] [lb_density #float] [viscosity #float] [friction #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [bulk_viscosity #float] [gamma_even #float] [gamma_odd #float] [T #float] [bjerrum_length #float]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics print vtk #string]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics node #int #int #int print \n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics reaction [reactant_index #int]\n", (char *)NULL); + Tcl_AppendResult(interp, " [product0_index #int]\n", (char *)NULL); + Tcl_AppendResult(interp, " [product1_index #int]\n", (char *)NULL); + Tcl_AppendResult(interp, " [reactant_resrv_density #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [product0_resrv_density #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [product1_resrv_density #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [reaction_rate #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [mass_reactant #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [mass_product0 #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [mass_product1 #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [reaction_fraction_pr_0 #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [reaction_fraction_pr_1 #float]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics reaction region #int [box]\n", (char *)NULL); + Tcl_AppendResult(interp, " [wall ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [sphere ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [cylinder ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [rhomboid ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [pore ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [stomatocyte ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [hollow_cone ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics boundary charge_density #float [wall ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [sphere ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [cylinder ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [rhomboid ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [pore ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [stomatocyte ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, " [hollow_cone ... (c.f. constraint command)]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics #int [density #float] [D #float] [valency #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [ext_force #float #float #float]\n", (char *)NULL); + Tcl_AppendResult(interp, " [print density vtk #string]\n", (char *)NULL); + Tcl_AppendResult(interp, " [print flux vtk #string]\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics #int node #int #int #int print density\n", (char *)NULL); + Tcl_AppendResult(interp, "electrokinetics pdb-parse #string #string\n", (char *)NULL); + return TCL_ERROR; + } + else if(ARG0_IS_S("pdb-parse")) + { +#ifndef EK_BOUNDARIES + Tcl_AppendResult(interp, "Feature EK_BOUNDARIES required", (char *) NULL); + return (TCL_ERROR); +#else + argc--; + argv++; + + if (argc != 2) + { + Tcl_AppendResult(interp, "You need to specify two filenames.\n", (char *) NULL); + Tcl_AppendResult(interp, "electrokinetics pdb-parse #string1 #string2\n", (char *)NULL); + Tcl_AppendResult(interp, "#string1 is the pdb-filename, #string2 is the itp-filename.\n", (char *)NULL); + } + if (!ek_initialized) + { + Tcl_AppendResult(interp, "Please initialize EK before you attempt parsing.", (char *) NULL); + return (TCL_ERROR); + } + if(pdb_parse(argv[0], argv[1]) != 0) + { + Tcl_AppendResult(interp, "Could not parse pdb- or itp-file. Please, check your format and filenames.", (char *) NULL); + return (TCL_ERROR); + } + lb_init_boundaries(); +#endif + } + else if(ARG0_IS_S("boundary")) + { +#ifndef EK_BOUNDARIES + Tcl_AppendResult(interp, "Feature EK_BOUNDARIES required", (char *) NULL); + return (TCL_ERROR); +#else + argc--; + argv++; + + if(!ARG0_IS_S("charge_density") || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "You need to specify the boundary charge density using\n", (char *) NULL); + Tcl_AppendResult(interp, "electrokinetics boundary charge_density #float ...\n", (char *)NULL); + return (TCL_ERROR); + } + + argc -= 2; + argv += 2; + + if(floatarg != 0.0) + { + species = -1; + + for(unsigned int i = 0; i < ek_parameters.number_of_species; i++) + if(ek_parameters.valency[i] != 0.0) + { + species = i; + break; + } + + if(species == -1) + { + Tcl_AppendResult(interp, "You need to define at least one charged species in order to use charged walls\n", (char *) NULL); + return (TCL_ERROR); + } + } + + int c_num; + LB_Boundary *lbboundary_tmp; + + if(ARG0_IS_S("wall")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_wall(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("sphere")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_sphere(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("cylinder")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_cylinder(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("rhomboid")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_rhomboid(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("pore")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_pore(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("stomatocyte")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_stomatocyte(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("hollow_cone")) + { + lbboundary_tmp = generate_lbboundary(); + err = tclcommand_lbboundary_hollow_cone(lbboundary_tmp, interp, argc - 1, argv + 1); + lbboundary_tmp->charge_density = floatarg; + } + else if(ARG0_IS_S("delete")) + { + if(argc < 3) + { + /* delete all */ + Tcl_AppendResult(interp, "Can only delete individual electrokinetics boundaries", (char *) NULL); + err = TCL_ERROR; + } + else + { + if(Tcl_GetInt(interp, argv[2], &(c_num)) == TCL_ERROR) + return (TCL_ERROR); + + if(c_num < 0 || c_num >= n_lb_boundaries) + { + Tcl_AppendResult(interp, "Can not delete non existing electrokinetics boundary", (char *) NULL); + return (TCL_ERROR); + } + } + } + else + { + Tcl_AppendResult(interp, "possible electrokinetics boundary charge_density #float parameters:", (char *) NULL); + Tcl_AppendResult(interp, "wall, sphere, cylinder, rhomboid, pore, stomatocyte, hollow_cone, delete {c} to delete a boundary", (char *) NULL); + return (TCL_ERROR); + } + + on_lbboundary_change(); +#endif /* EK_BOUNDARIES */ + } + else if(ARG0_IS_I(species)) + { + argc--; + argv++; + + if(species < 0 || species > MAX_NUMBER_OF_SPECIES) + { + sprintf(int_buffer, "%d", MAX_NUMBER_OF_SPECIES); + Tcl_AppendResult(interp, "electrokinetics #int requires a number between 0 and", int_buffer, "denoting the species\n", (char *)NULL); + return TCL_ERROR; + } + + while(argc > 0) + { + if(ARG0_IS_S("D")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics #int D requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg < 0) + { + Tcl_AppendResult(interp, "electrokinetics #int D can not be negative\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_D(species, floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics #int D\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("density")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics #int density requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg < 0) + { + Tcl_AppendResult(interp, "electrokinetics #int density must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_density(species, floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics #int density\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("ext_force")) + { + if(argc < 4 || !ARG_IS_D(1, vectarg[0]) || !ARG_IS_D(2, vectarg[1]) || !ARG_IS_D(3, vectarg[2])) + { + Tcl_AppendResult(interp, "electrokinetics #int ext_force requires three floating point numbers as arguments\n", (char *)NULL); + return TCL_ERROR; + } + else if(ek_set_ext_force(species, vectarg[0], vectarg[1], vectarg[2]) == 0) + { + argc -= 4; + argv += 4; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics #int ext_force\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("valency")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics #int valency requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_valency(species, floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics #int valency\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("node")) + { + argc--; + argv++; + + if( + argc != 5 || !ARG_IS_I(0, coord[0]) || + !ARG_IS_I(1, coord[1]) || !ARG_IS_I(2, coord[2]) || + !ARG_IS_S(3, "print") || !ARG_IS_S(4, "density") + ) + { + Tcl_AppendResult(interp, "Wrong usage of electrokinetics #int node #int #int #int print density\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 4; + argv += 4; + + if(ARG0_IS_S("density")) + { + if(ek_node_print_density(species, coord[0], coord[1], coord[2], &floatarg) == 0) + { + argc --; + argv ++; + + Tcl_PrintDouble(interp, floatarg, double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *) NULL); + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics #int node #int #int #int print density\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("print")) + { + argc--; + argv++; + + if(argc != 3 || !ARG1_IS_S("vtk") || ( !ARG0_IS_S("density") && !ARG0_IS_S("flux") ) ) + { + Tcl_AppendResult(interp, "Wrong usage of electrokinetics #int print vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + + if(ARG0_IS_S("density")) + { + if(ek_print_vtk_density(species, argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics #int print density vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("flux")) + { + if(ek_print_vtk_flux(species, argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics #int print flux vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else + { + Tcl_AppendResult(interp, "unknown feature \"", argv[0],"\" of electrokinetics #int\n", (char *)NULL); + return TCL_ERROR ; + } + } + } + else + { + Tcl_ResetResult(interp); + + while(argc > 0) + { + if(ARG0_IS_S("print")) + { + argc--; + argv++; + + if ( + argc != 3 || !ARG1_IS_S("vtk") || + ( !ARG0_IS_S("velocity") && !ARG0_IS_S("density") && + !ARG0_IS_S("boundary") && !ARG0_IS_S("potential") && + !ARG0_IS_S("pressure") && !ARG0_IS_S("lbforce") && + !ARG0_IS_S("reaction_tags") + ) + ) + { + Tcl_AppendResult(interp, "Wrong usage of electrokinetics print vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + + if(ARG0_IS_S("velocity")) + { + if(ek_lb_print_vtk_velocity(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print velocity vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("density")) + { + if(ek_lb_print_vtk_density(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print density vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("boundary")) + { +#ifndef EK_BOUNDARIES + Tcl_AppendResult(interp, "Feature EK_BOUNDARIES required", (char *) NULL); + return (TCL_ERROR); +#else + if(lb_lbfluid_print_vtk_boundary(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print boundary vtk #string\n", (char *)NULL); + return TCL_ERROR; + } +#endif /* EK_BOUNDARIES */ + } + else if(ARG0_IS_S("potential")) + { + if(ek_print_vtk_potential(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print lbforce vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("pressure")) + { +#ifndef EK_REACTION + Tcl_AppendResult(interp, "Feature EK_REACTION required", (char *) NULL); + return (TCL_ERROR); +#else + if( ek_parameters.number_of_species < 3 || + ( ek_parameters.reaction_species[0] == -1 || + ek_parameters.reaction_species[1] == -1 || + ek_parameters.reaction_species[2] == -1 ) + ) + { + Tcl_AppendResult(interp, "The reaction must be set up to use this command\n", (char *) NULL); + return (TCL_ERROR); + } + + if(ek_print_vtk_pressure(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print pressure vtk #string\n", (char *)NULL); + return TCL_ERROR; + } +#endif /* EK_PRESSURE */ + } + else if(ARG0_IS_S("reaction_tags")) + { +#ifndef EK_REACTION + Tcl_AppendResult(interp, "Feature EK_REACTION required", (char *) NULL); + return (TCL_ERROR); +#else + if( ek_parameters.number_of_species < 3 || + ( ek_parameters.reaction_species[0] == -1 || + ek_parameters.reaction_species[1] == -1 || + ek_parameters.reaction_species[2] == -1 ) + ) + { + Tcl_AppendResult(interp, "The reaction must be set up to use this command\n", (char *) NULL); + return (TCL_ERROR); + } + + if(ek_print_vtk_reaction_tags(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print reaction_tags vtk #string\n", (char *)NULL); + return TCL_ERROR; + } +#endif /* EK_PRESSURE */ + } + else if(ARG0_IS_S("lbforce")) + { + if(ek_print_vtk_lbforce(argv[2]) == 0) + { + argc -= 3; + argv += 3; + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics print potential vtk #string\n", (char *)NULL); + return TCL_ERROR; + } + } + else + { + Tcl_AppendResult(interp, "Unknown feature \"", argv[0], "\" in electrokinetics print\n", (char *)NULL); + return TCL_ERROR; + } + } + else if(ARG0_IS_S("node")) + { + argc--; + argv++; + + if ( + argc != 5 || !ARG_IS_I(0, coord[0]) || + !ARG_IS_I(1, coord[1]) || !ARG_IS_I(2, coord[2]) || + !ARG_IS_S(3, "print") || !ARG_IS_S(4, "velocity") + ) + { + Tcl_AppendResult(interp, "Wrong usage of electrokinetics node print \n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 4; + argv += 4; + + if(ARG0_IS_S("velocity")) + { + if(ek_node_print_velocity(coord[0], coord[1], coord[2], vectarg) == 0) + { + argc --; + argv ++; + + Tcl_PrintDouble(interp, vectarg[0], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, vectarg[1], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, vectarg[2], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *) NULL); + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + else + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Unknown error in electrokinetics node print velocity\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("T")) + { + argc--; + argv++; + + if(argc < 1 || !ARG0_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics T requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics T must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_T(floatarg) == 0) + { + argc --; + argv ++; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics T\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("bjerrum_length")) + { + argc--; + argv++; + + if(!ARG0_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics bjerrum_length requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics bjerrum_length must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_bjerrumlength(floatarg) == 0) + { + argc--; + argv++; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics bjerrum_length\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("agrid")) + { + argc--; + argv++; + + if(!ARG0_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics agrid requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics agrid must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_agrid(floatarg) == 0) + { + argc--; + argv++; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics agrid\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("lb_density")) + { + argc--; + argv++; + + if(!ARG0_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics lb_density requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics lb_density must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_lb_density(floatarg) == 0) + { + argc--; + argv++; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics lb_density\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("viscosity")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics viscosity requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if (floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics viscosity must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_viscosity(floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics viscosity\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("friction")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics friction requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics friction must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if (ek_set_friction(floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics friction\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("bulk_viscosity")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics bulk_viscosity requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(floatarg <= 0) + { + Tcl_AppendResult(interp, "electrokinetics bulk_viscosity must be positive\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_bulk_viscosity(floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics bulk_viscosity\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("gamma_odd")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics gamma_odd requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(fabs(floatarg) >= 1) + { + Tcl_AppendResult(interp, "electrokinetics gamma_odd must be smaller than 1\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_gamma_odd(floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics gamma_odd\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("gamma_even")) + { + if(argc < 2 || !ARG1_IS_D(floatarg)) + { + Tcl_AppendResult(interp, "electrokinetics gamma_even requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + else if(fabs(floatarg) >= 1) + { + Tcl_AppendResult(interp, "electrokinetics gamma_even must be smaller than 1\n", (char *)NULL); + return TCL_ERROR; + } + else + { + if(ek_set_gamma_even(floatarg) == 0) + { + argc -= 2; + argv += 2; + } + else + { + Tcl_AppendResult(interp, "Unknown error setting electrokinetics gamma_even\n", (char *)NULL); + return TCL_ERROR; + } + } + } + else if(ARG0_IS_S("reaction")) + { +#ifndef EK_REACTION + Tcl_AppendResult(interp, "EK_REACTION needs to be compiled in to use electrokinetics reaction\n", (char *)NULL); + return TCL_ERROR; +#else + argc--; + argv++; + + if( ARG0_IS_S("region") ) + { +#ifndef EK_BOUNDARIES + Tcl_AppendResult(interp, "Feature EK_BOUNDARIES required", (char *) NULL); + return (TCL_ERROR); +#else + if(ek_parameters.number_of_species < 3) + { + Tcl_AppendResult(interp, "to invoke the reaction command 3 species must first be set\n", (char *) NULL); + return (TCL_ERROR); + } + + if ( ek_parameters.reaction_species[0] == -1 || + ek_parameters.reaction_species[1] == -1 || + ek_parameters.reaction_species[2] == -1 ) + { + Tcl_AppendResult(interp, "You need to set up the reaction first,\n", (char *) NULL); + Tcl_AppendResult(interp, "before you can tag the reactive regions", (char *) NULL); + return (TCL_ERROR); + } + + argc--; + argv++; + + int reaction_type; + LB_Boundary lbboundary_tmp; + + if( !ARG0_IS_I(reaction_type) ) + { + Tcl_AppendResult(interp, "\nYou need to specify the reaction type you want to use\n", (char *) NULL); + Tcl_AppendResult(interp, "\nelectrokinetics reaction region #int ...\n", (char *)NULL); + return (TCL_ERROR); + } + + if ( reaction_type != 0 && + reaction_type != 1 && + reaction_type != 2 ) + { + Tcl_AppendResult(interp, "Not a valid choice for the type, choose from:\n", (char *) NULL); + Tcl_AppendResult(interp, "(0) no reaction, (1) reaction, (2) reservoir\n", (char *) NULL); + return (TCL_ERROR); + } + + argc--; + argv++; + + if(ARG0_IS_S("box")) + { + err = tclcommand_lbboundary_box(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("wall")) + { + err = tclcommand_lbboundary_wall(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("sphere")) + { + err = tclcommand_lbboundary_sphere(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("cylinder")) + { + err = tclcommand_lbboundary_cylinder(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("rhomboid")) + { + err = tclcommand_lbboundary_rhomboid(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("pore")) + { + err = tclcommand_lbboundary_pore(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("stomatocyte")) + { + err = tclcommand_lbboundary_stomatocyte(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else if(ARG0_IS_S("hollow_cone")) + { + err = tclcommand_lbboundary_hollow_cone(&lbboundary_tmp, interp, argc - 1, argv + 1); + } + else + { + Tcl_AppendResult(interp, "possible electrokinetics reaction region #int parameters:\n", (char *) NULL); + Tcl_AppendResult(interp, "box, wall, sphere, cylinder, rhomboid, pore, stomatocyte, hollow_cone", (char *) NULL); + return (TCL_ERROR); + } + + ek_tag_reaction_nodes( &lbboundary_tmp, char(reaction_type) ); + + return TCL_OK; +#endif + } + else + { + if(ek_parameters.number_of_species < 3) + { + Tcl_AppendResult(interp, "to invoke the reaction command 3 species must first be set\n", (char *) NULL); + return (TCL_ERROR); + } + + if( argc < 22 ) + { + Tcl_AppendResult(interp, "electrokinetics reaction requires 15 arguments:\n", (char *) NULL); + Tcl_AppendResult(interp, "11 quantifiers, 3 ints, and 8 floats\n", (char *)NULL); + return TCL_ERROR; + } + else + { + + int counter = 0; + + while(argc > 0 && counter < 13 ) + { + counter++; + + if ( ARG_IS_S_EXACT(0,"reactant_index") ) + { + + if ( !ARG_IS_I(1, reactant) ) + { + Tcl_AppendResult(interp, "electrokinetics reactant_index requires one int as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( (reactant < 0 || reactant > MAX_NUMBER_OF_SPECIES) ) + { + sprintf(int_buffer, "%d", MAX_NUMBER_OF_SPECIES); + Tcl_AppendResult(interp, "electrokinetics reactant_index #int requires a number between 0 and", int_buffer, "denoting the species\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if( ARG_IS_S_EXACT(0,"product0_index") ) + { + + if ( !ARG_IS_I(1, product0) ) + { + Tcl_AppendResult(interp, "electrokinetics product0_index requires one int as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( (product0 < 0 || product0 > MAX_NUMBER_OF_SPECIES) ) + { + sprintf(int_buffer, "%d", MAX_NUMBER_OF_SPECIES); + Tcl_AppendResult(interp, "electrokinetics product0_index #int requires a number between 0 and", int_buffer, "denoting the species\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if ( ARG_IS_S_EXACT(0,"product1_index") ) + { + + if ( !ARG_IS_I(1, product1) ) + { + Tcl_AppendResult(interp, "electrokinetics product1_index requires one int as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( (product1 < 0 || product1 > MAX_NUMBER_OF_SPECIES) ) + { + sprintf(int_buffer, "%d", MAX_NUMBER_OF_SPECIES); + Tcl_AppendResult(interp, "electrokinetics product1_index #int requires a number between 0 and", int_buffer, "denoting the species\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if ( ARG_IS_S_EXACT(0,"reactant_resrv_density") ) + { + + if ( !ARG_IS_D(1, rho_reactant_reservoir) ) + { + Tcl_AppendResult(interp, "electrokinetics reactant_resrv_density requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( rho_reactant_reservoir < 0 ) + { + Tcl_AppendResult(interp, "the reactant reservoir density has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"product0_resrv_density")) + { + + if ( !ARG_IS_D(1, rho_product0_reservoir) ) + { + Tcl_AppendResult(interp, "electrokinetics product0_resrv_density requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( rho_product0_reservoir < 0 ) + { + Tcl_AppendResult(interp, "the product0 reservoir density has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if ( ARG_IS_S_EXACT(0,"product1_resrv_density") ) + { + + if (!ARG_IS_D(1, rho_product1_reservoir)) + { + Tcl_AppendResult(interp, "electrokinetics product1_resrv_density requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( rho_product1_reservoir < 0 ) + { + Tcl_AppendResult(interp, "the product1 reservoir density has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if ( ARG_IS_S_EXACT(0,"reaction_rate") ) + { + + if ( !ARG_IS_D(1, ct_rate) ) + { + Tcl_AppendResult(interp, "electrokinetics reaction_rate requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( ct_rate < 0 ) + { + Tcl_AppendResult(interp, "catalytic reaction rate has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"mass_reactant")) + { + + if ( !ARG_IS_D(1, mass_reactant) ) + { + Tcl_AppendResult(interp, "electrokinetics mass_reactant requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( mass_reactant <= 0 ) + { + Tcl_AppendResult(interp, "the mass has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"mass_product0")) + { + + if ( !ARG_IS_D(1, mass_product0) ) + { + Tcl_AppendResult(interp, "electrokinetics mass_product0 requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( mass_product0 <= 0 ) + { + Tcl_AppendResult(interp, "the mass has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"mass_product1")) + { + + if ( !ARG_IS_D(1, mass_product1) ) + { + Tcl_AppendResult(interp, "electrokinetics mass_product1 requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( mass_product1 <= 0 ) + { + Tcl_AppendResult(interp, "the mass has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"reaction_fraction_pr_0")) + { + + if ( !ARG_IS_D(1, fraction0) ) + { + Tcl_AppendResult(interp, "electrokinetics reaction_fraction_pr_0 requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( fraction0 < 0 ) + { + Tcl_AppendResult(interp, "the fraction has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + + else if (ARG_IS_S_EXACT(0,"reaction_fraction_pr_1")) + { + + if ( !ARG_IS_D(1, fraction1) ) + { + Tcl_AppendResult(interp, "electrokinetics reaction_fraction_pr_1 requires one floating point number as argument\n", (char *)NULL); + return TCL_ERROR; + } + + if ( fraction1 < 0 ) + { + Tcl_AppendResult(interp, "the fraction has to be greater than zero\n", (char *)NULL); + return TCL_ERROR; + } + + argc -= 2; + argv += 2; + } + } + + if ( counter == 13 ) + { + Tcl_AppendResult(interp, "unknown option given, please check for spelling errors\n", (char *)NULL); + return TCL_ERROR; + } + + if ( (reactant == product0) || + (product0 == product1) || + (product1 == reactant) ) + { + Tcl_AppendResult(interp, "the reactant and product species need to be distinct\n", (char *)NULL); + return TCL_ERROR; + } + + if ( fabs( fraction0*mass_product0 + fraction1*mass_product1 - mass_reactant ) > 1.0e-06 ) + { + Tcl_AppendResult(interp, "the reaction does not conserve mass:\n", (char *)NULL); + Tcl_AppendResult(interp, "please choose different masses or fractions\n", (char *)NULL); + return TCL_ERROR; + } + + if ( ek_set_reaction( reactant, product0, product1, + rho_reactant_reservoir, rho_product0_reservoir, rho_product1_reservoir, + ct_rate, fraction0, fraction1, + mass_reactant, mass_product0, mass_product1 ) != 0 ) + { + Tcl_AppendResult(interp, "species are not set before invoking electrokinetics reaction\n", (char *)NULL); + return TCL_ERROR; + } + } + } +#endif + } + else + { + Tcl_AppendResult(interp, "unknown feature \"", argv[0],"\" of electrokinetics\n", (char *)NULL); + return TCL_ERROR ; + } + } + } + + if((err = gather_runtime_errors(interp, err)) != TCL_OK) + return TCL_ERROR; + + err = ek_init(); + + switch(err) + { + case 0: + return TCL_OK; + + case 2: + Tcl_AppendResult(interp, "electrokinetics agrid not compatible with box size\n", (char *)NULL); + + default: + sprintf(int_buffer, "%d", err); + Tcl_AppendResult(interp, "Error ", int_buffer, " during initialization of electrokinetics", (char *)NULL); + break; + } + + return TCL_ERROR; + +#endif /* defined ELECTROKINETICS */ +} diff --git a/src/tcl/electrokinetics_tcl.hpp b/src/tcl/electrokinetics_tcl.hpp new file mode 100644 index 00000000000..b8e482c0347 --- /dev/null +++ b/src/tcl/electrokinetics_tcl.hpp @@ -0,0 +1,27 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef ELECTROKINETICS_TCL_H +#define ELECTROKINETICS_TCL_H + +#include "config.hpp" +#include "parser.hpp" + +int tclcommand_electrokinetics(ClientData data, Tcl_Interp *interp, int argc, char **argv); + +#endif /* defined ELECTROKINETICS_TCL_H */ diff --git a/src/tcl/endangledist_tcl.cpp b/src/tcl/endangledist_tcl.cpp index 2f59112a722..e873a74876b 100644 --- a/src/tcl/endangledist_tcl.cpp +++ b/src/tcl/endangledist_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file endangledist_tcl.c +/** \file endangledist_tcl.cpp * * Implementation of \ref endangledist_tcl.hpp */ diff --git a/src/tcl/endangledist_tcl.hpp b/src/tcl/endangledist_tcl.hpp index 6dff92c8d09..f730d1d57b5 100644 --- a/src/tcl/endangledist_tcl.hpp +++ b/src/tcl/endangledist_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef _ENDANGLEDIST_TCL_H #define _ENDANGLEDIST_TCL_H /** \file endangledist_tcl.hpp - * Tcl interface for \ref endangledist.h + * Tcl interface for \ref endangledist.hpp */ #include "parser.hpp" diff --git a/src/tcl/energy_tcl.cpp b/src/tcl/energy_tcl.cpp index 63301c1d921..c64099e2b92 100644 --- a/src/tcl/energy_tcl.cpp +++ b/src/tcl/energy_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,13 +18,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file energy_tcl.c +/** \file energy_tcl.cpp * * Implements the analyze energy command. */ #include "utils.hpp" #include "parser.hpp" #include "energy.hpp" +#include "external_potential.hpp" /********************************************************************** * parser @@ -39,6 +40,10 @@ static void tclcommand_analyze_print_all(Tcl_Interp *interp) value = total_energy.data.e[0]; for (i = 1; i < total_energy.data.n; i++) value += total_energy.data.e[i]; + + for (i = 0; i < n_external_potentials; i++) { + value+=external_potentials[i].energy; + } Tcl_PrintDouble(interp, value, buffer); Tcl_AppendResult(interp, "{ energy ", buffer, " } ", (char *)NULL); @@ -103,6 +108,7 @@ static void tclcommand_analyze_print_all(Tcl_Interp *interp) Tcl_AppendResult(interp, " ", buffer, (char *)NULL); } } + Tcl_AppendResult(interp, " }", (char *)NULL); #endif #ifdef DIPOLES @@ -113,9 +119,17 @@ static void tclcommand_analyze_print_all(Tcl_Interp *interp) } } #endif - Tcl_AppendResult(interp, " }", (char *)NULL); } + #endif + if (n_external_potentials > 0) { + Tcl_AppendResult(interp, " { external_potential", (char *)NULL); + for (i = 0; i < n_external_potentials; i++) { + Tcl_PrintDouble(interp, external_potentials[i].energy, buffer); + Tcl_AppendResult(interp, " ", buffer, (char *)NULL); + } + } + } /************************************************************/ @@ -127,7 +141,7 @@ int tclcommand_analyze_parse_and_print_energy(Tcl_Interp *interp, int argc, char int i, j; double value; value = 0.0; - if (n_total_particles == 0) { + if (n_part == 0) { Tcl_AppendResult(interp, "(no particles)", (char *)NULL); return (TCL_OK); @@ -189,7 +203,7 @@ int tclcommand_analyze_parse_and_print_energy(Tcl_Interp *interp, int argc, char for (i = 0; i < total_energy.n_coulomb; i++) value += total_energy.coulomb[i]; #else - Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see myconfig.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see myconfig.hpp)\n", (char *)NULL); #endif } else if( ARG0_IS_S("magnetic")) { @@ -198,7 +212,7 @@ int tclcommand_analyze_parse_and_print_energy(Tcl_Interp *interp, int argc, char for (i = 0; i < total_energy.n_dipolar; i++) value += total_energy.dipolar[i]; #else - Tcl_AppendResult(interp, "DIPOLES not compiled (see myconfig.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "DIPOLES not compiled (see myconfig.hpp)\n", (char *)NULL); #endif } @@ -206,6 +220,10 @@ int tclcommand_analyze_parse_and_print_energy(Tcl_Interp *interp, int argc, char value = total_energy.data.e[0]; for (i = 1; i < total_energy.data.n; i++) value += total_energy.data.e[i]; + for (i = 0; i < n_external_potentials; i++) { + value += external_potentials[i].energy; + } + } else { Tcl_AppendResult(interp, "unknown feature of: analyze energy", diff --git a/src/tcl/external_potential_tcl.cpp b/src/tcl/external_potential_tcl.cpp new file mode 100644 index 00000000000..c8fec735895 --- /dev/null +++ b/src/tcl/external_potential_tcl.cpp @@ -0,0 +1,90 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#include "external_potential_tcl.hpp" + +int tclcommand_external_potential_tabulated(Tcl_Interp* interp, int argc, char **argv, ExternalPotential* e); + +int tclcommand_external_potential(ClientData _data, Tcl_Interp *interp, + int argc, char **argv) { + ExternalPotential* e; + int error = generate_external_potential(&e); + if (error == ES_ERROR) + return TCL_ERROR; + + if (argc<2) { + Tcl_AppendResult(interp, "Usage: external_potential \n" , (char *)NULL); + return TCL_ERROR; + } + if (ARG1_IS_S("tabulated")) { + return tclcommand_external_potential_tabulated(interp, argc-2, argv+2, e); + } + Tcl_AppendResult(interp, "Usage: external_potential \n" , (char *)NULL); + return TCL_ERROR; + +} + + + +int tclcommand_external_potential_tabulated(Tcl_Interp* interp, int argc, char **argv, ExternalPotential* e) +{ + char* filename =0; + + DoubleList scalelist; + + init_doublelist(&scalelist); + + while (argc>0) { + if (ARG0_IS_S("file") ) { + if (argc>1) { + filename = argv[1]; + argc-=2; + argv+=2; + } else { + Tcl_AppendResult(interp, "Usage: external_potential file \n" , (char *)NULL); + return TCL_ERROR; + } + } else if (ARG0_IS_S("scale")) { + if (argc>1 && ARG_IS_DOUBLELIST(1, scalelist)) { + argc-=2; + argv+=2; + } else { + Tcl_AppendResult(interp, "Usage: external_potential tabulated scale \n" , (char *)NULL); + return TCL_ERROR; + } + } else { + Tcl_AppendResult(interp, "Unknown argument to external_potential: " , argv[0], "\n", (char *)NULL); + return TCL_ERROR; + } + } + if (filename == 0) { + Tcl_AppendResult(interp, "No filename given to external_potential tabulated\n" , (char *)NULL); + return TCL_ERROR; + } + if (external_potential_tabulated_init(n_external_potentials-1, filename, scalelist.n, scalelist.e)==ES_ERROR) { + Tcl_AppendResult(interp, "Error creating external potential\n" , (char *)NULL); + return TCL_ERROR; + } + return gather_runtime_errors(interp, TCL_OK); +} + + + + diff --git a/src/tcl/external_potential_tcl.hpp b/src/tcl/external_potential_tcl.hpp new file mode 100644 index 00000000000..e44be9d183f --- /dev/null +++ b/src/tcl/external_potential_tcl.hpp @@ -0,0 +1,30 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef EXTERNAL_POTENTIAL_TCL_H +#define EXTERNAL_POTENTIAL_TCL_H + + +#include +#include "parser.hpp" +#include "external_potential.hpp" + +int tclcommand_external_potential(ClientData _data, Tcl_Interp *interp, + int argc, char **argv); + +#endif diff --git a/src/tcl/fene_tcl.cpp b/src/tcl/fene_tcl.cpp index 74e5f753c2f..5a4b3932ef7 100644 --- a/src/tcl/fene_tcl.cpp +++ b/src/tcl/fene_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file fene_tcl.c +/** \file fene_tcl.cpp * * Implementation of \ref fene_tcl.hpp */ diff --git a/src/tcl/fene_tcl.hpp b/src/tcl/fene_tcl.hpp index dbb15da8fad..905f4f53d82 100644 --- a/src/tcl/fene_tcl.hpp +++ b/src/tcl/fene_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef FENE_TCL_H #define FENE_TCL_H /** \file fene_tcl.hpp - * Tcl interface for \ref fene.h + * Tcl interface for \ref fene.hpp */ #include "parser.hpp" diff --git a/src/tcl/forcecap_tcl.cpp b/src/tcl/forcecap_tcl.cpp index 3d905bcaf84..5953890778b 100644 --- a/src/tcl/forcecap_tcl.cpp +++ b/src/tcl/forcecap_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/forcecap_tcl.hpp b/src/tcl/forcecap_tcl.hpp index a97c2aad900..b3ff916bf6f 100644 --- a/src/tcl/forcecap_tcl.hpp +++ b/src/tcl/forcecap_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/galilei_tcl.cpp b/src/tcl/galilei_tcl.cpp index 7bb0276b70d..391421ebe65 100644 --- a/src/tcl/galilei_tcl.cpp +++ b/src/tcl/galilei_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file reaction_tcl.c +/** \file reaction_tcl.cpp * */ @@ -124,6 +124,9 @@ int tclcommand_kill_particle_forces(ClientData data, Tcl_Interp * interp, int ar int tclcommand_system_CMS(ClientData data, Tcl_Interp * interp, int argc, char ** argv){ char buffer[256]; double cmspos[3]; +#ifdef LEES_EDWARDS + double v_le[3]; +#endif int box[3]; if (argc != 1 && argc != 2 ) { @@ -136,8 +139,12 @@ int tclcommand_system_CMS(ClientData data, Tcl_Interp * interp, int argc, char * memcpy(cmspos, gal.cms, 3*sizeof(double)); box[0] = 0; box[1] = 0; box[2] = 0; +#ifdef LEES_EDWARDS + fold_position(cmspos,v_le, box); +#else fold_position(cmspos, box); - +#endif + Tcl_PrintDouble(interp, cmspos[0], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); Tcl_PrintDouble(interp, cmspos[1], buffer); diff --git a/src/tcl/galilei_tcl.hpp b/src/tcl/galilei_tcl.hpp index b1acd5f268d..ce2dc3efe1a 100644 --- a/src/tcl/galilei_tcl.hpp +++ b/src/tcl/galilei_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/gaussian_tcl.cpp b/src/tcl/gaussian_tcl.cpp index cd9b81a83c9..e9559e99071 100644 --- a/src/tcl/gaussian_tcl.cpp +++ b/src/tcl/gaussian_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file gaussian_tcl.c +/** \file gaussian_tcl.cpp * * Implementation of \ref gaussian_tcl.hpp */ diff --git a/src/tcl/gaussian_tcl.hpp b/src/tcl/gaussian_tcl.hpp index c630488df7a..e69d0db87eb 100644 --- a/src/tcl/gaussian_tcl.hpp +++ b/src/tcl/gaussian_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef GAUSSIAN_TCL_H #define GAUSSIAN_TCL_H /** \file gaussian_tcl.hpp - * Tcl interface for \ref gaussian.h + * Tcl interface for \ref gaussian.hpp */ #include "parser.hpp" diff --git a/src/tcl/gb_tcl.cpp b/src/tcl/gb_tcl.cpp index 34b037bb255..66bcc5cbf3d 100644 --- a/src/tcl/gb_tcl.cpp +++ b/src/tcl/gb_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file gb_tcl.c +/** \file gb_tcl.cpp * * Implementation of \ref gb_tcl.hpp */ diff --git a/src/tcl/gb_tcl.hpp b/src/tcl/gb_tcl.hpp index 4fe14b06334..a4bdc746e47 100644 --- a/src/tcl/gb_tcl.hpp +++ b/src/tcl/gb_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef GB_TCL_H #define GB_TCL_H /** \file gb_tcl.hpp - * Tcl interface for \ref gb.h + * Tcl interface for \ref gb.hpp */ #include "parser.hpp" diff --git a/src/tcl/ghmc_tcl.cpp b/src/tcl/ghmc_tcl.cpp index 886b4dd48e3..a8860fa924b 100644 --- a/src/tcl/ghmc_tcl.cpp +++ b/src/tcl/ghmc_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file ghmc_tcl.c +/** \file ghmc_tcl.cpp For more information see \ref ghmc_tcl.hpp */ diff --git a/src/tcl/ghmc_tcl.hpp b/src/tcl/ghmc_tcl.hpp index f4efbd46edd..1271ed61d2b 100644 --- a/src/tcl/ghmc_tcl.hpp +++ b/src/tcl/ghmc_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/global_tcl.cpp b/src/tcl/global_tcl.cpp index 96b755b7523..01358e3c7e1 100644 --- a/src/tcl/global_tcl.cpp +++ b/src/tcl/global_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file global_tcl.c +/** \file global_tcl.cpp Implementation of \ref global_tcl.hpp "global_tcl.h". */ #include "utils.hpp" @@ -50,6 +50,12 @@ static int tclcallback_ro(Tcl_Interp *interp, void *data) return (TCL_ERROR); } +int tclcallback_warnings(Tcl_Interp *interp, void *data) +{ + warnings = ((int *)data)[0]; + return (TCL_OK); +} + static SetCallback *find_callback(int field) { if (field >= n_callbacks) diff --git a/src/tcl/global_tcl.hpp b/src/tcl/global_tcl.hpp index d5a20ad8096..00150715924 100644 --- a/src/tcl/global_tcl.hpp +++ b/src/tcl/global_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -32,4 +32,7 @@ typedef int (SetCallback)(Tcl_Interp *interp, void *data); /// Register a global variable, should be used only in \ref register_global_variables void register_global_callback(int field, SetCallback *callback); +/// Callback for warning settings. +int tclcallback_warnings(Tcl_Interp *interp, void *data); + #endif diff --git a/src/tcl/grid_tcl.cpp b/src/tcl/grid_tcl.cpp index 0b3052bb5e0..371546b596a 100644 --- a/src/tcl/grid_tcl.cpp +++ b/src/tcl/grid_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,15 +18,16 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file grid.c Domain decomposition for parallel computing. +/** \file grid.cpp Domain decomposition for parallel computing. * * For more information on the domain decomposition, - * see \ref grid.h "grid.h". + * see \ref grid.hpp "grid.h". */ #include "utils.hpp" #include "parser.hpp" #include "communication.hpp" #include "grid.hpp" +#include "global.hpp" int tclcallback_node_grid(Tcl_Interp *interp, void *_data) { diff --git a/src/tcl/grid_tcl.hpp b/src/tcl/grid_tcl.hpp index a1967cb1fc6..13f264f17d8 100644 --- a/src/tcl/grid_tcl.hpp +++ b/src/tcl/grid_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/harmonic_tcl.cpp b/src/tcl/harmonic_tcl.cpp index 70cb0a612fb..d89da74b4c0 100644 --- a/src/tcl/harmonic_tcl.cpp +++ b/src/tcl/harmonic_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file harmonic_tcl.c +/** \file harmonic_tcl.cpp * * Implementation of \ref harmonic_tcl.hpp */ diff --git a/src/tcl/harmonic_tcl.hpp b/src/tcl/harmonic_tcl.hpp index daa45c24141..7b3a2c1cf79 100644 --- a/src/tcl/harmonic_tcl.hpp +++ b/src/tcl/harmonic_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef HARMONIC_TCL_H #define HARMONIC_TCL_H /** \file harmonic_tcl.hpp - * Tcl interface for \ref harmonic.h + * Tcl interface for \ref harmonic.hpp */ #include "parser.hpp" diff --git a/src/tcl/hat_tcl.cpp b/src/tcl/hat_tcl.cpp index 31aefbc5e5b..e50f5a9b37d 100644 --- a/src/tcl/hat_tcl.cpp +++ b/src/tcl/hat_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file hat_tcl.c +/** \file hat_tcl.cpp * * Implementation of \ref hat_tcl.hpp */ diff --git a/src/tcl/hat_tcl.hpp b/src/tcl/hat_tcl.hpp index 95b9a71adc7..18abed70432 100644 --- a/src/tcl/hat_tcl.hpp +++ b/src/tcl/hat_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef HAT_TCL_H #define HAT_TCL_H /** \file hat_tcl.hpp - * Tcl interface for \ref hat.h + * Tcl interface for \ref hat.hpp */ #include "parser.hpp" diff --git a/src/tcl/hertzian_tcl.cpp b/src/tcl/hertzian_tcl.cpp index 1e47f4a5266..5747e4f340a 100644 --- a/src/tcl/hertzian_tcl.cpp +++ b/src/tcl/hertzian_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file hertzian_tcl.c +/** \file hertzian_tcl.cpp * * Implementation of \ref hertzian_tcl.hpp */ diff --git a/src/tcl/hertzian_tcl.hpp b/src/tcl/hertzian_tcl.hpp index a8342aea1e0..7fb4d34850c 100644 --- a/src/tcl/hertzian_tcl.hpp +++ b/src/tcl/hertzian_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef HERTZIAN_TCL_H #define HERTZIAN_TCL_H /** \file hertzian_tcl.hpp - * Tcl interface for \ref hertzian.h + * Tcl interface for \ref hertzian.hpp */ #include "parser.hpp" diff --git a/src/tcl/iccp3m_tcl.cpp b/src/tcl/iccp3m_tcl.cpp index e5137d7a5e7..3318a37f8ed 100644 --- a/src/tcl/iccp3m_tcl.cpp +++ b/src/tcl/iccp3m_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,13 +19,16 @@ along with this program. If not, see . */ -/** \file iccp3m.c - Detailed Information about the method is included in the corresponding header file \ref iccp3m.h. +/** \file iccp3m.cpp + Detailed Information about the method is included in the corresponding header file \ref iccp3m.hpp. */ #include "iccp3m.hpp" #include "parser.hpp" +#include +#include +#include #ifdef ELECTROSTATICS enum { ICCP3M_AREA , ICCP3M_EPSILON, ICCP3M_NORMAL, ICCP3M_SIGMA, ICCP3M_EXTFIELD } ; @@ -42,12 +45,6 @@ int tclcommand_iccp3m(ClientData data, Tcl_Interp *interp, int argc, char **argv iccp3m_initialized=1; } - iccp3m_cfg.num_iteration=30; - iccp3m_cfg.convergence=1e-2; - iccp3m_cfg.relax=0.7; - iccp3m_cfg.eout=1; - - if(argc < 2 ) { Tcl_AppendResult(interp, "Usage of ICCP3M: RTFM", (char *)NULL); return (TCL_ERROR); @@ -57,13 +54,17 @@ int tclcommand_iccp3m(ClientData data, Tcl_Interp *interp, int argc, char **argv if (iccp3m_cfg.set_flag==0) { Tcl_AppendResult(interp, "iccp3m parameters not set!", (char *)NULL); return (TCL_ERROR); - } - else{ + } else { Tcl_PrintDouble(interp,mpi_iccp3m_iteration(0),buffer); Tcl_AppendResult(interp, buffer, (char *) NULL); return TCL_OK; - } - } + } + } else if(ARG_IS_S(1,"no_iterations")) { + Tcl_PrintDouble(interp,iccp3m_cfg.citeration,buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; + + } } else { if(ARG_IS_I(1, iccp3m_cfg.n_ic)) { @@ -98,6 +99,14 @@ int tclcommand_iccp3m(ClientData data, Tcl_Interp *interp, int argc, char **argv Tcl_AppendResult(interp, "ICCP3M Usage: eps_out ", (char *)NULL); return (TCL_ERROR); } + } else if (ARG0_IS_S("ext_field")) { + if (argc>1 && ARG1_IS_D(iccp3m_cfg.extx) && ARG_IS_D(2,iccp3m_cfg.exty) && ARG_IS_D(3,iccp3m_cfg.extz)) { + argc-=4; + argv+=4; + } else { + Tcl_AppendResult(interp, "ICCP3M Usage: eps_out ", (char *)NULL); + return (TCL_ERROR); + } } else if (ARG0_IS_S("max_iterations")) { if (argc>1 && ARG1_IS_I(iccp3m_cfg.num_iteration)) { argc-=2; @@ -106,6 +115,14 @@ int tclcommand_iccp3m(ClientData data, Tcl_Interp *interp, int argc, char **argv Tcl_AppendResult(interp, "ICCP3M Usage: max_iterations ", (char *)NULL); return (TCL_ERROR); } + } else if (ARG0_IS_S("first_id")) { + if (argc>1 && ARG1_IS_I(iccp3m_cfg.first_id)) { + argc-=2; + argv+=2; + } else { + Tcl_AppendResult(interp, "ICCP3M Usage: first_id ", (char *)NULL); + return (TCL_ERROR); + } } else if (ARG0_IS_S("normals")) { if (argc>1) { if (tclcommand_iccp3m_parse_normals(interp, iccp3m_cfg.n_ic, argv[1]) != TCL_OK) { @@ -159,69 +176,50 @@ int tclcommand_iccp3m(ClientData data, Tcl_Interp *interp, int argc, char **argv iccp3m_initialized=1; iccp3m_cfg.set_flag = 1; - + if (!iccp3m_cfg.areas || !iccp3m_cfg.ein || !iccp3m_cfg.nvectorx) + return TCL_ERROR; + if (!iccp3m_cfg.sigma) { + iccp3m_cfg.sigma = (double*) malloc(iccp3m_cfg.n_ic*sizeof(double)); + memset(iccp3m_cfg.sigma, 0, iccp3m_cfg.n_ic*sizeof(double)); + } mpi_iccp3m_init(0); return TCL_OK; } int tclcommand_iccp3m_parse_normals(Tcl_Interp *interp,int n_ic, char *string) { - char *arg, *token; - int scan_succes; - arg=strdup(string); iccp3m_cfg.nvectorx = (double*) realloc(iccp3m_cfg.nvectorx,sizeof(double)*(iccp3m_cfg.n_ic)); iccp3m_cfg.nvectory = (double*) realloc(iccp3m_cfg.nvectory,sizeof(double)*(iccp3m_cfg.n_ic)); iccp3m_cfg.nvectorz = (double*) realloc(iccp3m_cfg.nvectorz,sizeof(double)*(iccp3m_cfg.n_ic)); - const char opening_bracket[] = "{"; - const char closing_bracket[] = "}"; - const char space[] = " "; - + const char opening_bracket = '{'; + const char closing_bracket = '}'; - // Searching for first opening bracket + std::string arg(string); + size_t beginVector; + size_t endVector; + std::string sVector; + std::stringstream ssVector; + + double x,y,z; for (int i = 0; i> x; + ssVector >> y; + ssVector >> z; + if (!ssVector.good()) { + Tcl_AppendResult(interp, "Could not understand ", ssVector.str().c_str(), (char *)NULL); return TCL_ERROR; } - // convert to float - scan_succes = sscanf(token,"%lf",&(iccp3m_cfg.nvectorz[i])); - if (!scan_succes) { - Tcl_AppendResult(interp, "Unexpected argument ", token, (char *)NULL); - return TCL_ERROR; - } - - token=strtok(NULL, opening_bracket); - + iccp3m_cfg.nvectorx[i] = x; + iccp3m_cfg.nvectory[i] = y; + iccp3m_cfg.nvectorz[i] = z; + arg.erase(0, endVector+1); } - free(arg); + return TCL_OK; } diff --git a/src/tcl/iccp3m_tcl.hpp b/src/tcl/iccp3m_tcl.hpp index 087285dcdf0..ba3820302e4 100644 --- a/src/tcl/iccp3m_tcl.hpp +++ b/src/tcl/iccp3m_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/imd_tcl.cpp b/src/tcl/imd_tcl.cpp index 5676a532267..3553a121237 100644 --- a/src/tcl/imd_tcl.cpp +++ b/src/tcl/imd_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file imd.c - Implementation of \ref imd.h "imd.h". +/** \file imd.cpp + Implementation of \ref imd.hpp "imd.h". */ #include #include @@ -238,23 +238,30 @@ int tclcommand_imd_parse_pos(Tcl_Interp *interp, int argc, char **argv) return (TCL_ERROR); } - if (n_total_particles != max_seen_particle + 1) { + if (n_part != max_seen_particle + 1) { Tcl_AppendResult(interp, "for IMD, store particles consecutively starting with 0.", (char *) NULL); return (TCL_ERROR); } updatePartCfg(WITH_BONDS); - coord = (float*)malloc(n_total_particles*3*sizeof(float)); + coord = (float*)malloc(n_part*3*sizeof(float)); /* sort partcles according to identities */ - for (i = 0; i < n_total_particles; i++) { + for (i = 0; i < n_part; i++) { int dummy[3] = {0,0,0}; double tmpCoord[3]; +#ifdef LEES_EDWARDS + double v_le[3]; +#endif tmpCoord[0] = partCfg[i].r.p[0]; tmpCoord[1] = partCfg[i].r.p[1]; tmpCoord[2] = partCfg[i].r.p[2]; if (flag == NONE) { // perform folding by particle +#ifdef LEES_EDWARDS + fold_position(tmpCoord, v_le, dummy); +#else fold_position(tmpCoord, dummy); +#endif } j = 3*partCfg[i].p.identity; coord[j ] = tmpCoord[0]; @@ -273,7 +280,7 @@ int tclcommand_imd_parse_pos(Tcl_Interp *interp, int argc, char **argv) } - if (imd_send_fcoords(sock, n_total_particles, coord)) { + if (imd_send_fcoords(sock, n_part, coord)) { Tcl_AppendResult(interp, "could not write to IMD socket.", (char *) NULL); return (TCL_ERROR); diff --git a/src/tcl/initialize_interpreter.cpp b/src/tcl/initialize_interpreter.cpp index 79aa6080541..91da7445238 100644 --- a/src/tcl/initialize_interpreter.cpp +++ b/src/tcl/initialize_interpreter.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -22,9 +22,10 @@ #include #include +#include "initialize_interpreter.hpp" #include "global.hpp" -#include "adresso_tcl.hpp" #include "binary_file_tcl.hpp" +#include "cells_tcl.hpp" #include "constraint_tcl.hpp" #include "domain_decomposition_tcl.hpp" #include "dpd_tcl.hpp" @@ -35,6 +36,7 @@ #include "integrate_tcl.hpp" #include "interaction_data_tcl.hpp" #include "lb_tcl.hpp" +#include "lees_edwards_tcl.hpp" #include "lj_tcl.hpp" #include "maggs_tcl.hpp" #include "metadynamics_tcl.hpp" @@ -53,7 +55,11 @@ #include "thermostat_tcl.hpp" #include "virtual_sites_com_tcl.hpp" #include "ghmc_tcl.hpp" +#include "external_potential_tcl.hpp" #include "tuning.hpp" +#include "electrokinetics_tcl.hpp" +#include "actor/HarmonicWell_tcl.hpp" + #ifdef TK #include @@ -64,48 +70,45 @@ *****************************************/ /** Implementation of the tcl command bin, which can be used - to bin data into arbitrary bins. See \ref bin_tcl.c + to bin data into arbitrary bins. See \ref bin_tcl.cpp */ int tclcommand_bin(ClientData data, Tcl_Interp *interp, int argc, char **argv); /** Implementation of the Tcl command blockfile. Allows to read and write - blockfile comfortably from Tcl. See \ref blockfile_tcl.c */ + blockfile comfortably from Tcl. See \ref blockfile_tcl.cpp */ int tclcommand_blockfile(ClientData data, Tcl_Interp *interp, int argc, char **argv); -/** implementation of the Tcl command cellsystem. See \ref cells_tcl.c */ -int tclcommand_cellsystem(ClientData data, Tcl_Interp *interp, - int argc, char **argv); -/** replaces one of TCLs standart channels with a named pipe. See \ref channels_tcl.c */ +/** replaces one of TCLs standart channels with a named pipe. See \ref channels_tcl.cpp */ int tclcommand_replacestdchannel(ClientData clientData, Tcl_Interp *interp, int argc, char **argv); /** Implements the Tcl command code_info. It provides information on the Version, Compilation status and the debug status of the used - code. See \ref config_tcl.c */ + code. See \ref config_tcl.cpp */ int tclcommand_code_info(ClientData data, Tcl_Interp *interp, int argc, char **argv); /** Set the CUDA device to use or retrieve information - available devices. See \ref cuda_init_tcl.c */ + available devices. See \ref cuda_init_tcl.cpp */ int tclcommand_cuda(ClientData data, Tcl_Interp *interp, int argc, char **argv); -/** VMD connection. See \ref imd_tcl.c */ +/** VMD connection. See \ref imd_tcl.cpp */ int tclcommand_imd(ClientData data, Tcl_Interp *interp, int argc, char **argv); /** tcl procedure for nemd steering. USAGE: nemd \ \ - see also \ref tclcommand_nemd. See \ref nemd_tcl.c */ + see also \ref tclcommand_nemd. See \ref nemd_tcl.cpp */ int tclcommand_nemd(ClientData data, Tcl_Interp *interp, int argc, char **argv); -/** Collision detection. See \ref collision_tcl.c */ +/** Collision detection. See \ref collision_tcl.cpp */ int tclcommand_on_collision(ClientData data, Tcl_Interp *interp, int argc, char **argv); /** Implementation of the tcl command "part". This command allows to - modify particle data. See \ref particle_data_tcl.c */ + modify particle data. See \ref particle_data_tcl.cpp */ int tclcommand_part(ClientData data, Tcl_Interp *interp, int argc, char **argv); -/** The C implementation of the tcl function uwerr. See \ref uwerr_tcl.c */ +/** The C implementation of the tcl function uwerr. See \ref uwerr_tcl.cpp */ int tclcommand_uwerr(ClientData data, Tcl_Interp *interp, int argc, char *argv[]); -/** callback for \ref timing_samples. See \ref tuning_tcl.c */ +/** callback for \ref timing_samples. See \ref tuning_tcl.cpp */ int tclcallback_timings(Tcl_Interp *interp, void *data); -/// from \ref scriptsdir.c +/// from \ref scriptsdir.cpp char *get_default_scriptsdir(); /** Returns runtime of the integration loop in seconds. From tuning_tcl.cpp **/ @@ -118,28 +121,29 @@ int tclcommand_time_integration(ClientData data, Tcl_Interp *interp, int argc, c #define REGISTER_COMMAND(name, routine) \ Tcl_CreateCommand(interp, name, (Tcl_CmdProc *)routine, 0, NULL); -static void register_tcl_commands(Tcl_Interp* interp) { - /* in cells.c */ +static void tcl_register_commands(Tcl_Interp* interp) { + /* in cells.cpp */ + REGISTER_COMMAND("sort_particles", tclcommand_sort_particles); REGISTER_COMMAND("cellsystem", tclcommand_cellsystem); - /* in integrate.c */ + /* in integrate.cpp */ REGISTER_COMMAND("invalidate_system", tclcommand_invalidate_system); REGISTER_COMMAND("integrate", tclcommand_integrate); - /* in global.c */ + /* in global.cpp */ REGISTER_COMMAND("setmd", tclcommand_setmd); - /* in grid.c */ + /* in grid.cpp */ REGISTER_COMMAND("change_volume", tclcommand_change_volume); - /* in config_tcl.c */ + /* in config_tcl.cpp */ REGISTER_COMMAND("code_info", tclcommand_code_info); - /* in interaction_data.c */ + /* in interaction_data.cpp */ REGISTER_COMMAND("inter",tclcommand_inter); - /* in particle_data.c */ + /* in particle_data.cpp */ REGISTER_COMMAND("part",tclcommand_part); - /* in file binaryfile.c */ + /* in file binaryfile.cpp */ REGISTER_COMMAND("writemd", tclcommand_writemd); REGISTER_COMMAND("readmd", tclcommand_readmd); - /* in file statistics.c */ + /* in file statistics.cpp */ REGISTER_COMMAND("analyze", tclcommand_analyze); - /* in file polymer.c */ + /* in file polymer.cpp */ REGISTER_COMMAND("polymer", tclcommand_polymer); REGISTER_COMMAND("counterions", tclcommand_counterions); REGISTER_COMMAND("salt", tclcommand_salt); @@ -148,67 +152,66 @@ static void register_tcl_commands(Tcl_Interp* interp) { REGISTER_COMMAND("crosslink", tclcommand_crosslink); REGISTER_COMMAND("diamond", tclcommand_diamond); REGISTER_COMMAND("icosaeder", tclcommand_icosaeder); - /* in file imd.c */ + /* in file imd.cpp */ REGISTER_COMMAND("imd", tclcommand_imd); - /* in file random.c */ + /* in file random.cpp */ REGISTER_COMMAND("t_random", tclcommand_t_random); REGISTER_COMMAND("bit_random", tclcommand_bit_random); - /* in file blockfile_tcl.c */ + /* in file blockfile_tcl.cpp */ REGISTER_COMMAND("blockfile", tclcommand_blockfile); - /* in constraint.c */ + /* in constraint.cpp */ REGISTER_COMMAND("constraint", tclcommand_constraint); + /* in external_potential.hpp */ + REGISTER_COMMAND("external_potential", tclcommand_external_potential); /* in uwerr.c */ REGISTER_COMMAND("uwerr", tclcommand_uwerr); - /* in nemd.c */ + /* in nemd.cpp */ REGISTER_COMMAND("nemd", tclcommand_nemd); - /* in thermostat.c */ + /* in thermostat.cpp */ REGISTER_COMMAND("thermostat", tclcommand_thermostat); - /* in bin.c */ + /* in bin.cpp */ REGISTER_COMMAND("bin", tclcommand_bin); - /* in ghmc.c */ + /* in ghmc.cpp */ REGISTER_COMMAND("ghmc", tclcommand_ghmc); REGISTER_COMMAND("save_state", tclcommand_save_state); REGISTER_COMMAND("load_state", tclcommand_load_state); - /* in lb.c */ + /* in lb.cpp */ REGISTER_COMMAND("lbfluid", tclcommand_lbfluid); REGISTER_COMMAND("lbnode", tclcommand_lbnode); REGISTER_COMMAND("lbboundary", tclcommand_lbboundary); /* here */ REGISTER_COMMAND("replacestdchannel", tclcommand_replacestdchannel); - /* in iccp3m.h */ + /* in iccp3m.hpp */ REGISTER_COMMAND("observable", tclcommand_observable); - /* in statistics_obsrvable.h */ + /* in statistics_obsrvable.hpp */ REGISTER_COMMAND("correlation", tclcommand_correlation); - /* in statistics_correlation.h */ + /* in statistics_correlation.hpp */ #ifdef ELECTROSTATICS #ifdef P3M REGISTER_COMMAND("iccp3m", tclcommand_iccp3m); -#endif -#endif - /* in adresso.h */ - REGISTER_COMMAND("adress", tclcommand_adress); -#ifdef ADRESS - /* #ifdef THERMODYNAMIC_FORCE */ - REGISTER_COMMAND("thermodynamic_force", tclcommand_thermodynamic_force); - /* #endif */ - REGISTER_COMMAND("update_adress_weights", tclcommand_update_adress_weights); +#endif + REGISTER_COMMAND("efield_caps", tclcommand_print_efield_capacitors); #endif #ifdef METADYNAMICS - /* in metadynamics.c */ + /* in metadynamics.cpp */ REGISTER_COMMAND("metadynamics", tclcommand_metadynamics); #endif #ifdef LB_GPU - /* in lbgpu_cfile.c */ + /* in lbgpu_cfile.cpp */ REGISTER_COMMAND("lbnode_extforce", tclcommand_lbnode_extforce_gpu); #endif #ifdef CUDA REGISTER_COMMAND("cuda", tclcommand_cuda); #endif - /* from collision.c */ + /* from collision.cpp */ #ifdef COLLISION_DETECTION REGISTER_COMMAND("on_collision", tclcommand_on_collision); #endif + +/* #ifdef LEES_EDWARDS Register the command even if not implemented, so it can return an informative error*/ + REGISTER_COMMAND("lees_edwards_offset", tclcommand_lees_edwards_offset); +/* #endif */ #ifdef CATALYTIC_REACTIONS REGISTER_COMMAND("reaction", tclcommand_reaction); #endif @@ -218,9 +221,13 @@ static void register_tcl_commands(Tcl_Interp* interp) { REGISTER_COMMAND("system_CMS_velocity", tclcommand_system_CMS_velocity); REGISTER_COMMAND("galilei_transform", tclcommand_galilei_transform); REGISTER_COMMAND("time_integration", tclcommand_time_integration); + REGISTER_COMMAND("electrokinetics", tclcommand_electrokinetics); +#ifdef CUDA + REGISTER_COMMAND("harmonic_well", tclcommand_HarmonicWell); +#endif } -static void register_global_variables(Tcl_Interp *interp) +static void tcl_register_global_variables(Tcl_Interp *interp) { /* register all writeable TCL variables with their callback functions */ register_global_callback(FIELD_BOXL, tclcallback_box_l); @@ -235,9 +242,10 @@ static void register_global_variables(Tcl_Interp *interp) register_global_callback(FIELD_TIMESTEP, tclcallback_time_step); register_global_callback(FIELD_TIMINGSAMP, tclcallback_timings); register_global_callback(FIELD_MIN_GLOBAL_CUT, tclcallback_min_global_cut); + register_global_callback(FIELD_WARNINGS, tclcallback_warnings); } -int appinit(Tcl_Interp *interp) +int tcl_appinit(Tcl_Interp *interp) { if (Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR; @@ -250,8 +258,8 @@ int appinit(Tcl_Interp *interp) /* installation of tcl commands */ - register_tcl_commands(interp); - register_global_variables(interp); + tcl_register_commands(interp); + tcl_register_global_variables(interp); /* evaluate the Tcl initialization script */ char *scriptdir = getenv("ESPRESSO_SCRIPTS"); diff --git a/src/tcl/initialize_interpreter.hpp b/src/tcl/initialize_interpreter.hpp new file mode 100644 index 00000000000..0c469507b2a --- /dev/null +++ b/src/tcl/initialize_interpreter.hpp @@ -0,0 +1,20 @@ +/* + Copyright (C) 2014 The ESPResSo project + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include +int tcl_appinit(Tcl_Interp *interp); diff --git a/src/tcl/integrate_tcl.cpp b/src/tcl/integrate_tcl.cpp index 0c18290766a..b73e30bea27 100644 --- a/src/tcl/integrate_tcl.cpp +++ b/src/tcl/integrate_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,13 +19,14 @@ along with this program. If not, see . */ -/** \file integrate.c Molecular dynamics integrator. +/** \file integrate.cpp Molecular dynamics integrator. * * For more information about the integrator - * see \ref integrate.h "integrate.h". + * see \ref integrate.hpp "integrate.h". */ #include "integrate.hpp" +#include "global.hpp" #include "npt.hpp" #include "interaction_data.hpp" #include "lb.hpp" @@ -33,17 +34,21 @@ #include "communication.hpp" #include "parser.hpp" #include "statistics_correlation.hpp" +#include "statistics_observable.hpp" int tclcommand_invalidate_system(ClientData data, Tcl_Interp *interp, int argc, char **argv) { - mpi_bcast_event(INVALIDATE_SYSTEM); - return TCL_OK; + Tcl_AppendResult(interp, "invalidate_system is no longer supported ", + "as it's behavior is actually undefined.\n", + "For consistency after reading a checkpoint, use sort_particles.\n", + "For timing purposes, use the recalc_forces flag of integrate\n", (char *)NULL); + return TCL_ERROR; } /** Hand over integrate usage information to tcl interpreter. */ int tclcommand_integrate_print_usage(Tcl_Interp *interp) { Tcl_AppendResult(interp, "Usage of tcl-command integrate:\n", (char *)NULL); - Tcl_AppendResult(interp, "'integrate ' for integrating n steps \n", (char *)NULL); + Tcl_AppendResult(interp, "'integrate [reuse_forces|recalc_forces]' for integrating n steps\n", (char *)NULL); Tcl_AppendResult(interp, "'integrate set' for printing integrator status \n", (char *)NULL); Tcl_AppendResult(interp, "'integrate set nvt' for enabling NVT integration or \n" , (char *)NULL); #ifdef NPT @@ -194,7 +199,7 @@ int tclcommand_integrate_set_npt_isotropic(Tcl_Interp *interp, int argc, char ** int tclcommand_integrate(ClientData data, Tcl_Interp *interp, int argc, char **argv) { - int n_steps; + int n_steps, reuse_forces = 0; INTEG_TRACE(fprintf(stderr,"%d: integrate:\n",this_node)); @@ -213,16 +218,51 @@ int tclcommand_integrate(ClientData data, Tcl_Interp *interp, int argc, char **a Tcl_AppendResult(interp, "unknown integrator method:\n", (char *)NULL); return tclcommand_integrate_print_usage(interp); } - } else if ( !ARG_IS_I(1,n_steps) ) return tclcommand_integrate_print_usage(interp); + } else { + if ( !ARG_IS_I(1,n_steps) ) return tclcommand_integrate_print_usage(interp); + // actual integration + if ((argc == 3) && ARG_IS_S(2, "reuse_forces")) { + reuse_forces = 1; + } + else if ((argc == 3) && ARG_IS_S(2, "recalc_forces")) { + reuse_forces = -1; + } + else if (argc != 2) return tclcommand_integrate_print_usage(interp); + } /* go on with integrate */ if(n_steps < 0) { Tcl_AppendResult(interp, "illegal number of steps (must be >0) \n", (char *) NULL); return tclcommand_integrate_print_usage(interp);; } + + /* if skin wasn't set, do an educated guess now */ + if (!skin_set) { + if (max_cut == 0.0) { + Tcl_AppendResult(interp, "cannot automatically determine skin, please set it manually via \"setmd kin\"\n", (char *) NULL); + return TCL_ERROR; + } + skin = 0.4*max_cut; + mpi_bcast_parameter(FIELD_SKIN); + } + /* perform integration */ - if (mpi_integrate(n_steps)) - return gather_runtime_errors(interp, TCL_OK); + if (!correlations_autoupdate && !observables_autoupdate) { + if (mpi_integrate(n_steps, reuse_forces)) + return gather_runtime_errors(interp, TCL_OK); + } else { + for (int i=0; i. */ -/** \file interaction_data.c - Implementation of interaction_data.h +/** \file interaction_data.cpp + Implementation of interaction_data.hpp */ #include #include #include "interaction_data_tcl.hpp" #include "interaction_data.hpp" #include "communication.hpp" +#include "global.hpp" #include "comforce_tcl.hpp" #include "comfixed_tcl.hpp" @@ -39,12 +40,18 @@ #include "tab.hpp" #include "buckingham.hpp" -// nonbonded +//for surface charge output +#include "mmm2d.hpp" +#include "mmm-common.hpp" +#include "elc.hpp" + +// Nonbonded #include "bmhtf-nacl_tcl.hpp" #include "buckingham_tcl.hpp" #include "gb_tcl.hpp" #include "gaussian_tcl.hpp" #include "hat_tcl.hpp" +#include "lb_tcl.hpp" #include "lj_tcl.hpp" #include "ljangle_tcl.hpp" #include "ljcos_tcl.hpp" @@ -66,6 +73,8 @@ #include "mmm2d_tcl.hpp" #include "p3m_tcl.hpp" #include "reaction_field_tcl.hpp" +#include "actor/Mmm1dgpu_tcl.hpp" +#include "actor/Ewaldgpu_tcl.hpp" // Magnetostatics #include "mdlc_correction_tcl.hpp" @@ -83,6 +92,8 @@ #include "fene_tcl.hpp" #include "overlap_tcl.hpp" #include "harmonic_tcl.hpp" +#include "quartic_tcl.hpp" +#include "bonded_coulomb_tcl.hpp" #include "subt_lj_tcl.hpp" #include "tcl/object-in-fluid/area_force_local_tcl.hpp" #include "tcl/object-in-fluid/area_force_global_tcl.hpp" @@ -91,13 +102,12 @@ #include "tcl/object-in-fluid/stretchlin_force_tcl.hpp" #include "tcl/object-in-fluid/bending_force_tcl.hpp" -int tclprint_to_result_CoulombIA(Tcl_Interp *interp); - #ifdef DIPOLES int tclprint_to_result_DipolarIA(Tcl_Interp *interp); #endif #ifdef ELECTROSTATICS +int tclprint_to_result_CoulombIA(Tcl_Interp *interp); /********************************************************************************/ /* electrostatics */ @@ -181,6 +191,14 @@ int tclcommand_inter_parse_coulomb(Tcl_Interp * interp, int argc, char ** argv) REGISTER_COULOMB("memd", tclcommand_inter_coulomb_parse_maggs); + #ifdef MMM1D_GPU + REGISTER_COULOMB("mmm1dgpu", tclcommand_inter_coulomb_parse_mmm1dgpu); + #endif + + #ifdef EWALD_GPU + REGISTER_COULOMB("ewaldgpu", tclcommand_inter_coulomb_parse_ewaldgpu); + #endif + /* fallback */ coulomb.method = COULOMB_NONE; coulomb.bjerrum = 0.0; @@ -316,6 +334,12 @@ int tclprint_to_result_BondedIA(Tcl_Interp *interp, int i) #endif case BONDED_IA_HARMONIC: return tclprint_to_result_harmonicIA(interp, params); + case BONDED_IA_QUARTIC: + return tclprint_to_result_quarticIA(interp, params); +#ifdef ELECTROSTATICS + case BONDED_IA_BONDED_COULOMB: + return tclprint_to_result_bonded_coulombIA(interp, params); +#endif #ifdef BOND_ANGLE_OLD case BONDED_IA_ANGLE_OLD: return tclprint_to_result_angleIA(interp, params); @@ -364,6 +388,8 @@ int tclprint_to_result_BondedIA(Tcl_Interp *interp, int i) Tcl_AppendResult(interp, "unknown bonded interaction number ",buffer, (char *) NULL); return (TCL_ERROR); + default: // keep the compiler happy if interactions are compiled out + break; } /* if none of the above */ Tcl_ResetResult(interp); @@ -371,30 +397,6 @@ int tclprint_to_result_BondedIA(Tcl_Interp *interp, int i) return (TCL_ERROR); } -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -int tclprint_to_result_TF(Tcl_Interp *interp, int i) -{ - char buffer[TCL_DOUBLE_SPACE + 2*TCL_INTEGER_SPACE]; - TF_parameters *data = get_tf_param(i); - - if (!data) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "thermodynamic force does not exist", - (char *) NULL); - return (TCL_ERROR); - } - sprintf(buffer, "%d ", i); - Tcl_AppendResult(interp, buffer, (char *) NULL); - - if(data->TF_TAB_maxval !=0) - Tcl_AppendResult(interp, "thermodynamic_force \"", data->TF_TAB_filename,"\"", (char *) NULL); - - return(TCL_OK); -} -/* #endif */ -#endif - int tclprint_to_result_NonbondedIA(Tcl_Interp *interp, int i, int j) { char buffer[TCL_DOUBLE_SPACE + 2*TCL_INTEGER_SPACE]; @@ -471,11 +473,6 @@ int tclprint_to_result_NonbondedIA(Tcl_Interp *interp, int i, int j) Tcl_AppendResult(interp, "tabulated \"", data->TAB_filename,"\"", (char *) NULL); #endif -#if defined(ADRESS) && defined(INTERFACE_CORRECTION) - if(data->ADRESS_TAB_maxval > 0.0) - Tcl_AppendResult(interp, "adress \"", data->ADRESS_TAB_filename,"\"", (char *) NULL); -#endif - #ifdef COMFORCE if (data->COMFORCE_flag > 0.0) tclprint_to_result_comforceIA(interp,i,j); #endif @@ -499,6 +496,9 @@ int tclprint_to_result_NonbondedIA(Tcl_Interp *interp, int i, int j) #ifdef TUNABLE_SLIP if (data->TUNABLE_SLIP_r_cut > 0.0) tclprint_to_result_tunable_slipIA(interp,i,j); #endif +#ifdef SHANCHEN + if (data->affinity_on == 1 ) tclprint_to_result_affinityIA(interp,i,j); +#endif return (TCL_OK); } @@ -526,14 +526,20 @@ int tclprint_to_result_CoulombIA(Tcl_Interp *interp) case COULOMB_RF: tclprint_to_result_rf(interp,"rf"); break; case COULOMB_INTER_RF: tclprint_to_result_rf(interp,"inter_rf"); break; case COULOMB_MMM1D: tclprint_to_result_MMM1D(interp); break; +#ifdef MMM1D_GPU + case COULOMB_MMM1D_GPU: tclprint_to_result_MMM1DGPU(interp); break; +#endif case COULOMB_MMM2D: tclprint_to_result_MMM2D(interp); break; case COULOMB_MAGGS: tclprint_to_result_Maggs(interp); break; +#ifdef EWALD_GPU + case COULOMB_EWALD_GPU: tclprint_to_result_ewaldgpu(interp); break; +#endif default: break; } Tcl_AppendResult(interp, "}",(char *) NULL); #else - Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.h)",(char *) NULL); + Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.hpp)",(char *) NULL); #endif return (TCL_OK); } @@ -695,24 +701,6 @@ int tclcommand_inter_print_non_bonded(Tcl_Interp * interp, return tclprint_to_result_NonbondedIA(interp, part_type_a, part_type_b); } -#ifdef ADRESS -/* #ifdef THERMODYNAMIC_FORCE */ -/* TODO: This function is not used anywhere. To be removed? */ -int tf_print(Tcl_Interp * interp, int part_type) -{ - //TF_parameters *data; - Tcl_ResetResult(interp); - - make_particle_type_exist(part_type); - - //data = get_tf_param(part_type); - - return tclprint_to_result_TF(interp, part_type); -} -/* #endif */ -#endif - - int tclcommand_inter_parse_non_bonded(Tcl_Interp * interp, int part_type_a, int part_type_b, int argc, char ** argv) @@ -821,12 +809,11 @@ int tclcommand_inter_parse_non_bonded(Tcl_Interp * interp, #ifdef MOL_CUT REGISTER_NONBONDED("molcut", tclcommand_inter_parse_molcut); #endif - -#ifdef ADRESS -#ifdef INTERFACE_CORRECTION - REGISTER_NONBONDED("adress_tab_ic", tclcommand_inter_parse_adress_tab); -#endif + +#ifdef SHANCHEN + REGISTER_NONBONDED("affinity",tclcommand_inter_parse_affinity); #endif + else { Tcl_AppendResult(interp, "excessive parameter/unknown interaction type \"", argv[0], "\" in parsing non bonded interaction", @@ -867,6 +854,43 @@ int tclcommand_inter_print_partner_num(Tcl_Interp *interp, int bond_type) return TCL_ERROR; } +#ifdef ELECTROSTATICS +/* print applied/induced efields for capacitor feature in ic-mmm2d and ic-elc */ +int tclcommand_print_efield_capacitors(ClientData data, Tcl_Interp * interp, int argc, char ** argv) +{ + char buffer[TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE + 2]; + double value=0; + + if (!( + (coulomb.method == COULOMB_MMM2D && mmm2d_params.const_pot_on) +#ifdef P3M + || (coulomb.method == COULOMB_ELC_P3M && elc_params.const_pot_on) +#endif + )) { + Tcl_AppendResult(interp, "Electric field output only available for mmm2d or p3m+elc with capacitor feature", (char *) NULL); + return TCL_ERROR; + } + else if (argc > 2) { + Tcl_AppendResult(interp, "wrong # arguments: efield_caps <{total} | {induced} | {applied}>", (char *) NULL); + return TCL_ERROR; + } + else if (argc == 1 || ARG1_IS_S("total")) { + value = field_induced + field_applied; + } + else if (ARG1_IS_S("induced")) { + value = field_induced; + } + else if (ARG1_IS_S("applied")) { + value = field_applied; + } + + Tcl_PrintDouble(interp, value, buffer); + Tcl_AppendResult(interp, buffer, (char *)NULL); + + return TCL_OK; +} +#endif + /********************************************************************************/ /* parsing */ /********************************************************************************/ @@ -907,6 +931,10 @@ int tclcommand_inter_parse_bonded(Tcl_Interp *interp, REGISTER_BONDED("volume_force", tclcommand_inter_parse_volume_force); #endif REGISTER_BONDED("harmonic", tclcommand_inter_parse_harmonic); + REGISTER_BONDED("quartic", tclcommand_inter_parse_quartic); +#ifdef ELECTROSTATICS + REGISTER_BONDED("bonded_coulomb", tclcommand_inter_parse_bonded_coulomb); +#endif #ifdef LENNARD_JONES REGISTER_BONDED("subt_lj", tclcommand_inter_parse_subt_lj); #endif @@ -977,7 +1005,7 @@ int tclcommand_inter_parse_rest(Tcl_Interp * interp, int argc, char ** argv) #ifdef ELECTROSTATICS return tclcommand_inter_parse_coulomb(interp, argc-1, argv+1); #else - Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.h)", (char *) NULL); + Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.hpp)", (char *) NULL); #endif } @@ -985,7 +1013,7 @@ int tclcommand_inter_parse_rest(Tcl_Interp * interp, int argc, char ** argv) #ifdef DIPOLES return tclcommand_inter_parse_magnetic(interp, argc-1, argv+1); #else - Tcl_AppendResult(interp, "DIPOLES not compiled (see config.h)", (char *) NULL); + Tcl_AppendResult(interp, "DIPOLES not compiled (see config.hpp)", (char *) NULL); #endif } diff --git a/src/tcl/interaction_data_tcl.hpp b/src/tcl/interaction_data_tcl.hpp index 088b546dd00..1e3ada275eb 100644 --- a/src/tcl/interaction_data_tcl.hpp +++ b/src/tcl/interaction_data_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -42,4 +42,9 @@ int tclcommand_constraint(ClientData _data, Tcl_Interp *interp, /** datafield callback for \ref min_global_cut. Sets the minimal cell size. */ int tclcallback_min_global_cut(Tcl_Interp *interp, void *_data); +/* Print the surface charge for capacitor feature in ic-mmm2d and ic-elc */ +int tclcommand_print_efield_capacitors(ClientData data, Tcl_Interp * interp, + int argc, char ** argv); + + #endif diff --git a/src/tcl/lb-boundaries_tcl.cpp b/src/tcl/lb-boundaries_tcl.cpp index a44facba5f7..e1a8bb00727 100644 --- a/src/tcl/lb-boundaries_tcl.cpp +++ b/src/tcl/lb-boundaries_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb-boundaries_tcl.c +/** \file lb-boundaries_tcl.cpp * * Boundary conditions parser file for Lattice Boltzmann fluid dynamics. * @@ -30,6 +30,7 @@ #include "interaction_data.hpp" #include "lb-boundaries.hpp" #include "communication.hpp" +#include #if defined(LB_BOUNDARIES) || defined(LB_BOUNDARIES_GPU) @@ -40,6 +41,7 @@ int tclcommand_lbboundary_sphere(LB_Boundary *lbb, Tcl_Interp *interp, int argc, int tclcommand_lbboundary_cylinder(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); int tclcommand_lbboundary_pore(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); int tclcommand_lbboundary_stomatocyte(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_hollow_cone(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); int tclcommand_printLbBoundaryToResult(Tcl_Interp *interp, int i); int tclcommand_printLbBoundaryToResult(Tcl_Interp *interp, int i) @@ -189,6 +191,37 @@ int tclcommand_printLbBoundaryToResult(Tcl_Interp *interp, int i) Tcl_PrintDouble(interp, lbb->c.stomatocyte.direction, buffer); Tcl_AppendResult(interp, " direction ", buffer, (char *) NULL); + break; + + case LB_BOUNDARY_HOLLOW_CONE: + Tcl_PrintDouble(interp, lbb->c.hollow_cone.position_x, buffer); + Tcl_AppendResult(interp, "hollow_cone center ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, lbb->c.hollow_cone.position_y, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, lbb->c.hollow_cone.position_z, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.orientation_x, buffer); + Tcl_AppendResult(interp, " orientation ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, lbb->c.hollow_cone.orientation_y, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, lbb->c.hollow_cone.orientation_z, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.outer_radius, buffer); + Tcl_AppendResult(interp, " outer radius ", buffer, " ", (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.inner_radius, buffer); + Tcl_AppendResult(interp, " inner radius ", buffer, " ", (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.width, buffer); + Tcl_AppendResult(interp, " width ", buffer, " ", (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.opening_angle, buffer); + Tcl_AppendResult(interp, " opening angle ", buffer, " ", (char *) NULL); + + Tcl_PrintDouble(interp, lbb->c.hollow_cone.direction, buffer); + Tcl_AppendResult(interp, " direction ", buffer, (char *) NULL); break; default: @@ -219,15 +252,26 @@ int tclcommand_lbboundary_print_all(Tcl_Interp *interp) LB_Boundary *generate_lbboundary() { n_lb_boundaries++; + lb_boundaries = (LB_Boundary*) realloc(lb_boundaries,n_lb_boundaries*sizeof(LB_Boundary)); + lb_boundaries[n_lb_boundaries-1].type = LB_BOUNDARY_BOUNCE_BACK; + lb_boundaries[n_lb_boundaries-1].velocity[0]= lb_boundaries[n_lb_boundaries-1].velocity[1]= lb_boundaries[n_lb_boundaries-1].velocity[2]=0; + lb_boundaries[n_lb_boundaries-1].force[0]= lb_boundaries[n_lb_boundaries-1].force[1]= lb_boundaries[n_lb_boundaries-1].force[2]=0; +#ifdef EK_BOUNDARIES + if (ek_initialized) + { + lb_boundaries[n_lb_boundaries-1].charge_density = 0.0; + } +#endif + return &lb_boundaries[n_lb_boundaries-1]; } @@ -235,7 +279,7 @@ int tclcommand_lbboundary_wall(LB_Boundary *lbb, Tcl_Interp *interp, int argc, c { int i; double norm; - + lbb->type = LB_BOUNDARY_WAL; /* invalid entries to start of */ @@ -485,6 +529,31 @@ int tclcommand_lbboundary_cylinder(LB_Boundary *lbb, Tcl_Interp *interp, int arg argc -= 2; argv += 2; } + else if(ARG_IS_S(0, "velocity")) { + if(argc < 4) { + Tcl_AppendResult(interp, "lbboundary cylinder velocity expected", (char *) NULL); + return (TCL_ERROR); + } + + if(Tcl_GetDouble(interp, argv[1], &(lbb->velocity[0])) == TCL_ERROR || + Tcl_GetDouble(interp, argv[2], &(lbb->velocity[1])) == TCL_ERROR || + Tcl_GetDouble(interp, argv[3], &(lbb->velocity[2])) == TCL_ERROR) + return (TCL_ERROR); + + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + /* No velocity rescaling is required */ +#endif + } else { +#ifdef LB + lbb->velocity[0]*=lbpar.tau/lbpar.agrid; + lbb->velocity[1]*=lbpar.tau/lbpar.agrid; + lbb->velocity[2]*=lbpar.tau/lbpar.agrid; +#endif + } + + argc -= 4; argv += 4; + } else break; } @@ -588,6 +657,31 @@ int tclcommand_lbboundary_rhomboid(LB_Boundary *lbb, Tcl_Interp *interp, int arg argc -= 4; argv += 4; } + else if(ARG_IS_S(0, "velocity")) { + if(argc < 4) { + Tcl_AppendResult(interp, "lbboundary rhomboid velocity expected", (char *) NULL); + return (TCL_ERROR); + } + + if(Tcl_GetDouble(interp, argv[1], &(lbb->velocity[0])) == TCL_ERROR || + Tcl_GetDouble(interp, argv[2], &(lbb->velocity[1])) == TCL_ERROR || + Tcl_GetDouble(interp, argv[3], &(lbb->velocity[2])) == TCL_ERROR) + return (TCL_ERROR); + + if (lattice_switch & LATTICE_LB_GPU) { +#ifdef LB_GPU + /* No velocity rescaling is required */ +#endif + } else { +#ifdef LB + lbb->velocity[0]*=lbpar.tau/lbpar.agrid; + lbb->velocity[1]*=lbpar.tau/lbpar.agrid; + lbb->velocity[2]*=lbpar.tau/lbpar.agrid; +#endif + } + + argc -= 4; argv += 4; + } else if(ARG_IS_S(0, "direction")) { if (argc < 2) { Tcl_AppendResult(interp, "lbboundary rhomboid direction {inside|outside} expected", (char *) NULL); @@ -666,6 +760,9 @@ int tclcommand_lbboundary_pore(LB_Boundary *lbb, Tcl_Interp *interp, int argc, c lbb->c.pore.smoothing_radius = 1.; + lbb->c.pore.outer_rad_left = std::numeric_limits::max(); + lbb->c.pore.outer_rad_right = std::numeric_limits::max(); + while (argc > 0) { if(ARG_IS_S(0, "center")) { if(argc < 4) { @@ -705,7 +802,19 @@ int tclcommand_lbboundary_pore(LB_Boundary *lbb, Tcl_Interp *interp, int argc, c lbb->c.pore.rad_right = lbb->c.pore.rad_left; argc -= 2; argv += 2; } - else if(ARG_IS_S(0, "smoothing_radius")) { + else if(!strncmp(argv[0], "outer_radius", strlen(argv[0]))) { + if(argc < 1) { + Tcl_AppendResult(interp, "lbboundary pore outer_radius expected", (char *) NULL); + return (TCL_ERROR); + } + + if(Tcl_GetDouble(interp, argv[1], &(lbb->c.pore.outer_rad_left)) == TCL_ERROR) + return (TCL_ERROR); + + lbb->c.pore.outer_rad_right = lbb->c.pore.outer_rad_left; + argc -= 2; argv += 2; + } + else if(!strncmp(argv[0], "smoothing_radius", strlen(argv[0]))) { if (argc < 1) { Tcl_AppendResult(interp, "lbboundary pore smoothing_radius expected", (char *) NULL); return (TCL_ERROR); @@ -730,7 +839,21 @@ int tclcommand_lbboundary_pore(LB_Boundary *lbb, Tcl_Interp *interp, int argc, c argc -= 3; argv += 3; } - else if(ARG_IS_S(0, "length")) { + else if(!strncmp(argv[0], "outer_radii", strlen(argv[0]))) { + if(argc < 1) { + Tcl_AppendResult(interp, "lbboundary pore outer_radii expected", (char *) NULL); + return (TCL_ERROR); + } + + if (Tcl_GetDouble(interp, argv[1], &(lbb->c.pore.outer_rad_left)) == TCL_ERROR) + return (TCL_ERROR); + + if (Tcl_GetDouble(interp, argv[2], &(lbb->c.pore.outer_rad_right)) == TCL_ERROR) + return (TCL_ERROR); + + argc -= 3; argv += 3; + } + else if(!strncmp(argv[0], "length", strlen(argv[0]))) { if (argc < 1) { Tcl_AppendResult(interp, "lbboundary pore length expected", (char *) NULL); return (TCL_ERROR); @@ -903,12 +1026,190 @@ int tclcommand_lbboundary_stomatocyte(LB_Boundary *lbb, Tcl_Interp *interp, int return (TCL_OK); } + +int tclcommand_lbboundary_hollow_cone(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv) +{ + /* DON'T PLAY WITH THIS CONSTRAINT UNLESS + YOU KNOW WHAT IT IS THAT YOU ARE DOING */ + + lbb->type = LB_BOUNDARY_HOLLOW_CONE; + + /* invalid entries to start of */ + + lbb->c.hollow_cone.position_x = -M_PI; + lbb->c.hollow_cone.position_y = -M_PI; + lbb->c.hollow_cone.position_z = -M_PI; + lbb->c.hollow_cone.orientation_x = -M_PI; + lbb->c.hollow_cone.orientation_y = -M_PI; + lbb->c.hollow_cone.orientation_z = -M_PI; + lbb->c.hollow_cone.outer_radius = -1.0; + lbb->c.hollow_cone.inner_radius = -1.0; + lbb->c.hollow_cone.width = -1.0; + lbb->c.hollow_cone.opening_angle = -1.0; + lbb->c.hollow_cone.direction = 0; + + /* read the data */ + + while ( argc > 0 ) + { + if ( ARG_IS_S( 0, "center" ) ) + { + if(argc < 4) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone center expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, lbb->c.hollow_cone.position_x ) || + !ARG_IS_D( 2, lbb->c.hollow_cone.position_y ) || + !ARG_IS_D( 3, lbb->c.hollow_cone.position_z ) ) + { + return (TCL_ERROR); + } + + argc -= 4; argv += 4; + } + else if ( ARG_IS_S( 0, "orientation" ) ) + { + if(argc < 4) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone orientation expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, lbb->c.hollow_cone.orientation_x ) || + !ARG_IS_D( 2, lbb->c.hollow_cone.orientation_y ) || + !ARG_IS_D( 3, lbb->c.hollow_cone.orientation_z ) ) + { + return (TCL_ERROR); + } + + argc -= 4; argv += 4; + } + else if ( ARG_IS_S( 0, "outer_radius" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone outer_radius expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D(1, lbb->c.hollow_cone.outer_radius ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "inner_radius" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone inner_radius expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, lbb->c.hollow_cone.inner_radius ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "width" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone width expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, lbb->c.hollow_cone.width ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "opening_angle" ) ) + { + if(argc < 2) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone opening_angle expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( !ARG_IS_D( 1, lbb->c.hollow_cone.opening_angle ) ) + return (TCL_ERROR); + + argc -= 2; argv += 2; + } + else if ( ARG_IS_S( 0, "direction" ) ) + { + if ( argc < 2 ) + { + Tcl_AppendResult(interp, "lbboundary hollow_cone direction {-1|1} or {inside|outside} is expected", (char *) NULL); + return (TCL_ERROR); + } + + if ( ARG_IS_S( 1, "inside" ) ) + lbb->c.hollow_cone.direction = -1; + else if ( ARG_IS_S( 1, "outside" ) ) + lbb->c.hollow_cone.direction = 1; + else if ( !ARG_IS_D( 1, lbb->c.hollow_cone.direction ) ) + return (TCL_ERROR); + argc -= 2; argv += 2; + } + else + break; + } + + if ( lbb->c.hollow_cone.outer_radius < 0.0 || + lbb->c.hollow_cone.inner_radius < 0.0 || + lbb->c.hollow_cone.width < 0.0 ) + { + Tcl_AppendResult(interp, "hollow_cone radii and width have to be greater than zero", + (char *) NULL); + return (TCL_ERROR); + } + + if ( lbb->c.hollow_cone.opening_angle < 0.0 || + lbb->c.hollow_cone.opening_angle > M_PI ) + { + Tcl_AppendResult(interp, "hollow_cone requires 0.0 <= opening_angle <= Pi", + (char *) NULL); + return (TCL_ERROR); + } + + if ( fabs( fmod( lbb->c.hollow_cone.outer_radius , 1.0 ) ) < 1.0e-05 || + fabs( fmod( lbb->c.hollow_cone.inner_radius , 1.0 ) ) < 1.0e-05 || + fabs( fmod( lbb->c.hollow_cone.width , 1.0 ) ) < 1.0e-05 ) + { + fprintf( stderr, "Warning: Using (almost) exact integer values for the radii or width.\n"); + fprintf( stderr, " can lead to numerical problems when the LB grid points coincide\n"); + fprintf( stderr, " with the lattice, for specific values of the position and\n"); + fprintf( stderr, " orientation. Consider adding or subtracting a small number\n"); + fprintf( stderr, " to/from the specified sizes to overcome such problems.\n"); + fflush(stdout); + } + + return (TCL_OK); +} + + +int tclcommand_lbboundary_box(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv) +{ + lbb->type = LB_BOUNDARY_BOX; + lbb->c.box.value = 0; + + return (TCL_OK); +} + #endif /* LB_BOUNDARIES or LB_BOUNDARIES_GPU */ int tclcommand_lbboundary(ClientData data, Tcl_Interp *interp, int argc, char **argv) { #if defined (LB_BOUNDARIES) || defined (LB_BOUNDARIES_GPU) int status = TCL_ERROR, c_num; + + if ( lattice_switch == LATTICE_OFF ) { + fprintf (stderr ,"WARNING: Specifying boundaries before using lbfluid assumes a CPU implementation of the LB.\n"); + fprintf (stderr ,"WARNING: This will lead to unexpected behavior if a GPU LB fluid is later used since the boundaries wont exist.\n"); + } if (argc < 2) return tclcommand_lbboundary_print_all(interp); @@ -955,6 +1256,13 @@ int tclcommand_lbboundary(ClientData data, Tcl_Interp *interp, int argc, char ** } else mpi_bcast_lbboundary(-1); } + else if(ARG_IS_S(1, "hollow_cone")) { + status = tclcommand_lbboundary_hollow_cone(generate_lbboundary(),interp, argc - 2, argv + 2); + if (lattice_switch & LATTICE_LB_GPU) { + mpi_bcast_lbboundary(-3); + } else + mpi_bcast_lbboundary(-1); + } else if(ARG_IS_S(1, "force")) { if(argc != 3 || Tcl_GetInt(interp, argv[2], &(c_num)) == TCL_ERROR) { Tcl_AppendResult(interp, "Usage: lbboundary force $n",(char *) NULL); @@ -981,23 +1289,21 @@ int tclcommand_lbboundary(ClientData data, Tcl_Interp *interp, int argc, char ** else if(ARG_IS_S(1, "delete")) { if(argc < 3) { /* delete all */ - if (lattice_switch & LATTICE_LB_GPU) { - Tcl_AppendResult(interp, "Cannot delete individual lb boundaries",(char *) NULL); - status = TCL_ERROR; - } else mpi_bcast_lbboundary(-2); - status = TCL_OK; + status = TCL_OK; } else { + if (lattice_switch & LATTICE_LB_GPU) { + Tcl_AppendResult(interp, "Cannot delete individual lb boundaries",(char *) NULL); + return(TCL_ERROR); + } + if(Tcl_GetInt(interp, argv[2], &(c_num)) == TCL_ERROR) return (TCL_ERROR); if(c_num < 0 || c_num >= n_lb_boundaries) { Tcl_AppendResult(interp, "Can not delete non existing lbboundary",(char *) NULL); return (TCL_ERROR); } - if (lattice_switch & LATTICE_LB_GPU) { - mpi_bcast_lbboundary(-3); - } else - mpi_bcast_lbboundary(c_num); + mpi_bcast_lbboundary(c_num); status = TCL_OK; } } @@ -1006,7 +1312,7 @@ int tclcommand_lbboundary(ClientData data, Tcl_Interp *interp, int argc, char ** status = TCL_OK; } else { - Tcl_AppendResult(interp, "possible lbboundary parameters: wall, sphere, cylinder, rhomboid, pore, stomatocyte, delete {c} to delete lbboundary",(char *) NULL); + Tcl_AppendResult(interp, "possible lbboundary parameters: wall, sphere, cylinder, rhomboid, pore, stomatocyte, hollow_cone, delete {c} to delete lbboundary",(char *) NULL); return (TCL_ERROR); } diff --git a/src/tcl/lb-boundaries_tcl.hpp b/src/tcl/lb-boundaries_tcl.hpp new file mode 100644 index 00000000000..f1602f94b8f --- /dev/null +++ b/src/tcl/lb-boundaries_tcl.hpp @@ -0,0 +1,45 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _LBBOUNDARIES_TCL_H +#define _LBBOUNDARIES_TCL_H + +#include "parser.hpp" +#include "lb-boundaries.hpp" + + +#if defined (LB_BOUNDARIES) || defined (LB_BOUNDARIES_GPU) + +// TCL Parser functions +LB_Boundary *generate_lbboundary(); +int tclcommand_lbboundary(ClientData _data, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_wall(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_sphere(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_cylinder(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_rhomboid(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_pore(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_stomatocyte(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_hollow_cone(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_lbboundary_box(LB_Boundary *lbb, Tcl_Interp *interp, int argc, char **argv); +int tclcommand_printLbBoundaryToResult(Tcl_Interp *interp, int i); + +#endif /* LB_BOUNDARIES || LB_BOUNDARIES_GPU */ + +#endif /* _LBBOUNDARIES_TCL_H */ diff --git a/src/tcl/lb_tcl.cpp b/src/tcl/lb_tcl.cpp index a9aa512e369..933baae96cc 100644 --- a/src/tcl/lb_tcl.cpp +++ b/src/tcl/lb_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,47 +18,107 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file lb_tcl.c +/** \file lb_tcl.cpp * * TCL Interface for the Lattice Boltzmann algorithm for hydrodynamic degrees of freedom. * */ + #include "thermostat.hpp" #include "lb_tcl.hpp" #include "lb.hpp" #include "lbgpu.hpp" #include "parser.hpp" +#include "electrokinetics.hpp" #ifdef LB_GPU -static int lbnode_parse_set(Tcl_Interp *interp, int argc, char **argv, int *ind) { + +#ifdef SHANCHEN +int tclprint_to_result_affinityIA(Tcl_Interp *interp, int i, int j) +{ + char buffer[TCL_DOUBLE_SPACE]; + IA_parameters *data = get_ia_param(i, j); + + Tcl_PrintDouble(interp, data->affinity[0], buffer); + Tcl_AppendResult(interp, "affinity ", buffer, " ", (char *) NULL); + + for(int ii=1;iiaffinity[ii], buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + } + + return TCL_OK; +} + +int tclcommand_inter_parse_affinity(Tcl_Interp * interp,int part_type_a,int part_type_b, int argc, char ** argv) +{ + double affinity[LB_COMPONENTS]; + + if (argc != LB_COMPONENTS+1 ) + { + Tcl_AppendResult(interp, "Not enough values for affinity", (char *) NULL); + return 0; + } + + for (int ii=0;ii 0) { - if(ARG0_IS_S("force")){ - if (argc < 4 || - !ARG_IS_D(1, f[0]) || - !ARG_IS_D(2, f[1]) || - !ARG_IS_D(3, f[2]) - ) { - Tcl_AppendResult(interp, "force expects three doubles as argument", (char *)NULL); - return TCL_ERROR; + while (argc > 0) + { + if(ARG0_IS_S_EXACT("force")) + { + if ( argc < 4 || + !ARG_IS_D(1, f[0]) || + !ARG_IS_D(2, f[1]) || + !ARG_IS_D(3, f[2]) + ) + { + Tcl_AppendResult(interp, "force expects three doubles as argument", (char *)NULL); + return TCL_ERROR; } + argc -= 4; argv += 4; - if (argc > 0) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "Error in lbnode_extforce force. You can only change one field at the same time.", (char *)NULL); - return ES_ERROR; + + if (argc > 0) + { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "Error in lbnode_extforce force. You can only change one field at the same time.", (char *)NULL); + return ES_ERROR; } } - else { + else + { Tcl_AppendResult(interp, "unknown parameter \"", argv[0], "\" to set", (char *)NULL); return TCL_ERROR; } } - if (lb_lbnode_set_extforce_GPU(ind, f) == ES_ERROR) { + if (lb_lbnode_set_extforce_GPU(ind, f) == ES_ERROR) + { Tcl_AppendResult(interp, "position is not in the LB lattice", (char *)NULL); return TCL_ERROR; } @@ -75,36 +135,46 @@ int tclcommand_lbnode_extforce_gpu(ClientData data, Tcl_Interp *interp, int argc --argc; ++argv; - if (argc < 3) { + if (argc < 3) + { Tcl_AppendResult(interp, "too few arguments for lbnode_extforce", (char *)NULL); return ES_ERROR; } - if (!ARG_IS_I(0,coord[0]) || !ARG_IS_I(1,coord[1]) || !ARG_IS_I(2,coord[2])) { + if (!ARG_IS_I(0,coord[0]) || !ARG_IS_I(1,coord[1]) || !ARG_IS_I(2,coord[2])) + { Tcl_AppendResult(interp, "wrong arguments for lbnode", (char *)NULL); return ES_ERROR; } argc-=3; argv+=3; - if (argc == 0 ) { + if (argc == 0 ) + { Tcl_AppendResult(interp, "lbnode_extforce syntax: lbnode_extforce X Y Z [ print | set ] [ F(X) | F(Y) | F(Z) ]", (char *)NULL); return ES_ERROR; } - if (ARG0_IS_S("set")) + if (ARG0_IS_S_EXACT("set")) + { err = lbnode_parse_set(interp, argc-1, argv+1, coord); - else { + } + else + { Tcl_AppendResult(interp, "unknown feature \"", argv[0], "\" of lbnode_extforce", (char *)NULL); return ES_ERROR; - } + } + return err; } -#endif/* LB_GPU */ +#endif /* LB_GPU */ #if defined (LB) || defined (LB_GPU) + /* ********************* TCL Interface part *************************************/ /* ******************************************************************************/ -void lbfluid_tcl_print_usage(Tcl_Interp *interp) { + +void lbfluid_tcl_print_usage(Tcl_Interp *interp) +{ Tcl_AppendResult(interp, "Usage of \"lbfluid\":\n", (char *)NULL); Tcl_AppendResult(interp, "lbfluid [ agrid #float ] [ dens #float ] [ visc #float ] [ tau #tau ]\n", (char *)NULL); #ifdef SHANCHEN @@ -116,27 +186,42 @@ void lbfluid_tcl_print_usage(Tcl_Interp *interp) { Tcl_AppendResult(interp, " [ coupling #float ]\n", (char *)NULL); #endif } -void lbnode_tcl_print_usage(Tcl_Interp *interp) { + +void lbnode_tcl_print_usage(Tcl_Interp *interp) +{ Tcl_AppendResult(interp, "lbnode syntax:\n", (char *)NULL); Tcl_AppendResult(interp, "lbnode X Y Z print [ rho | u | pi | pi_neq | boundary | populations ]\n", (char *)NULL); Tcl_AppendResult(interp, " or\n", (char *)NULL); Tcl_AppendResult(interp, "lbnode X Y Z set [ rho | u | populations ] #nofloats", (char *)NULL); } -#endif + +#endif /* LB || LB_GPU */ #if defined (LB) || defined (LB_GPU) int tclcommand_lbfluid_print_interpolated_velocity(Tcl_Interp *interp, int argc, char **argv); #endif /** TCL Interface: The \ref lbfluid command. */ -int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **argv) { +int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **argv) +{ + +#ifdef ELECTROKINETICS + if ( ek_initialized ) + { + Tcl_AppendResult(interp, "ERROR: Electrokinetics automatically intializes the LB on the GPU and can therefore not be used in conjunction with LB.\n"); + Tcl_AppendResult(interp, "ERROR: Please run either electrokinetics or LB.\n"); + + return TCL_ERROR; + } +#endif #if defined (LB) || defined (LB_GPU) argc--; argv++; - + /**if we have LB the LB cpu is set by default */ #ifdef LB - if(!(lattice_switch & LATTICE_LB_GPU)) lattice_switch = lattice_switch | LATTICE_LB; + if( !(lattice_switch & LATTICE_LB_GPU) ) + lattice_switch = lattice_switch | LATTICE_LB; #else lattice_switch = lattice_switch | LATTICE_LB_GPU; #endif @@ -145,21 +230,27 @@ int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **arg double floatarg; double vectarg[3+LB_COMPONENTS + (LB_COMPONENTS*(LB_COMPONENTS-1))/2]; - if (argc < 1) { + if (argc < 1) + { lbfluid_tcl_print_usage(interp); return TCL_ERROR; } - else if (ARG0_IS_S("off")) { + else if (ARG0_IS_S_EXACT("off")) + { lbfluid_tcl_print_usage(interp); return TCL_ERROR; } - else if (ARG0_IS_S("init")) { + else if (ARG0_IS_S_EXACT("init")) + { lbfluid_tcl_print_usage(interp); return TCL_ERROR; } else - while (argc > 0) { - if (ARG0_IS_S("gpu") || ARG0_IS_S("GPU")) { + { + while (argc > 0) + { + if (ARG0_IS_S_EXACT("gpu") || ARG0_IS_S_EXACT("GPU")) + { #ifdef LB_GPU lattice_switch = (lattice_switch &~ LATTICE_LB) | LATTICE_LB_GPU; argc--; argv++; @@ -168,7 +259,8 @@ int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **arg return TCL_ERROR; #endif } - else if (ARG0_IS_S("cpu") || ARG0_IS_S("CPU")) { + else if (ARG0_IS_S_EXACT("cpu") || ARG0_IS_S_EXACT("CPU")) + { #ifdef LB lattice_switch = (lattice_switch & ~LATTICE_LB_GPU) | LATTICE_LB; argc--; argv++; @@ -177,357 +269,581 @@ int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **arg return TCL_ERROR; #endif } - else if (ARG0_IS_S("grid") || ARG0_IS_S("agrid")) { - if ( argc < 2 || !ARG1_IS_D(floatarg) ) { - Tcl_AppendResult(interp, "agrid requires 1 argument", (char *)NULL); + else if ( ARG0_IS_S_EXACT("grid") || ARG0_IS_S_EXACT("agrid") ) + { + if ( argc < 2 || !ARG1_IS_D(floatarg) ) + { + Tcl_AppendResult(interp, "agrid requires 1 argument", (char *)NULL); return TCL_ERROR; - } else if (floatarg <= 0) { - Tcl_AppendResult(interp, "agrid must be positive", (char *)NULL); + } + else if (floatarg <= 0) + { + Tcl_AppendResult(interp, "agrid must be positive", (char *)NULL); return TCL_ERROR; - } else if (0) { - // agrid is not compatible with box_l; - // Not necessary because this is caught on the mpi level! - } else { - if ( lb_lbfluid_set_agrid(floatarg) == 0 ) { + } + else + { + if ( lb_lbfluid_set_agrid(floatarg) == 0 ) + { argc-=2; argv+=2; - } else { - Tcl_AppendResult(interp, "Unknown Error setting agrid", (char *)NULL); + } + else + { + Tcl_AppendResult(interp, "Unknown Error setting agrid", (char *)NULL); return TCL_ERROR; } } } - else if (ARG0_IS_S("tau")) { - if ( argc < 2 || !ARG1_IS_D(floatarg) ) { - Tcl_AppendResult(interp, "tau requires 1 argument", (char *)NULL); + else if (ARG0_IS_S_EXACT("tau")) + { + if ( argc < 2 || !ARG1_IS_D(floatarg) ) + { + Tcl_AppendResult(interp, "tau requires 1 argument", (char *)NULL); return TCL_ERROR; - } else if (floatarg <= 0) { - Tcl_AppendResult(interp, "tau must be positive", (char *)NULL); + } + else if (floatarg <= 0) + { + Tcl_AppendResult(interp, "tau must be positive", (char *)NULL); return TCL_ERROR; - } else if (floatarg < time_step ) { - Tcl_AppendResult(interp, "tau must larger than the MD time step", (char *)NULL); + } + else if (floatarg < time_step ) + { + Tcl_AppendResult(interp, "tau must larger than the MD time step", (char *)NULL); return TCL_ERROR; - } else { - if ( lb_lbfluid_set_tau(floatarg) == 0 ) { + } + else + { + if ( lb_lbfluid_set_tau(floatarg) == 0 ) + { argc-=2; argv+=2; - } else { - Tcl_AppendResult(interp, "Unknown Error setting tau", (char *)NULL); + } + else + { + Tcl_AppendResult(interp, "Unknown Error setting tau", (char *)NULL); return TCL_ERROR; } } } #ifdef SHANCHEN - else if (ARG0_IS_S("sc_coupling") ) { + else if (ARG0_IS_S_EXACT("sc_coupling") ) + { /* when SHANCHEN==1 we allow liquid/gas phase transitions and require a second parameter (rho_0) besides the coupling */ - int nargs=( (LB_COMPONENTS==1) ? 2 : (LB_COMPONENTS*(LB_COMPONENTS+1))/2) ; - if ( argc < 1+nargs ) { - char str[1024]; - sprintf(str,"sc_coupling requires %d arguments",nargs); - Tcl_AppendResult(interp, str, (char *)NULL); - return TCL_ERROR; - } else { - int i; - for(i=0;i= 1){ - Tcl_AppendResult(interp, "gamma_odd must be < 1", (char *)NULL); - return TCL_ERROR; - } - } // for - if ( lb_lbfluid_set_gamma_odd(vectarg) == 0 ) { - argc-=(1+LB_COMPONENTS); argv+=(1+LB_COMPONENTS) ; - } else { - Tcl_AppendResult(interp, "Unknown Error setting gamma_odd", (char *)NULL); - return TCL_ERROR; - } - } - } - else if (ARG0_IS_S("gamma_even") ) { - if ( argc < (LB_COMPONENTS+1) ){ - Tcl_AppendResult(interp, "gamma_even requires arguments", (char *)NULL); // TODO: fix this and similar ones... + } + else + { + if ( ARG1_IS_S_EXACT("2pt") || ARG1_IS_S_EXACT("2PT") || ARG1_IS_S_EXACT("2Pt") ) + { + lb_lbfluid_set_couple_flag (LB_COUPLE_TWO_POINT); + } + else if ( ARG1_IS_S_EXACT("3pt") || ARG1_IS_S_EXACT("3PT") || ARG1_IS_S_EXACT("3Pt") ) + { + lb_lbfluid_set_couple_flag (LB_COUPLE_THREE_POINT); + } + else + { + Tcl_AppendResult(interp, "Did not understand argument to couple, please send 2pt or 3pt.", (char *)NULL); + return TCL_ERROR; + } + + argc-=2; argv+=2; + } + } + else if (ARG0_IS_S_EXACT("gamma_odd") ) + { + if ( argc < (LB_COMPONENTS+1) ) + { + Tcl_AppendResult(interp, "gamma_odd requires arguments", (char *)NULL); // TODO: fix this and similar ones... return TCL_ERROR; - } else { - int i; - for(i=0;i= 1){ - Tcl_AppendResult(interp, "gamma_even must be < 1 ", (char *)NULL); - return TCL_ERROR; - } - } // for - if ( lb_lbfluid_set_bulk_visc(vectarg) == 0 ) { - argc-=(1+LB_COMPONENTS); argv+=(1+LB_COMPONENTS) ; - } else { - Tcl_AppendResult(interp, "Unknown Error setting dens", (char *)NULL); - return TCL_ERROR; - } + } + else + { + int i; + + for(i=0;i= 1) + { + Tcl_AppendResult(interp, "gamma_odd must be < 1", (char *)NULL); + return TCL_ERROR; + } + } + + if ( lb_lbfluid_set_gamma_odd(vectarg) == 0 ) + { + argc-=(1+LB_COMPONENTS); argv+=(1+LB_COMPONENTS); + } + else + { + Tcl_AppendResult(interp, "Unknown Error setting gamma_odd", (char *)NULL); + return TCL_ERROR; + } } } + else if (ARG0_IS_S_EXACT("gamma_even") ) + { + if ( argc < (LB_COMPONENTS+1) ) + { + Tcl_AppendResult(interp, "gamma_even requires arguments", (char *)NULL); // TODO: fix this and similar ones... + return TCL_ERROR; + } + else + { + int i; + for(i=0;i= 1) + { + Tcl_AppendResult(interp, "gamma_even must be < 1 ", (char *)NULL); + return TCL_ERROR; + } + } - else if (ARG0_IS_S("ext_force")) { + if ( lb_lbfluid_set_bulk_visc(vectarg) == 0 ) + { + argc-=(1+LB_COMPONENTS); argv+=(1+LB_COMPONENTS); + } + else + { + Tcl_AppendResult(interp, "Unknown Error setting dens", (char *)NULL); + return TCL_ERROR; + } + } + } + else if (ARG0_IS_S_EXACT("ext_force")) + { #ifdef EXTERNAL_FORCES - if ( argc < 4 || !ARG_IS_D(1, vectarg[0]) || !ARG_IS_D(2, vectarg[1]) || !ARG_IS_D(3, vectarg[2]) ) { - Tcl_AppendResult(interp, "friction requires 1 argument", (char *)NULL); - return TCL_ERROR; - } else if (lb_lbfluid_set_ext_force(vectarg[0], vectarg[1], vectarg[2]) == 0) { - argc-=4; argv+=4; - } else { - Tcl_AppendResult(interp, "Unknown Error setting ext_force", (char *)NULL); - return TCL_ERROR; + int i; + + if ( argc <= 3*LB_COMPONENTS ) + { + Tcl_AppendResult(interp, "ext_force requires 3 arguments per component", (char *)NULL); + return TCL_ERROR; + } + for(i=0;i", (char *)NULL); return TCL_ERROR; - } else { + } + else + { return lb_lbfluid_save_checkpoint(argv[1], 0); } } - else if (ARG0_IS_S("save_binary_checkpoint")) { - if (argc < 2) { + else if (ARG0_IS_S_EXACT("save_binary_checkpoint")) + { + if (argc < 2) + { Tcl_AppendResult(interp, "usage: lbfluid save_binary_checkpoint ", (char *)NULL); return TCL_ERROR; - } else { + } + else + { return lb_lbfluid_save_checkpoint(argv[1], 1); } } - else if (ARG0_IS_S("load_ascii_checkpoint")) { - if (argc < 2) { + else if (ARG0_IS_S_EXACT("load_ascii_checkpoint")) + { + if (argc < 2) + { Tcl_AppendResult(interp, "usage: lbfluid load_ascii_checkpoint ", (char *)NULL); return TCL_ERROR; - } else { + } + else + { return lb_lbfluid_load_checkpoint(argv[1], 0); } } - else if (ARG0_IS_S("load_binary_checkpoint")) { - if (argc < 2) { + else if (ARG0_IS_S_EXACT("load_binary_checkpoint")) + { + if (argc < 2) + { Tcl_AppendResult(interp, "usage: lbfluid load_binary_checkpoint ", (char *)NULL); return TCL_ERROR; - } else { + } + else + { return lb_lbfluid_load_checkpoint(argv[1], 1); } } #if defined(LB) || defined(LB_GPU) - else if (ARG0_IS_S("print_interpolated_velocity")) { //this has to come after print - return tclcommand_lbfluid_print_interpolated_velocity(interp, argc-1, argv+1); - } + else if (ARG0_IS_S_EXACT("print_interpolated_velocity")) + { + //this has to come after print + return tclcommand_lbfluid_print_interpolated_velocity(interp, argc-1, argv+1); + } #endif - else { - Tcl_AppendResult(interp, "unknown feature \"", argv[0],"\" of lbfluid", (char *)NULL); - return TCL_ERROR ; + else + { + Tcl_AppendResult(interp, "unknown feature \"", argv[0],"\" of lbfluid", (char *)NULL); + return TCL_ERROR ; } if ((err = gather_runtime_errors(interp, err)) != TCL_OK) - return TCL_ERROR; - } + return TCL_ERROR; + } /* END OF WHILE LOOP */ + } /* END OF ELSE */ mpi_bcast_parameter(FIELD_LATTICE_SWITCH); @@ -535,7 +851,6 @@ int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **arg thermo_switch = (thermo_switch | THERMO_LB); mpi_bcast_parameter(FIELD_THERMO_SWITCH); - return TCL_OK; #else /* !defined LB */ Tcl_AppendResult(interp, "LB is not compiled in!", NULL); @@ -544,201 +859,300 @@ int tclcommand_lbfluid(ClientData data, Tcl_Interp *interp, int argc, char **arg } /** Parser for the \ref tclcommand_lbnode command. */ -int tclcommand_lbnode(ClientData data, Tcl_Interp *interp, int argc, char **argv) { - +int tclcommand_lbnode(ClientData data, Tcl_Interp *interp, int argc, char **argv) +{ #if defined (LB) || defined (LB_GPU) - int coord[3]; - int counter; - double double_return[19*LB_COMPONENTS]; - char double_buffer[TCL_DOUBLE_SPACE]; + int coord[3]; + int counter; + double double_return[19*LB_COMPONENTS]; + char double_buffer[TCL_DOUBLE_SPACE]; - for (counter = 0; counter < 19; counter++) - double_return[counter]=0; + for (counter = 0; counter < 19; counter++) + double_return[counter]=0; + --argc; ++argv; - --argc; ++argv; - if (lattice_switch & LATTICE_LB_GPU) { - } else { + if (lattice_switch & LATTICE_LB_GPU) + { + // Do nothing + } + else + { #ifdef LB - if (lbfluid[0][0]==0) { - Tcl_AppendResult(interp, "lbnode: lbfluid not correctly initialized", (char *)NULL); - return TCL_ERROR; - } + if (lbfluid[0][0]==0) + { + Tcl_AppendResult(interp, "lbnode: lbfluid not correctly initialized", (char *)NULL); + return TCL_ERROR; + } #endif - } + } - if (argc < 3) { - lbnode_tcl_print_usage(interp); - return TCL_ERROR; - } + if (argc < 3) + { + lbnode_tcl_print_usage(interp); + return TCL_ERROR; + } - if (!ARG_IS_I(0,coord[0]) || !ARG_IS_I(1,coord[1]) || !ARG_IS_I(2,coord[2])) { - Tcl_AppendResult(interp, "Coordinates are not integer.", (char *)NULL); - return TCL_ERROR; - } + if (!ARG_IS_I(0,coord[0]) || !ARG_IS_I(1,coord[1]) || !ARG_IS_I(2,coord[2])) + { + Tcl_AppendResult(interp, "Coordinates are not integer.", (char *)NULL); + return TCL_ERROR; + } - if (lattice_switch & LATTICE_LB_GPU) { + if (lattice_switch & LATTICE_LB_GPU) + { #ifdef LB_GPU - if (coord[0]<0 || coord[0]>(box_l[0])/lbpar_gpu.agrid-1 || coord[1]<0 || coord[1]>(box_l[1])/lbpar_gpu.agrid-1 || coord[2]<0 || coord[2]>(box_l[2])/lbpar_gpu.agrid-1) { - Tcl_AppendResult(interp, "Coordinates do not correspond to a valid LB node index", (char *)NULL); - return TCL_ERROR; + if (coord[0]<0 || coord[0]>(box_l[0])/lbpar_gpu.agrid-1 || coord[1]<0 || coord[1]>(box_l[1])/lbpar_gpu.agrid-1 || coord[2]<0 || coord[2]>(box_l[2])/lbpar_gpu.agrid-1) + { + Tcl_AppendResult(interp, "Coordinates do not correspond to a valid LB node index", (char *)NULL); + return TCL_ERROR; } #endif } - else { + else + { #ifdef LB - if (coord[0]<0 || coord[0]>(box_l[0])/lbpar.agrid-1 || coord[1]<0 || coord[1]>(box_l[1])/lbpar.agrid-1 || coord[2]<0 || coord[2]>(box_l[2])/lbpar.agrid-1) { - Tcl_AppendResult(interp, "Coordinates do not correspond to a valid LB node index", (char *)NULL); - return TCL_ERROR; - } + if (coord[0]<0 || coord[0]>(box_l[0])/lbpar.agrid-1 || coord[1]<0 || coord[1]>(box_l[1])/lbpar.agrid-1 || coord[2]<0 || coord[2]>(box_l[2])/lbpar.agrid-1) + { + Tcl_AppendResult(interp, "Coordinates do not correspond to a valid LB node index", (char *)NULL); + return TCL_ERROR; + } #endif } + argc-=3; + argv+=3; + + if (ARG0_IS_S_EXACT("print")) + { + argc--; + argv++; + + while (argc > 0) + { + if (ARG0_IS_S_EXACT("rho") || ARG0_IS_S_EXACT("density")) + { + lb_lbnode_get_rho(coord, double_return); + + for (counter = 0; counter < LB_COMPONENTS; counter++) + { + Tcl_PrintDouble(interp, double_return[counter], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); + } + + argc--; argv++; + } + else if (ARG0_IS_S_EXACT("u") || ARG0_IS_S_EXACT("v") || ARG0_IS_S_EXACT("velocity")) + { + lb_lbnode_get_u(coord, double_return); + + for (counter = 0; counter < 3; counter++) + { + Tcl_PrintDouble(interp, double_return[counter], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); + } + + argc--; argv++; + } + else if (ARG0_IS_S_EXACT("pi") || ARG0_IS_S_EXACT("pressure")) + { + lb_lbnode_get_pi(coord, double_return); + + for (counter = 0; counter < 6; counter++) + { + Tcl_PrintDouble(interp, double_return[counter], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); + } + + argc--; argv++; + } + else if (ARG0_IS_S_EXACT("pi_neq")) + { + /* this has to come after pi */ + + lb_lbnode_get_pi_neq(coord, double_return); + + for (counter = 0; counter < 6; counter++) + { + Tcl_PrintDouble(interp, double_return[counter], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); + } - argc-=3; argv+=3; - if (ARG0_IS_S("print")) { - argc--; argv++; - while (argc > 0) { - if (ARG0_IS_S("rho") || ARG0_IS_S("density")) { - lb_lbnode_get_rho(coord, double_return); - for (counter = 0; counter < LB_COMPONENTS; counter++) { - Tcl_PrintDouble(interp, double_return[counter], double_buffer); - Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); - } - argc--; argv++; - } - else if (ARG0_IS_S("u") || ARG0_IS_S("v") || ARG0_IS_S("velocity")) { - lb_lbnode_get_u(coord, double_return); - for (counter = 0; counter < 3; counter++) { - Tcl_PrintDouble(interp, double_return[counter], double_buffer); - Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); - } - argc--; argv++; - } + argc--; argv++; + } #ifndef SHANCHEN - else if (ARG0_IS_S("pi") || ARG0_IS_S("pressure")) { - lb_lbnode_get_pi(coord, double_return); - for (counter = 0; counter < 6; counter++) { - Tcl_PrintDouble(interp, double_return[counter], double_buffer); - Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); - } - argc--; argv++; - } - else if (ARG0_IS_S("pi_neq")) { /* this has to come after pi */ - lb_lbnode_get_pi_neq(coord, double_return); - for (counter = 0; counter < 6; counter++) { - Tcl_PrintDouble(interp, double_return[counter], double_buffer); - Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); - } - argc--; argv++; - } - else if (ARG0_IS_S("boundary")) { - char integer_buffer[TCL_INTEGER_SPACE]; - int integer_return = 0; - lb_lbnode_get_boundary(coord, &integer_return); - sprintf(integer_buffer, "%d", integer_return); - Tcl_AppendResult(interp, integer_buffer, " ", (char *)NULL); - argc--; argv++; - } + else if (ARG0_IS_S_EXACT("boundary")) + { + char integer_buffer[TCL_INTEGER_SPACE]; + int integer_return = 0; + + lb_lbnode_get_boundary(coord, &integer_return); + sprintf(integer_buffer, "%d", integer_return); + Tcl_AppendResult(interp, integer_buffer, " ", (char *)NULL); + + argc--; argv++; + } #endif // SHANCHEN - else if (ARG0_IS_S("populations") || ARG0_IS_S("pop")) { - lb_lbnode_get_pop(coord, double_return); - for (counter = 0; counter < 19; counter++) { - Tcl_PrintDouble(interp, double_return[counter], double_buffer); - Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); - } - argc--; argv++; - } - else { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "unknown fluid data \"", argv[0], "\" requested", (char *)NULL); - return TCL_ERROR; - } - } - } - else if (ARG0_IS_S("set")) { - argc--; argv++; - if (ARG0_IS_S("rho") || ARG0_IS_S("density")) { - argc--; argv++; - for (counter = 0; counter < LB_COMPONENTS; counter++) { - if (!ARG0_IS_D(double_return[counter])) { - Tcl_AppendResult(interp, "recieved not a double but \"", argv[0], "\" requested", (char *)NULL); - return TCL_ERROR; - } - argc--; argv++; - } - //SAW TODO: clean code/naming, there is ambiguity with lbfluid_set_dens - if (lb_lbnode_set_rho(coord, double_return) != 0) { - Tcl_AppendResult(interp, "General Error on lbnode set rho.", (char *)NULL); - return TCL_ERROR; - } - } - else if (ARG0_IS_S("u") || ARG0_IS_S("v") || ARG0_IS_S("velocity")) { - argc--; argv++; - if(argc!=3) { - Tcl_AppendResult(interp, "lbnode set velocity|u|v needs three arguments", (char *)NULL); - return TCL_ERROR; - } - for (counter = 0; counter < 3; counter++) { - if (!ARG0_IS_D(double_return[counter])) { - Tcl_AppendResult(interp, "received not a double but \"", argv[0], "\" requested", (char *)NULL); - return TCL_ERROR; - } - argc--; argv++; - } - if (lb_lbnode_set_u(coord, double_return) != 0) { - Tcl_AppendResult(interp, "General Error on lbnode set u.", (char *)NULL); - return TCL_ERROR; - } - } - else if (ARG0_IS_S("pop") || ARG0_IS_S("populations") ) { - argc--; argv++; - for (counter = 0; counter < 19; counter++) { - if (!ARG0_IS_D(double_return[counter])) { - Tcl_AppendResult(interp, "recieved not a double but \"", argv[0], "\" requested", (char *)NULL); - return TCL_ERROR; - } - argc--; argv++; - } - if (lb_lbnode_set_pop(coord, double_return) != 0) { - Tcl_AppendResult(interp, "General Error on lbnode set pop.", (char *)NULL); - return TCL_ERROR; - } - } - else { - Tcl_AppendResult(interp, "unknown feature \"", argv[0], "\" of lbnode x y z set", (char *)NULL); - return TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "unknown feature \"", argv[0], "\" of lbnode", (char *)NULL); - return TCL_ERROR; - } - - return TCL_OK; + else if (ARG0_IS_S_EXACT("populations") || ARG0_IS_S_EXACT("pop")) + { + lb_lbnode_get_pop(coord, double_return); + + for (counter = 0; counter < 19; counter++) + { + Tcl_PrintDouble(interp, double_return[counter], double_buffer); + Tcl_AppendResult(interp, double_buffer, " ", (char *)NULL); + } + + argc--; argv++; + } + else + { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "unknown fluid data \"", argv[0], "\" requested", (char *)NULL); + + return TCL_ERROR; + } + } + } + else if (ARG0_IS_S_EXACT("set")) + { + argc--; + argv++; + + if (ARG0_IS_S_EXACT("rho") || ARG0_IS_S_EXACT("density")) + { + argc--; argv++; + + if (argc!=LB_COMPONENTS) + { + char integer_buffer[TCL_INTEGER_SPACE]; + + sprintf(integer_buffer, "%d", LB_COMPONENTS); + Tcl_AppendResult(interp, "LB node set density requires ", integer_buffer, " double(s).", (char *)NULL); + + return TCL_ERROR; + } + + for (counter = 0; counter < LB_COMPONENTS; counter++) + { + if (!ARG0_IS_D(double_return[counter])) + { + Tcl_AppendResult(interp, "received not a double but \"", argv[0], "\" requested", (char *)NULL); + return TCL_ERROR; + } + + argc--; argv++; + } + + //SAW TODO: clean code/naming, there is ambiguity with lbfluid_set_dens + if (lb_lbnode_set_rho(coord, double_return) != 0) + { + Tcl_AppendResult(interp, "General Error on lbnode set rho.", (char *)NULL); + return TCL_ERROR; + } + } + else if (ARG0_IS_S_EXACT("u") || ARG0_IS_S_EXACT("v") || ARG0_IS_S_EXACT("velocity")) + { + argc--; argv++; + + if(argc!=3) + { + Tcl_AppendResult(interp, "lbnode set velocity|u|v needs three arguments (vx vy vz)", (char *)NULL); + return TCL_ERROR; + } + + for (counter = 0; counter < 3; counter++) + { + if (!ARG0_IS_D(double_return[counter])) + { + Tcl_AppendResult(interp, "received not a double but \"", argv[0], "\" requested", (char *)NULL); + return TCL_ERROR; + } + + argc--; argv++; + } + + if (lb_lbnode_set_u(coord, double_return) != 0) + { + Tcl_AppendResult(interp, "General Error on lbnode set u.", (char *)NULL); + return TCL_ERROR; + } + } + else if (ARG0_IS_S_EXACT("pop") || ARG0_IS_S_EXACT("populations") ) + { + argc--; argv++; + + if (argc!=19) + { + Tcl_AppendResult(interp, "LB node set populations requires 19 doubles.", (char *)NULL); + return TCL_ERROR; + } + + for (counter = 0; counter < 19; counter++) + { + if (!ARG0_IS_D(double_return[counter])) + { + Tcl_AppendResult(interp, "received not a double but \"", argv[0], "\" requested", (char *)NULL); + return TCL_ERROR; + } + + argc--; argv++; + } + + if (lb_lbnode_set_pop(coord, double_return) != 0) + { + Tcl_AppendResult(interp, "General Error on lbnode set pop.", (char *)NULL); + return TCL_ERROR; + } + } + else + { + Tcl_AppendResult(interp, "unknown feature \"", argv[0], "\" of lbnode x y z set", (char *)NULL); + return TCL_ERROR; + } + } + else + { + Tcl_AppendResult(interp, "unknown feature \"", argv[0], "\" of lbnode", (char *)NULL); + return TCL_ERROR; + } + + return TCL_OK; + #else /* !defined LB */ Tcl_AppendResult(interp, "LB is not compiled in!", NULL); return TCL_ERROR; #endif } -int tclcommand_lbfluid_print_interpolated_velocity(Tcl_Interp *interp, int argc, char **argv) { +int tclcommand_lbfluid_print_interpolated_velocity(Tcl_Interp *interp, int argc, char **argv) +{ #if defined (LB) || defined (LB_GPU) double p[3], v[3]; char buffer[3*TCL_DOUBLE_SPACE+3]; - if (argc!=3) { + + if (argc!=3) + { printf("usage: print_interpolated_velocity $x $y $z"); return TCL_ERROR; } - for (int i = 0; i < 3; i++) { + + for (int i = 0; i < 3; i++) + { if (!ARG_IS_D(i, p[i])) printf("usage: print_interpolated_velocity $x $y $z"); } + lb_lbfluid_get_interpolated_velocity_global(p, v); - for (int i = 0; i < 3; i++) { + + for (int i = 0; i < 3; i++) + { Tcl_PrintDouble(interp, v[i], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); } + return TCL_OK; + #else Tcl_AppendResult(interp, "LB is not compiled in!", NULL); return TCL_ERROR; diff --git a/src/tcl/lb_tcl.hpp b/src/tcl/lb_tcl.hpp index 3581f71d535..21b1ea53b87 100644 --- a/src/tcl/lb_tcl.hpp +++ b/src/tcl/lb_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -32,7 +32,18 @@ int tclcommand_lbfluid_print_interpolated_velocity(Tcl_Interp *interp, int argc, int tclcommand_lbnode_extforce_gpu(ClientData data, Tcl_Interp *interp, int argc, char **argv); -/** lb boundary command. From \ref lb-boundaries_tcl.c */ +int tclcommand_inter_parse_affinity(Tcl_Interp * interp, int part_type_a, int part_type_b, int argc, char ** argv); + + +/** lb boundary command. From \ref lb-boundaries_tcl.cpp */ extern int tclcommand_lbboundary(ClientData _data, Tcl_Interp *interp, int argc, char **argv); +extern int affinity_set_params(int part_type_a, int part_type_b, double * affinity); + +#ifdef SHANCHEN +int tclprint_to_result_affinityIA(Tcl_Interp *interp, int i, int j); +#endif + + +extern int ek_initialized; #endif /* LB_TCL_H */ diff --git a/src/tcl/lees_edwards_tcl.cpp b/src/tcl/lees_edwards_tcl.cpp new file mode 100644 index 00000000000..8fded2d22c6 --- /dev/null +++ b/src/tcl/lees_edwards_tcl.cpp @@ -0,0 +1,64 @@ +/* + Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file lees_edwards_tcl.cpp TCL interface for setting the Lees Edwards PBC shear rate. + * + * For more information on LE-PBCs + * see \ref lees_edwards.hpp "less_edwards.hpp". +*/ +#include "utils.hpp" +#include "parser.hpp" +#include "communication.hpp" +#include "global.hpp" +#include "lees_edwards.hpp" + +int tclcommand_lees_edwards_offset(ClientData data, Tcl_Interp *interp, int argc, char **argv) +{ + /* check usage */ +#ifndef LEES_EDWARDS + Tcl_AppendResult(interp, "ERROR: Requested a feature which was not compiled in, please reconfigure and recompile with LEES_EDWARDS defined.", (char *)NULL); + return (TCL_ERROR); +#else + + char buffer[120 + TCL_DOUBLE_SPACE]; + double new_offset; + + + if (argc < 1 || argc > 2) { + Tcl_AppendResult(interp, "Wrong # of args! Usage: lees_edwards_offset { new_offset }", (char *)NULL); return (TCL_ERROR); + } + + /* return the old value, whether we have set a new one or not */ + sprintf(buffer, "%f ", lees_edwards_offset); + + /* set the new value if requested */ + if (argc == 2 ){ + if (Tcl_GetDouble(interp, argv[1], &new_offset) == TCL_ERROR) return (TCL_ERROR); + lees_edwards_offset = new_offset; + mpi_bcast_parameter(FIELD_LEES_EDWARDS_OFFSET); + } + Tcl_AppendResult(interp, buffer, (char *)NULL); + + return gather_runtime_errors(interp, TCL_OK); +#endif +} + + + diff --git a/src/tcl/lees_edwards_tcl.hpp b/src/tcl/lees_edwards_tcl.hpp new file mode 100644 index 00000000000..656bfd5c90a --- /dev/null +++ b/src/tcl/lees_edwards_tcl.hpp @@ -0,0 +1,35 @@ +/* + Copyright (C) 2010,2011,2012 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _LEES_EDWARDS_TCL_H +#define _LEES_EDWARDS_TCL_H +#include "parser.hpp" + +/** \name Exported Functions */ +/************************************************************/ +/*@{*/ + +/** return data for \ref #lees_edwards. Get or set current PBC image offset. */ +int tclcommand_lees_edwards_offset(ClientData data, Tcl_Interp *interp, int argc, char **argv); + + +/*@}*/ + +#endif diff --git a/src/tcl/lj_tcl.cpp b/src/tcl/lj_tcl.cpp index 69f63c285ab..9952dc6362a 100644 --- a/src/tcl/lj_tcl.cpp +++ b/src/tcl/lj_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -68,12 +68,17 @@ int tclcommand_inter_parse_ljforcecap(Tcl_Interp * interp, int argc, char ** arg return tclcommand_inter_parse_forcecap(interp, argc, argv); } + + int tclcommand_inter_parse_lj(Tcl_Interp * interp, int part_type_a, int part_type_b, int argc, char ** argv) { /* parameters needed for LJ */ double eps, sig, cut, shift, offset, cap_radius, min; +#ifdef SHANCHEN + double *affinity=NULL; +#endif int compute_auto_shift, change; /* get lennard-jones interaction type */ diff --git a/src/tcl/lj_tcl.hpp b/src/tcl/lj_tcl.hpp index b65bd6fed1a..92d9a88753a 100644 --- a/src/tcl/lj_tcl.hpp +++ b/src/tcl/lj_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/ljangle_tcl.cpp b/src/tcl/ljangle_tcl.cpp index 59f9d664343..408c76036a5 100644 --- a/src/tcl/ljangle_tcl.cpp +++ b/src/tcl/ljangle_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file ljangle.h +/** \file ljangle.hpp * Routines to calculate the lennard-jones 12-10 with angular dependance. * The potential is a product of a 12-10 LJ potential with two cos^2. * The potential actually relies on 6 particles: the 2 primary beads @@ -34,7 +34,7 @@ * interaction strength in this medium. The interaction strengh of the second * environment must be *stronger* than of the first one. * - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" @@ -60,26 +60,29 @@ int tclprint_to_result_ljangleIA(Tcl_Interp *interp, int i, int j) Tcl_PrintDouble(interp, data->LJANGLE_cut, buffer); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); // Who are the bonded partners? - Tcl_PrintDouble(interp, data->LJANGLE_bonded1pos, buffer); + sprintf(buffer,"%d ",data->LJANGLE_bonded1pos); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_bonded1neg, buffer); + sprintf(buffer,"%d ",data->LJANGLE_bonded1neg); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_bonded2pos, buffer); + sprintf(buffer,"%d ",data->LJANGLE_bonded2pos); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_bonded2neg, buffer); + sprintf(buffer,"%d ",data->LJANGLE_bonded2neg); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); // Optional argument: cap radius Tcl_PrintDouble(interp, data->LJANGLE_capradius, buffer); Tcl_AppendResult(interp, buffer, " ", (char *) NULL); // Optional arguments: simulate two different interaction strengths - Tcl_PrintDouble(interp, data->LJANGLE_z0, buffer); - Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_dz, buffer); - Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_kappa, buffer); - Tcl_AppendResult(interp, buffer, " ", (char *) NULL); - Tcl_PrintDouble(interp, data->LJANGLE_epsprime, buffer); - Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + if ( data->LJANGLE_dz > 0 ) { + /* LJANGLE_dz is set to -1 by default if no optional parameter is set. */ + Tcl_PrintDouble(interp, data->LJANGLE_z0, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, data->LJANGLE_dz, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, data->LJANGLE_kappa, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, data->LJANGLE_epsprime, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *) NULL); + } return TCL_OK; diff --git a/src/tcl/ljangle_tcl.hpp b/src/tcl/ljangle_tcl.hpp index 786728b8bf7..3d5aebdc83c 100644 --- a/src/tcl/ljangle_tcl.hpp +++ b/src/tcl/ljangle_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/ljcos2_tcl.cpp b/src/tcl/ljcos2_tcl.cpp index 7e4632d67db..03bfd6b0f04 100644 --- a/src/tcl/ljcos2_tcl.cpp +++ b/src/tcl/ljcos2_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,11 +19,11 @@ along with this program. If not, see . */ -/** \file ljcos2.h +/** \file ljcos2.hpp * Routines to calculate the lennard-jones with cosine tail energy and/or force - * for a particle pair. Cosine tail is different from that in ljcos.h + * for a particle pair. Cosine tail is different from that in ljcos.hpp * Used for attractive tail/tail interactions in lipid bilayer calculations - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/tcl/ljcos2_tcl.hpp b/src/tcl/ljcos2_tcl.hpp index cd556a2b450..28a5bba459b 100644 --- a/src/tcl/ljcos2_tcl.hpp +++ b/src/tcl/ljcos2_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/ljcos_tcl.cpp b/src/tcl/ljcos_tcl.cpp index 7db46fed817..5f254d1c3cc 100644 --- a/src/tcl/ljcos_tcl.cpp +++ b/src/tcl/ljcos_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/ljcos_tcl.hpp b/src/tcl/ljcos_tcl.hpp index b79d695ec68..89a09a91da6 100644 --- a/src/tcl/ljcos_tcl.hpp +++ b/src/tcl/ljcos_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/ljgen_tcl.cpp b/src/tcl/ljgen_tcl.cpp index 4b7828fcace..87bb5c19180 100644 --- a/src/tcl/ljgen_tcl.cpp +++ b/src/tcl/ljgen_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,13 +19,13 @@ along with this program. If not, see . */ -/** \file ljgen.c Routines to calculate the generalized lennard jones +/** \file ljgen.cpp Routines to calculate the generalized lennard jones * energy and/or force for a particle pair. "Generalized" here means * that the LJ energy is of the form * * eps * [ b1 * (sigma/(r-r_offset))^a1 - b2 * (sigma/(r-r_offset))^a2 + shift] * - * \ref forces.c + * \ref forces.cpp */ #include "config.hpp" diff --git a/src/tcl/ljgen_tcl.hpp b/src/tcl/ljgen_tcl.hpp index 0d262b22d19..e6f8e989584 100644 --- a/src/tcl/ljgen_tcl.hpp +++ b/src/tcl/ljgen_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/maggs_tcl.cpp b/src/tcl/maggs_tcl.cpp index 1fed8e6d732..581307f6eee 100644 --- a/src/tcl/maggs_tcl.cpp +++ b/src/tcl/maggs_tcl.cpp @@ -1,6 +1,6 @@ /* Copyright (C) 2010,2011 Florian Fahrenberger - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ along with this program. If not, see . */ -/** \file maggs.c +/** \file maggs.cpp * Maxwell Equations Molecular Dynamics (MEMD) method for electrostatic * interactions. * diff --git a/src/tcl/maggs_tcl.hpp b/src/tcl/maggs_tcl.hpp index 5e67a9edb2a..609b722bca1 100644 --- a/src/tcl/maggs_tcl.hpp +++ b/src/tcl/maggs_tcl.hpp @@ -1,6 +1,6 @@ /* Copyright (C) 2010,2011 Florian Fahrenberger - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -20,7 +20,7 @@ along with this program. If not, see . */ -/** \file maggs.h +/** \file maggs.hpp * Maxwell Equations Molecular Dynamics (MEMD) method for electrostatic * interactions. * diff --git a/src/tcl/magnetic_non_p3m_methods_tcl.cpp b/src/tcl/magnetic_non_p3m_methods_tcl.cpp index bed463b0af4..3ca915b3ffd 100644 --- a/src/tcl/magnetic_non_p3m_methods_tcl.cpp +++ b/src/tcl/magnetic_non_p3m_methods_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file magnetic_non_p3m_methods.c All 3d non P3M methods to deal with the magnetic dipoles +/** \file magnetic_non_p3m_methods.cpp All 3d non P3M methods to deal with the magnetic dipoles * * DAWAANR => DIPOLAR_ALL_WITH_ALL_AND_NO_REPLICA * Handling of a system of dipoles where no replicas diff --git a/src/tcl/magnetic_non_p3m_methods_tcl.hpp b/src/tcl/magnetic_non_p3m_methods_tcl.hpp index c96b670a9f7..509dd0f7cc7 100644 --- a/src/tcl/magnetic_non_p3m_methods_tcl.hpp +++ b/src/tcl/magnetic_non_p3m_methods_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/main.cpp b/src/tcl/main.cpp index f87b59c570b..0f73288bd53 100644 --- a/src/tcl/main.cpp +++ b/src/tcl/main.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,21 +18,18 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file main.c +/** \file main.cpp Main file of Espresso. Initialization of tcl interpreter. */ /* first, since we need the TK define */ #include "utils.hpp" -#include #ifdef TK #include #endif +#include "initialize_interpreter.hpp" #include "initialize.hpp" #include "communication.hpp" -// forward from initialize_interpreter.c -int appinit(Tcl_Interp *interp); - int main(int argc, char **argv) { /* first thing to do: fire up MPI */ @@ -43,9 +40,9 @@ int main(int argc, char **argv) if (this_node == 0) { /* master node */ #ifdef TK - Tk_Main(argc, argv, appinit); + Tk_Main(argc, argv, tcl_appinit); #else - Tcl_Main(argc, argv, appinit); + Tcl_Main(argc, argv, tcl_appinit); #endif } else { diff --git a/src/tcl/mdlc_correction_tcl.cpp b/src/tcl/mdlc_correction_tcl.cpp index deeb4f4c98f..8685bbc6575 100644 --- a/src/tcl/mdlc_correction_tcl.cpp +++ b/src/tcl/mdlc_correction_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mdlc_correction_tcl.c +/** \file mdlc_correction_tcl.cpp * * Implementation of \ref mdlc_correction_tcl.hpp */ diff --git a/src/tcl/mdlc_correction_tcl.hpp b/src/tcl/mdlc_correction_tcl.hpp index a7dfb8365ff..e5af30f6ccf 100644 --- a/src/tcl/mdlc_correction_tcl.hpp +++ b/src/tcl/mdlc_correction_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef MDLC_CORRECTION_TCL_H #define MDLC_CORRECTION_TCL_H /** \file mdlc_correction_tcl.hpp - * Tcl interface for \ref mdlc_correction.h + * Tcl interface for \ref mdlc_correction.hpp */ #include "parser.hpp" diff --git a/src/tcl/metadynamics_tcl.cpp b/src/tcl/metadynamics_tcl.cpp index 249bd8b914c..8122928245e 100644 --- a/src/tcl/metadynamics_tcl.cpp +++ b/src/tcl/metadynamics_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/metadynamics_tcl.hpp b/src/tcl/metadynamics_tcl.hpp index a7e913fdbce..3d8b36b76d2 100644 --- a/src/tcl/metadynamics_tcl.hpp +++ b/src/tcl/metadynamics_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/mmm1d_tcl.cpp b/src/tcl/mmm1d_tcl.cpp index 8e1bbc314e6..1683b31f7a1 100644 --- a/src/tcl/mmm1d_tcl.cpp +++ b/src/tcl/mmm1d_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm1d.c MMM1D algorithm for long range coulomb interaction. +/** \file mmm1d.cpp MMM1D algorithm for long range coulomb interaction. * - * For more information about MMM1D, see \ref mmm1d.h "mmm1d.h". + * For more information about MMM1D, see \ref mmm1d.hpp "mmm1d.h". */ #include @@ -46,8 +46,6 @@ int tclprint_to_result_MMM1D(Tcl_Interp *interp) Tcl_PrintDouble(interp, sqrt(mmm1d_params.far_switch_radius_2), buffer); Tcl_AppendResult(interp, "mmm1d ", buffer, " ",(char *) NULL); - sprintf(buffer, "%d", mmm1d_params.bessel_cutoff); - Tcl_AppendResult(interp, buffer, " ",(char *) NULL); Tcl_PrintDouble(interp, mmm1d_params.maxPWerror, buffer); Tcl_AppendResult(interp, buffer,(char *) NULL); @@ -57,7 +55,6 @@ int tclprint_to_result_MMM1D(Tcl_Interp *interp) int tclcommand_inter_coulomb_parse_mmm1d(Tcl_Interp *interp, int argc, char **argv) { double switch_rad, maxPWerror; - int bessel_cutoff; if (argc < 2) { Tcl_AppendResult(interp, "wrong # arguments: inter coulomb mmm1d " @@ -69,7 +66,6 @@ int tclcommand_inter_coulomb_parse_mmm1d(Tcl_Interp *interp, int argc, char **ar /* autodetermine bessel cutoff AND switching radius */ if (! ARG_IS_D(1, maxPWerror)) return TCL_ERROR; - bessel_cutoff = -1; switch_rad = -1; } else { @@ -78,23 +74,10 @@ int tclcommand_inter_coulomb_parse_mmm1d(Tcl_Interp *interp, int argc, char **ar if ((! ARG_IS_D(0, switch_rad)) || (! ARG_IS_D(1, maxPWerror))) return TCL_ERROR; - bessel_cutoff = -1; - } - else if (argc == 3) { - /* fully manual */ - if((! ARG_IS_D(0, switch_rad)) || - (! ARG_IS_I(1, bessel_cutoff)) || - (! ARG_IS_D(2, maxPWerror))) - return TCL_ERROR; - - if (bessel_cutoff <=0) { - Tcl_AppendResult(interp, "bessel cutoff too small", (char *)NULL); - return TCL_ERROR; - } } else { Tcl_AppendResult(interp, "wrong # arguments: inter coulomb mmm1d " - "{} | tune ", (char *) NULL); + " | tune ", (char *) NULL); return TCL_ERROR; } @@ -104,7 +87,7 @@ int tclcommand_inter_coulomb_parse_mmm1d(Tcl_Interp *interp, int argc, char **ar } } - MMM1D_set_params(switch_rad, bessel_cutoff, maxPWerror); + MMM1D_set_params(switch_rad, maxPWerror); char *log = NULL; int result = mmm1d_tune(&log) == ES_OK ? TCL_OK : TCL_ERROR; diff --git a/src/tcl/mmm1d_tcl.hpp b/src/tcl/mmm1d_tcl.hpp index a2b821bab30..db696e4aa1f 100644 --- a/src/tcl/mmm1d_tcl.hpp +++ b/src/tcl/mmm1d_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm1d.h MMM1D algorithm for long range coulomb interactions. +/** \file mmm1d.hpp MMM1D algorithm for long range coulomb interactions. Implementation of the MMM1D method for the calculation of the electrostatic interaction in one dimensionally periodic systems. For details on the method see MMM in general. The MMM1D diff --git a/src/tcl/mmm2d_tcl.cpp b/src/tcl/mmm2d_tcl.cpp index 402c9dc75b3..6189df7ccb7 100644 --- a/src/tcl/mmm2d_tcl.cpp +++ b/src/tcl/mmm2d_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm2d.c MMM2D algorithm for long range coulomb interaction. +/** \file mmm2d.cpp MMM2D algorithm for long range coulomb interaction. * - * For more information about MMM2D, see \ref mmm2d.h "mmm2d.h". + * For more information about MMM2D, see \ref mmm2d.hpp "mmm2d.h". */ //#include @@ -48,7 +48,11 @@ int tclprint_to_result_MMM2D(Tcl_Interp *interp) Tcl_PrintDouble(interp, mmm2d_params.far_cut, buffer); Tcl_AppendResult(interp, " ", buffer,(char *) NULL); - if (mmm2d_params.dielectric_contrast_on) { + if (mmm2d_params.const_pot_on) { + Tcl_PrintDouble(interp, mmm2d_params.pot_diff, buffer); + Tcl_AppendResult(interp, " capacitor ", buffer, (char *) NULL); + } + else if (mmm2d_params.dielectric_contrast_on) { Tcl_PrintDouble(interp, mmm2d_params.delta_mid_top, buffer); Tcl_AppendResult(interp, " dielectric-contrasts ", buffer, (char *) NULL); Tcl_PrintDouble(interp, mmm2d_params.delta_mid_bot, buffer); @@ -65,10 +69,12 @@ int tclcommand_inter_coulomb_parse_mmm2d(Tcl_Interp * interp, int argc, char ** double far_cut = -1; double top = 1, mid = 1, bot = 1; double delta_top = 0, delta_bot = 0; + double pot_diff = 0; + int const_pot_on = 0; if (argc < 1) { Tcl_AppendResult(interp, "wrong # arguments: inter coulomb mmm2d " - "{} {dielectric } | {dielectric-contrasts }", (char *) NULL); + "{} <{dielectric } | {dielectric-contrasts } | {capacitor }>", (char *) NULL); return TCL_ERROR; } @@ -95,9 +101,17 @@ int tclcommand_inter_coulomb_parse_mmm2d(Tcl_Interp * interp, int argc, char ** else if (argc == 3 && ARG0_IS_S("dielectric-contrasts")) { if (!ARG_IS_D(1,delta_top) || !ARG_IS_D(2,delta_bot)) return TCL_ERROR; - } else { + } + else if (argc == 2 && ARG0_IS_S("capacitor")) { + if (!ARG_IS_D(1,pot_diff)) + return TCL_ERROR; + delta_top = -1; + delta_bot = -1; + const_pot_on = 1; + } + else { Tcl_AppendResult(interp, "wrong # arguments: inter coulomb mmm2d " - "{} {dielectric } | {dielectric-contrasts }", (char *) NULL); + "{} <{dielectric } | {dielectric-contrasts } | {capacitor }>", (char *) NULL); return TCL_ERROR; } } @@ -108,7 +122,7 @@ int tclcommand_inter_coulomb_parse_mmm2d(Tcl_Interp * interp, int argc, char ** return TCL_ERROR; } - if ((err = MMM2D_set_params(maxPWerror, far_cut, delta_top, delta_bot)) > 0) { + if ((err = MMM2D_set_params(maxPWerror, far_cut, delta_top, delta_bot, const_pot_on, pot_diff)) > 0) { Tcl_AppendResult(interp, mmm2d_errors[err], (char *)NULL); return TCL_ERROR; } diff --git a/src/tcl/mmm2d_tcl.hpp b/src/tcl/mmm2d_tcl.hpp index ab3d52febe6..70b3432f7ae 100644 --- a/src/tcl/mmm2d_tcl.hpp +++ b/src/tcl/mmm2d_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mmm2d.h MMM2D algorithm for long range coulomb interaction +/** \file mmm2d.hpp MMM2D algorithm for long range coulomb interaction in 2d+h geometries. Implementation of the MMM2D method for the calculation of the electrostatic interaction for two dimensionally periodic systems. For details on the method see MMM general. The diff --git a/src/tcl/mol_cut_tcl.cpp b/src/tcl/mol_cut_tcl.cpp index f005e9f333c..ef2479e84aa 100644 --- a/src/tcl/mol_cut_tcl.cpp +++ b/src/tcl/mol_cut_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file mol_cut_tcl.c +/** \file mol_cut_tcl.cpp * * Implementation of \ref mol_cut_tcl.hpp */ diff --git a/src/tcl/mol_cut_tcl.hpp b/src/tcl/mol_cut_tcl.hpp index 540b20edd06..6914e08c8ff 100644 --- a/src/tcl/mol_cut_tcl.hpp +++ b/src/tcl/mol_cut_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef MOL_CUT_TCL_H #define MOL_CUT_TCL_H /** \file mol_cut_tcl.hpp - * Tcl interface for \ref mol_cut.h + * Tcl interface for \ref mol_cut.hpp */ #include "parser.hpp" diff --git a/src/tcl/morse_tcl.cpp b/src/tcl/morse_tcl.cpp index f69a6b02e53..7ffc71bc4eb 100644 --- a/src/tcl/morse_tcl.cpp +++ b/src/tcl/morse_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file morse_tcl.c +/** \file morse_tcl.cpp * TCL interface for the Morse potential */ diff --git a/src/tcl/morse_tcl.hpp b/src/tcl/morse_tcl.hpp index a509eda7b55..6cddfbcc90d 100644 --- a/src/tcl/morse_tcl.hpp +++ b/src/tcl/morse_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/nemd_tcl.cpp b/src/tcl/nemd_tcl.cpp index 638769d4ecb..c9f7e6ae91f 100644 --- a/src/tcl/nemd_tcl.cpp +++ b/src/tcl/nemd_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file nemd.c +/** \file nemd.cpp - For more information see \ref nemd.h + For more information see \ref nemd.hpp */ #include "nemd.hpp" #include diff --git a/src/tcl/object-in-fluid/area_force_global_tcl.cpp b/src/tcl/object-in-fluid/area_force_global_tcl.cpp index da5570408d1..27a16a6a918 100644 --- a/src/tcl/object-in-fluid/area_force_global_tcl.cpp +++ b/src/tcl/object-in-fluid/area_force_global_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/** \file area_force_global.h +/** \file area_force_global.hpp * Routines to calculate the AREA_FORCE_GLOBAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/tcl/object-in-fluid/area_force_global_tcl.hpp b/src/tcl/object-in-fluid/area_force_global_tcl.hpp index c4ac0dc07e4..3a1f33b9e49 100644 --- a/src/tcl/object-in-fluid/area_force_global_tcl.hpp +++ b/src/tcl/object-in-fluid/area_force_global_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_AREA_FORCE_GLOBAL_TCL_H #define _OBJECT_IN_FLUID_AREA_FORCE_GLOBAL_TCL_H -/** \file area_force_global.h +/** \file area_force_global.hpp * Routines to calculate the AREA_FORCE_GLOBAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ diff --git a/src/tcl/object-in-fluid/area_force_local_tcl.cpp b/src/tcl/object-in-fluid/area_force_local_tcl.cpp index 1b26d3017fa..896a4bcba51 100644 --- a/src/tcl/object-in-fluid/area_force_local_tcl.cpp +++ b/src/tcl/object-in-fluid/area_force_local_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/** \file area_force_local.h +/** \file area_force_local.hpp * Routines to calculate the AREA_FORCE_LOCAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "utils.hpp" diff --git a/src/tcl/object-in-fluid/area_force_local_tcl.hpp b/src/tcl/object-in-fluid/area_force_local_tcl.hpp index e7e52990050..48cf5cfa7a5 100644 --- a/src/tcl/object-in-fluid/area_force_local_tcl.hpp +++ b/src/tcl/object-in-fluid/area_force_local_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_AREA_FORCE_LOCAL_TCL_H #define _OBJECT_IN_FLUID_AREA_FORCE_LOCAL_TCL_H -/** \file area_force_local.h +/** \file area_force_local.hpp * Routines to calculate the AREA_FORCE_LOCAL energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "tcl/parser.hpp" diff --git a/src/tcl/object-in-fluid/bending_force_tcl.cpp b/src/tcl/object-in-fluid/bending_force_tcl.cpp index 40a5a9f7371..516418745b8 100644 --- a/src/tcl/object-in-fluid/bending_force_tcl.cpp +++ b/src/tcl/object-in-fluid/bending_force_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,7 +17,7 @@ along with this program. If not, see . */ -/** \file bending_force.h Routines to calculate the bending_force energy or/and +/** \file bending_force.hpp Routines to calculate the bending_force energy or/and * and force for a particle quadruple (two triangles that have 2 particles in common) */ diff --git a/src/tcl/object-in-fluid/bending_force_tcl.hpp b/src/tcl/object-in-fluid/bending_force_tcl.hpp index 8bc6ee6a191..d3ff31df44d 100644 --- a/src/tcl/object-in-fluid/bending_force_tcl.hpp +++ b/src/tcl/object-in-fluid/bending_force_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2013 The ESPResSo project + Copyright (C) 2010,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group, PO Box 3148, 55021 Mainz, Germany This file is part of ESPResSo. @@ -19,7 +19,7 @@ */ #ifndef BENDING_FORCE_TCL_H #define BENDING_FORCE_TCL_H -/** \file bending_force.h Routines to calculate the bending_force energy or/and +/** \file bending_force.hpp Routines to calculate the bending_force energy or/and * and force for a particle quadruple (two triangles that have 2 particles in common) */ diff --git a/src/tcl/object-in-fluid/stretching_force_tcl.cpp b/src/tcl/object-in-fluid/stretching_force_tcl.cpp index d1479e4e913..1da8fee1818 100644 --- a/src/tcl/object-in-fluid/stretching_force_tcl.cpp +++ b/src/tcl/object-in-fluid/stretching_force_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -22,10 +22,10 @@ #include "stretching_force_tcl.hpp" #include "object-in-fluid/stretching_force.hpp" -/** \file stretching_force.h +/** \file stretching_force.hpp * Routines to calculate the STRETCHING_FORCE Energy or/and STRETCHING_FORCE force * for a particle pair. (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ /************************************************************/ diff --git a/src/tcl/object-in-fluid/stretching_force_tcl.hpp b/src/tcl/object-in-fluid/stretching_force_tcl.hpp index 24aff7f9a4e..12904cfab81 100644 --- a/src/tcl/object-in-fluid/stretching_force_tcl.hpp +++ b/src/tcl/object-in-fluid/stretching_force_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/src/tcl/object-in-fluid/stretchlin_force_tcl.cpp b/src/tcl/object-in-fluid/stretchlin_force_tcl.cpp index 3f5727b8538..f8438792d18 100644 --- a/src/tcl/object-in-fluid/stretchlin_force_tcl.cpp +++ b/src/tcl/object-in-fluid/stretchlin_force_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -25,7 +25,7 @@ /** \file stretchlin_force.hpp * Routines to calculate the STRETCHLIN_FORCE Energy or/and STRETCHLIN_FORCE force * for a particle pair. (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ /************************************************************/ diff --git a/src/tcl/object-in-fluid/stretchlin_force_tcl.hpp b/src/tcl/object-in-fluid/stretchlin_force_tcl.hpp index 39e86def5dd..e6936759a53 100644 --- a/src/tcl/object-in-fluid/stretchlin_force_tcl.hpp +++ b/src/tcl/object-in-fluid/stretchlin_force_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/src/tcl/object-in-fluid/volume_force_tcl.cpp b/src/tcl/object-in-fluid/volume_force_tcl.cpp index 88854aefb37..32ff337a193 100644 --- a/src/tcl/object-in-fluid/volume_force_tcl.cpp +++ b/src/tcl/object-in-fluid/volume_force_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -17,10 +17,10 @@ along with this program. If not, see . */ -/* \file volume_force.h +/* \file volume_force.hpp * Routines to calculate the VOLUME_FORCE energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ diff --git a/src/tcl/object-in-fluid/volume_force_tcl.hpp b/src/tcl/object-in-fluid/volume_force_tcl.hpp index 36db60bc58a..87cb2d45c72 100644 --- a/src/tcl/object-in-fluid/volume_force_tcl.hpp +++ b/src/tcl/object-in-fluid/volume_force_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012,2013 The ESPResSo project + Copyright (C) 2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -18,10 +18,10 @@ */ #ifndef _OBJECT_IN_FLUID_VOLUME_FORCE_TCL_H #define _OBJECT_IN_FLUID_VOLUME_FORCE_TCL_H -/** \file volume_force.h +/** \file volume_force.hpp * Routines to calculate the VOLUME_FORCE energy or/and and force * for a particle triple (triangle from mesh). (Dupin2007) - * \ref forces.c + * \ref forces.cpp */ #include "tcl/parser.hpp" diff --git a/src/tcl/overlap_tcl.cpp b/src/tcl/overlap_tcl.cpp index ab86c8bbb80..4c89ebe540b 100644 --- a/src/tcl/overlap_tcl.cpp +++ b/src/tcl/overlap_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file overlap_tcl.c +/** \file overlap_tcl.cpp * * Implementation of \ref overlap_tcl.hpp */ @@ -32,7 +32,7 @@ int tclcommand_inter_parse_overlapped_bonded(Tcl_Interp *interp, int bond_type, int argc, char **argv) { - int overlap_type = OVERLAP_UNKNOWN; + OverlappedBondedInteraction overlap_type = OVERLAP_UNKNOWN; if (argc < 3 ) { Tcl_AppendResult(interp, "overlappedd needs two string parameter: " diff --git a/src/tcl/overlap_tcl.hpp b/src/tcl/overlap_tcl.hpp index ee38f0f76e7..7f23435e5b8 100644 --- a/src/tcl/overlap_tcl.hpp +++ b/src/tcl/overlap_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef OVERLAP_TCL_H #define OVERLAP_TCL_H /** \file overlap_tcl.hpp - * Tcl interface for \ref overlap.h + * Tcl interface for \ref overlap.hpp */ #include "parser.hpp" diff --git a/src/tcl/p3m-dipolar_tcl.cpp b/src/tcl/p3m-dipolar_tcl.cpp index 6ebd8ba2b04..47c1ee1c69b 100644 --- a/src/tcl/p3m-dipolar_tcl.cpp +++ b/src/tcl/p3m-dipolar_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file p3m-dipolar.c P3M algorithm for long range magnetic dipole-dipole interaction. +/** \file p3m-dipolar.cpp P3M algorithm for long range magnetic dipole-dipole interaction. * NB: In general the magnetic dipole-dipole functions bear the same name than the charge-charge but, adding in front of the name a D diff --git a/src/tcl/p3m-dipolar_tcl.hpp b/src/tcl/p3m-dipolar_tcl.hpp index 17f805730cd..6b5ab40c2e7 100644 --- a/src/tcl/p3m-dipolar_tcl.hpp +++ b/src/tcl/p3m-dipolar_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/p3m_tcl.cpp b/src/tcl/p3m_tcl.cpp index b781542357c..852ebcc3b6f 100644 --- a/src/tcl/p3m_tcl.cpp +++ b/src/tcl/p3m_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -24,8 +24,6 @@ #include "p3m_tcl.hpp" #include "p3m.hpp" - - int tclcommand_inter_coulomb_parse_p3m_tune(Tcl_Interp * interp, int argc, char ** argv, int adaptive) { int cao = -1, n_interpol = -1; diff --git a/src/tcl/p3m_tcl.hpp b/src/tcl/p3m_tcl.hpp index 58506f65d2c..dd259b84029 100644 --- a/src/tcl/p3m_tcl.hpp +++ b/src/tcl/p3m_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -62,7 +62,7 @@ int tclcommand_inter_coulomb_parse_p3m_opt_params(Tcl_Interp * interp, int argc, The function returns a log of the performed tuning. - The function is based on routines of the program HE_Q.c written by M. Deserno. + The function is based on routines of the program HE_Q.cpp written by M. Deserno. */ int tclcommand_inter_coulomb_p3m_print_tune_parameters(Tcl_Interp *interp); diff --git a/src/tcl/parser.cpp b/src/tcl/parser.cpp index 66865546707..c827875b40e 100644 --- a/src/tcl/parser.cpp +++ b/src/tcl/parser.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,44 +18,51 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file parser.c - Implementation of \ref parser.h "parser.h". \ref parse_int_list is too long for inlining. +/** \file parser.cpp + Implementation of \ref parser.hpp "parser.h". \ref parse_int_list is too long for inlining. */ #include "utils.hpp" #include "parser.hpp" #include "communication.hpp" +#include "errorhandling.hpp" +#include +#include -int parse_int_list(Tcl_Interp *interp, char *list, IntList *il) -{ - int i, tmp_argc, res = 1; +using namespace std; + +int parse_int_list(Tcl_Interp *interp, char *list, IntList *il) { + int tmp_argc, res = 1; char **tmp_argv; Tcl_SplitList(interp, list, &tmp_argc, &tmp_argv); realloc_intlist(il, il->n = tmp_argc); - for(i = 0 ; i < tmp_argc; i++) if (Tcl_GetInt(interp, tmp_argv[i], &(il->e[i])) == TCL_ERROR) { res = 0; break; } + for (int i = 0 ; i < tmp_argc; i++) + if (Tcl_GetInt(interp, tmp_argv[i], &(il->e[i])) == TCL_ERROR) { + res = 0; + break; + } Tcl_Free((char *)tmp_argv); return res; } -int parse_double_list(Tcl_Interp *interp, char *list, DoubleList *dl) -{ - int i, tmp_argc, res = 1; +int parse_double_list(Tcl_Interp *interp, char *list, DoubleList *dl) { + int tmp_argc, res = 1; char **tmp_argv; Tcl_SplitList(interp, list, &tmp_argc, &tmp_argv); realloc_doublelist(dl, dl->n = tmp_argc); - for(i = 0 ; i < tmp_argc; i++) if (Tcl_GetDouble(interp, tmp_argv[i], &(dl->e[i])) == TCL_ERROR) { res = 0; break; } + for (int i = 0 ; i < tmp_argc; i++) + if (Tcl_GetDouble(interp, tmp_argv[i], &(dl->e[i])) == TCL_ERROR) { + res = 0; + break; + } Tcl_Free((char *)tmp_argv); return res; } -int gather_runtime_errors(Tcl_Interp *interp, int error_code) -{ - char **errors =(char **)malloc(n_nodes*sizeof(char *)); +int gather_runtime_errors(Tcl_Interp *interp, int error_code) { + list errors = mpiRuntimeErrorCollectorGather(); - if (mpi_gather_runtime_errors(errors) == ES_OK) { - free(errors); - return error_code; - } + if (errors.size() == 0) return error_code; /* reset any results of the previous command, since we got an error during evaluation, they are at best bogus. But any normal error @@ -69,27 +76,9 @@ int gather_runtime_errors(Tcl_Interp *interp, int error_code) Tcl_AppendResult(interp, "background_errors ", (char *) NULL); - for (int node = 0; node < n_nodes; node++) { - if (errors[node] != NULL) { - char nr_buf[TCL_INTEGER_SPACE + 3]; - sprintf(nr_buf, "%d ", node); - - /* check whether it's the same message as from the master, then - just consent */ - if (node > 0 && errors[0] && strcmp(errors[node], errors[0]) == 0) - Tcl_AppendResult(interp, nr_buf, " ", (char *) NULL); - else - Tcl_AppendResult(interp, nr_buf, errors[node], (char *) NULL); - - /* we still need the master nodes error for squashing, see - above */ - if (node > 0) - free(errors[node]); - } - } - - free(errors[0]); - free(errors); + for (list::const_iterator it = errors.begin(); + it != errors.end(); ++it) + Tcl_AppendResult(interp, it->c_str(), (char*)NULL); return TCL_ERROR; } diff --git a/src/tcl/parser.hpp b/src/tcl/parser.hpp index 91b7b9b0d57..d3d710d787d 100644 --- a/src/tcl/parser.hpp +++ b/src/tcl/parser.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,9 +18,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef _PARSER_H -#define _PARSER_H -/** \file parser.h +#ifndef _TCL_PARSER_H +#define _TCL_PARSER_H +/** \file parser.hpp This file contains macros for parsing the parameters to the 'inter' command. */ diff --git a/src/tcl/particle_data_tcl.cpp b/src/tcl/particle_data_tcl.cpp index b267654cd6c..72ec0970d8f 100644 --- a/src/tcl/particle_data_tcl.cpp +++ b/src/tcl/particle_data_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -119,7 +119,21 @@ void tclcommand_part_print_torque_lab_frame(Particle *part, char *buffer, Tcl_In Tcl_AppendResult(interp, buffer, (char *)NULL); } +/* Print velocity in the body frame */ +void tclcommand_part_print_v_body(Particle *part, char *buffer, Tcl_Interp *interp) +{ + double vel[3]; + //Convert the velocity to body-fixed coordinates from space-fixed coordinates. + convert_vel_space_to_body(part, vel); + /* unscale velocities ! */ + Tcl_PrintDouble(interp, vel[0]/time_step, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); + Tcl_PrintDouble(interp, vel[1]/time_step, buffer); + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); + Tcl_PrintDouble(interp, vel[2]/time_step, buffer); + Tcl_AppendResult(interp, buffer, (char *)NULL); +} void tclcommand_part_print_quat(Particle *part, char *buffer, Tcl_Interp *interp) { @@ -208,16 +222,26 @@ void tclcommand_part_print_solvation(Particle *part, char *buffer, Tcl_Interp *i } } + +void tclcommand_part_print_composition(Particle *part, char *buffer, Tcl_Interp *interp) +{ + int ii; + for(ii=0;iir.composition[ii], buffer); + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); + } +} + #endif void tclcommand_part_print_f(Particle *part, char *buffer, Tcl_Interp *interp) { /* unscale forces ! */ - Tcl_PrintDouble(interp, part->f.f[0]/(0.5*time_step*time_step), buffer); + Tcl_PrintDouble(interp, part->f.f[0]*PMASS(*part)/(0.5*time_step*time_step), buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); - Tcl_PrintDouble(interp, part->f.f[1]/(0.5*time_step*time_step), buffer); + Tcl_PrintDouble(interp, part->f.f[1]*PMASS(*part)/(0.5*time_step*time_step), buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); - Tcl_PrintDouble(interp, part->f.f[2]/(0.5*time_step*time_step), buffer); + Tcl_PrintDouble(interp, part->f.f[2]*PMASS(*part)/(0.5*time_step*time_step), buffer); Tcl_AppendResult(interp, buffer, (char *)NULL); } @@ -227,7 +251,13 @@ void tclcommand_part_print_position(Particle *part, char *buffer, Tcl_Interp *in int img[3]; memcpy(ppos, part->r.p, 3*sizeof(double)); memcpy(img, part->l.i, 3*sizeof(int)); + + +#ifdef LEES_EDWARDS +// do not unfold position by default for LE case. +#else unfold_position(ppos, img); +#endif Tcl_PrintDouble(interp, ppos[0], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); Tcl_PrintDouble(interp, ppos[1], buffer); @@ -242,14 +272,33 @@ void tclcommand_part_print_folded_position(Particle *part, char *buffer, Tcl_Int int img[3]; memcpy(ppos, part->r.p, 3*sizeof(double)); memcpy(img, part->l.i, 3*sizeof(int)); + +#ifdef LEES_EDWARDS + double pvel[3]; + memcpy(pvel, part->m.v, 3*sizeof(double)); + fold_position(ppos, pvel, img); +#else fold_position(ppos, img); - +#endif + Tcl_PrintDouble(interp, ppos[0], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); Tcl_PrintDouble(interp, ppos[1], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL); Tcl_PrintDouble(interp, ppos[2], buffer); +#ifdef LEES_EDWARDS + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); +#else Tcl_AppendResult(interp, buffer, (char *)NULL); +#endif +#ifdef LEES_EDWARDS + Tcl_PrintDouble(interp, pvel[0], buffer); + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); + Tcl_PrintDouble(interp, pvel[1], buffer); + Tcl_AppendResult(interp, buffer, " ", (char *)NULL); + Tcl_PrintDouble(interp, pvel[2], buffer); + Tcl_AppendResult(interp, buffer, (char *)NULL); +#endif } void tclcommand_part_print_bonding_structure(Particle *part, char *buffer, Tcl_Interp *interp) @@ -292,7 +341,7 @@ void tclcommand_part_print_bond_partners(Particle *part, char *buffer, Tcl_Inter updatePartCfg(WITH_BONDS); /* determine initial connectivity */ - for (p = 0; p < n_total_particles; p++) { + for (p = 0; p < n_part; p++) { part1 = &partCfg[p]; p1 = part1->p.identity; for (i = 0; i < part1->bl.n;) { @@ -465,6 +514,9 @@ int tclprint_to_result_Particle(Tcl_Interp *interp, int part_num) Tcl_AppendResult(interp, " torque_body ", (char *)NULL); tclcommand_part_print_torque_body_frame(&part, buffer, interp); + + Tcl_AppendResult(interp, " body_frame_velocity ", (char *)NULL); + tclcommand_part_print_v_body(&part, buffer, interp); #endif #ifdef ROTATION_PER_PARTICLE @@ -516,6 +568,9 @@ int tclprint_to_result_Particle(Tcl_Interp *interp, int part_num) #ifdef SHANCHEN Tcl_AppendResult(interp, " solvation ", (char *)NULL); tclcommand_part_print_solvation(&part, buffer, interp); + + Tcl_AppendResult(interp, " composition ", (char *)NULL); + tclcommand_part_print_composition(&part, buffer, interp); #endif #ifdef EXTERNAL_FORCES @@ -582,7 +637,7 @@ int tclcommand_part_parse_print(Tcl_Interp *interp, int argc, char **argv, int part_num) { - char buffer[TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; + char buffer[6*(TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE)]; Particle part; if (part_num > max_seen_particle) { @@ -625,6 +680,9 @@ int tclcommand_part_parse_print(Tcl_Interp *interp, int argc, char **argv, else if (ARG0_IS_S("solvation")) { tclcommand_part_print_solvation(&part, buffer, interp); } + else if (ARG0_IS_S("composition")) { + tclcommand_part_print_composition(&part, buffer, interp); + } #endif #ifdef ELECTROSTATICS else if (ARG0_IS_S("q")) { @@ -653,6 +711,8 @@ int tclcommand_part_parse_print(Tcl_Interp *interp, int argc, char **argv, tclcommand_part_print_torque_lab_frame(&part, buffer, interp); else if ( ARG0_IS_S_EXACT("torque_body") || ARG0_IS_S("tbf") ) tclcommand_part_print_torque_body_frame(&part, buffer, interp); + else if ( ARG0_IS_S_EXACT("body_frame_velocity") ) + tclcommand_part_print_v_body(&part, buffer, interp); #endif #ifdef ROTATION_PER_PARTICLE else if (ARG0_IS_S("rotation")) @@ -811,6 +871,8 @@ int tclcommand_part_parse_solvation(Tcl_Interp *interp, int argc, char **argv, return TCL_OK; } + + #endif @@ -992,7 +1054,7 @@ int tclcommand_part_parse_virtual(Tcl_Interp *interp, int argc, char **argv, int part_parse_vs_relative(Tcl_Interp *interp, int argc, char **argv, int part_num, int * change) { - // See particle_data.h for explanation of the quantities + // See particle_data.hpp for explanation of the quantities int vs_relative_to; double vs_distance; @@ -1210,15 +1272,6 @@ int tclcommand_part_parse_type(Tcl_Interp *interp, int argc, char **argv, return TCL_ERROR; } -//#ifdef GRANDCANONICAL -// if ( Type_array_init ) { -// if ( add_particle_to_list(part_num) == ES_ERROR ){ -// Tcl_AppendResult(interp, "gc particle add failed", (char *) NULL); -// return TCL_ERROR; -// } -// } -//#endif - return TCL_OK; } @@ -1598,7 +1651,6 @@ int part_parse_gamma(Tcl_Interp *interp, int argc, char **argv, #endif -#ifdef GRANDCANONICAL int part_parse_gc(Tcl_Interp *interp, int argc, char **argv){ char buffer[100 + TCL_DOUBLE_SPACE + 3*TCL_INTEGER_SPACE]; @@ -1657,8 +1709,6 @@ int part_parse_gc(Tcl_Interp *interp, int argc, char **argv){ } int id; if (find_particle_type(type, &id) == ES_ERROR ){ - //char buffer[TCL_INTEGER_SPACE + 32]; - //sprintf(buffer, "no particle of type %d found", type); Tcl_AppendResult(interp, "-1", (char *) NULL); return TCL_OK; } @@ -1685,7 +1735,6 @@ int part_parse_gc(Tcl_Interp *interp, int argc, char **argv){ Tcl_AppendResult(interp, "no negative types", (char *) NULL); return TCL_ERROR; } - //if ( gc_status(type) == ES_ERROR ) { if ( type_array!=(TypeList *) 0 && type_array[Index.type[type]].max_entry!= 0 ) { int indexed=0; for ( int i=0; i 0) { + return tclcommand_part_parse_print(interp, argc-1, argv+1, part_num); + + // various setters + while (argc > 0) { if (ARG0_IS_S("delete")) err = tclcommand_part_parse_delete(interp, argc-1, argv+1, part_num, &change); @@ -2167,13 +2215,11 @@ int tclcommand_part_parse_cmd(Tcl_Interp *interp, int argc, char **argv, else if (ARG0_IS_S("gamma")) err = part_parse_gamma(interp, argc-1, argv+1, part_num, &change); #endif -#ifdef GRANDCANONICAL else if (ARG0_IS_S("gc")) { argc--; argv++; err = part_parse_gc(interp, argc, argv); } -#endif else { Tcl_AppendResult(interp, "unknown particle parameter \"", @@ -2236,7 +2282,6 @@ int tclcommand_part(ClientData data, Tcl_Interp *interp, } #endif -#ifdef GRANDCANONICAL else if ( ARG1_IS_S("gc")) { argc-=2; argv+=2; @@ -2244,7 +2289,6 @@ int tclcommand_part(ClientData data, Tcl_Interp *interp, return TCL_ERROR; return TCL_OK; } -#endif /* only one argument is given */ diff --git a/src/tcl/polymer_tcl.cpp b/src/tcl/polymer_tcl.cpp index a5674a02e2d..824bdb67c8d 100644 --- a/src/tcl/polymer_tcl.cpp +++ b/src/tcl/polymer_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file polymer.c +/** \file polymer.cpp This file contains everything needed to create a start-up configuration of (partially charged) polymer chains with counterions and salt molecules, assigning velocities to the particles and crosslinking the polymers if necessary. - The corresponding header file is polymer.h. + The corresponding header file is polymer.hpp. Created: 27.02.2003 by BAM Based upon 'polymer.tcl' by BAM (20.02.2003). @@ -261,7 +261,7 @@ else { } int tclcommand_counterions (ClientData data, Tcl_Interp *interp, int argc, char **argv) { - int N_CI; int part_id = n_total_particles; + int N_CI; int part_id = n_part; int mode = 0; double shield = 0.0; int tmp_try,max_try = 30000; /* mode==0 equals "SAW", mode==1 equals "RW" */ double val_CI = -1.0; int type_CI = 2; char buffer[128 + TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; @@ -345,7 +345,7 @@ int tclcommand_counterions (ClientData data, Tcl_Interp *interp, int argc, char } int tclcommand_salt (ClientData data, Tcl_Interp *interp, int argc, char **argv) { - int N_pS, N_nS; int part_id = n_total_particles; + int N_pS, N_nS; int part_id = n_part; int mode = 0; double shield = 0.0; int tmp_try,max_try = 30000; /* mode==0 equals "SAW", mode==1 equals "RW" */ double val_pS = 1.0, val_nS = -1.0; int type_pS = 3, type_nS = 4; double rad=0.; @@ -462,7 +462,7 @@ int tclcommand_salt (ClientData data, Tcl_Interp *interp, int argc, char **argv) } int tclcommand_velocities (ClientData data, Tcl_Interp *interp, int argc, char **argv) { - double v_max; int part_id = 0, N_T = n_total_particles; + double v_max; int part_id = 0, N_T = n_part; double tmp_try; char buffer[128 + TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; int i; @@ -484,8 +484,8 @@ int tclcommand_velocities (ClientData data, Tcl_Interp *interp, int argc, char * Tcl_ResetResult(interp); Tcl_AppendResult(interp, "Index of first particle must be integer (got: ",argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } else { - if ((part_id < 0) || (part_id>=n_total_particles)) { - sprintf(buffer,"Index of first particle must be in [0,%d[ (got: ", n_total_particles); + if ((part_id < 0) || (part_id>=n_part)) { + sprintf(buffer,"Index of first particle must be in [0,%d[ (got: ", n_part); Tcl_AppendResult(interp, buffer, argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } } i++; } @@ -499,8 +499,8 @@ int tclcommand_velocities (ClientData data, Tcl_Interp *interp, int argc, char * Tcl_ResetResult(interp); Tcl_AppendResult(interp, "The amount of particles to be set must be integer (got: ",argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } else { - if ((N_T < 0) || (part_id+N_T > n_total_particles)) { - sprintf(buffer,"The amount of particles to be set must be in [0,%d] (got: ",n_total_particles-part_id); + if ((N_T < 0) || (part_id+N_T > n_part)) { + sprintf(buffer,"The amount of particles to be set must be in [0,%d] (got: ",n_part-part_id); Tcl_AppendResult(interp, buffer, argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } } i++; } @@ -511,7 +511,7 @@ int tclcommand_velocities (ClientData data, Tcl_Interp *interp, int argc, char * /* default */ else { Tcl_AppendResult(interp, "The parameters you supplied do not seem to be valid (stuck at: ",argv[i],")!", (char *)NULL); return (TCL_ERROR); } } - if (part_id+N_T > n_total_particles) N_T = n_total_particles - part_id; + if (part_id+N_T > n_part) N_T = n_part - part_id; POLY_TRACE(printf("double v_max %f, int part_id %d, int N_T %d\n", v_max, part_id, N_T)); @@ -521,7 +521,7 @@ int tclcommand_velocities (ClientData data, Tcl_Interp *interp, int argc, char * } int tclcommand_maxwell_velocities (ClientData data, Tcl_Interp *interp, int argc, char **argv) { - int part_id = 0, N_T = n_total_particles; + int part_id = 0, N_T = n_part; double tmp_try; char buffer[128 + TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; int i; @@ -535,8 +535,8 @@ int tclcommand_maxwell_velocities (ClientData data, Tcl_Interp *interp, int argc Tcl_ResetResult(interp); Tcl_AppendResult(interp, "Index of first particle must be integer (got: ",argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } else { - if ((part_id < 0) || (part_id>=n_total_particles)) { - sprintf(buffer,"Index of first particle must be in [0,%d[ (got: ", n_total_particles); + if ((part_id < 0) || (part_id>=n_part)) { + sprintf(buffer,"Index of first particle must be in [0,%d[ (got: ", n_part); Tcl_AppendResult(interp, buffer, argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } } i++; } @@ -550,8 +550,8 @@ int tclcommand_maxwell_velocities (ClientData data, Tcl_Interp *interp, int argc Tcl_ResetResult(interp); Tcl_AppendResult(interp, "The amount of particles to be set must be integer (got: ",argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } else { - if ((N_T < 0) || (part_id+N_T > n_total_particles)) { - sprintf(buffer,"The amount of particles to be set must be in [0,%d] (got: ",n_total_particles-part_id); + if ((N_T < 0) || (part_id+N_T > n_part)) { + sprintf(buffer,"The amount of particles to be set must be in [0,%d] (got: ",n_part-part_id); Tcl_AppendResult(interp, buffer, argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } } i++; } @@ -559,7 +559,7 @@ int tclcommand_maxwell_velocities (ClientData data, Tcl_Interp *interp, int argc /* default */ else { Tcl_AppendResult(interp, "The parameters you supplied do not seem to be valid (stuck at: ",argv[i],")!", (char *)NULL); return (TCL_ERROR); } } - if (part_id+N_T > n_total_particles) N_T = n_total_particles - part_id; + if (part_id+N_T > n_part) N_T = n_part - part_id; POLY_TRACE(printf("int part_id %d, int N_T %d\n", part_id, N_T)); @@ -599,8 +599,8 @@ int tclcommand_crosslink (ClientData data, Tcl_Interp *interp, int argc, char ** if (!ARG_IS_I(i+1, part_id)) { Tcl_AppendResult(interp, "Index of first particle must be integer (got: ",argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } else { - if ((part_id < 0) || (part_id > n_total_particles - N_P*MPC)) { - sprintf(buffer,"Index of first particle must be in [0,%d] (got: ", n_total_particles - N_P*MPC); + if ((part_id < 0) || (part_id > n_part - N_P*MPC)) { + sprintf(buffer,"Index of first particle must be in [0,%d] (got: ", n_part - N_P*MPC); Tcl_AppendResult(interp, buffer, argv[i+1],")!", (char *)NULL); return (TCL_ERROR); } } i++; } diff --git a/src/tcl/polymer_tcl.hpp b/src/tcl/polymer_tcl.hpp index a2b237c0304..fcd70da1393 100644 --- a/src/tcl/polymer_tcl.hpp +++ b/src/tcl/polymer_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/pressure_tcl.cpp b/src/tcl/pressure_tcl.cpp index 4ce3d6032c8..2383d6ad7b9 100644 --- a/src/tcl/pressure_tcl.cpp +++ b/src/tcl/pressure_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file pressure.c - Implementation of \ref pressure.h "pressure.h". +/** \file pressure.cpp + Implementation of \ref pressure.hpp "pressure.h". */ #include "pressure.hpp" #include "parser.hpp" @@ -203,7 +203,7 @@ int tclcommand_analyze_parse_and_print_pressure(Tcl_Interp *interp, int v_comp, double value, p_vel[3]; value = 0.0; - if (n_total_particles == 0) { + if (n_part == 0) { Tcl_AppendResult(interp, "(no particles)", (char *)NULL); return (TCL_OK); @@ -325,7 +325,7 @@ int tclcommand_analyze_parse_and_print_pressure(Tcl_Interp *interp, int v_comp, for (i = 0; i < total_pressure.n_coulomb; i++) value += total_pressure.coulomb[i]; #else - Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.hpp)\n", (char *)NULL); #endif } else if( ARG0_IS_S("dipolar")) { @@ -334,7 +334,7 @@ int tclcommand_analyze_parse_and_print_pressure(Tcl_Interp *interp, int v_comp, for (i = total_pressure.n_coulomb-1; i < total_pressure.n_coulomb; i++) /*when DLC will be installed this has to be changed */ value += total_pressure.coulomb[i]; #else - Tcl_AppendResult(interp, "DIPOLES not compiled (see config.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "DIPOLES not compiled (see config.hpp)\n", (char *)NULL); #endif } #ifdef VIRTUAL_SITES_RELATIVE @@ -493,7 +493,7 @@ static void tclcommand_analyze_print_stress_tensor_all(Tcl_Interp *interp) #ifdef DIPOLES if(coulomb.Dmethod != DIPOLAR_NONE) { - fprintf(stderr,"tensor magnetostatics, something should go here, file pressure.c ... \n"); + fprintf(stderr,"tensor magnetostatics, something should go here, file pressure.cpp ... \n"); } #endif @@ -520,7 +520,7 @@ int tclcommand_analyze_parse_and_print_stress_tensor(Tcl_Interp *interp, int v_c double p_vel[3], tvalue[9]; for(j=0; j<9; j++) tvalue[j] = 0.0; - if (n_total_particles == 0) { + if (n_part == 0) { Tcl_AppendResult(interp, "(no particles)", (char *)NULL); return (TCL_OK); @@ -641,15 +641,15 @@ int tclcommand_analyze_parse_and_print_stress_tensor(Tcl_Interp *interp, int v_c #ifdef ELECTROSTATICS for(j=0; j<9; j++) tvalue[j] = total_p_tensor.coulomb[j]; #else - Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "ELECTROSTATICS not compiled (see config.hpp)\n", (char *)NULL); #endif } else if( ARG0_IS_S("dipolar")) { #ifdef DIPOLES /* for(j=0; j<9; j++) tvalue[j] = total_p_tensor.coulomb[j];*/ - fprintf(stderr," stress tensor, magnetostatics, something should go here, file pressure.c "); + fprintf(stderr," stress tensor, magnetostatics, something should go here, file pressure.cpp "); #else - Tcl_AppendResult(interp, "DIPOLES not compiled (see config.h)\n", (char *)NULL); + Tcl_AppendResult(interp, "DIPOLES not compiled (see config.hpp)\n", (char *)NULL); #endif } #ifdef VIRTUAL_SITES_RELATIVE diff --git a/src/tcl/pressure_tcl.hpp b/src/tcl/pressure_tcl.hpp index d464f3ee8ab..93202db92fc 100644 --- a/src/tcl/pressure_tcl.hpp +++ b/src/tcl/pressure_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file pressure.h - Pressure calculation. Really similar to \ref energy.h "energy.h". +/** \file pressure.hpp + Pressure calculation. Really similar to \ref energy.hpp "energy.h". */ #ifndef _PRESSURE_TCL_H diff --git a/src/tcl/quartic_tcl.cpp b/src/tcl/quartic_tcl.cpp new file mode 100644 index 00000000000..aff71a19560 --- /dev/null +++ b/src/tcl/quartic_tcl.cpp @@ -0,0 +1,69 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** \file quartic_tcl.cpp + * + * Implementation of \ref quartic_tcl.hpp + */ +#include "quartic_tcl.hpp" +#include "quartic.hpp" + +int tclcommand_inter_parse_quartic(Tcl_Interp *interp, int bond_type, int argc, char **argv) +{ + double k0, k1, r,r_cut; + + if (argc < 4) { + Tcl_AppendResult(interp, "quartic needs at least 3 parameters: " + " []", (char *) NULL); + return TCL_ERROR; + } + + if ((! ARG_IS_D(1, k0)) || (! ARG_IS_D(2, k1)) || (! ARG_IS_D(3, r))) { + Tcl_AppendResult(interp, "quartic needs at least 2 DOUBLE parameters: " + " []", (char *) NULL); + return TCL_ERROR; + } + + if (argc < 5) { + r_cut = -1.0; + } else if (! ARG_IS_D(4, r_cut)) { + Tcl_AppendResult(interp, " should be DOUBLE", (char *) NULL); + return TCL_ERROR; + } + + CHECK_VALUE(quartic_set_params(bond_type, k0, k1, r, r_cut), "bond type must be nonnegative"); +} + +int tclprint_to_result_quarticIA(Tcl_Interp *interp, Bonded_ia_parameters *params) +{ + char buffer[TCL_DOUBLE_SPACE]; + + Tcl_PrintDouble(interp, params->p.quartic.k0, buffer); + Tcl_AppendResult(interp, "QUARTIC ", buffer, " ", (char *) NULL); + Tcl_PrintDouble(interp, params->p.quartic.k1, buffer); + Tcl_AppendResult(interp, buffer," ", (char *) NULL); + Tcl_PrintDouble(interp, params->p.quartic.r, buffer); + Tcl_AppendResult(interp, buffer," ", (char *) NULL); + if (params->p.quartic.r_cut > 0.0) { + Tcl_PrintDouble(interp, params->p.quartic.r_cut, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + return TCL_OK; +} diff --git a/src/tcl/quartic_tcl.hpp b/src/tcl/quartic_tcl.hpp new file mode 100644 index 00000000000..62c29ac34ae --- /dev/null +++ b/src/tcl/quartic_tcl.hpp @@ -0,0 +1,36 @@ +/* + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project + Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + Max-Planck-Institute for Polymer Research, Theory Group + + This file is part of ESPResSo. + + ESPResSo is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ESPResSo is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef QUARTIC_TCL_H +#define QUARTIC_TCL_H +/** \file quartic_tcl.hpp + * Tcl interface for \ref quartic.hpp + */ + +#include "parser.hpp" +#include "interaction_data.hpp" + +/// parse parameters for the quartic potential +int tclcommand_inter_parse_quartic(Tcl_Interp *interp, int bond_type, int argc, char **argv); + +/// +int tclprint_to_result_quarticIA(Tcl_Interp *interp, Bonded_ia_parameters *params); + +#endif diff --git a/src/tcl/random_tcl.cpp b/src/tcl/random_tcl.cpp index 6b5cda000c7..679c04309ce 100644 --- a/src/tcl/random_tcl.cpp +++ b/src/tcl/random_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -22,8 +22,7 @@ #include #include #include "utils.hpp" -//#include "global.hpp" -#include "../random.hpp" +#include "random.hpp" #include "parser.hpp" #include "tcl.h" #include "communication.hpp" diff --git a/src/tcl/random_tcl.hpp b/src/tcl/random_tcl.hpp index 3d38bb80f6e..409af63f5f1 100644 --- a/src/tcl/random_tcl.hpp +++ b/src/tcl/random_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/rattle_tcl.cpp b/src/tcl/rattle_tcl.cpp index cdfcce2139e..c56fed4c40f 100644 --- a/src/tcl/rattle_tcl.cpp +++ b/src/tcl/rattle_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file rattle_tcl.c +/** \file rattle_tcl.cpp * * Implementation of \ref rattle_tcl.hpp */ diff --git a/src/tcl/rattle_tcl.hpp b/src/tcl/rattle_tcl.hpp index 9873bd76e85..a5b5aa85d54 100644 --- a/src/tcl/rattle_tcl.hpp +++ b/src/tcl/rattle_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef RATTLE_TCL_H #define RATTLE_TCL_H /** \file rattle_tcl.hpp - * Tcl interface for \ref rattle.h + * Tcl interface for \ref rattle.hpp */ #include "parser.hpp" diff --git a/src/tcl/reaction_field_tcl.cpp b/src/tcl/reaction_field_tcl.cpp index b8c0561bf3a..29ff874f183 100644 --- a/src/tcl/reaction_field_tcl.cpp +++ b/src/tcl/reaction_field_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file reaction_field_tcl.c +/** \file reaction_field_tcl.cpp * * Implementation of \ref reaction_field_tcl.hpp */ @@ -45,7 +45,7 @@ int tclprint_to_result_rf(Tcl_Interp *interp, const char *name) } int tclcommand_inter_coulomb_parse_rf(Tcl_Interp * interp, - int argc, char ** argv,int method) + int argc, char ** argv, CoulombMethod method) { double kappa,epsilon1,epsilon2, r_cut; int i; diff --git a/src/tcl/reaction_field_tcl.hpp b/src/tcl/reaction_field_tcl.hpp index 01fb363160d..aade0846ca2 100644 --- a/src/tcl/reaction_field_tcl.hpp +++ b/src/tcl/reaction_field_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,10 +21,11 @@ #ifndef REACTION_FIELD_TCL_H #define REACTION_FIELD_TCL_H /** \file reaction_field_tcl.hpp - * Tcl interface for \ref reaction_field.h + * Tcl interface for \ref reaction_field.hpp */ #include "parser.hpp" +#include "interaction_data.hpp" #ifdef ELECTROSTATICS @@ -33,7 +34,7 @@ int tclprint_to_result_rf(Tcl_Interp *interp, const char *name); /// int tclcommand_inter_coulomb_parse_rf(Tcl_Interp * interp, - int argc, char ** argv,int method); + int argc, char ** argv, CoulombMethod method); #ifdef INTER_RF diff --git a/src/tcl/reaction_tcl.cpp b/src/tcl/reaction_tcl.cpp index a9b3d194dbf..8c49040eb5a 100644 --- a/src/tcl/reaction_tcl.cpp +++ b/src/tcl/reaction_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -19,7 +19,7 @@ along with this program. If not, see . */ -/** \file reaction_tcl.c +/** \file reaction_tcl.cpp * */ diff --git a/src/tcl/reaction_tcl.hpp b/src/tcl/reaction_tcl.hpp index ec2658219f0..bb93cf29ab4 100644 --- a/src/tcl/reaction_tcl.hpp +++ b/src/tcl/reaction_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/scriptsdir.cpp b/src/tcl/scriptsdir.cpp index 3cdf8c2fd8a..904fd23ab4f 100644 --- a/src/tcl/scriptsdir.cpp +++ b/src/tcl/scriptsdir.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2010 Olaf Lenz This file is part of ESPResSo. diff --git a/src/tcl/soft_sphere_tcl.cpp b/src/tcl/soft_sphere_tcl.cpp index ff1b0a9ba2e..f131b66f6a4 100644 --- a/src/tcl/soft_sphere_tcl.cpp +++ b/src/tcl/soft_sphere_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file soft_sphere_tcl.c +/** \file soft_sphere_tcl.cpp * * Implementation of \ref soft_sphere_tcl.hpp */ diff --git a/src/tcl/soft_sphere_tcl.hpp b/src/tcl/soft_sphere_tcl.hpp index d4ee724bc60..4670feaa97e 100644 --- a/src/tcl/soft_sphere_tcl.hpp +++ b/src/tcl/soft_sphere_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -21,7 +21,7 @@ #ifndef SOFT_SPHERE_TCL_H #define SOFT_SPHERE_TCL_H /** \file soft_sphere_tcl.hpp - * Tcl interface for \ref soft_sphere.h + * Tcl interface for \ref soft_sphere.hpp */ #include "parser.hpp" diff --git a/src/tcl/statistics_chain_tcl.cpp b/src/tcl/statistics_chain_tcl.cpp index 2f1ed8056a1..d6e873475cb 100644 --- a/src/tcl/statistics_chain_tcl.cpp +++ b/src/tcl/statistics_chain_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,8 +18,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_chain.c - Implementation of \ref statistics_chain.h "statistics_chain.h". +/** \file statistics_chain.cpp + Implementation of \ref statistics_chain.hpp "statistics_chain.h". */ #include "statistics.hpp" #include "parser.hpp" @@ -275,8 +275,8 @@ int tclcommand_analyze_parse_g123(Tcl_Interp *interp, int average, int argc, cha if (init) { init_g123(); return TCL_OK; } if (partCoord_g == NULL || partCM_g == NULL) { Tcl_AppendResult(interp, "please call with -init first", (char *)NULL); return TCL_ERROR; } - if (chain_n_chains != n_chains_g || n_total_particles != n_part_g) { - fprintf(stderr, "%d %d %d %d\n", chain_n_chains, n_chains_g, n_total_particles, n_part_g); + if (chain_n_chains != n_chains_g || n_part != n_part_g) { + fprintf(stderr, "%d %d %d %d\n", chain_n_chains, n_chains_g, n_part, n_part_g); Tcl_AppendResult(interp, "initial config has different topology", (char *)NULL); return TCL_ERROR; } diff --git a/src/tcl/statistics_chain_tcl.hpp b/src/tcl/statistics_chain_tcl.hpp index 2dbd50eebaf..437b78d9486 100644 --- a/src/tcl/statistics_chain_tcl.hpp +++ b/src/tcl/statistics_chain_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/statistics_cluster_tcl.cpp b/src/tcl/statistics_cluster_tcl.cpp index 072e3d705ce..edfe6091171 100644 --- a/src/tcl/statistics_cluster_tcl.cpp +++ b/src/tcl/statistics_cluster_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,12 +18,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_cluster.c +/** \file statistics_cluster.cpp * * This file contains the necklace cluster algorithm. It can be used * to identify the substructures 'pearls' and 'strings' on a linear * chain. - * See also \ref statistics_cluster.h + * See also \ref statistics_cluster.hpp */ @@ -83,7 +83,7 @@ int tclcommand_analyze_parse_necklace(Tcl_Interp *interp, int argc, char **argv) Tcl_AppendResult(interp, "analyze necklace: identity of first particle can not be negative", (char *)NULL); return TCL_ERROR; } - if( first+length > n_total_particles+1) { + if( first+length > n_part+1) { Tcl_AppendResult(interp, "analyze necklace: identity of last particle out of partCfg array", (char *)NULL); return TCL_ERROR; } diff --git a/src/tcl/statistics_cluster_tcl.hpp b/src/tcl/statistics_cluster_tcl.hpp index bb0ee1ce0ea..f3192a15a27 100644 --- a/src/tcl/statistics_cluster_tcl.hpp +++ b/src/tcl/statistics_cluster_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2012,2013 The ESPResSo project + Copyright (C) 2010,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group diff --git a/src/tcl/statistics_correlation_tcl.cpp b/src/tcl/statistics_correlation_tcl.cpp index 6b57df026d2..8d49e4389c0 100644 --- a/src/tcl/statistics_correlation_tcl.cpp +++ b/src/tcl/statistics_correlation_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -397,6 +397,7 @@ int tclcommand_correlation_parse_corr(Tcl_Interp* interp, int no, int argc, char error = double_correlation_get_data(&correlations[no]); if (error) { Tcl_AppendResult(interp, double_correlation_get_data_errors[error], (char *)NULL); + return TCL_ERROR; } else { return TCL_OK; } @@ -427,7 +428,7 @@ int tclcommand_correlation_parse_corr(Tcl_Interp* interp, int no, int argc, char // Else we must parse the other arguments and see if we can construct a fully // working correlation class instance from that. while (argc > 0) { - if ( ARG0_IS_S("first_obs") || ARG0_IS_S("obs1") ) { + if ( ARG0_IS_S("first_obs") || ARG0_IS_S_EXACT("obs1") ) { if (argc>1 && ARG1_IS_I(temp)) { if (temp>=n_observables) { Tcl_AppendResult(interp, "Error in correlation observable. The specified observable does not exist\n", (char *)NULL); @@ -440,7 +441,7 @@ int tclcommand_correlation_parse_corr(Tcl_Interp* interp, int no, int argc, char tclcommand_correlation_print_usage(interp); return TCL_ERROR; } - } else if ( ARG0_IS_S("second_obs") || ARG0_IS_S("obs2") ) { + } else if ( ARG0_IS_S("second_obs") || ARG0_IS_S_EXACT("obs2") ) { if (argc>1 && ARG1_IS_I(temp)) { if (temp>=n_observables) { Tcl_AppendResult(interp, "Error in correlation observable. The specified observable does not exist\n", (char *)NULL); @@ -577,6 +578,9 @@ int parse_corr_operation(Tcl_Interp* interp, int argc, char** argv, int* change, } else if (ARG_IS_S_EXACT(0,"complex_conjugate_product")) { *change=1; return TCL_OK; + } else if (ARG_IS_S_EXACT(0,"tensor_product")) { + *change=1; + return TCL_OK; } else if (ARG_IS_S_EXACT(0,"square_distance_componentwise")) { *change=1; return TCL_OK; @@ -638,7 +642,7 @@ int double_correlation_print_spherically_averaged_sf(double_correlation* self, T int qi,qj,qk,qn, dim_sf, order2; double dt=self->dt; - observable_sf_params* params=(observable_sf_params*)self->A_obs->args; + observable_sf_params* params=(observable_sf_params*)self->A_obs->container; char buffer[TCL_DOUBLE_SPACE]; int *q_vals; double *q_density; diff --git a/src/tcl/statistics_correlation_tcl.hpp b/src/tcl/statistics_correlation_tcl.hpp index d8bd71b6a0a..f9ef4566285 100644 --- a/src/tcl/statistics_correlation_tcl.hpp +++ b/src/tcl/statistics_correlation_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. diff --git a/src/tcl/statistics_fluid_tcl.cpp b/src/tcl/statistics_fluid_tcl.cpp index 0fa0ec37062..1487d24d281 100644 --- a/src/tcl/statistics_fluid_tcl.cpp +++ b/src/tcl/statistics_fluid_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -18,10 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -/** \file statistics_fluid.c +/** \file statistics_fluid.cpp * * Fluid related analysis functions. - * Implementation of \ref statistics_fluid.h. + * Implementation of \ref statistics_fluid.hpp. * */ @@ -127,7 +127,7 @@ static int tclcommand_analyze_fluid_parse_densprof(Tcl_Interp *interp, int argc, lb_master_calc_densprof(profile, pdir, x1, x2); for (i=0; i. */ -/** \file statistics_fluid.h +/** \file statistics_fluid.hpp * * Fluid related analysis functions. - * Header file for \ref statistics_fluid.c. + * Header file for \ref statistics_fluid.cpp. * */ diff --git a/src/tcl/statistics_observable_tcl.cpp b/src/tcl/statistics_observable_tcl.cpp index a561d89bde6..49833bd7d05 100644 --- a/src/tcl/statistics_observable_tcl.cpp +++ b/src/tcl/statistics_observable_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -28,9 +28,9 @@ /* forward declarations */ int tclcommand_observable_print_formatted(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs, double* values); int tclcommand_observable_print(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs); +int tclcommand_observable_update(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs); static int convert_types_to_ids(IntList * type_list, IntList * id_list); -static int observable_tclcommand(void* _container, double* A, unsigned int n_A); int parse_id_list(Tcl_Interp* interp, int argc, char** argv, int* change, IntList** ids ) { int i,ret; @@ -48,6 +48,11 @@ int parse_id_list(Tcl_Interp* interp, int argc, char** argv, int* change, IntLis } + //Observables rely on the partCfg being sortable. If this is not true, an ambiguous error pops up later + if (!sortPartCfg()) { + Tcl_AppendResult(interp, "Error parsing particle specifications.\nProbably your particle ids are not contiguous.\n", (char *)NULL); + return TCL_ERROR; + } if (ARG0_IS_S("ids")) { if (!parse_int_list(interp, argv[1],input)) { Tcl_AppendResult(interp, "Error parsing id list\n", (char *)NULL); @@ -55,7 +60,7 @@ int parse_id_list(Tcl_Interp* interp, int argc, char** argv, int* change, IntLis } *ids=input; for (i=0; in; i++) { - if (input->e[i] >= n_total_particles) { + if (input->e[i] >= n_part) { Tcl_AppendResult(interp, "Error parsing ID list. Given particle ID exceeds the number of existing particles\n", (char *)NULL); return TCL_ERROR; } @@ -100,7 +105,7 @@ int sf_print_usage(Tcl_Interp* interp); int tclcommand_observable_print_profile_formatted(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs, double* values, int groupsize, int shifted) { - profile_data* pdata=(profile_data*) obs->args; + profile_data* pdata=(profile_data*) obs->container; char buffer[TCL_DOUBLE_SPACE]; double data; int linear_index; @@ -165,7 +170,7 @@ int tclcommand_observable_print_profile_formatted(Tcl_Interp* interp, int argc, } int tclcommand_observable_print_radial_profile_formatted(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs, double* values, int groupsize, int shifted) { - radial_profile_data* pdata=(radial_profile_data*) obs->args; + radial_profile_data* pdata=(radial_profile_data*) obs->container; char buffer[TCL_DOUBLE_SPACE]; double data; int linear_index; @@ -245,9 +250,11 @@ int tclcommand_observable_tclcommand(Tcl_Interp* interp, int argc, char** argv, container->n_A = n_A; container->interp = interp; - obs->fun=&observable_tclcommand; + obs->calculate=&observable_calc_tclcommand; + obs->update=0; obs->n=n_A; - obs->args=(void*) container; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); + obs->container=(void*) container; return TCL_OK; } @@ -257,9 +264,25 @@ int tclcommand_observable_particle_velocities(Tcl_Interp* interp, int argc, char int temp; if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->fun=&observable_particle_velocities; - obs->args=ids; + obs->calculate=&observable_calc_particle_velocities; + obs->update=0; + obs->container=ids; obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); + *change=1+temp; + return TCL_OK; +} + +int tclcommand_observable_particle_body_velocities(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { + IntList* ids; + int temp; + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) + return TCL_ERROR; + obs->calculate=&observable_calc_particle_body_velocities; + obs->update=0; + obs->container=ids; + obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -269,9 +292,25 @@ int tclcommand_observable_particle_angular_momentum(Tcl_Interp* interp, int argc int temp; if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->fun=&observable_particle_angular_momentum; - obs->args=ids; + obs->calculate=&observable_calc_particle_angular_momentum; + obs->update=0; + obs->container=ids; obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); + *change=1+temp; + return TCL_OK; +} + +int tclcommand_observable_particle_body_angular_momentum(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { + IntList* ids; + int temp; + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) + return TCL_ERROR; + obs->calculate=&observable_calc_particle_body_angular_momentum; + obs->update=0; + obs->container=ids; + obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -288,9 +327,11 @@ int tclcommand_observable_com_velocity(Tcl_Interp* interp, int argc, char** argv } if (argc>0 && ARG0_IS_S("blocked")) { if (argc >= 2 && ARG1_IS_I(blocksize) && (ids->n % blocksize ==0 )) { - obs->fun=&observable_blocked_com_velocity; - obs->args=ids; + obs->calculate=&observable_calc_blocked_com_velocity; + obs->update=0; + obs->container=ids; obs->n=3*ids->n/blocksize; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=3+temp; printf("found %d ids and a blocksize of %d, that makes %d dimensions\n", ids->n, blocksize, obs->n); return TCL_OK; @@ -299,9 +340,11 @@ int tclcommand_observable_com_velocity(Tcl_Interp* interp, int argc, char** argv return TCL_ERROR; } } else /* if nonblocked com is to be taken */ { - obs->fun=&observable_com_velocity; - obs->args=ids; + obs->calculate=&observable_calc_com_velocity; + obs->update=0; + obs->container=ids; obs->n=3; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -319,9 +362,11 @@ int tclcommand_observable_com_position(Tcl_Interp* interp, int argc, char** argv } if (argc>0 && ARG0_IS_S("blocked")) { if (argc >= 2 && ARG1_IS_I(blocksize) && (ids->n % blocksize ==0 )) { - obs->fun=&observable_blocked_com_position; - obs->args=ids; + obs->calculate=&observable_calc_blocked_com_position; + obs->update=0; + obs->container=ids; obs->n=3*ids->n/blocksize; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=3+temp; printf("found %d ids and a blocksize of %d, that makes %d dimensions\n", ids->n, blocksize, obs->n); return TCL_OK; @@ -330,9 +375,11 @@ int tclcommand_observable_com_position(Tcl_Interp* interp, int argc, char** argv return TCL_ERROR; } } else /* if nonblocked com is to be taken */ { - obs->fun=&observable_com_position; - obs->args=ids; + obs->calculate=&observable_calc_com_position; + obs->update=0; + obs->container=ids; obs->n=3; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -351,9 +398,11 @@ int tclcommand_observable_com_force(Tcl_Interp* interp, int argc, char** argv, i } if (argc>0 && ARG0_IS_S("blocked")) { if (argc >= 2 && ARG1_IS_I(blocksize) && (ids->n % blocksize ==0 )) { - obs->fun=&observable_blocked_com_force; - obs->args=ids; + obs->calculate=&observable_calc_blocked_com_force; + obs->update=0; + obs->container=ids; obs->n=3*ids->n/blocksize; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=3+temp; printf("found %d ids and a blocksize of %d, that makes %d dimensions\n", ids->n, blocksize, obs->n); return TCL_OK; @@ -362,9 +411,11 @@ int tclcommand_observable_com_force(Tcl_Interp* interp, int argc, char** argv, i return TCL_ERROR; } } else /* if nonblocked com is to be taken */ { - obs->fun=&observable_com_force; - obs->args=ids; + obs->calculate=&observable_calc_com_force; + obs->update=0; + obs->container=ids; obs->n=3; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -375,9 +426,11 @@ int tclcommand_observable_particle_positions(Tcl_Interp* interp, int argc, char* int temp; if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->fun = &observable_particle_positions; - obs->args=(void*)ids; + obs->calculate=&observable_calc_particle_positions; + obs->update=0; + obs->container=(void*)ids; obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -387,9 +440,11 @@ int tclcommand_observable_particle_forces(Tcl_Interp* interp, int argc, char** a int temp; if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->fun = &observable_particle_forces; - obs->args=(void*)ids; + obs->calculate=&observable_calc_particle_forces; + obs->update=0; + obs->container=(void*)ids; obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -397,18 +452,22 @@ int tclcommand_observable_particle_forces(Tcl_Interp* interp, int argc, char** a int tclcommand_observable_stress_tensor(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { - obs->fun = &observable_stress_tensor; - obs->args=(void*)NULL; + obs->calculate=&observable_stress_tensor; + obs->update=0; + obs->container=(void*)NULL; obs->n=9; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1; return TCL_OK; } int tclcommand_observable_stress_tensor_acf_obs(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { - obs->fun = &observable_stress_tensor_acf_obs; - obs->args=(void*)NULL; + obs->calculate=&observable_calc_stress_tensor_acf_obs; + obs->update=0; + obs->container=(void*)NULL; obs->n=6; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1; return TCL_OK; } @@ -417,15 +476,17 @@ int tclcommand_observable_stress_tensor_acf_obs(Tcl_Interp* interp, int argc, ch int tclcommand_observable_density_profile(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs){ int temp; profile_data* pdata; - obs->fun = &observable_density_profile; - if (! tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) == TCL_OK ) + obs->calculate=&observable_calc_density_profile; + obs->update=0; + if (tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) != TCL_OK ) return TCL_ERROR; if (pdata->id_list==0) { Tcl_AppendResult(interp, "Error in radial_profile: particle ids/types not specified\n" , (char *)NULL); return TCL_ERROR; } - obs->args=(void*)pdata; + obs->container=(void*)pdata; obs->n=pdata->xbins*pdata->ybins*pdata->zbins; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -436,11 +497,13 @@ int tclcommand_observable_lb_velocity_profile(Tcl_Interp* interp, int argc, char #else int temp; profile_data* pdata; - obs->fun = &observable_lb_velocity_profile; - if (! tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) == TCL_OK ) + obs->calculate=&observable_calc_lb_velocity_profile; + obs->update=0; + if (tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) != TCL_OK ) return TCL_ERROR; - obs->args=(void*)pdata; + obs->container=(void*)pdata; obs->n=3*pdata->xbins*pdata->ybins*pdata->zbins; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; #endif @@ -450,15 +513,17 @@ int tclcommand_observable_lb_velocity_profile(Tcl_Interp* interp, int argc, char int tclcommand_observable_radial_density_profile(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs){ int temp; radial_profile_data* rpdata; - obs->fun = &observable_radial_density_profile; - if (! tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) == TCL_OK ) + obs->calculate=&observable_calc_radial_density_profile; + obs->update=0; + if (tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) != TCL_OK ) return TCL_ERROR; if (rpdata->id_list==0) { Tcl_AppendResult(interp, "Error in radial_profile: particle ids/types not specified\n" , (char *)NULL); return TCL_ERROR; } - obs->args=(void*)rpdata; + obs->container=(void*)rpdata; obs->n=rpdata->rbins*rpdata->phibins*rpdata->zbins; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -466,15 +531,20 @@ int tclcommand_observable_radial_density_profile(Tcl_Interp* interp, int argc, c int tclcommand_observable_radial_flux_density_profile(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs){ int temp; radial_profile_data* rpdata; - obs->fun = &observable_radial_flux_density_profile; - if (! tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) == TCL_OK ) + obs->calculate=&observable_calc_radial_flux_density_profile; + obs->update=0; + if (tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) != TCL_OK ) return TCL_ERROR; if (rpdata->id_list==0) { Tcl_AppendResult(interp, "Error in radial_profile: particle ids/types not specified\n" , (char *)NULL); return TCL_ERROR; } - obs->args=(void*)rpdata; + obs->container=(void*)rpdata; obs->n=3*rpdata->rbins*rpdata->phibins*rpdata->zbins; + rpdata->container=(double*)malloc(3*rpdata->id_list->n*sizeof(double)); + double* temptemp=(double*) rpdata->container; + *temptemp=CONST_UNITITIALIZED; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -482,15 +552,17 @@ int tclcommand_observable_radial_flux_density_profile(Tcl_Interp* interp, int ar int tclcommand_observable_flux_density_profile(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs){ int temp; profile_data* pdata; - obs->fun = &observable_flux_density_profile; - if (! tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) == TCL_OK ) + obs->calculate=&observable_calc_flux_density_profile; + obs->update=0; + if (tclcommand_parse_profile(interp, argc-1, argv+1, &temp, &obs->n, &pdata) != TCL_OK ) return TCL_ERROR; if (pdata->id_list==0) { Tcl_AppendResult(interp, "Error in radial_profile: particle ids/types not specified\n" , (char *)NULL); return TCL_ERROR; } - obs->args=(void*)pdata; + obs->container=(void*)pdata; obs->n=3*pdata->xbins*pdata->ybins*pdata->zbins; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; } @@ -501,11 +573,13 @@ int tclcommand_observable_lb_radial_velocity_profile(Tcl_Interp* interp, int arg #else int temp; radial_profile_data* rpdata; - obs->fun = &observable_lb_radial_velocity_profile; - if (! tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) == TCL_OK ) + obs->calculate=&observable_calc_lb_radial_velocity_profile; + obs->update=0; + if (tclcommand_parse_radial_profile(interp, argc-1, argv+1, &temp, &obs->n, &rpdata) != TCL_OK ) return TCL_ERROR; - obs->args=(void*)rpdata; + obs->container=(void*)rpdata; obs->n=3*rpdata->rbins*rpdata->phibins*rpdata->zbins; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; #endif @@ -515,11 +589,13 @@ int tclcommand_observable_particle_currents(Tcl_Interp* interp, int argc, char** #ifdef ELECTROSTATICS int temp; IntList* ids; - obs->fun = &observable_particle_currents; - if (! parse_id_list(interp, argc-1, argv+1, &temp, &ids) == TCL_OK ) + obs->calculate=&observable_calc_particle_currents; + obs->update=0; + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->args=(void*)ids; + obs->container=(void*)ids; obs->n=3*ids->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; #else @@ -533,11 +609,13 @@ int tclcommand_observable_currents(Tcl_Interp* interp, int argc, char** argv, in #ifdef ELECTROSTATICS int temp; IntList* ids; - obs->fun = &observable_currents; - if (! parse_id_list(interp, argc-1, argv+1, &temp, &ids) == TCL_OK ) + obs->calculate=&observable_calc_currents; + obs->update=0; + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->args=(void*)ids; + obs->container=(void*)ids; obs->n=3; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; #else @@ -550,11 +628,13 @@ int tclcommand_observable_dipole_moment(Tcl_Interp* interp, int argc, char** arg #ifdef ELECTROSTATICS int temp; IntList* ids; - obs->fun = &observable_dipole_moment; - if (! parse_id_list(interp, argc-1, argv+1, &temp, &ids) == TCL_OK ) + obs->calculate=&observable_calc_dipole_moment; + obs->update=0; + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids) != TCL_OK ) return TCL_ERROR; - obs->args=(void*)ids; + obs->container=(void*)ids; obs->n=3; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); *change=1+temp; return TCL_OK; #else @@ -563,36 +643,38 @@ int tclcommand_observable_dipole_moment(Tcl_Interp* interp, int argc, char** arg #endif } -//int tclcommand_observable_structure_factor(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { -// int order; -// int* order_p; -// -//// Tcl_AppendResult(interp, "Structure Factor not available yet!!", (char *)NULL); -//// return TCL_ERROR; -// if (argc > 1 && ARG1_IS_I(order)) { -// obs->fun = &observable_structure_factor; -// order_p=malloc(sizeof(int)); -// *order_p=order; -// obs->args=(void*) order_p; -// int order2,i,j,k,l,n ; -// order2=order*order; -// l=0; -// // lets counter the number of entries for the DSF -// for(i=-order; i<=order; i++) -// for(j=-order; j<=order; j++) -// for(k=-order; k<=order; k++) { -// n = i*i + j*j + k*k; -// if ((n<=order2) && (n>=1)) -// l=l+2; -// } -// obs->n=l; -// *change=2; -// return TCL_OK; -// } else { -// sf_print_usage(interp); -// return TCL_ERROR; -// } -//} +int tclcommand_observable_structure_factor(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { + int order; + int* order_p; + +// Tcl_AppendResult(interp, "Structure Factor not available yet!!", (char *)NULL); +// return TCL_ERROR; + if (argc > 1 && ARG1_IS_I(order)) { + obs->calculate=&observable_calc_structure_factor; + order_p=(int*)malloc(sizeof(int)); + *order_p=order; + obs->container=(void*) order_p; + int order2,i,j,k,l,n ; + order2=order*order; + l=0; + // lets counter the number of entries for the DSF + for(i=-order; i<=order; i++) + for(j=-order; j<=order; j++) + for(k=-order; k<=order; k++) { + n = i*i + j*j + k*k; + if (n<=order2){ + l=l+2; + } + } + obs->n=l; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); + *change=2; + return TCL_OK; + } else { + sf_print_usage(interp); + return TCL_ERROR; + } +} // FIXME this is the old implementation of structure factor (before observables and correlations were strictly separated) //int parse_structure_factor (Tcl_Interp* interp, int argc, char** argv, int* change, void** A_args, int *tau_lin_p, double *tau_max_p, double* delta_t_p) { @@ -700,11 +782,12 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar IntList *ids1, *ids2; int temp; double cutoff; - obs->fun = &observable_interacts_with; + obs->calculate=&observable_calc_interacts_with; + obs->update=0; ids1=(IntList*)malloc(sizeof(IntList)); ids2=(IntList*)malloc(sizeof(IntList)); iw_params* iw_params_p=(iw_params*) malloc(sizeof(iw_params)); - if (! parse_id_list(interp, argc-1, argv+1, &temp, &ids1) == TCL_OK ) { + if (parse_id_list(interp, argc-1, argv+1, &temp, &ids1) != TCL_OK ) { free(ids1); free(ids2); free(iw_params_p); @@ -713,7 +796,7 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar iw_params_p=(iw_params*)malloc(sizeof(iw_params)); iw_params_p->ids1=ids1; *change=1+temp; - if (! parse_id_list(interp, argc-3, argv+3, &temp, &ids2) == TCL_OK ) { + if (parse_id_list(interp, argc-3, argv+3, &temp, &ids2) != TCL_OK ) { free(ids1); free(ids2); free(iw_params_p); @@ -722,7 +805,7 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar *change+=temp; iw_params_p->ids2=ids2; if ( argc < 5 || !ARG_IS_D(5,cutoff)) { - Tcl_AppendResult(interp, "aUsage: analyze correlation ... interacts_with id_list1 id_list2 cutoff", (char *)NULL); + Tcl_AppendResult(interp, "Usage: analyze correlation ... interacts_with id_list1 id_list2 cutoff", (char *)NULL); free(ids1); free(ids2); free(iw_params_p); @@ -730,11 +813,40 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar } *change+=1; iw_params_p->cutoff=cutoff; - obs->args=(void*)iw_params_p; + obs->container=(void*)iw_params_p; obs->n=ids1->n; // number of ids from the 1st argument + obs->last_value=(double*)malloc(obs->n*sizeof(double)); return TCL_OK; } +int tclcommand_observable_average(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { + int reference_observable; + if (argc < 2) { + Tcl_AppendResult(interp, "observable new average ", (char *)NULL); + return TCL_ERROR; + } + if (!ARG_IS_I(1,reference_observable)) { + Tcl_AppendResult(interp, "observable new average ", (char *)NULL); + return TCL_ERROR; + } + if (reference_observable >= n_observables) { + Tcl_AppendResult(interp, "The reference observable does not exist.", (char *)NULL); + return TCL_ERROR; + } + observable_average_container* container=(observable_average_container*)malloc(sizeof(observable_average_container)); + container->reference_observable = observables[reference_observable]; + container->n_sweeps = 0; + obs->n = container->reference_observable->n; + obs->last_value=(double*)malloc(obs->n*sizeof(double)); + for (int i=0; in; i++) + obs->last_value[i] = 0; + + obs->container=container; + obs->update=&observable_update_average; + obs->calculate=0; + + return TCL_OK; +} @@ -779,7 +891,10 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar #define REGISTER_OBSERVABLE(name,parser,id) \ if (ARG_IS_S(2,#name)) { \ - observables[id]=(observable*)malloc(sizeof(observable)); \ + observables[id]=(s_observable*)malloc(sizeof(observable)); \ + observable_init(observables[id]); \ + observables[id]->obs_name = (char*)malloc((1+strlen(#name))*sizeof(char)); \ + strcpy(observables[id]->obs_name,#name); \ if (parser(interp, argc-2, argv+2, &temp, observables[n_observables]) ==TCL_OK) { \ n_observables++; \ argc-=1+temp; \ @@ -788,6 +903,7 @@ int tclcommand_observable_interacts_with(Tcl_Interp* interp, int argc, char** ar Tcl_AppendResult(interp,buffer,(char *)NULL);\ return TCL_OK; \ } else { \ + free(observables[n_observables]->obs_name);\ free(observables[n_observables]);\ Tcl_AppendResult(interp, "\nError parsing observable ", #name, "\n", (char *)NULL); \ return TCL_ERROR; \ @@ -826,8 +942,12 @@ int tclcommand_observable(ClientData data, Tcl_Interp *interp, int argc, char ** if (id==n_observables) observables=(observable**) realloc(observables, (n_observables+1)*sizeof(observable*)); + + REGISTER_OBSERVABLE(average, tclcommand_observable_average,id); REGISTER_OBSERVABLE(particle_velocities, tclcommand_observable_particle_velocities,id); + REGISTER_OBSERVABLE(particle_body_velocities, tclcommand_observable_particle_body_velocities,id); REGISTER_OBSERVABLE(particle_angular_momentum, tclcommand_observable_particle_angular_momentum,id); + REGISTER_OBSERVABLE(particle_body_angular_momentum, tclcommand_observable_particle_body_angular_momentum,id); REGISTER_OBSERVABLE(particle_forces, tclcommand_observable_particle_forces,id); REGISTER_OBSERVABLE(com_velocity, tclcommand_observable_com_velocity,id); REGISTER_OBSERVABLE(com_position, tclcommand_observable_com_position,id); @@ -838,7 +958,7 @@ int tclcommand_observable(ClientData data, Tcl_Interp *interp, int argc, char ** REGISTER_OBSERVABLE(particle_currents, tclcommand_observable_particle_currents,id); REGISTER_OBSERVABLE(currents, tclcommand_observable_currents,id); REGISTER_OBSERVABLE(dipole_moment, tclcommand_observable_dipole_moment,id); -// REGISTER_OBSERVABLE(structure_factor, tclcommand_observable_structure_factor,id); + REGISTER_OBSERVABLE(structure_factor, tclcommand_observable_structure_factor,id); REGISTER_OBSERVABLE(interacts_with, tclcommand_observable_interacts_with,id); // REGISTER_OBSERVABLE(obs_nothing, tclcommand_observable_obs_nothing,id); // REGISTER_OBSERVABLE(flux_profile, tclcommand_observable_flux_profile,id); @@ -863,6 +983,28 @@ int tclcommand_observable(ClientData data, Tcl_Interp *interp, int argc, char ** if (argc > 2 && ARG_IS_S(2,"print")) { return tclcommand_observable_print(interp, argc-3, argv+3, &temp, observables[n]); } + if (argc > 2 && ARG_IS_S(2,"update")) { + return tclcommand_observable_update(interp, argc-3, argv+3, &temp, observables[n]); + } + if (argc > 2 && ARG_IS_S(2,"reset") && observables[n]->update == observable_update_average) { + observable_reset_average(observables[n]); + return TCL_OK; + } + if (argc > 2 && ARG_IS_S(2,"autoupdate") ) { + if (argc > 3 && ARG_IS_D(3, observables[n]->autoupdate_dt) ) { + if (observables[n]->autoupdate_dt < 1e-5) { + observables[n]->autoupdate=0; + } else { + observables[n]->autoupdate=1; + observables_autoupdate = 1; + } + return TCL_OK; + } else { + Tcl_AppendResult(interp, "Usage observable autoupdate
    \n", (char *)NULL); + return TCL_ERROR; + } + + } } Tcl_AppendResult(interp, "Unknown observable ", argv[1] ,"\n", (char *)NULL); return TCL_ERROR; @@ -873,7 +1015,7 @@ int tclcommand_observable(ClientData data, Tcl_Interp *interp, int argc, char ** static int convert_types_to_ids(IntList * type_list, IntList * id_list){ int i,j,n_ids=0,flag; sortPartCfg(); - for ( i = 0; izbins=1; while (argc>0) { if (ARG0_IS_S("ids") || ARG0_IS_S("types") || ARG0_IS_S("all")) { - if (!parse_id_list(interp, argc, argv, &temp, &pdata->id_list )==TCL_OK) { + if (parse_id_list(interp, argc, argv, &temp, &pdata->id_list ) != TCL_OK) { Tcl_AppendResult(interp, "Error reading profile: Error parsing particle id information\n" , (char *)NULL); return TCL_ERROR; } else { @@ -1128,7 +1270,7 @@ int tclcommand_parse_radial_profile(Tcl_Interp* interp, int argc, char** argv, i } while (argc>0) { if (ARG0_IS_S("ids") || ARG0_IS_S("types") || ARG0_IS_S("all")) { - if (!parse_id_list(interp, argc, argv, &temp, &pdata->id_list )==TCL_OK) { + if (parse_id_list(interp, argc, argv, &temp, &pdata->id_list ) != TCL_OK) { Tcl_AppendResult(interp, "Error reading profile: Error parsing particle id information\n" , (char *)NULL); return TCL_ERROR; } else { @@ -1264,43 +1406,45 @@ int tclcommand_parse_radial_profile(Tcl_Interp* interp, int argc, char** argv, i int tclcommand_observable_print(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { char buffer[TCL_DOUBLE_SPACE]; - double* values=(double*)malloc(obs->n*sizeof(double)); - if ( (*obs->fun)(obs->args, values, obs->n) ) { - Tcl_AppendResult(interp, "\nFailed to compute observable tclcommand\n", (char *)NULL ); + if ( observable_calculate(obs) ) { + Tcl_AppendResult(interp, "\nFailed to compute observable ", obs->obs_name, "\n", (char *)NULL ); return TCL_ERROR; } if (argc==0) { for (int i = 0; in; i++) { - Tcl_PrintDouble(interp, values[i], buffer); + Tcl_PrintDouble(interp, obs->last_value[i], buffer); Tcl_AppendResult(interp, buffer, " ", (char *)NULL ); } } else if (argc>0 && ARG0_IS_S("formatted")) { - tclcommand_observable_print_formatted(interp, argc-1, argv+1, change, obs, values); + tclcommand_observable_print_formatted(interp, argc-1, argv+1, change, obs, obs->last_value); } else { Tcl_AppendResult(interp, "Unknown argument to observable print: ", argv[0], "\n", (char *)NULL ); return TCL_ERROR; } - free(values); return TCL_OK; } int tclcommand_observable_print_formatted(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs, double* values) { + + if (obs->update == (&observable_update_average)) + obs = ((observable_average_container*)obs->container)->reference_observable; + if (0) { #ifdef LB - } else if (obs->fun == (&observable_lb_velocity_profile)) { + } else if (obs->calculate == (&observable_calc_lb_velocity_profile)) { return tclcommand_observable_print_profile_formatted(interp, argc, argv, change, obs, values, 3, 0); #endif - } else if (obs->fun == (&observable_density_profile)) { + } else if (obs->calculate == (&observable_calc_density_profile)) { return tclcommand_observable_print_profile_formatted(interp, argc, argv, change, obs, values, 1, 1); #ifdef LB - } else if (obs->fun == (&observable_lb_radial_velocity_profile)) { + } else if (obs->calculate == (&observable_calc_lb_radial_velocity_profile)) { return tclcommand_observable_print_radial_profile_formatted(interp, argc, argv, change, obs, values, 3, 0); #endif - } else if (obs->fun == (&observable_radial_density_profile)) { + } else if (obs->calculate == (&observable_calc_radial_density_profile)) { return tclcommand_observable_print_radial_profile_formatted(interp, argc, argv, change, obs, values, 1, 1); - } else if (obs->fun == (&observable_radial_flux_density_profile)) { + } else if (obs->calculate == (&observable_calc_radial_flux_density_profile)) { return tclcommand_observable_print_radial_profile_formatted(interp, argc, argv, change, obs, values, 3, 1); - } else if (obs->fun == (&observable_flux_density_profile)) { + } else if (obs->calculate == (&observable_calc_flux_density_profile)) { return tclcommand_observable_print_profile_formatted(interp, argc, argv, change, obs, values, 3, 1); } else { Tcl_AppendResult(interp, "Observable can not be printed formatted\n", (char *)NULL ); @@ -1309,14 +1453,21 @@ int tclcommand_observable_print_formatted(Tcl_Interp* interp, int argc, char** a } +int tclcommand_observable_update(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs) { + if ( observable_update(obs) ) { + Tcl_AppendResult(interp, "\nFailed to update observable\n", (char *)NULL ); + return TCL_ERROR; + } + return TCL_OK; +} int sf_print_usage(Tcl_Interp* interp) { Tcl_AppendResult(interp, "\nusage: structure_factor order delta_t tau_max tau_lin", (char *)NULL); return TCL_ERROR; } -static int observable_tclcommand(void* _container, double* A, unsigned int n_A) { - Observable_Tclcommand_Arg_Container* container = (Observable_Tclcommand_Arg_Container*) _container; +int observable_calc_tclcommand(observable* self) { + Observable_Tclcommand_Arg_Container* container = (Observable_Tclcommand_Arg_Container*) self->container; Tcl_Interp* interp = (Tcl_Interp*) container->interp; int error = Tcl_Eval(interp, container->command); if (error) { @@ -1324,15 +1475,16 @@ static int observable_tclcommand(void* _container, double* A, unsigned int n_A) } char* result = Tcl_GetStringResult(interp); char* token; - unsigned counter=0; + int counter=0; + double* A=self->last_value; token = strtok(result, " "); - while (token != NULL && counter < n_A) { + while ( token != NULL && counter < self->n) { A[counter] = atof(token); token = strtok(NULL, " "); counter++; } Tcl_ResetResult(interp); - if (counter != n_A) { + if (counter != self->n) { return 1; } return 0; diff --git a/src/tcl/statistics_observable_tcl.hpp b/src/tcl/statistics_observable_tcl.hpp index 1644ceabd7c..94a2a5e0318 100644 --- a/src/tcl/statistics_observable_tcl.hpp +++ b/src/tcl/statistics_observable_tcl.hpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project This file is part of ESPResSo. @@ -27,6 +27,7 @@ int tclcommand_observable(ClientData data, Tcl_Interp *interp, int argc, char ** int tclcommand_observable_print_formatted(Tcl_Interp* interp, int argc, char** argv, int* change, observable* obs, double* values); int parse_id_list(Tcl_Interp* interp, int argc, char** argv, int* change, IntList** ids ); +int observable_calc_tclcommand(observable* self); typedef struct { Tcl_Interp* interp; diff --git a/src/tcl/statistics_tcl.cpp b/src/tcl/statistics_tcl.cpp index 95e8424a58f..dabdeaafd12 100644 --- a/src/tcl/statistics_tcl.cpp +++ b/src/tcl/statistics_tcl.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2010,2011,2012,2013 The ESPResSo project + Copyright (C) 2010,2011,2012,2013,2014 The ESPResSo project Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Max-Planck-Institute for Polymer Research, Theory Group @@ -17,11 +17,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ -/** \file statistics.c + */ +/** \file statistics.cpp This is the place for analysis (so far...). - Implementation of statistics.h -*/ + Implementation of statistics.hpp + */ #include #include #include @@ -47,2109 +47,2267 @@ #include "initialize.hpp" #include "statistics_chain_tcl.hpp" -/** Set the topology. See \ref topology_tcl.c */ +/** Set the topology. See \ref topology_tcl.cpp */ int tclcommand_analyze_parse_set(Tcl_Interp *interp, int argc, char **argv); -/** write out energy. See \ref energy_tcl.c */ +/** write out energy. See \ref energy_tcl.cpp */ int tclcommand_analyze_parse_and_print_energy(Tcl_Interp *interp, int argc, char **argv); /** Variables for measuring the compressibility from volume fluctuations. Will be used by \ref parse_Vkappa exclusively. */ typedef struct { - /** sum of all the considered volumes resp. volumes squared so far */ - double Vk1; double Vk2; - /** amount of considered volumes so far */ - double avk; + /** sum of all the considered volumes resp. volumes squared so far */ + double Vk1; + double Vk2; + /** amount of considered volumes so far */ + double avk; } Vkappa_struct; -Vkappa_struct Vkappa = { 0.0, 0.0, 0.0 }; +Vkappa_struct Vkappa = {0.0, 0.0, 0.0}; /**************************************************************************************** * helper functions ****************************************************************************************/ - - /** Parses a reference point, i.e. either three doubles representing a position, or a particle id. */ static int tclcommand_analyze_parse_reference_point(Tcl_Interp *interp, int *argc, char ***argv, - double pos[3], int *pid) -{ - *pid = -1; - - if (*argc >= 3 && - (Tcl_GetDouble(interp, (*argv)[0], &pos[0]) != TCL_ERROR) && - (Tcl_GetDouble(interp, (*argv)[1], &pos[1]) != TCL_ERROR) && - (Tcl_GetDouble(interp, (*argv)[2], &pos[2]) != TCL_ERROR)) { - /* Found three doubles representing a position. */ - (*argc) -= 3; - (*argv) += 3; - return TCL_OK; - } - /* else */ - if (*argc >= 1 && - (Tcl_GetInt(interp, (*argv)[0], pid) != TCL_ERROR)) { - /* Found a single integer representing a particle id. */ - Particle ref; - - if (get_particle_data(*pid, &ref) != TCL_OK) { - Tcl_AppendResult(interp, "reference particle does not exist", (char *)NULL); - return TCL_ERROR; - } - pos[0] = ref.r.p[0]; - pos[1] = ref.r.p[1]; - pos[2] = ref.r.p[2]; - - (*argc)--; - (*argv)++; - - free_particle(&ref); - return TCL_OK; - } - /* else */ - return TCL_ERROR; + double pos[3], int *pid) { + *pid = -1; + + if (*argc >= 3 && + (Tcl_GetDouble(interp, (*argv)[0], &pos[0]) != TCL_ERROR) && + (Tcl_GetDouble(interp, (*argv)[1], &pos[1]) != TCL_ERROR) && + (Tcl_GetDouble(interp, (*argv)[2], &pos[2]) != TCL_ERROR)) { + /* Found three doubles representing a position. */ + (*argc) -= 3; + (*argv) += 3; + return TCL_OK; + } + /* else */ + if (*argc >= 1 && + (Tcl_GetInt(interp, (*argv)[0], pid) != TCL_ERROR)) { + /* Found a single integer representing a particle id. */ + Particle ref; + + if (get_particle_data(*pid, &ref) != TCL_OK) { + Tcl_AppendResult(interp, "reference particle does not exist", (char *) NULL); + return TCL_ERROR; + } + pos[0] = ref.r.p[0]; + pos[1] = ref.r.p[1]; + pos[2] = ref.r.p[2]; + + (*argc)--; + (*argv)++; + + free_particle(&ref); + return TCL_OK; + } + /* else */ + return TCL_ERROR; } -void tclcommand_analyze_print_vel_distr(Tcl_Interp *interp, int type,int bins,double given_max) -{ - int i,j,p_count,dist_count,ind; - double min,max,bin_width,inv_bin_width,com[3],vel; - long distribution[bins]; - char buffer[2*TCL_DOUBLE_SPACE+TCL_INTEGER_SPACE+256]; - - max=given_max*time_step; - min=-given_max*time_step; - p_count=0; - for(i=0; i vel ){min = vel;} - if (max < vel ){max = vel;} +void tclcommand_analyze_print_vel_distr(Tcl_Interp *interp, int type, int bins, double given_max) { + int i, j, p_count, dist_count, ind; + double min, max, bin_width, inv_bin_width, com[3], vel; + long distribution[bins]; + char buffer[2 * TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE + 256]; + + max = given_max*time_step; + min = -given_max*time_step; + p_count = 0; + for (i = 0; i < bins; i++) { + distribution[i] = 0; + } + + centermass_vel(type, com); + + for (i = 0; i < n_part; i++) { + if (partCfg[i].p.type == type) { + p_count++; + for (j = 0; j < 3; j++) { + vel = partCfg[i].m.v[j] - com[j]; + if (min > vel) { + min = vel; + } + if (max < vel) { + max = vel; + } + } } - } - } - - if (p_count==0) {return;} - - if ( (-min) > max ) { - max = -min; - } - else{ - min = -max; - } - - bin_width = (max-min) / (double)bins; - inv_bin_width = 1.0 / bin_width; - dist_count=0; - for (i=0;i max) { + max = -min; + } else { + min = -max; + } + + bin_width = (max - min) / (double) bins; + inv_bin_width = 1.0 / bin_width; + dist_count = 0; + for (i = 0; i < n_part; i++) { + if (partCfg[i].p.type == type) { + for (j = 0; j < 3; j++) { + vel = partCfg[i].m.v[j] - com[j]; + ind = (int) ((vel - min) * inv_bin_width); + distribution[ind]++; + dist_count++; + } } - } - } - - vel=min + bin_width/2.0; - Tcl_AppendResult(interp, " {\n", (char *)NULL); - for(i=0; i 0) - { - if ( ARG0_IS_S("-molecule") ) { - flag = FOLD_MOLS; - change = 1; - } - - if ( ARG0_IS_S("shift") ) { - if ( !ARG_IS_D(1,shift[0]) || !ARG_IS_D(2,shift[1]) || !ARG_IS_D(3,shift[2]) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze get_folded_positions [-molecule] [shift ]", (char *)NULL); - return (TCL_ERROR); - } - change = 4; - } - argc -= change; - argv += change; - STAT_TRACE(fprintf(stderr,"%d,argc = %d \n",this_node, argc)); - } - - freePartCfg(); - updatePartCfg(WITH_BONDS); - if (!sortPartCfg()) { - char *errtxt = runtime_error(128); - ERROR_SPRINTF(errtxt, "{058 could not sort partCfg, particles have to start at 0 and have consecutive identities} "); - return TCL_ERROR; - } - coord = (float*)malloc(n_total_particles*3*sizeof(float)); - /* Construct the array coord*/ - for (i = 0; i < n_total_particles; i++) { - int dummy[3] = {0,0,0}; - double tmpCoord[3]; - tmpCoord[0] = partCfg[i].r.p[0]; - tmpCoord[1] = partCfg[i].r.p[1]; - tmpCoord[2] = partCfg[i].r.p[2]; - if (flag == NONE) { // perform folding by particle - fold_position(tmpCoord, dummy); - } - coord[i*3 ] = (float)(tmpCoord[0]); - coord[i*3 + 1] = (float)(tmpCoord[1]); - coord[i*3 + 2] = (float)(tmpCoord[2]); - } - - - // Use information from the analyse set command to fold chain molecules - if ( flag == FOLD_MOLS ) { - if( analyze_fold_molecules(coord, shift) != TCL_OK ){ - Tcl_AppendResult(interp, "could not fold chains: \"analyze set chains \" must be used first", - (char *) NULL); - return (TCL_ERROR);; - } - } - - // Tcl_AppendResult(interp, "{ ", (char *)NULL); - for ( i = 0 ; i < n_total_particles ; i++) { + STAT_TRACE(fprintf(stderr, "%d,parsing get_folded_positions \n", this_node)); + while (argc > 0) { + if (ARG0_IS_S("-molecule")) { + flag = FOLD_MOLS; + change = 1; + } + + if (ARG0_IS_S("shift")) { + if (!ARG_IS_D(1, shift[0]) || !ARG_IS_D(2, shift[1]) || !ARG_IS_D(3, shift[2])) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze get_folded_positions [-molecule] [shift ]", (char *) NULL); + return (TCL_ERROR); + } + change = 4; + } + argc -= change; + argv += change; + STAT_TRACE(fprintf(stderr, "%d,argc = %d \n", this_node, argc)); + } + + freePartCfg(); + updatePartCfg(WITH_BONDS); + if (!sortPartCfg()) { + ostringstream msg; + msg <<"could not sort partCfg, particles have to start at 0 and have consecutive identities"; + runtimeError(msg); + return TCL_ERROR; + } + coord = (float*) malloc(n_part * 3 * sizeof (float)); +#ifdef LEES_EDWARDS + velocities = (double *)malloc(n_part*3*sizeof(double)); +#endif + /* Construct the array coord*/ + for (i = 0; i < n_part; i++) { + int dummy[3] = {0, 0, 0}; + double tmpCoord[3]; +#ifdef LEES_EDWARDS + v_le[0] = partCfg[i].m.v[0]; + v_le[1] = partCfg[i].m.v[1]; + v_le[2] = partCfg[i].m.v[2]; +#endif + tmpCoord[0] = partCfg[i].r.p[0]; + tmpCoord[1] = partCfg[i].r.p[1]; + tmpCoord[2] = partCfg[i].r.p[2]; + if (flag == NONE) { // perform folding by particle +#ifdef LEES_EDWARDS + fold_position(tmpCoord, v_le, dummy); +#else + fold_position(tmpCoord, dummy); +#endif + } + coord[i * 3 ] = (float) (tmpCoord[0]); + coord[i * 3 + 1] = (float) (tmpCoord[1]); + coord[i * 3 + 2] = (float) (tmpCoord[2]); +#ifdef LEES_EDWARDS + velocities[i*3] = v_le[0]; + velocities[i*3+1] = v_le[1]; + velocities[i*3+2] = v_le[2]; +#endif + } + + + // Use information from the analyse set command to fold chain molecules + if (flag == FOLD_MOLS) { + if (analyze_fold_molecules(coord, shift) != TCL_OK) { + Tcl_AppendResult(interp, "could not fold chains: \"analyze set chains \" must be used first", + (char *) NULL); + return (TCL_ERROR); + ; + } + } + + // Tcl_AppendResult(interp, "{ ", (char *)NULL); + for (i = 0; i < n_part; i++) { +#ifdef LEES_EDWARDS + sprintf(buffer, " { %d %f %f %f %f %f %f } ", partCfg[i].p.identity , + coord[i*3] , coord[i*3+1] , coord[i*3+2] , + velocities[i*3] , velocities[i*3+1] , velocities[i*3+2] ); +#else sprintf(buffer, " { %d %f %f %f } ", partCfg[i].p.identity , coord[i*3] , coord[i*3+1] , coord[i*3+2] ); - Tcl_AppendResult(interp, buffer , (char *)NULL); - } - // Tcl_AppendResult(interp, "} ", (char *)NULL); +#endif + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + // Tcl_AppendResult(interp, "} ", (char *)NULL); - return TCL_OK; + return TCL_OK; } #ifdef MODES -static int tclcommand_analyze_parse_get_lipid_orients(Tcl_Interp *interp, int argc, char **argv) -{ - char buffer[TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; - int i; - IntList l_orient; - init_intlist(&l_orient); +static int tclcommand_analyze_parse_get_lipid_orients(Tcl_Interp *interp, int argc, char **argv) { + char buffer[TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE]; + int i; + IntList l_orient; + init_intlist(&l_orient); + + STAT_TRACE(fprintf(stderr, "%d,parsing get_lipid_orients \n", this_node)); + /* Check that the grid has been set */ + if (xdir + ydir + zdir == -3) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "get_lipid_orients requires a grid. You must set grid first", (char *) NULL); + return (TCL_ERROR); + } - STAT_TRACE(fprintf(stderr,"%d,parsing get_lipid_orients \n",this_node)); - /* Check that the grid has been set */ - if ( xdir + ydir + zdir == -3 ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"get_lipid_orients requires a grid. You must set grid first", (char *)NULL); - return (TCL_ERROR); - } - - realloc_intlist(&l_orient, n_molecules); - get_lipid_orients(&l_orient); - + realloc_intlist(&l_orient, n_molecules); + get_lipid_orients(&l_orient); - Tcl_AppendResult(interp, "{ Lipid_orientations } { ", (char *)NULL); - for ( i = 0 ; i < n_molecules ; i++) { - sprintf(buffer, "%d ", l_orient.e[i]); - Tcl_AppendResult(interp, buffer , (char *)NULL); - } - Tcl_AppendResult(interp, "} ", (char *)NULL); - realloc_intlist(&l_orient,0); + Tcl_AppendResult(interp, "{ Lipid_orientations } { ", (char *) NULL); + for (i = 0; i < n_molecules; i++) { + sprintf(buffer, "%d ", l_orient.e[i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + Tcl_AppendResult(interp, "} ", (char *) NULL); + + realloc_intlist(&l_orient, 0); - return TCL_OK; + return TCL_OK; } -static int tclcommand_analyze_parse_modes2d(Tcl_Interp *interp, int argc, char **argv) -{ - STAT_TRACE(fprintf(stderr,"%d,parsing modes2d height grid \n",this_node);) - /* 'analyze modes2d' */ - char buffer[TCL_DOUBLE_SPACE]; - int i,j; - fftw_complex* result_ht; - fftw_complex* result_th; +static int tclcommand_analyze_parse_modes2d(Tcl_Interp *interp, int argc, char **argv) { + STAT_TRACE(fprintf(stderr, "%d,parsing modes2d height grid \n", this_node);) + /* 'analyze modes2d' */ + char buffer[TCL_DOUBLE_SPACE]; + int i, j; + fftw_complex* result_ht; + fftw_complex* result_th; + + /* Check that the grid has been set */ + if (xdir + ydir + zdir == -3) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "modes2d requires a grid. You must set grid first", (char *) NULL); + return (TCL_ERROR); + } - /* Check that the grid has been set */ - if ( xdir + ydir + zdir == -3 ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"modes2d requires a grid. You must set grid first", (char *)NULL); - return (TCL_ERROR); - } - - if (n_total_particles <= 2) { - Tcl_AppendResult(interp, "(not enough particles for mode analysis)", - (char *)NULL); - return (TCL_OK); - } - - result_ht = (fftw_complex*) malloc((mode_grid_3d[ydir]/2+1)*(mode_grid_3d[xdir])*sizeof(fftw_complex)); - result_th = (fftw_complex*) malloc((mode_grid_3d[ydir]/2+1)*(mode_grid_3d[xdir])*sizeof(fftw_complex)); + if (n_part <= 2) { + Tcl_AppendResult(interp, "(not enough particles for mode analysis)", + (char *) NULL); + return (TCL_OK); + } - if (!modes2d(result_th, 0) || !modes2d(result_ht,1)) { - fprintf(stderr,"%d,mode analysis failed \n",this_node); - return TCL_ERROR; - } - else { STAT_TRACE(fprintf(stderr,"%d,mode analysis done \n",this_node));} - + result_ht = (fftw_complex*) malloc((mode_grid_3d[ydir] / 2 + 1)*(mode_grid_3d[xdir]) * sizeof (fftw_complex)); + result_th = (fftw_complex*) malloc((mode_grid_3d[ydir] / 2 + 1)*(mode_grid_3d[xdir]) * sizeof (fftw_complex)); + + if (!modes2d(result_th, 0) || !modes2d(result_ht, 1)) { + fprintf(stderr, "%d,mode analysis failed \n", this_node); + return TCL_ERROR; + } else { + STAT_TRACE(fprintf(stderr, "%d,mode analysis done \n", this_node)); + } + + + /* Output is of the form : + ht_RE ht_IM th_RE th_IM + */ + Tcl_AppendResult(interp, "{ Modes } { ", (char *) NULL); + for (i = 0; i < mode_grid_3d[xdir]; i++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (j = 0; j < mode_grid_3d[ydir] / 2 + 1; j++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + Tcl_PrintDouble(interp, FFTW_REAL(result_ht[j + i * (mode_grid_3d[ydir] / 2 + 1)]), buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + Tcl_PrintDouble(interp, FFTW_IMAG(result_ht[j + i * (mode_grid_3d[ydir] / 2 + 1)]), buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + Tcl_PrintDouble(interp, FFTW_REAL(result_th[j + i * (mode_grid_3d[ydir] / 2 + 1)]), buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + Tcl_PrintDouble(interp, FFTW_IMAG(result_th[j + i * (mode_grid_3d[ydir] / 2 + 1)]), buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " } ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + } - /* Output is of the form : - ht_RE ht_IM th_RE th_IM - */ - Tcl_AppendResult(interp, "{ Modes } { ", (char *)NULL); - for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( j = 0 ; j < mode_grid_3d[ydir]/2 + 1 ; j++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - Tcl_PrintDouble(interp,FFTW_REAL(result_ht[j+i*(mode_grid_3d[ydir]/2+1)]),buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - Tcl_PrintDouble(interp,FFTW_IMAG(result_ht[j+i*(mode_grid_3d[ydir]/2+1)]),buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - Tcl_PrintDouble(interp,FFTW_REAL(result_th[j+i*(mode_grid_3d[ydir]/2+1)]),buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - Tcl_PrintDouble(interp,FFTW_IMAG(result_th[j+i*(mode_grid_3d[ydir]/2+1)]),buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - - - Tcl_AppendResult(interp, " } ", (char *)NULL); - - free(result_ht); - free(result_th); - - return TCL_OK; + + Tcl_AppendResult(interp, " } ", (char *) NULL); + + free(result_ht); + free(result_th); + + return TCL_OK; } -static int tclcommand_analyze_parse_bilayer_set(Tcl_Interp *interp, int argc, char **argv) -{ - int change; - change = 0; - while ( argc > 0 ) { - if ( ARG0_IS_S("grid") ) { - if ( !ARG_IS_I(1,mode_grid_3d[0]) || !ARG_IS_I(2,mode_grid_3d[1]) || !ARG_IS_I(3,mode_grid_3d[2]) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_set [grid ] [straycut ]", (char *)NULL); - return (TCL_ERROR); - } - STAT_TRACE(fprintf(stderr,"%d,set has args %d,%d,%d \n",this_node,mode_grid_3d[0],mode_grid_3d[1],mode_grid_3d[2])); - change = 4; - /* Update global parameters */ - map_to_2dgrid(); - mode_grid_changed = 1; - argc -= change; - argv += change; - } - - if ( ARG0_IS_S("straycut") ) { - if ( !ARG_IS_D(1,stray_cut_off) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_set [grid ] [straycut ]", (char *)NULL); - return (TCL_ERROR); - } - STAT_TRACE(fprintf(stderr,"%d,setgrid has args %d,%d,%d \n",this_node,mode_grid_3d[0],mode_grid_3d[1],mode_grid_3d[2])); - change = 2; - argc -= change; - argv += change; - } - - } - return TCL_OK; +static int tclcommand_analyze_parse_bilayer_set(Tcl_Interp *interp, int argc, char **argv) { + int change; + change = 0; + while (argc > 0) { + if (ARG0_IS_S("grid")) { + if (!ARG_IS_I(1, mode_grid_3d[0]) || !ARG_IS_I(2, mode_grid_3d[1]) || !ARG_IS_I(3, mode_grid_3d[2])) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_set [grid ] [straycut ]", (char *) NULL); + return (TCL_ERROR); + } + STAT_TRACE(fprintf(stderr, "%d,set has args %d,%d,%d \n", this_node, mode_grid_3d[0], mode_grid_3d[1], mode_grid_3d[2])); + change = 4; + /* Update global parameters */ + map_to_2dgrid(); + mode_grid_changed = 1; + argc -= change; + argv += change; + } + + if (ARG0_IS_S("straycut")) { + if (!ARG_IS_D(1, stray_cut_off)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_set [grid ] [straycut ]", (char *) NULL); + return (TCL_ERROR); + } + STAT_TRACE(fprintf(stderr, "%d,setgrid has args %d,%d,%d \n", this_node, mode_grid_3d[0], mode_grid_3d[1], mode_grid_3d[2])); + change = 2; + argc -= change; + argv += change; + } + + } + return TCL_OK; } +static int tclcommand_analyze_parse_radial_density_map(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze radial density profile ' */ + char buffer[TCL_DOUBLE_SPACE + 256]; + int i, j, k; + IntList beadtypes; + double rotation_axis[3]; + double rotation_center[3]; + int xbins, ybins, thetabins; + double xrange, yrange; + DoubleList *density_profile = NULL; + DoubleList *density_map = NULL; + thetabins = 0; + init_intlist(&beadtypes); + alloc_intlist(&beadtypes, 1); + + + + if (!ARG_IS_I(0, xbins) || !ARG_IS_I(1, ybins) || !ARG_IS_D(2, xrange) || !ARG_IS_D(3, yrange)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "first 4 args usage: analyze radial_density_map {} {} { { } [thetabins]", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 4; + argv += 4; + } + + if (!ARG_IS_D(0, rotation_axis[0]) || !ARG_IS_D(1, rotation_axis[1]) || !ARG_IS_D(2, rotation_axis[2])) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "rotation_axis usage: analyze radial_density_map {} {} { { } [thetabins]", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 3; + argv += 3; + } + + if (!ARG_IS_D(0, rotation_center[0]) || !ARG_IS_D(1, rotation_center[1]) || !ARG_IS_D(2, rotation_center[2])) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "rotation_center usage: analyze radial_density_map {} {} { { } [thetabins]", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 3; + argv += 3; + } -static int tclcommand_analyze_parse_radial_density_map(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze radial density profile ' */ - char buffer[TCL_DOUBLE_SPACE+256]; - int i,j,k; - IntList beadtypes; - double rotation_axis[3]; - double rotation_center[3]; - int xbins,ybins,thetabins; - double xrange,yrange; - DoubleList *density_profile = NULL; - DoubleList *density_map = NULL; - thetabins = 0; - init_intlist(&beadtypes); - alloc_intlist(&beadtypes,1); + if (!ARG_IS_INTLIST(0, beadtypes)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, " beadtypes usage: analyze radial_density_map {} {} { { } [thetabins] ", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 1; + argv += 1; + } + /* Now check for the optional thetabins argument */ + if (argc > 0) { + if (!ARG_IS_I(0, thetabins)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "thetabins usage: analyze radial_density_map {} {} { { } [thetabins] ", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 1; + argv += 1; + } + } - if ( !ARG_IS_I(0,xbins) || !ARG_IS_I(1,ybins) || !ARG_IS_D(2,xrange) || !ARG_IS_D(3,yrange) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"first 4 args usage: analyze radial_density_map {} {} { { } [thetabins]", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 4; - argv += 4; - } - - if ( !ARG_IS_D(0,rotation_axis[0]) || !ARG_IS_D(1,rotation_axis[1]) || !ARG_IS_D(2,rotation_axis[2]) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"rotation_axis usage: analyze radial_density_map {} {} { { } [thetabins]", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 3; - argv += 3; - } - - if ( !ARG_IS_D(0,rotation_center[0] ) || !ARG_IS_D(1,rotation_center[1] ) || !ARG_IS_D(2,rotation_center[2] ) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"rotation_center usage: analyze radial_density_map {} {} { { } [thetabins]", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 3; - argv += 3; - } - - if ( !ARG_IS_INTLIST(0,beadtypes)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp," beadtypes usage: analyze radial_density_map {} {} { { } [thetabins] ", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 1; - argv += 1; - } - - /* Now check for the optional thetabins argument */ - if ( argc > 0 ) { - if ( !ARG_IS_I(0,thetabins)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"thetabins usage: analyze radial_density_map {} {} { { } [thetabins] ", (char *)NULL); - return (TCL_ERROR); + printf("nbtypes %d \n", beadtypes.max); + printf("bt %d \n", beadtypes.e[0]); + printf("bins %d %d %d %f %f \n", xbins, ybins, thetabins, xrange, yrange); + printf("rotationaxis %f %f %f \n", rotation_axis[0], rotation_axis[1], rotation_axis[2]); + printf("center %f %f %f \n", rotation_center[0], rotation_center[1], rotation_center[2]); + + /* allocate memory for the profile if necessary */ + if (thetabins > 0) { + density_profile = (DoubleList*) malloc(beadtypes.max * sizeof (DoubleList)); + if (density_profile) { + for (i = 0; i < beadtypes.max; i++) { + init_doublelist(&density_profile[i]); + alloc_doublelist(&density_profile[i], thetabins); + for (j = 0; j < thetabins; j++) { + density_profile[i].e[j] = 0.0; + } + } + } else { + Tcl_AppendResult(interp, "could not allocate memory for density_profile", (char *) NULL); + return (TCL_ERROR); + } + } + /* Allocate a doublelist of bins for each beadtype so that we + can keep track of beads separately */ + density_map = (DoubleList*) malloc(beadtypes.max * sizeof (DoubleList)); + if (density_map) { + /* Initialize all the subprofiles in density profile */ + for (i = 0; i < beadtypes.max; i++) { + // printf("initializing for beadtype %d and i: %d \n",beadtypes.e[i],i); + init_doublelist(&density_map[i]); + alloc_doublelist(&density_map[i], xbins * ybins); + if (!density_map[i].e) { + Tcl_AppendResult(interp, "could not allocate memory for density_map", (char *) NULL); + return (TCL_ERROR); + } else { + for (j = 0; j < xbins * ybins; j++) { + // printf("j: %d max: %d",j,density_map[i].max); + density_map[i].e[j] = 0.0; + } + + } + // printf("done initializing at i: %d j: %d\n",i,j); + } } else { - argc -= 1; - argv += 1; + Tcl_AppendResult(interp, "could not allocate memory for density_map", (char *) NULL); + return (TCL_ERROR); } - } - - printf("nbtypes %d \n",beadtypes.max); - printf("bt %d \n",beadtypes.e[0]); - printf("bins %d %d %d %f %f \n",xbins,ybins,thetabins,xrange,yrange); - printf("rotationaxis %f %f %f \n",rotation_axis[0],rotation_axis[1],rotation_axis[2]); - printf("center %f %f %f \n",rotation_center[0],rotation_center[1],rotation_center[2]); - - /* allocate memory for the profile if necessary */ - if (thetabins > 0 ) { - density_profile = (DoubleList*) malloc(beadtypes.max*sizeof(DoubleList)); + // printf("about to calculate profile \n"); + if (calc_radial_density_map(xbins, ybins, thetabins, xrange, yrange, rotation_axis, rotation_center, &beadtypes, density_map, density_profile) != TCL_OK) { + Tcl_AppendResult(interp, "Error calculating radial density profile ", (char *) NULL); + return TCL_ERROR; + } + + // printf("done calculating profile \n"); + + Tcl_AppendResult(interp, "{ RadialDensityMap { ", (char *) NULL); + for (i = 0; i < beadtypes.n; i++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (j = 0; j < xbins; j++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (k = 0; k < ybins; k++) { + Tcl_PrintDouble(interp, density_map[i].e[j * ybins + k], buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + Tcl_AppendResult(interp, " } ", (char *) NULL); + if (thetabins > 0) { + Tcl_AppendResult(interp, "{ RadialDensityThetaProfile { ", (char *) NULL); + for (i = 0; i < beadtypes.n; i++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (j = 0; j < thetabins; j++) { + Tcl_PrintDouble(interp, density_profile[i].e[j], buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + Tcl_AppendResult(interp, " } ", (char *) NULL); + + /* Dealloc the density profile*/ + for (i = 0; i < beadtypes.max; i++) { + realloc_doublelist(&density_profile[i], 0); + } + free(density_profile); + } + + + /* Dealloc all subprofiles in density map */ + for (i = 0; i < beadtypes.max; i++) { + realloc_doublelist(&density_map[i], 0); + } + free(density_map); + + realloc_intlist(&beadtypes, 0); + return TCL_OK; +} + +static int tclcommand_analyze_parse_bilayer_density_profile(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze bilayer density profile ' */ + char buffer[TCL_DOUBLE_SPACE]; + int change, nbins, i, j; + IntList beadtypes; + double hrange; + int usegrid; + double sradius, cx, cy, cz; + cx = cy = cz = 0.0; + DoubleList* density_profile = NULL; + int errorValue; + double scenter[3] = {cx, cy, cz}; + /* Defaults */ + sradius = 0.0; + + init_intlist(&beadtypes); + usegrid = 1; + if (!ARG0_IS_D(hrange)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 1; + argv += 1; + } + + if (!ARG0_IS_I(nbins)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *) NULL); + return (TCL_ERROR); + } else { + argc -= 1; + argv += 1; + } + + if (!ARG0_IS_INTLIST(beadtypes)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *) NULL); + return (TCL_ERROR); + } else { + change = 1; + argc -= change; + argv += change; + } + + + while (argc > 0) { + + if (ARG0_IS_S("withsphere")) { + if (!ARG_IS_D(1, sradius) || !ARG_IS_D(2, cx) || !ARG_IS_D(3, cy) || !ARG_IS_D(4, cz)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *) NULL); + return (TCL_ERROR); + } + change = 5; + } + + if (ARG0_IS_S("nogrid")) { + usegrid = 0; + change = 1; + } + argc -= change; + argv += change; + } + + + /* If we said we wanted to use a grid then check to make sure one is set */ + if (xdir + ydir + zdir == -3 && usegrid) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "analyze bilayer_density_profile requires a grid. You must set grid first", (char *) NULL); + return (TCL_ERROR); + } + + + + /* Allocate a two doublelists of bins for each beadtype so that we + can keep track of beads in upper or lower lipids */ + density_profile = (DoubleList *) malloc(beadtypes.max * 2 * sizeof (DoubleList)); if (density_profile) { - for ( i = 0 ; i < beadtypes.max ; i++ ) { - init_doublelist(&density_profile[i]); - alloc_doublelist(&density_profile[i],thetabins); - for ( j = 0 ; j < thetabins ; j++ ) { - density_profile[i].e[j] = 0.0; - } - } + /* Initialize all the subprofiles in density profile */ + for (i = 0; i < beadtypes.max * 2; i++) { + init_doublelist(&density_profile[i]); + alloc_doublelist(&density_profile[i], nbins); + for (j = 0; j < nbins; j++) { + density_profile[i].e[j] = 0.0; + } + } } else { - Tcl_AppendResult(interp,"could not allocate memory for density_profile", (char *)NULL); - return (TCL_ERROR); - } - } - /* Allocate a doublelist of bins for each beadtype so that we - can keep track of beads separately */ - density_map = (DoubleList*) malloc(beadtypes.max*sizeof(DoubleList)); - if ( density_map ) { - /* Initialize all the subprofiles in density profile */ - for ( i = 0 ; i < beadtypes.max ; i++ ) { - // printf("initializing for beadtype %d and i: %d \n",beadtypes.e[i],i); - init_doublelist(&density_map[i]); - alloc_doublelist(&density_map[i],xbins*ybins); - if (!density_map[i].e) { - Tcl_AppendResult(interp,"could not allocate memory for density_map", (char *)NULL); - return (TCL_ERROR); - } else { - for ( j = 0 ; j < xbins*ybins ; j++ ) { - // printf("j: %d max: %d",j,density_map[i].max); - density_map[i].e[j] = 0.0; - } - - } - // printf("done initializing at i: %d j: %d\n",i,j); - } - } else { - Tcl_AppendResult(interp,"could not allocate memory for density_map", (char *)NULL); - return (TCL_ERROR); - } - - // printf("about to calculate profile \n"); - if(calc_radial_density_map(xbins,ybins,thetabins,xrange,yrange,rotation_axis,rotation_center,&beadtypes, density_map ,density_profile) != TCL_OK) { - Tcl_AppendResult(interp, "Error calculating radial density profile ", (char *)NULL); - return TCL_ERROR; - } - - // printf("done calculating profile \n"); - - Tcl_AppendResult(interp, "{ RadialDensityMap { ", (char *)NULL); - for ( i = 0 ; i < beadtypes.n ; i++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( j = 0 ; j < xbins ; j++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( k = 0 ; k < ybins ; k++) { - Tcl_PrintDouble(interp,density_map[i].e[j*ybins+k],buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - Tcl_AppendResult(interp, " } ", (char *)NULL); - if ( thetabins > 0 ) { - Tcl_AppendResult(interp, "{ RadialDensityThetaProfile { ", (char *)NULL); - for ( i = 0 ; i < beadtypes.n ; i++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( j = 0 ; j < thetabins ; j++ ) { - Tcl_PrintDouble(interp,density_profile[i].e[j],buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - Tcl_AppendResult(interp, " } ", (char *)NULL); - - /* Dealloc the density profile*/ - for ( i = 0 ; i < beadtypes.max ; i++ ) { - realloc_doublelist(&density_profile[i],0); + Tcl_AppendResult(interp, "could not allocate memory for density_profile", (char *) NULL); + return (TCL_ERROR); + } + + if (sradius > 0) { + errorValue = bilayer_density_profile_sphere(&beadtypes, hrange, density_profile, sradius, scenter); + } else { + errorValue = bilayer_density_profile(&beadtypes, hrange, density_profile, usegrid); + } + + if (!errorValue) { + Tcl_AppendResult(interp, "Error calculating bilayer density profile ", (char *) NULL); + return TCL_ERROR; + } + + Tcl_AppendResult(interp, "{ DensityProfile } { ", (char *) NULL); + for (i = 0; i < beadtypes.n * 2; i++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (j = 0; j < nbins; j++) { + Tcl_PrintDouble(interp, density_profile[i].e[j], buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + } + Tcl_AppendResult(interp, " } ", (char *) NULL); + + /* Initialize all the subprofiles in density profile */ + for (i = 0; i < beadtypes.max * 2; i++) { + realloc_doublelist(&density_profile[i], 0); } free(density_profile); - } + realloc_intlist(&beadtypes, 0); + return TCL_OK; +} +static int tclcommand_analyze_parse_lipid_orient_order(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze lipid_orient_order ' */ + double result; + double* stored_dirs; + char buffer[TCL_DOUBLE_SPACE]; + int i, j; + result = 0; + + if (n_part <= 1) { + Tcl_AppendResult(interp, "(not enough particles)", + (char *) NULL); + return (TCL_OK); + } - /* Dealloc all subprofiles in density map */ - for ( i = 0 ; i < beadtypes.max ; i++ ) { - realloc_doublelist(&density_map[i],0); - } - free(density_map); + stored_dirs = (double*) malloc(sizeof (double)*n_molecules * 3); + /* Do the calculation */ + if (orient_order(&result, stored_dirs) != TCL_OK) { + Tcl_AppendResult(interp, "Error calculating orientational order ", (char *) NULL); + return TCL_ERROR; + } - realloc_intlist(&beadtypes,0); - return TCL_OK; + if (argc == 0) { + /* If no options are specified then only give the average + orientational order */ + Tcl_PrintDouble(interp, result, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; + } else { + /* If the -all option is specified then print everything */ + if (ARG0_IS_S("all")) { + Tcl_PrintDouble(interp, result, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (i = 0; i < n_molecules; i++) { + Tcl_AppendResult(interp, " { ", (char *) NULL); + for (j = 0; j < 3; j++) { + Tcl_PrintDouble(interp, stored_dirs[i * 3 + j], buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " ", (char *) NULL); + } + Tcl_AppendResult(interp, "} ", (char *) NULL); + } + Tcl_AppendResult(interp, "} ", (char *) NULL); + } + return TCL_OK; + } + + Tcl_AppendResult(interp, "Error calculating orientational order ", (char *) NULL); + free(stored_dirs); + return TCL_ERROR; } +#endif -static int tclcommand_analyze_parse_bilayer_density_profile(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze bilayer density profile ' */ - char buffer[TCL_DOUBLE_SPACE]; - int change,nbins,i,j; - IntList beadtypes; - double hrange; - int usegrid; - double sradius, cx,cy,cz; - cx = cy = cz = 0.0; - DoubleList* density_profile = NULL; - int errorValue; - double scenter[3] = { cx, cy ,cz }; - /* Defaults */ - sradius = 0.0; - - init_intlist(&beadtypes); - usegrid = 1; - if ( !ARG0_IS_D(hrange) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 1; - argv += 1; - } - - if ( !ARG0_IS_I(nbins) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *)NULL); - return (TCL_ERROR); - } else { - argc -= 1; - argv += 1; - } - - if ( !ARG0_IS_INTLIST(beadtypes) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *)NULL); - return (TCL_ERROR); - } else { - change = 1; - argc -= change; - argv += change; - } +static int tclcommand_analyze_parse_aggregation(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze centermass []' */ + char buffer[256 + 3 * TCL_INTEGER_SPACE + 2 * TCL_DOUBLE_SPACE]; + int i, target1; + int *agg_id_list; + double dist_criteria, dist_criteria2; + int charge_criteria, min_contact, *head_list, *link_list; + int agg_num = 0, *agg_size, agg_min = n_molecules, agg_max = 0, agg_std = 0, agg_avg = 0; + float fagg_avg; + int s_mol_id, f_mol_id; + + agg_id_list = (int *) malloc(n_molecules * sizeof (int)); + head_list = (int *) malloc(n_molecules * sizeof (int)); + link_list = (int *) malloc(n_molecules * sizeof (int)); + agg_size = (int *) malloc(n_molecules * sizeof (int)); + /* parse arguments */ + if (argc < 3) { + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); + } - while ( argc > 0 ) { + if (!ARG_IS_D(0, dist_criteria)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); + } + dist_criteria2 = dist_criteria * dist_criteria; - if ( ARG0_IS_S("withsphere") ) { - if ( !ARG_IS_D(1,sradius) || !ARG_IS_D(2,cx) || !ARG_IS_D(3,cy) || !ARG_IS_D(4,cz) ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"usage: analyze bilayer_density_profile .. [withsphere ] [nogrid]", (char *)NULL); - return (TCL_ERROR); - } - change = 5; + if (!ARG_IS_I(1, s_mol_id)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); + } + if (!ARG_IS_I(2, f_mol_id)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); } - if ( ARG0_IS_S("nogrid") ) { - usegrid = 0; - change = 1; + if (n_nodes > 1) { + Tcl_AppendResult(interp, "aggregation can only be calculated on a single processor", (char *) NULL); + return TCL_ERROR; } - argc -= change; - argv += change; - } + if (cell_structure.type != CELL_STRUCTURE_DOMDEC) { + Tcl_AppendResult(interp, "aggregation can only be calculated with the domain decomposition cell system", (char *) NULL); + return TCL_ERROR; + } - /* If we said we wanted to use a grid then check to make sure one is set */ - if ( xdir + ydir + zdir == -3 && usegrid ) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp,"analyze bilayer_density_profile requires a grid. You must set grid first", (char *)NULL); - return (TCL_ERROR); - } - - - - /* Allocate a two doublelists of bins for each beadtype so that we - can keep track of beads in upper or lower lipids */ - density_profile = (DoubleList *)malloc(beadtypes.max*2*sizeof(DoubleList)); - if ( density_profile ) { - /* Initialize all the subprofiles in density profile */ - for ( i = 0 ; i < beadtypes.max*2 ; i++ ) { - init_doublelist(&density_profile[i]); - alloc_doublelist(&density_profile[i],nbins); - for ( j = 0 ; j < nbins ; j++ ) { - density_profile[i].e[j] = 0.0; - } - } - } else { - Tcl_AppendResult(interp,"could not allocate memory for density_profile", (char *)NULL); - return (TCL_ERROR); - } - - if ( sradius > 0 ) { - errorValue = bilayer_density_profile_sphere(&beadtypes, hrange, density_profile,sradius,scenter ); - } else { - errorValue = bilayer_density_profile(&beadtypes, hrange, density_profile, usegrid ); - } - - if (!errorValue) { - Tcl_AppendResult(interp, "Error calculating bilayer density profile ", (char *)NULL); - return TCL_ERROR; - } - - Tcl_AppendResult(interp, "{ DensityProfile } { ", (char *)NULL); - for ( i = 0 ; i < beadtypes.n*2 ; i++) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( j = 0 ; j < nbins ; j++) { - Tcl_PrintDouble(interp,density_profile[i].e[j],buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - } - Tcl_AppendResult(interp, " } ", (char *)NULL); - - /* Initialize all the subprofiles in density profile */ - for ( i = 0 ; i < beadtypes.max*2 ; i++ ) { - realloc_doublelist(&density_profile[i],0); - } - free(density_profile); - realloc_intlist(&beadtypes,0); - return TCL_OK; -} + if ((s_mol_id < 0) || (s_mol_id > n_molecules) || (f_mol_id < 0) || (f_mol_id > n_molecules)) { + Tcl_AppendResult(interp, "check your start and finish molecule id's", (char *) NULL); + return TCL_ERROR; + } -static int tclcommand_analyze_parse_lipid_orient_order(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze lipid_orient_order ' */ - double result; - double* stored_dirs; - char buffer[TCL_DOUBLE_SPACE]; - int i , j ; - result = 0; - - if (n_total_particles <= 1) { - Tcl_AppendResult(interp, "(not enough particles)", - (char *)NULL); - return (TCL_OK); - } + if (max_cut_nonbonded < dist_criteria) { + Tcl_AppendResult(interp, "dist_criteria is larger than max_cut_nonbonded.", (char *) NULL); + return TCL_ERROR; + } - stored_dirs = (double*) malloc(sizeof(double)*n_molecules*3); - /* Do the calculation */ - if ( orient_order(&result,stored_dirs) != TCL_OK ) { - Tcl_AppendResult(interp, "Error calculating orientational order ", (char *)NULL); - return TCL_ERROR; - } - - if ( argc == 0 ) { - /* If no options are specified then only give the average - orientational order */ - Tcl_PrintDouble(interp, result, buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return TCL_OK; - } else { - /* If the -all option is specified then print everything */ - if ( ARG0_IS_S("all") ) { - Tcl_PrintDouble(interp, result, buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( i = 0 ; i < n_molecules ; i++ ) { - Tcl_AppendResult(interp, " { ", (char *)NULL); - for ( j = 0 ; j < 3 ; j++ ) { - Tcl_PrintDouble(interp,stored_dirs[i*3+j],buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - Tcl_AppendResult(interp, " ", (char *)NULL); - } - Tcl_AppendResult(interp, "} ", (char *)NULL); - } - Tcl_AppendResult(interp, "} ", (char *)NULL); + if (argc == 4) { + if (!ARG_IS_I(3, min_contact)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); + } + } else { + min_contact = 1; + } + + if (argc == 5) { + if (!ARG_IS_I(4, charge_criteria)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *) NULL); + return (TCL_ERROR); + } + } else { + charge_criteria = 0; + } + + + aggregation(dist_criteria2, min_contact, s_mol_id, f_mol_id, head_list, link_list, agg_id_list, + &agg_num, agg_size, &agg_max, &agg_min, &agg_avg, &agg_std, charge_criteria); + + fagg_avg = (float) (agg_avg) / agg_num; + sprintf(buffer, " MAX %d MIN %d AVG %f STD %f AGG_NUM %d AGGREGATES", + agg_max, agg_min, fagg_avg, sqrt((float) (agg_std / (float) (agg_num) - fagg_avg * fagg_avg)), agg_num); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + for (i = s_mol_id; i <= f_mol_id; i++) { + if (head_list[i] != -2) { + target1 = head_list[i]; + sprintf(buffer, " { %d ", target1); + Tcl_AppendResult(interp, buffer, (char *) NULL); + while (link_list[target1] != -1) { + target1 = link_list[target1]; + sprintf(buffer, "%d ", target1); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + sprintf(buffer, "} "); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } } + + free(agg_id_list); + free(head_list); + free(link_list); + free(agg_size); + return TCL_OK; - } - - Tcl_AppendResult(interp, "Error calculating orientational order ", (char *)NULL); - free(stored_dirs); - return TCL_ERROR; } -#endif +static int tclcommand_analyze_parse_mindist(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze mindist [ ]' */ + double result; + char buffer[TCL_DOUBLE_SPACE]; + IntList p1, p2; -static int tclcommand_analyze_parse_aggregation(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze centermass []' */ - char buffer[256 + 3*TCL_INTEGER_SPACE + 2*TCL_DOUBLE_SPACE]; - int i, target1; - int *agg_id_list; - double dist_criteria, dist_criteria2; - int charge_criteria, min_contact, *head_list, *link_list; - int agg_num =0, *agg_size, agg_min= n_molecules, agg_max = 0, agg_std = 0, agg_avg = 0; - float fagg_avg; - int s_mol_id, f_mol_id; - - agg_id_list = (int *) malloc(n_molecules *sizeof(int)); - head_list = (int *) malloc(n_molecules *sizeof(int)); - link_list = (int *) malloc(n_molecules *sizeof(int)); - agg_size = (int *) malloc(n_molecules *sizeof(int)); - - /* parse arguments */ - if (argc < 3) { - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - - if (!ARG_IS_D(0,dist_criteria)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - dist_criteria2 = dist_criteria * dist_criteria; + init_intlist(&p1); + init_intlist(&p2); - if (!ARG_IS_I(1,s_mol_id)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - if (!ARG_IS_I(2,f_mol_id)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - - if (n_nodes > 1) { - Tcl_AppendResult(interp, "aggregation can only be calculated on a single processor", (char *)NULL); - return TCL_ERROR; - } + if (n_part <= 1) { + Tcl_AppendResult(interp, "(not enough particles)", + (char *) NULL); + return (TCL_OK); + } + if (argc == 0) + result = mindist(NULL, NULL); + else { + /* parse arguments */ + if (argc < 2) { + Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *) NULL); + return (TCL_ERROR); + } - if (cell_structure.type != CELL_STRUCTURE_DOMDEC) { - Tcl_AppendResult(interp, "aggregation can only be calculated with the domain decomposition cell system", (char *)NULL); - return TCL_ERROR; - } + if (!ARG0_IS_INTLIST(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *) NULL); + return (TCL_ERROR); + } + if (!ARG1_IS_INTLIST(p2)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *) NULL); + return (TCL_ERROR); + } + result = mindist(&p1, &p2); + } - if ( (s_mol_id < 0) || (s_mol_id > n_molecules) || (f_mol_id < 0) || (f_mol_id > n_molecules) ) { - Tcl_AppendResult(interp, "check your start and finish molecule id's", (char *)NULL); - return TCL_ERROR; - } + Tcl_PrintDouble(interp, result, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; +} - if ( max_cut_nonbonded < dist_criteria) { - Tcl_AppendResult(interp, "dist_criteria is larger than max_cut_nonbonded.", (char *)NULL); - return TCL_ERROR; - } - - if (argc == 4) { - if (!ARG_IS_I(3,min_contact)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - } else { - min_contact = 1; - } - - if (argc == 5) { - if (!ARG_IS_I(4, charge_criteria)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze aggregation [] []", (char *)NULL); - return (TCL_ERROR); - } - } else { - charge_criteria = 0; - } - - - aggregation(dist_criteria2, min_contact, s_mol_id, f_mol_id, head_list, link_list, agg_id_list, - &agg_num, agg_size, &agg_max, &agg_min, &agg_avg, &agg_std, charge_criteria); - - fagg_avg = (float) (agg_avg)/agg_num; - sprintf (buffer, " MAX %d MIN %d AVG %f STD %f AGG_NUM %d AGGREGATES", - agg_max, agg_min, fagg_avg, sqrt( (float) (agg_std/(float)(agg_num)-fagg_avg*fagg_avg)), agg_num); - Tcl_AppendResult(interp, buffer, (char *)NULL); - - for (i = s_mol_id ; i <= f_mol_id ; i++) { - if (head_list[i] != -2) { - target1= head_list[i]; - sprintf(buffer, " { %d ", target1); - Tcl_AppendResult(interp, buffer, (char *)NULL); - while( link_list[target1] != -1) { - target1= link_list[target1]; - sprintf(buffer, "%d ", target1); - Tcl_AppendResult(interp, buffer, (char *)NULL); - } - sprintf(buffer, "} "); - Tcl_AppendResult(interp, buffer, (char *)NULL); - } - } - - free(agg_id_list); - free(head_list); - free(link_list); - free(agg_size); - - return TCL_OK; +static int tclcommand_analyze_parse_centermass(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze centermass []' */ + double com[3]; + char buffer[3 * TCL_DOUBLE_SPACE + 3]; + int p1; + + /* parse arguments */ + if (argc != 1) { + Tcl_AppendResult(interp, "usage: analyze centermass []", (char *) NULL); + return (TCL_ERROR); + } + + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze centermass []", (char *) NULL); + return (TCL_ERROR); + } + + centermass(p1, com); + + sprintf(buffer, "%f %f %f", com[0], com[1], com[2]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; } +static int tclcommand_analyze_parse_angularmomentum(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze angularmomentum []' */ + double com[3]; + char buffer[3 * TCL_DOUBLE_SPACE + 3]; + int p1; -static int tclcommand_analyze_parse_mindist(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze mindist [ ]' */ - double result; - char buffer[TCL_DOUBLE_SPACE]; - IntList p1, p2; + /* parse arguments */ + if (argc != 1) { + Tcl_AppendResult(interp, "usage: analyze angularmomentum []", (char *) NULL); + return (TCL_ERROR); + } + + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze angularmomentum []", (char *) NULL); + return (TCL_ERROR); + } - init_intlist(&p1); init_intlist(&p2); + angularmomentum(p1, com); + + sprintf(buffer, "%f %f %f", com[0], com[1], com[2]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; +} + +static int tclcommand_analyze_parse_cluster_size_dist(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze cluster_size_dist []' */ + char buffer[3 * TCL_DOUBLE_SPACE + 3]; + int p1; + double dist; + int i, j, max_cluster_number, size; + int cluster_number[n_part]; //cluster number of particle number + int cluster_size[n_part + 1]; //number of clusters with some size - if (n_total_particles <= 1) { - Tcl_AppendResult(interp, "(not enough particles)", - (char *)NULL); - return (TCL_OK); - } - if (argc == 0) - result = mindist(NULL, NULL); - else { /* parse arguments */ - if (argc < 2) { - Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *)NULL); - return (TCL_ERROR); + if (argc != 2) { + Tcl_AppendResult(interp, "usage: analyze cluster_size_dist ", (char *) NULL); + return (TCL_ERROR); } - if (!ARG0_IS_INTLIST(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *)NULL); - return (TCL_ERROR); + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ERROR: type must be int !", (char *) NULL); + return (TCL_ERROR); } - if (!ARG1_IS_INTLIST(p2)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze mindist [ ]", (char *)NULL); - return (TCL_ERROR); + + if (!ARG1_IS_D(dist)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ERROR: dist must be double !", (char *) NULL); + return (TCL_ERROR); + } + + updatePartCfg(WITHOUT_BONDS); + for (i = 0; i < n_part; i++) { + cluster_number[i] = 0; + cluster_size[i] = 0; + } + cluster_size[n_part] = 0; + + max_cluster_number = 1; + for (i = 0; i < n_part - 1; i++) { + //if particle was not marked till now + if ((partCfg[i].p.type == p1) && (cluster_number[i] == 0)) { + //mark current particle with max_cluster_number + cluster_number[i] = max_cluster_number; + mark_neighbours(p1, i, dist, cluster_number); + max_cluster_number++; + } + } + + for (i = 0; i < n_part; i++) { + if ((partCfg[i].p.type == p1) && (cluster_number[i] == 0)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ERROR: at least one particle is not marked !", (char *) NULL); + return (TCL_ERROR); + } + } + + for (i = 1; i < max_cluster_number; i++) { + size = 0; + for (j = 0; j < n_part; j++) { + //Finding particles belonging to cluster i + if ((partCfg[j].p.type == p1) && (cluster_number[j] == i)) { + size++; + } + } + cluster_size[size]++; + } + + sprintf(buffer, "%i %f", p1, dist); + Tcl_AppendResult(interp, "{ analyze cluster_size_dist ", buffer, "} {\n", (char *) NULL); + for (i = 0; i < n_part + 1; i++) { + if (cluster_size[i] != 0) { + sprintf(buffer, "%i %i", i, cluster_size[i]); + Tcl_AppendResult(interp, "{ ", buffer, " }\n", (char *) NULL); + } } - result = mindist(&p1, &p2); - } + Tcl_AppendResult(interp, "}", (char *) NULL); - Tcl_PrintDouble(interp, result, buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return TCL_OK; + return TCL_OK; } -static int tclcommand_analyze_parse_centermass(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze centermass []' */ - double com[3]; - char buffer[3*TCL_DOUBLE_SPACE+3]; - int p1; - - /* parse arguments */ - if (argc != 1) { - Tcl_AppendResult(interp, "usage: analyze centermass []", (char *)NULL); - return (TCL_ERROR); - } +static int tclcommand_analyze_parse_momentofinertiamatrix(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze momentofinertiamatrix []' */ + double MofImatrix[9]; + char buffer[9 * TCL_DOUBLE_SPACE + 9]; + int p1; + + /* parse arguments */ + if (argc != 1) { + Tcl_AppendResult(interp, "usage: analyze momentofinertiamatrix []", (char *) NULL); + return (TCL_ERROR); + } + + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze momentofinertiamatrix []", (char *) NULL); + return (TCL_ERROR); + } + momentofinertiamatrix(p1, MofImatrix); + + sprintf(buffer, "%f %f %f %f %f %f %f %f %f", + MofImatrix[0], MofImatrix[1], MofImatrix[2], MofImatrix[3], MofImatrix[4], + MofImatrix[5], MofImatrix[6], MofImatrix[7], MofImatrix[8]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_OK; +} + +static int tclcommand_analyze_parse_gyration_tensor(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze gyration_tensor' */ + char buffer[6 * TCL_DOUBLE_SPACE + 10]; + double *gt; + int type; + /* parse arguments */ + if (argc == 0) { + /* Calculate gyration tensor for all particles in the system */ + type = -1; + } else if (argc == 1) { + /* Calculate gyration tensor for a specific type of particles */ + if (!ARG0_IS_I(type)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze gyration_tensor []", (char *) NULL); + return (TCL_ERROR); + } else if (type < 0 || type >= n_particle_types) { + Tcl_ResetResult(interp); + sprintf(buffer, "%d", type); + Tcl_AppendResult(interp, "Particle type ", buffer, " does not exist!", (char *) NULL); + return (TCL_ERROR); + } + } + else { + Tcl_AppendResult(interp, "usage: analyze gyration_tensor []", (char *) NULL); + return (TCL_ERROR); + } + calc_gyration_tensor(type, >); - if (!ARG0_IS_I(p1)) { Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze centermass []", (char *)NULL); - return (TCL_ERROR); - } - - centermass(p1, com); - - sprintf(buffer,"%f %f %f",com[0],com[1],com[2]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return TCL_OK; + sprintf(buffer, "%f", gt[3]); /* Squared Radius of Gyration */ + Tcl_AppendResult(interp, "{ Rg^2 ", buffer, " } ", (char *) NULL); + + sprintf(buffer, "%f %f %f", gt[4], gt[5], gt[6]); /* Shape descriptors */ + Tcl_AppendResult(interp, "{ shape ", buffer, " } ", (char *) NULL); + + sprintf(buffer, "%f", gt[0]); /* Eigenvalue 0 */ + Tcl_AppendResult(interp, "{ eva0 ", buffer, " : ", (char *) NULL); + sprintf(buffer, "%f %f %f", gt[7], gt[8], gt[9]); /* Eigenvector of eva0 */ + Tcl_AppendResult(interp, buffer, " } ", (char *) NULL); + + sprintf(buffer, "%f", gt[1]); /* Eigenvalue 1 */ + Tcl_AppendResult(interp, "{ eva1 ", buffer, " : ", (char *) NULL); + sprintf(buffer, "%f %f %f", gt[10], gt[11], gt[12]); /* Eigenvector of eva1 */ + Tcl_AppendResult(interp, buffer, " } ", (char *) NULL); + + sprintf(buffer, "%f", gt[2]); /* Eigenvalue 2 */ + Tcl_AppendResult(interp, "{ eva2 ", buffer, " : ", (char *) NULL); + sprintf(buffer, "%f %f %f", gt[13], gt[14], gt[15]); /* Eigenvector of eva2 */ + Tcl_AppendResult(interp, buffer, " }", (char *) NULL); + + free(gt); + return (TCL_OK); } -static int tclcommand_analyze_parse_angularmomentum(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze angularmomentum []' */ - double com[3]; - char buffer[3*TCL_DOUBLE_SPACE+3]; - int p1; +static int tclcommand_analyze_parse_find_principal_axis(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze find_principal_axis []' */ + double MofImatrix[9], eva[3], eve[3]; + char buffer[4 * TCL_DOUBLE_SPACE + 20]; + int p1; - /* parse arguments */ - if (argc != 1) { - Tcl_AppendResult(interp, "usage: analyze angularmomentum []", (char *)NULL); - return (TCL_ERROR); - } + /* parse arguments */ + if (argc != 1) { + Tcl_AppendResult(interp, "usage: analyze find_principal_axis []", (char *) NULL); + return (TCL_ERROR); + } - if (!ARG0_IS_I(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze angularmomentum []", (char *)NULL); - return (TCL_ERROR); - } + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze find_principal_axis []", (char *) NULL); + return (TCL_ERROR); + } - angularmomentum(p1, com); + momentofinertiamatrix(p1, MofImatrix); + calc_eigenvalues_3x3(MofImatrix, eva); - sprintf(buffer,"%f %f %f",com[0],com[1],com[2]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return TCL_OK; + sprintf(buffer, "{eigenval eigenvector} "); + Tcl_AppendResult(interp, buffer, (char *) NULL); + for (int j = 0; j < 3; j++) { + calc_eigenvector_3x3(MofImatrix, eva[j], eve); + sprintf(buffer, " { %f { %f %f %f } }", eva[j], eve[0], eve[1], eve[2]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + return TCL_OK; } +static int tclcommand_analyze_parse_nbhood(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze nbhood [-planar ] { | } ' */ + int p, i; + double pos[3]; + double r_catch; + char buffer[TCL_INTEGER_SPACE + 2]; + IntList il; + int planedims[3], change; + + if (n_part == 0) { + Tcl_AppendResult(interp, "(no particles)", + (char *) NULL); + return (TCL_OK); + } + planedims[0] = planedims[1] = planedims[2] = 1; + + /* Optional planar argument */ + if (ARG0_IS_S("planar")) { + if (argc < 6) { + Tcl_AppendResult(interp, "planar option requires exactly 3 integer arguments", + (char *) NULL); + return TCL_ERROR; + } + /* Now read in the dimensions to be used */ + if (!ARG_IS_I(1, planedims[0])) + return TCL_ERROR; + if (!ARG_IS_I(2, planedims[1])) + return TCL_ERROR; + if (!ARG_IS_I(3, planedims[2])) + return TCL_ERROR; + + /* Check to make sure that we actually specified a plane */ + if ((planedims[0] + planedims[1] + planedims[2]) != 2) { + Tcl_AppendResult(interp, "you specified the planar option. Please specify exactly 2 dimensions eg 1 1 0 for xy plane", + (char *) NULL); + return TCL_ERROR; + } + change = 4; + argc -= change; + argv += change; -static int tclcommand_analyze_parse_cluster_size_dist(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze cluster_size_dist []' */ - char buffer[3*TCL_DOUBLE_SPACE+3]; - int p1; - double dist; - int i,j,max_cluster_number,size; - int cluster_number[n_total_particles];//cluster number of particle number - int cluster_size[n_total_particles+1]; //number of clusters with some size + } - /* parse arguments */ - if (argc != 2) { - Tcl_AppendResult(interp, "usage: analyze cluster_size_dist ", (char *)NULL); - return (TCL_ERROR); - } + /* Process obligatory arguments */ + tclcommand_analyze_parse_reference_point(interp, &argc, &argv, pos, &p); + if (!ARG0_IS_D(r_catch)) { + Tcl_AppendResult(interp, "usage: nbhood [planar ] { | } ", + (char *) NULL); + return (TCL_ERROR); + } + argc--; + argv++; - if (!ARG0_IS_I(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "ERROR: type must be int !", (char *)NULL); - return (TCL_ERROR); - } + updatePartCfg(WITHOUT_BONDS); + nbhood(pos, r_catch, &il, planedims); - if (!ARG1_IS_D(dist)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "ERROR: dist must be double !", (char *)NULL); - return (TCL_ERROR); - } - - updatePartCfg(WITHOUT_BONDS); - for (i=0;i]' */ - double MofImatrix[9]; - char buffer[9*TCL_DOUBLE_SPACE+9]; - int p1; +static int tclcommand_analyze_parse_distto(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze distto { | }' */ + double result; + int p; + double pos[3]; + char buffer[TCL_DOUBLE_SPACE], usage[150]; + sprintf(usage, "distto { | }"); + + if (n_part == 0) { + Tcl_AppendResult(interp, "(no particles)", + (char *) NULL); + return (TCL_OK); + } - /* parse arguments */ - if (argc != 1) { - Tcl_AppendResult(interp, "usage: analyze momentofinertiamatrix []", (char *)NULL); - return (TCL_ERROR); - } + if (argc == 0) { + Tcl_AppendResult(interp, "usage: ", usage, (char*) NULL); + return TCL_ERROR; + } - if (!ARG0_IS_I(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze momentofinertiamatrix []", (char *)NULL); - return (TCL_ERROR); - } - momentofinertiamatrix(p1, MofImatrix); - - sprintf(buffer,"%f %f %f %f %f %f %f %f %f", - MofImatrix[0],MofImatrix[1],MofImatrix[2],MofImatrix[3],MofImatrix[4], - MofImatrix[5],MofImatrix[6],MofImatrix[7],MofImatrix[8]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return TCL_OK; -} + tclcommand_analyze_parse_reference_point(interp, &argc, &argv, pos, &p); + if (argc != 0) { + Tcl_AppendResult(interp, "usage: ", usage, (char *) NULL); + return TCL_ERROR; + } -static int tclcommand_analyze_parse_gyration_tensor(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze gyration_tensor' */ - char buffer[6*TCL_DOUBLE_SPACE+10]; - double *gt; - int type; - /* parse arguments */ - if (argc == 0) { - /* Calculate gyration tensor for all particles in the system */ - type = -1; - } - else if (argc == 1) { - /* Calculate gyration tensor for a specific type of particles */ - if (!ARG0_IS_I(type)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze gyration_tensor []", (char *)NULL); - return (TCL_ERROR); - } - else if ( type < 0 || type >= n_particle_types ) { - Tcl_ResetResult(interp); - sprintf(buffer,"%d",type); - Tcl_AppendResult(interp, "Particle type ", buffer, " does not exist!", (char *)NULL); - return (TCL_ERROR); - } - } - else { - Tcl_AppendResult(interp, "usage: analyze gyration_tensor []", (char *)NULL); - return (TCL_ERROR); - } - calc_gyration_tensor(type,>); - - Tcl_ResetResult(interp); - sprintf(buffer,"%f",gt[3]); /* Squared Radius of Gyration */ - Tcl_AppendResult(interp, "{ Rg^2 ",buffer," } ", (char *)NULL); - - sprintf(buffer,"%f %f %f",gt[4],gt[5],gt[6]); /* Shape descriptors */ - Tcl_AppendResult(interp, "{ shape ",buffer," } ", (char *)NULL); - - sprintf(buffer,"%f",gt[0]); /* Eigenvalue 0 */ - Tcl_AppendResult(interp, "{ eva0 ",buffer," : ", (char *)NULL); - sprintf(buffer,"%f %f %f",gt[7],gt[8],gt[9]); /* Eigenvector of eva0 */ - Tcl_AppendResult(interp, buffer," } ", (char *)NULL); - - sprintf(buffer,"%f",gt[1]); /* Eigenvalue 1 */ - Tcl_AppendResult(interp, "{ eva1 ",buffer," : ", (char *)NULL); - sprintf(buffer,"%f %f %f",gt[10],gt[11],gt[12]); /* Eigenvector of eva1 */ - Tcl_AppendResult(interp, buffer," } ", (char *)NULL); - - sprintf(buffer,"%f",gt[2]); /* Eigenvalue 2 */ - Tcl_AppendResult(interp, "{ eva2 ",buffer," : ", (char *)NULL); - sprintf(buffer,"%f %f %f",gt[13],gt[14],gt[15]); /* Eigenvector of eva2 */ - Tcl_AppendResult(interp, buffer," }", (char *)NULL); - - free(gt); - return (TCL_OK); + result = distto(pos, p); + + Tcl_PrintDouble(interp, result, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return (TCL_OK); } -static int tclcommand_analyze_parse_find_principal_axis(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze find_principal_axis []' */ - double MofImatrix[9],eva[3],eve[3]; - char buffer[4*TCL_DOUBLE_SPACE+20]; - int p1; +static int tclcommand_analyze_parse_cell_gpb(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze cell_gpb [ [<# of interations>]]' */ + double result[3] = {0, 0, 0}, xi_m, Rc, ro; + double gacc = 1e-6; + int maxtry = 30000; + char buffer[3 * TCL_DOUBLE_SPACE + 20], usage[150]; + sprintf(usage, "analyze cell_gpb [ [<# of interations>]]"); + + if ((argc < 3) || (argc > 5)) { + Tcl_AppendResult(interp, "usage: ", usage, (char *) NULL); + return TCL_ERROR; + } else if (!ARG_IS_D(0, xi_m) || !ARG_IS_D(1, Rc) || !ARG_IS_D(2, ro)) + return TCL_ERROR; + if (argc == 4) if (!ARG_IS_D(3, gacc)) + return TCL_ERROR; + if (argc == 5) if (!ARG_IS_I(4, maxtry)) + return TCL_ERROR; + if ((xi_m < 0) || !((Rc > 0) && (ro > 0))) { + Tcl_ResetResult(interp); + sprintf(buffer, "%f %f %f", xi_m, Rc, ro); + Tcl_AppendResult(interp, "usage: ", usage, "\n", (char *) NULL); + Tcl_AppendResult(interp, "ERROR: All three arguments must be positive, the latter two even non-zero (got: ", buffer, ")! Aborting...", (char*) NULL); + return (TCL_ERROR); + } - /* parse arguments */ - if (argc != 1) { - Tcl_AppendResult(interp, "usage: analyze find_principal_axis []", (char *)NULL); - return (TCL_ERROR); - } + calc_cell_gpb(xi_m, Rc, ro, gacc, maxtry, result); + + if (result[2] == -2.0) { + Tcl_ResetResult(interp); + sprintf(buffer, "%d", maxtry); + Tcl_AppendResult(interp, "ERROR: Maximum number of iterations exceeded (", buffer, ")! "); + sprintf(buffer, "%f and %f", result[0], result[1]); + Tcl_AppendResult(interp, "Got ", buffer, " so far, aborting now...", (char*) NULL); + return (TCL_ERROR); + } else if (result[2] == -3.0) { + Tcl_ResetResult(interp); + sprintf(buffer, "%f and %f", result[0], result[1]); + Tcl_AppendResult(interp, "ERROR: gamma is not bracketed by the programs initial guess (", buffer, ")! Aborting...", (char*) NULL); + return (TCL_ERROR); + } else if (result[2] == -4.0) { + Tcl_ResetResult(interp); + sprintf(buffer, "%f and %f", result[0], result[1]); + Tcl_AppendResult(interp, "ERROR: lower boundary on wrong side of the function (", buffer, ")! Aborting...", (char*) NULL); + return (TCL_ERROR); + } else if (result[2] == -5.0) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "ERROR: Something went wrong! Aborting...", (char*) NULL); + return (TCL_ERROR); + } + sprintf(buffer, "%f %f %f", result[0], result[1], result[2]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return (TCL_OK); +} - if (!ARG0_IS_I(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze find_principal_axis []", (char *)NULL); - return (TCL_ERROR); - } - - momentofinertiamatrix(p1, MofImatrix); - calc_eigenvalues_3x3(MofImatrix, eva); - - sprintf(buffer,"{eigenval eigenvector} "); - Tcl_AppendResult(interp, buffer, (char *)NULL); - for (int j= 0; j < 3; j++) { - calc_eigenvector_3x3(MofImatrix,eva[j],eve); - sprintf(buffer," { %f { %f %f %f } }",eva[j],eve[0],eve[1],eve[2]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - } - return TCL_OK; +/** Has something to do with computing compressibility from volume fluctuations. Docs missing. + */ +static int tclcommand_analyze_parse_Vkappa(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze Vkappa [{ reset | read | set }]' */ + double result = 0.0; + char buffer[3 * TCL_DOUBLE_SPACE + 3]; + + if (argc > 0) + if (ARG0_IS_S("reset")) + Vkappa.Vk1 = Vkappa.Vk2 = Vkappa.avk = 0.0; + else if (ARG0_IS_S("read")) { + sprintf(buffer, "%f %f %f ", Vkappa.Vk1, Vkappa.Vk2, Vkappa.avk); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return (TCL_OK); + } else if (ARG0_IS_S("set")) { + if (argc < 4 || !ARG_IS_D(1, Vkappa.Vk1) || !ARG_IS_D(2, Vkappa.Vk2) || !ARG_IS_D(3, Vkappa.avk)) { + Tcl_AppendResult(interp, "usage: analyze Vkappa [{ reset | read | set }] ", (char *) NULL); + return TCL_ERROR; + } + if (Vkappa.avk <= 0.0) { + Tcl_AppendResult(interp, "ERROR: # of averages must be positiv! Resetting values...", (char *) NULL); + result = Vkappa.Vk1 = Vkappa.Vk2 = Vkappa.avk = 0.0; + return TCL_ERROR; + } + result = Vkappa.Vk2 / Vkappa.avk - SQR(Vkappa.Vk1 / Vkappa.avk); + } else { + Tcl_AppendResult(interp, "usage: analyze Vkappa [{ reset | read | set }] ", (char *) NULL); + return TCL_ERROR; + } else { + Vkappa.Vk1 += box_l[0] * box_l[1] * box_l[2]; + Vkappa.Vk2 += SQR(box_l[0] * box_l[1] * box_l[2]); + Vkappa.avk += 1.0; + result = Vkappa.Vk2 / Vkappa.avk - SQR(Vkappa.Vk1 / Vkappa.avk); + } + + Tcl_PrintDouble(interp, result, buffer); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return (TCL_OK); } -static int tclcommand_analyze_parse_nbhood(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze nbhood [-planar ] { | } ' */ - int p, i; - double pos[3]; - double r_catch; - char buffer[TCL_INTEGER_SPACE + 2]; - IntList il; - int planedims[3], change; - - if (n_total_particles == 0) { - Tcl_AppendResult(interp, "(no particles)", - (char *)NULL); +static int tclcommand_analyze_parse_distribution(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze distribution { } { } [ [ [ [ []]]]]' */ + /*********************************************************************************************************************************/ + char buffer[2 * TCL_DOUBLE_SPACE + 3 * TCL_INTEGER_SPACE + 256]; + IntList p1, p2; + double r_min = 0, r_max = -1.0; + int r_bins = 0, log_flag = 0, int_flag = 0; + int i; + double *distribution, low; + + init_intlist(&p1); + init_intlist(&p2); + + if (argc < 2) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *) NULL); + return (TCL_ERROR); + } + + if (!ARG0_IS_INTLIST(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *) NULL); + return (TCL_ERROR); + } + if (!ARG1_IS_INTLIST(p2)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *) NULL); + return (TCL_ERROR); + } + + argc -= 2; + argv += 2; + + if (argc > 0) { + if (!ARG0_IS_D(r_min)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_D(r_max)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_I(r_bins)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_I(log_flag)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_I(int_flag)) return (TCL_ERROR); + argc--; + argv++; + } + + /* if not given set defaults */ + if (r_max == -1.) r_max = min_box_l / 2.0; + if (r_bins < 0) r_bins = n_part / 20; + + /* give back what you do */ + Tcl_AppendResult(interp, "{ analyze distribution { ", (char *) NULL); + for (i = 0; i < p1.max; i++) { + sprintf(buffer, "%d ", p1.e[i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + Tcl_AppendResult(interp, "} { ", (char *) NULL); + for (i = 0; i < p2.max; i++) { + sprintf(buffer, "%d ", p2.e[i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + sprintf(buffer, "} %f %f %d %d %d", r_min, r_max, r_bins, log_flag, int_flag); + Tcl_AppendResult(interp, buffer, " }", (char *) NULL); + /* some sanity checks */ + if (r_min < 0.0 || (log_flag == 1 && r_min == 0.0)) return TCL_ERROR; + if (r_max <= r_min) return TCL_ERROR; + if (r_bins < 1) return TCL_ERROR; + /* calculate distribution */ + distribution = (double*) malloc(r_bins * sizeof (double)); + updatePartCfg(WITHOUT_BONDS); + calc_part_distribution(p1.e, p1.max, p2.e, p2.max, r_min, r_max, r_bins, log_flag, &low, distribution); + if (int_flag == 1) { + distribution[0] += low; + for (i = 0; i < r_bins - 1; i++) distribution[i + 1] += distribution[i]; + } + /* append result */ + { + double log_fac = 0.0, bin_width = 0.0, r = 0.0; + if (log_flag == 1) { + log_fac = pow((r_max / r_min), (1.0 / (double) r_bins)); + r = r_min * sqrt(log_fac); + } + else { + bin_width = (r_max - r_min) / (double) r_bins; + r = r_min + bin_width / 2.0; + } + Tcl_AppendResult(interp, " {\n", (char *) NULL); + for (i = 0; i < r_bins; i++) { + sprintf(buffer, "%f %f", r, distribution[i]); + Tcl_AppendResult(interp, "{ ", buffer, " }\n", (char *) NULL); + if (log_flag == 1) r *= log_fac; + else r += bin_width; + } + Tcl_AppendResult(interp, "}\n", (char *) NULL); + } + free(distribution); return (TCL_OK); - } - planedims[0] = planedims[1] = planedims[2] = 1; - - /* Optional planar argument */ - if ( ARG0_IS_S("planar")) { - if ( argc < 6 ) { - Tcl_AppendResult(interp, "planar option requires exactly 3 integer arguments", - (char *)NULL); - return TCL_ERROR; - } - - /* Now read in the dimensions to be used */ - if (! ARG_IS_I(1,planedims[0] )) - return TCL_ERROR; - if (! ARG_IS_I(2,planedims[1] )) - return TCL_ERROR; - if (! ARG_IS_I(3,planedims[2] )) - return TCL_ERROR; - - /* Check to make sure that we actually specified a plane */ - if ( (planedims[0] + planedims[1] + planedims[2] ) != 2 ) { - Tcl_AppendResult(interp, "you specified the planar option. Please specify exactly 2 dimensions eg 1 1 0 for xy plane", - (char *)NULL); - return TCL_ERROR; - } - change = 4; - argc -= change; - argv += change; - - } - - /* Process obligatory arguments */ - tclcommand_analyze_parse_reference_point(interp, &argc, &argv, pos, &p); - if (!ARG0_IS_D(r_catch)) { - Tcl_AppendResult(interp, "usage: nbhood [planar ] { | } ", - (char *)NULL); - return (TCL_ERROR); - } - argc--; - argv++; - - updatePartCfg(WITHOUT_BONDS); - nbhood(pos, r_catch, &il, planedims ); +} - - for (i = 0; i < il.n; i++) { - sprintf(buffer, "%d ", il.e[i]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - } - realloc_intlist(&il, 0); - return (TCL_OK); +static int tclcommand_analyze_parse_vel_distr(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze vel_distr []' */ + char buffer[3 * TCL_DOUBLE_SPACE + 3]; + int p1; + int bins = 100; + double max = 0.0; + + /* parse arguments */ + if (argc == 0) { + Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *) NULL); + return (TCL_ERROR); + } + + if (!ARG0_IS_I(p1)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *) NULL); + return (TCL_ERROR); + } + + if (argc > 1) { + if (!ARG1_IS_I(bins)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *) NULL); + return (TCL_ERROR); + } + } + + if (argc > 2) { + if (!ARG_IS_D(2, max)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *) NULL); + return (TCL_ERROR); + } + } + + sprintf(buffer, "%i %i %f", p1, bins, max); + Tcl_AppendResult(interp, "{ analyze vel_distr ", buffer, "} ", (char *) NULL); + updatePartCfg(WITHOUT_BONDS); + tclcommand_analyze_print_vel_distr(interp, p1, bins, max); + + return TCL_OK; } -static int tclcommand_analyze_parse_distto(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze distto { | }' */ - double result; - int p; - double pos[3]; - char buffer[TCL_DOUBLE_SPACE], usage[150]; - sprintf(usage, "distto { | }"); - - if (n_total_particles == 0) { - Tcl_AppendResult(interp, "(no particles)", - (char *)NULL); - return (TCL_OK); - } +static int tclcommand_analyze_parse_rdf(Tcl_Interp *interp, int average, int argc, char **argv) { + /* 'analyze rdf' (radial distribution function) */ + /************************************************/ + char buffer[2 * TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE + 256]; + IntList p1, p2; + double r_min = 0, r_max = -1.0; + double x_min = 0, x_max = -1.0; + int r_bins = 100, n_conf = 1, i; + double *rdf; + + init_intlist(&p1); + init_intlist(&p2); + + if (argc < 2 || (!ARG0_IS_INTLIST(p1)) || (!ARG1_IS_INTLIST(p2))) { + Tcl_ResetResult(interp); + if (average != 3) { + Tcl_AppendResult(interp, "usage: analyze {rdf||} [ [ [ []]]]", (char *) NULL); + } + return (TCL_ERROR); + } + argc -= 2; + argv += 2; + + if (average == 3) { + if (argc > 0) { + if (!ARG0_IS_D(x_min)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_D(x_max)) return (TCL_ERROR); + argc--; + argv++; + } + } - if (argc == 0) { - Tcl_AppendResult(interp, "usage: ", usage, (char*)NULL); - return TCL_ERROR; - } + if (argc > 0) { + if (!ARG0_IS_D(r_min)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_D(r_max)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_I(r_bins)) return (TCL_ERROR); + argc--; + argv++; + } - tclcommand_analyze_parse_reference_point(interp, &argc, &argv, pos, &p); - if (argc != 0) { - Tcl_AppendResult(interp, "usage: ", usage, (char *)NULL); - return TCL_ERROR; - } + if (average != 0) { + if (n_configs == 0) { + Tcl_AppendResult(interp, "no configurations found! ", (char *) NULL); + Tcl_AppendResult(interp, "Use 'analyze append' to save some, or 'analyze rdf' to only look at current RDF!", (char *) NULL); + return TCL_ERROR; + } + if (argc > 0) { + if (!ARG0_IS_I(n_conf)) return (TCL_ERROR); + argc--; + argv++; + } else + n_conf = n_configs; + } + + /* if not given use default */ + if (r_max == -1.0) r_max = min_box_l / 2.0; + if (x_max == -1.0) x_max = min_box_l / 2.0; + + /* give back what you do */ + if (average == 0) + Tcl_AppendResult(interp, "{ analyze rdf { ", (char *) NULL); + else if (average == 1) + Tcl_AppendResult(interp, "{ analyze { ", (char *) NULL); + else if (average == 2) + Tcl_AppendResult(interp, "{ analyze { ", (char *) NULL); + else { + Tcl_AppendResult(interp, "WRONG PARAMETER PASSED ", (char *) NULL); + return TCL_ERROR; + } - result = distto(pos, p); + for (i = 0; i < p1.max; i++) { + sprintf(buffer, "%d ", p1.e[i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + Tcl_AppendResult(interp, "} { ", (char *) NULL); + for (i = 0; i < p2.max; i++) { + sprintf(buffer, "%d ", p2.e[i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + sprintf(buffer, "} %f %f %d", r_min, r_max, r_bins); - Tcl_PrintDouble(interp, result, buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return (TCL_OK); -} + if (average == 3) { + sprintf(buffer, "} %f %f %f %f %d", x_min, x_max, r_min, r_max, r_bins); + } + Tcl_AppendResult(interp, buffer, (char *) NULL); + if (average) { + sprintf(buffer, " %d", n_conf); + Tcl_AppendResult(interp, buffer, " }", (char *) NULL); + } else + Tcl_AppendResult(interp, " }", (char *) NULL); + rdf = (double*) malloc(r_bins * sizeof (double)); + + if (!sortPartCfg()) { + Tcl_AppendResult(interp, "for analyze, store particles consecutively starting with 0.", (char *) NULL); + return (TCL_ERROR); + } -static int tclcommand_analyze_parse_cell_gpb(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze cell_gpb [ [<# of interations>]]' */ - double result[3] = {0, 0, 0}, xi_m, Rc, ro; - double gacc = 1e-6; - int maxtry = 30000; - char buffer[3*TCL_DOUBLE_SPACE+20], usage[150]; - sprintf(usage,"analyze cell_gpb [ [<# of interations>]]"); + switch (average) { + case 0: + calc_rdf(p1.e, p1.max, p2.e, p2.max, r_min, r_max, r_bins, rdf); + break; + case 1: + calc_rdf_av(p1.e, p1.max, p2.e, p2.max, r_min, r_max, r_bins, rdf, n_conf); + break; + case 2: + calc_rdf_intermol_av(p1.e, p1.max, p2.e, p2.max, r_min, r_max, r_bins, rdf, n_conf); + break; + default:; + } - if ((argc < 3) || (argc > 5)) { - Tcl_AppendResult(interp, "usage: ",usage,(char *)NULL); return TCL_ERROR; } - else if (!ARG_IS_D(0,xi_m) || !ARG_IS_D(1,Rc) || !ARG_IS_D(2,ro)) - return TCL_ERROR; - if (argc == 4) if (!ARG_IS_D(3,gacc)) - return TCL_ERROR; - if (argc == 5) if (!ARG_IS_I(4,maxtry)) - return TCL_ERROR; - if ((xi_m < 0) || !((Rc > 0) && (ro > 0))) { - Tcl_ResetResult(interp); sprintf(buffer,"%f %f %f",xi_m,Rc,ro); - Tcl_AppendResult(interp, "usage: ",usage,"\n",(char *)NULL); - Tcl_AppendResult(interp, "ERROR: All three arguments must be positive, the latter two even non-zero (got: ",buffer,")! Aborting...", (char*)NULL); - return(TCL_ERROR); - } - - calc_cell_gpb(xi_m,Rc,ro,gacc,maxtry,result); - - if (result[2] == -2.0) { - Tcl_ResetResult(interp); sprintf(buffer,"%d",maxtry); Tcl_AppendResult(interp, "ERROR: Maximum number of iterations exceeded (",buffer,")! "); - sprintf(buffer,"%f and %f",result[0],result[1]); Tcl_AppendResult(interp, "Got ",buffer," so far, aborting now...", (char*)NULL); - return(TCL_ERROR); - } else if (result[2] == -3.0) { - Tcl_ResetResult(interp); sprintf(buffer,"%f and %f",result[0],result[1]); - Tcl_AppendResult(interp, "ERROR: gamma is not bracketed by the programs initial guess (",buffer,")! Aborting...", (char*)NULL); - return(TCL_ERROR); - } else if (result[2] == -4.0) { - Tcl_ResetResult(interp); sprintf(buffer,"%f and %f",result[0],result[1]); - Tcl_AppendResult(interp, "ERROR: lower boundary on wrong side of the function (",buffer,")! Aborting...", (char*)NULL); - return(TCL_ERROR); - } else if (result[2] == -5.0) { - Tcl_ResetResult(interp); Tcl_AppendResult(interp, "ERROR: Something went wrong! Aborting...", (char*)NULL); - return(TCL_ERROR); - } - sprintf(buffer,"%f %f %f",result[0],result[1],result[2]); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return (TCL_OK); + /* append result */ + { + double bin_width = 0.0, r = 0.0; + bin_width = (r_max - r_min) / (double) r_bins; + r = r_min + bin_width / 2.0; + Tcl_AppendResult(interp, " {\n", (char *) NULL); + for (i = 0; i < r_bins; i++) { + sprintf(buffer, "%f %f", r, rdf[i]); + Tcl_AppendResult(interp, "{ ", buffer, " }\n", (char *) NULL); + r += bin_width; + } + Tcl_AppendResult(interp, "}\n", (char *) NULL); + } + free(rdf); + return (TCL_OK); } - -/** Has something to do with computing compressibility from volume fluctuations. Docs missing. -*/ -static int tclcommand_analyze_parse_Vkappa(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze Vkappa [{ reset | read | set }]' */ - double result = 0.0; - char buffer[3*TCL_DOUBLE_SPACE+3]; - - if (argc > 0) - if (ARG0_IS_S("reset")) - Vkappa.Vk1 = Vkappa.Vk2 = Vkappa.avk = 0.0; - else if (ARG0_IS_S("read")) { - sprintf(buffer,"%f %f %f ",Vkappa.Vk1,Vkappa.Vk2,Vkappa.avk); - Tcl_AppendResult(interp, buffer, (char *)NULL); return (TCL_OK); } - else if (ARG0_IS_S("set")) { - if (argc < 4 || !ARG_IS_D(1,Vkappa.Vk1) || !ARG_IS_D(2,Vkappa.Vk2) || !ARG_IS_D(3,Vkappa.avk)) { - Tcl_AppendResult(interp, "usage: analyze Vkappa [{ reset | read | set }] ", (char *)NULL); return TCL_ERROR; } - if (Vkappa.avk <= 0.0) { - Tcl_AppendResult(interp, "ERROR: # of averages must be positiv! Resetting values...", (char *)NULL); - result = Vkappa.Vk1 = Vkappa.Vk2 = Vkappa.avk = 0.0; return TCL_ERROR; } - result = Vkappa.Vk2/Vkappa.avk - SQR(Vkappa.Vk1/Vkappa.avk); } - else { - Tcl_AppendResult(interp, "usage: analyze Vkappa [{ reset | read | set }] ", (char *)NULL); return TCL_ERROR; } - else { - Vkappa.Vk1 += box_l[0]*box_l[1]*box_l[2]; - Vkappa.Vk2 += SQR(box_l[0]*box_l[1]*box_l[2]); - Vkappa.avk += 1.0; - result = Vkappa.Vk2/Vkappa.avk - SQR(Vkappa.Vk1/Vkappa.avk); - } - - Tcl_PrintDouble(interp, result, buffer); - Tcl_AppendResult(interp, buffer, (char *)NULL); - return (TCL_OK); +int tclcommand_analyze_parse_structurefactor(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze { stucturefactor } ' */ + /***********************************************************************************************************/ + char buffer[2 * TCL_DOUBLE_SPACE + 4]; + int i, type, order; + double qfak, *sf; + if (argc < 2) { + Tcl_AppendResult(interp, "Wrong # of args! Usage: analyze structurefactor [ ]", + (char *) NULL); + return (TCL_ERROR); + } else { + if (!ARG0_IS_I(type)) + return (TCL_ERROR); + if (!ARG1_IS_I(order)) + return (TCL_ERROR); + argc -= 2; + argv += 2; + } + updatePartCfg(WITHOUT_BONDS); + calc_structurefactor(type, order, &sf); + + qfak = 2.0 * PI / box_l[0]; + for (i = 0; i < order * order; i++) { + if (sf[2 * i + 1] > 0) { + sprintf(buffer, "{%f %f} ", qfak * sqrt(i + 1), sf[2 * i]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + } + free(sf); + return (TCL_OK); } +static int tclcommand_analyze_parse_density_profile_av(Tcl_Interp *interp, int argc, char **argv) { + /* 'analyze [ ]' */ + int n_conf; + int n_bin; + double density; + int dir; + double *rho_ave; + int type; + int i; + char buffer[2 * TCL_DOUBLE_SPACE + TCL_INTEGER_SPACE + 256]; -static int tclcommand_analyze_parse_distribution(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze distribution { } { } [ [ [ [ []]]]]' */ - /*********************************************************************************************************************************/ - char buffer[2*TCL_DOUBLE_SPACE+3*TCL_INTEGER_SPACE+256]; - IntList p1,p2; - double r_min=0, r_max=-1.0; - int r_bins=0, log_flag=0, int_flag=0; - int i; - double *distribution, low; + /* parse arguments */ + if (argc < 5) { + Tcl_AppendResult(interp, "usage: analyze [ ]", (char *) NULL); + return (TCL_ERROR); + } - init_intlist(&p1); init_intlist(&p2); + if (!ARG0_IS_I(n_bin)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze [ ]", (char *) NULL); + return (TCL_ERROR); + } - if (argc < 2) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *)NULL); - return (TCL_ERROR); - } + if (!ARG1_IS_D(density)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze [ ]", (char *) NULL); + return (TCL_ERROR); + } + argc -= 2; + argv += 2; - if (!ARG0_IS_INTLIST(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *)NULL); - return (TCL_ERROR); - } - if (!ARG1_IS_INTLIST(p2)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze distribution [ ]", (char *)NULL); - return (TCL_ERROR); - } - - argc -= 2; argv += 2; - - if( argc>0 ) { if (!ARG0_IS_D(r_min)) return (TCL_ERROR); argc--; argv++; } - if( argc>0 ) { if (!ARG0_IS_D(r_max)) return (TCL_ERROR); argc--; argv++; } - if( argc>0 ) { if (!ARG0_IS_I(r_bins)) return (TCL_ERROR); argc--; argv++; } - if( argc>0 ) { if (!ARG0_IS_I(log_flag)) return (TCL_ERROR); argc--; argv++; } - if( argc>0 ) { if (!ARG0_IS_I(int_flag)) return (TCL_ERROR); argc--; argv++; } - - /* if not given set defaults */ - if(r_max == -1.) r_max = min_box_l/2.0; - if(r_bins < 0 ) r_bins = n_total_particles / 20; - - /* give back what you do */ - Tcl_AppendResult(interp, "{ analyze distribution { ", (char *)NULL); - for(i=0; i 0) { + if (!ARG0_IS_I(dir)) return (TCL_ERROR); + argc--; + argv++; + } + if (argc > 0) { + if (!ARG0_IS_I(n_conf)) return (TCL_ERROR); + argc--; + argv++; + } else + n_conf = n_configs; -static int tclcommand_analyze_parse_vel_distr(Tcl_Interp *interp, int argc, char **argv) -{ - /* 'analyze vel_distr []' */ - char buffer[3*TCL_DOUBLE_SPACE+3]; - int p1; - int bins=100; - double max=0.0; - - /* parse arguments */ - if (argc == 0) { - Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *)NULL); - return (TCL_ERROR); - } - - if (!ARG0_IS_I(p1)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *)NULL); - return (TCL_ERROR); - } + if (!ARG0_IS_I(type)) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "usage: analyze [ ]", (char *) NULL); + return (TCL_ERROR); + } - if (argc > 1){ - if (!ARG1_IS_I(bins)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *)NULL); - return (TCL_ERROR); + rho_ave = (double*) malloc(n_bin * sizeof (double)); + for (i = 0; i < n_bin; i++) + rho_ave[i] = 0.0; + + if (!sortPartCfg()) { + Tcl_AppendResult(interp, "for analyze, store particles consecutively starting with 0.", (char *) NULL); + return (TCL_ERROR); } - } - if (argc > 2){ - if (!ARG_IS_D(2,max)) { - Tcl_ResetResult(interp); - Tcl_AppendResult(interp, "usage: analyze vel_distr [bins max]", (char *)NULL); - return (TCL_ERROR); + density_profile_av(n_conf, n_bin, density, dir, rho_ave, type); + /* append result */ + double r_bin, r; + r_bin = box_l[dir] / (double) (n_bin); + r = r_bin / 2.0; + Tcl_AppendResult(interp, " {\n", (char *) NULL); + for (i = 0; i < n_bin; i++) { + sprintf(buffer, "%f %f", r, rho_ave[i]); + Tcl_AppendResult(interp, "{ ", buffer, " }\n", (char *) NULL); + r += r_bin; } - } + Tcl_AppendResult(interp, "}\n", (char *) NULL); - sprintf(buffer,"%i %i %f",p1,bins,max); - Tcl_AppendResult(interp, "{ analyze vel_distr ",buffer,"} ",(char *)NULL); - updatePartCfg(WITHOUT_BONDS); - tclcommand_analyze_print_vel_distr(interp,p1,bins,max); + free(rho_ave); - return TCL_OK; + return TCL_OK; } -static int tclcommand_analyze_parse_rdf(Tcl_Interp *interp, int average, int argc, char **argv) -{ - /* 'analyze rdf' (radial distribution function) */ - /************************************************/ - char buffer[2*TCL_DOUBLE_SPACE+TCL_INTEGER_SPACE+256]; - IntList p1,p2; - double r_min=0, r_max=-1.0; - double x_min=0, x_max=-1.0; - int r_bins=100, n_conf=1, i; - double *rdf; +static int tclcommand_analyze_parse_diffusion_profile(Tcl_Interp *interp, int argc, char **argv) { + int i; + int nbins, n_part, n_conf, time, type, dir; + double xmin, xmax; + double *bins; + char buffer[TCL_DOUBLE_SPACE]; - init_intlist(&p1); init_intlist(&p2); + /* parse arguments */ + if (argc < 8) { + Tcl_AppendResult(interp, "usage: analyze [