Commit 195c19b8 authored by Rudolf Weeber's avatar Rudolf Weeber

Merge branch 'python' of git://github.com/espressomd/espresso into scafacos_default

parents 18e9a4b0 71481b17
......@@ -205,6 +205,16 @@ empty:
- linux
- cuda
ubuntu:wo-dependencies:
stage: build
image: gitlab.icp.uni-stuttgart.de:4567/espressomd/docker/$CI_JOB_NAME
script:
- export myconfig=maxset make_check=false
- bash maintainer/CI/build_cmake.sh
tags:
- docker
- linux
### Builds with ROCm
rocm-maxset:
......
......@@ -73,6 +73,7 @@ option(WITH_CUDA "Build with GPU support" ON)
option(WITH_HDF5 "Build with HDF5 support" ON)
option(WITH_TESTS "Enable tests" ON)
option(WITH_SCAFACOS "Build with Scafacos support" OFF)
option(WITH_BENCHMARKS "Enable benchmarks" OFF)
option(WITH_VALGRIND_INSTRUMENTATION "Build with valgrind instrumentation markers" OFF)
if( CMAKE_VERSION VERSION_GREATER 3.5.2 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
option(WITH_CLANG_TIDY "Run Clang-Tidy during compilation" OFF)
......@@ -179,7 +180,8 @@ if (WITH_CUDA)
target_link_libraries(${target} ${CUFFT_LIBRARY})
endfunction()
else()
find_package(HIP QUIET MODULE)
list(APPEND CMAKE_MODULE_PATH "/opt/rocm/hip/cmake")
find_package(HIP 1.5.18494 QUIET MODULE)
if(HIP_FOUND)
set(HCC_PATH "${HIP_ROOT_DIR}")
find_package(HIP MODULE)
......@@ -476,6 +478,11 @@ if(WITH_TESTS)
add_subdirectory(testsuite)
endif(WITH_TESTS)
if(WITH_BENCHMARKS)
add_custom_target(benchmark)
add_subdirectory(maintainer/benchmarks)
endif(WITH_BENCHMARKS)
#######################################################################
# Subdirectories
#######################################################################
......
This diff is collapsed.
###############################################################################
# Runs commands using HIPCC
###############################################################################
###############################################################################
# This file runs the hipcc commands to produce the desired output file
# along with the dependency file needed by CMake to compute dependencies.
#
# Input variables:
#
# verbose:BOOL=<> OFF: Be as quiet as possible (default)
# ON : Describe each step
# build_configuration:STRING=<> Build configuration. Defaults to Debug.
# generated_file:STRING=<> File to generate. Mandatory argument.
if(NOT build_configuration)
set(build_configuration Debug)
endif()
if(NOT generated_file)
message(FATAL_ERROR "You must specify generated_file on the command line")
endif()
# Set these up as variables to make reading the generated file easier
set(HIP_HIPCC_EXECUTABLE "@HIP_HIPCC_EXECUTABLE@") # path
set(HIP_HIPCONFIG_EXECUTABLE "@HIP_HIPCONFIG_EXECUTABLE@") #path
set(HIP_HOST_COMPILER "@HIP_HOST_COMPILER@") # path
set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path
set(HIP_run_make2cmake "@HIP_run_make2cmake@") # path
set(HCC_HOME "@HCC_HOME@") #path
@HIP_HOST_FLAGS@
@_HIP_HIPCC_FLAGS@
@_HIP_HCC_FLAGS@
@_HIP_NVCC_FLAGS@
set(HIP_HIPCC_INCLUDE_ARGS "@HIP_HIPCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly)
set(cmake_dependency_file "@cmake_dependency_file@") # path
set(source_file "@source_file@") # path
set(host_flag "@host_flag@") # bool
# Determine compiler and compiler flags
execute_process(COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --platform OUTPUT_VARIABLE HIP_PLATFORM OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT host_flag)
set(__CC ${HIP_HIPCC_EXECUTABLE})
if(HIP_PLATFORM STREQUAL "hcc")
if(NOT "x${HCC_HOME}" STREQUAL "x")
set(ENV{HCC_HOME} ${HCC_HOME})
endif()
set(__CC_FLAGS ${HIP_HIPCC_FLAGS} ${HIP_HCC_FLAGS} ${HIP_HIPCC_FLAGS_${build_configuration}} ${HIP_HCC_FLAGS_${build_configuration}})
else()
set(__CC_FLAGS ${HIP_HIPCC_FLAGS} ${HIP_NVCC_FLAGS} ${HIP_HIPCC_FLAGS_${build_configuration}} ${HIP_NVCC_FLAGS_${build_configuration}})
endif()
else()
set(__CC ${HIP_HOST_COMPILER})
set(__CC_FLAGS ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}})
endif()
set(__CC_INCLUDES ${HIP_HIPCC_INCLUDE_ARGS})
# hip_execute_process - Executes a command with optional command echo and status message.
# status - Status message to print if verbose is true
# command - COMMAND argument from the usual execute_process argument structure
# ARGN - Remaining arguments are the command with arguments
# HIP_result - Return value from running the command
macro(hip_execute_process status command)
set(_command ${command})
if(NOT "x${_command}" STREQUAL "xCOMMAND")
message(FATAL_ERROR "Malformed call to hip_execute_process. Missing COMMAND as second argument. (command = ${command})")
endif()
if(verbose)
execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status})
# Build command string to print
set(hip_execute_process_string)
foreach(arg ${ARGN})
# Escape quotes if any
string(REPLACE "\"" "\\\"" arg ${arg})
# Surround args with spaces with quotes
if(arg MATCHES " ")
list(APPEND hip_execute_process_string "\"${arg}\"")
else()
list(APPEND hip_execute_process_string ${arg})
endif()
endforeach()
# Echo the command
execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${hip_execute_process_string})
endif()
# Run the command
execute_process(COMMAND ${ARGN} RESULT_VARIABLE HIP_result)
endmacro()
# Delete the target file
hip_execute_process(
"Removing ${generated_file}"
COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
)
# Generate the dependency file
hip_execute_process(
"Generating dependency file: ${cmake_dependency_file}.pre"
COMMAND "${__CC}"
-M
"${source_file}"
-o "${cmake_dependency_file}.pre"
${__CC_FLAGS}
${__CC_INCLUDES}
)
if(HIP_result)
message(FATAL_ERROR "Error generating ${generated_file}")
endif()
# Generate the cmake readable dependency file to a temp file
hip_execute_process(
"Generating temporary cmake readable file: ${cmake_dependency_file}.tmp"
COMMAND "${CMAKE_COMMAND}"
-D "input_file:FILEPATH=${cmake_dependency_file}.pre"
-D "output_file:FILEPATH=${cmake_dependency_file}.tmp"
-D "verbose=${verbose}"
-P "${HIP_run_make2cmake}"
)
if(HIP_result)
message(FATAL_ERROR "Error generating ${generated_file}")
endif()
# Copy the file if it is different
hip_execute_process(
"Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}"
)
if(HIP_result)
message(FATAL_ERROR "Error generating ${generated_file}")
endif()
# Delete the temporary file
hip_execute_process(
"Removing ${cmake_dependency_file}.tmp and ${cmake_dependency_file}.pre"
COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" "${cmake_dependency_file}.pre"
)
if(HIP_result)
message(FATAL_ERROR "Error generating ${generated_file}")
endif()
# Generate the output file
hip_execute_process(
"Generating ${generated_file}"
COMMAND "${__CC}"
-c
"${source_file}"
-o "${generated_file}"
${__CC_FLAGS}
${__CC_INCLUDES}
)
if(HIP_result)
# Make sure that we delete the output file
hip_execute_process(
"Removing ${generated_file}"
COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
)
message(FATAL_ERROR "Error generating file ${generated_file}")
else()
if(verbose)
message("Generated ${generated_file} successfully.")
endif()
endif()
# vim: ts=4:sw=4:expandtab:smartindent
###############################################################################
# Computes dependencies using HIPCC
###############################################################################
###############################################################################
# This file converts dependency files generated using hipcc to a format that
# cmake can understand.
# Input variables:
#
# input_file:STRING=<> Dependency file to parse. Required argument
# output_file:STRING=<> Output file to generate. Required argument
if(NOT input_file OR NOT output_file)
message(FATAL_ERROR "You must specify input_file and output_file on the command line")
endif()
file(READ ${input_file} depend_text)
if (NOT "${depend_text}" STREQUAL "")
string(REPLACE " /" "\n/" depend_text ${depend_text})
string(REGEX REPLACE "^.*:" "" depend_text ${depend_text})
string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text})
set(dependency_list "")
foreach(file ${depend_text})
string(REGEX REPLACE "^ +" "" file ${file})
if(NOT EXISTS "${file}")
message(WARNING " Removing non-existent dependency file: ${file}")
set(file "")
endif()
if(NOT IS_DIRECTORY "${file}")
get_filename_component(file_absolute "${file}" ABSOLUTE)
list(APPEND dependency_list "${file_absolute}")
endif()
endforeach()
endif()
# Remove the duplicate entries and sort them.
list(REMOVE_DUPLICATES dependency_list)
list(SORT dependency_list)
foreach(file ${dependency_list})
set(hip_hipcc_depend "${hip_hipcc_depend} \"${file}\"\n")
endforeach()
file(WRITE ${output_file} "# Generated by: FindHIP.cmake. Do not edit.\nSET(HIP_HIPCC_DEPEND\n ${hip_hipcc_depend})\n\n")
# vim: ts=4:sw=4:expandtab:smartindent
......@@ -103,7 +103,7 @@ ROCm SDK to make use of GPU computation:
wget -qO - http://repo.radeon.com/rocm/apt/debian/rocm.gpg.key | sudo apt-key add -
echo 'deb [arch=amd64] http://repo.radeon.com/rocm/apt/debian/ xenial main' | sudo tee /etc/apt/sources.list.d/rocm.list
sudo apt update
sudo apt install libnuma-dev rocm-dkms rocblas rocfft rocrand
sudo apt install libnuma-dev rocm-dkms rocblas rocfft rocrand hip-thrust
.. _Installing Requirements on Mac OS X:
......
if(NOT DEFINED TEST_NP)
include(ProcessorCount)
ProcessorCount(NP)
math(EXPR TEST_NP "${NP}/2 + 1")
endif()
if(EXISTS ${MPIEXEC})
# OpenMPI 3.0 and higher checks the number of processes against the number of CPUs
execute_process(COMMAND ${MPIEXEC} --version RESULT_VARIABLE mpi_version_result OUTPUT_VARIABLE mpi_version_output ERROR_VARIABLE mpi_version_output)
if (mpi_version_result EQUAL 0 AND mpi_version_output MATCHES "\\(Open(RTE| MPI)\\) ([3-9]\\.|1[0-9])")
set(MPIEXEC_OVERSUBSCRIBE "-oversubscribe")
else()
set(MPIEXEC_OVERSUBSCRIBE "")
endif()
endif()
function(PYTHON_BENCHMARK)
cmake_parse_arguments(BENCHMARK "" "FILE;RUN_WITH_MPI;MIN_NUM_PROC;MAX_NUM_PROC" "ARGUMENTS;DEPENDENCIES" ${ARGN})
get_filename_component(BENCHMARK_NAME ${BENCHMARK_FILE} NAME_WE)
foreach(argument IN LISTS BENCHMARK_ARGUMENTS)
string(REGEX REPLACE "[^-a-zA-Z0-9_\\.]+" "_" argument ${argument})
string(REGEX REPLACE "^[-_]+" "" argument ${argument})
set(BENCHMARK_NAME "${BENCHMARK_NAME}__${argument}")
endforeach(argument)
configure_file(${BENCHMARK_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${BENCHMARK_FILE})
foreach(dependency IN LISTS BENCHMARK_DEPENDENCIES)
configure_file(${dependency} ${CMAKE_CURRENT_BINARY_DIR}/${dependency})
endforeach(dependency)
set(BENCHMARK_FILE "${CMAKE_CURRENT_BINARY_DIR}/${BENCHMARK_FILE}")
list(APPEND BENCHMARK_ARGUMENTS "--output=${CMAKE_BINARY_DIR}/benchmarks.csv.part")
# default values
if (NOT DEFINED BENCHMARK_RUN_WITH_MPI)
set(BENCHMARK_RUN_WITH_MPI TRUE)
endif()
if (NOT DEFINED BENCHMARK_MIN_NUM_PROC)
set(BENCHMARK_MIN_NUM_PROC 1)
endif()
if (NOT DEFINED BENCHMARK_MAX_NUM_PROC)
set(BENCHMARK_MAX_NUM_PROC ${NP})
endif()
# parallel schemes
if(EXISTS ${MPIEXEC} AND ${BENCHMARK_RUN_WITH_MPI})
set(BENCHMARK_CONFIGURATIONS "0")
if(${NP} GREATER 0 AND ${BENCHMARK_MAX_NUM_PROC} GREATER 0 AND ${BENCHMARK_MIN_NUM_PROC} LESS 2)
list(APPEND BENCHMARK_CONFIGURATIONS 1)
endif()
if(${NP} GREATER 1 AND ${BENCHMARK_MAX_NUM_PROC} GREATER 1 AND ${BENCHMARK_MIN_NUM_PROC} LESS 3)
list(APPEND BENCHMARK_CONFIGURATIONS 2)
endif()
if(${NP} GREATER 3 AND ${BENCHMARK_MAX_NUM_PROC} GREATER 3 AND ${BENCHMARK_MIN_NUM_PROC} LESS 5)
list(APPEND BENCHMARK_CONFIGURATIONS 4)
endif()
if(${NP} GREATER 7 AND ${BENCHMARK_MAX_NUM_PROC} GREATER 7 AND ${BENCHMARK_MIN_NUM_PROC} LESS 9)
list(APPEND BENCHMARK_CONFIGURATIONS 8)
endif()
if(${NP} GREATER 15 AND ${BENCHMARK_MAX_NUM_PROC} GREATER 15 AND ${BENCHMARK_MIN_NUM_PROC} LESS 17)
list(APPEND BENCHMARK_CONFIGURATIONS 16)
endif()
list(REMOVE_AT BENCHMARK_CONFIGURATIONS 0)
foreach(nproc IN LISTS BENCHMARK_CONFIGURATIONS)
add_test(NAME benchmark__${BENCHMARK_NAME}__parallel_${nproc}
COMMAND ${MPIEXEC} ${MPIEXEC_OVERSUBSCRIBE} ${MPIEXEC_NUMPROC_FLAG} ${nproc}
${CMAKE_BINARY_DIR}/pypresso ${BENCHMARK_FILE} ${BENCHMARK_ARGUMENTS}
CONFIGURATIONS "parallel")
endforeach(nproc)
else()
add_test(NAME benchmark__${BENCHMARK_NAME}__serial
COMMAND ${CMAKE_BINARY_DIR}/pypresso ${BENCHMARK_FILE} ${BENCHMARK_ARGUMENTS}
CONFIGURATIONS "serial")
endif()
endfunction(PYTHON_BENCHMARK)
python_benchmark(FILE lj.py ARGUMENTS "--particles_per_core=1000;--volume_fraction=0.50")
python_benchmark(FILE lj.py ARGUMENTS "--particles_per_core=1000;--volume_fraction=0.02")
python_benchmark(FILE lj.py ARGUMENTS "--particles_per_core=10000;--volume_fraction=0.50")
python_benchmark(FILE lj.py ARGUMENTS "--particles_per_core=10000;--volume_fraction=0.02")
python_benchmark(FILE p3m.py ARGUMENTS "--particles_per_core=1000;--volume_fraction=0.25;--bjerrum_length=4")
python_benchmark(FILE p3m.py ARGUMENTS "--particles_per_core=10000;--volume_fraction=0.25;--bjerrum_length=4")
add_custom_target(benchmark_python_serial COMMAND ${CMAKE_CTEST_COMMAND} $(ARGS) -C serial --output-on-failure)
add_dependencies(benchmark_python_serial pypresso)
add_custom_target(benchmark_python_parallel COMMAND ${CMAKE_CTEST_COMMAND} $(ARGS) -C parallel --output-on-failure)
add_dependencies(benchmark_python_parallel pypresso)
add_custom_target(benchmark_python)
if(EXISTS ${MPIEXEC})
add_dependencies(benchmark_python pypresso benchmark_python_parallel)
else()
add_dependencies(benchmark_python pypresso benchmark_python_serial)
endif()
add_dependencies(benchmark benchmark_python)
#
# Copyright (C) 2013-2018 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 <http://www.gnu.org/licenses/>.
#
from __future__ import print_function
import os
import sys
import numpy as np
from time import time, sleep
import argparse
parser = argparse.ArgumentParser(description="Benchmark LJ simulations. "
"Save the results to a CSV file.")
parser.add_argument("--particles_per_core", metavar="N", action="store",
type=int, default=1000, required=False,
help="Number of particles in the simulation box")
parser.add_argument("--volume_fraction", metavar="FRAC", action="store",
type=float, default=0.50, required=False,
help="Fraction of the simulation box volume occupied by "
"particles (range: [0.01-0.74], default: 0.50)")
group = parser.add_mutually_exclusive_group()
group.add_argument("--output", metavar="FILEPATH", action="store",
type=str, required=False, default="benchmarks.csv",
help="Output file (default: benchmarks.csv)")
group.add_argument("--visualizer", action="store_true",
help="Starts the visualizer (for debugging purposes)")
args = parser.parse_args()
# process and check arguments
n_proc = int(os.environ.get("OMPI_COMM_WORLD_SIZE", 1))
n_part = n_proc * args.particles_per_core
measurement_steps = int(np.round(5e6 / args.particles_per_core, -2))
assert args.volume_fraction > 0, "volume_fraction must be a positive number"
assert args.volume_fraction < np.pi / (3 * np.sqrt(2)), \
"volume_fraction exceeds the physical limit of sphere packing (~0.74)"
if not args.visualizer:
assert(measurement_steps >= 100), \
"{} steps per tick are too short".format(measurement_steps)
import espressomd
from espressomd import thermostat
if args.visualizer:
from espressomd import visualization
from threading import Thread
required_features = ["LENNARD_JONES"]
espressomd.assert_features(required_features)
print(espressomd.features())
# Interaction parameters (Lennard-Jones)
#############################################################
lj_eps = 1.0 # LJ epsilon
lj_sig = 1.0 # particle diameter
lj_cut = lj_sig * 2**(1. / 6.) # cutoff distance
# System parameters
#############################################################
# volume of N spheres with radius r: N * (4/3*pi*r^3)
box_l = (n_part * 4. / 3. * np.pi * (lj_sig / 2.)**3
/ args.volume_fraction)**(1. / 3.)
# System
#############################################################
system = espressomd.System(box_l=3 * (box_l,))
# PRNG seeds
#############################################################
system.random_number_generator_state = list(range(
n_proc * (system._get_PRNG_state_size() + 1)))
#np.random.seed(1)
# Integration parameters
#############################################################
system.time_step = 0.01
system.cell_system.skin = 0.5
system.thermostat.turn_off()
#############################################################
# Setup System #
#############################################################
# Interaction setup
#############################################################
system.non_bonded_inter[0, 0].lennard_jones.set_params(
epsilon=lj_eps, sigma=lj_sig, cutoff=lj_cut, shift="auto")
print("LJ-parameters:")
print(system.non_bonded_inter[0, 0].lennard_jones.get_params())
# Particle setup
#############################################################
for i in range(n_part):
system.part.add(id=i, pos=np.random.random(3) * system.box_l)
#############################################################
# Warmup Integration #
#############################################################
system.integrator.set_steepest_descent(
f_max=0,
gamma=0.001,
max_displacement=0.01)
# warmup
while system.analysis.energy()["total"] > 3 * n_part:
print("minimization: {:.1f}".format(system.analysis.energy()["total"]))
system.integrator.run(10)
print()
system.integrator.set_vv()
system.thermostat.set_langevin(kT=1.0, gamma=1.0)
# tune skin
print("Tune skin: {}".format(system.cell_system.tune_skin(
min_skin=0.2, max_skin=1, tol=0.05, int_steps=100)))
system.integrator.run(min(5 * measurement_steps, 60000))
print("Tune skin: {}".format(system.cell_system.tune_skin(
min_skin=0.2, max_skin=1, tol=0.05, int_steps=100)))
system.integrator.run(min(10 * measurement_steps, 60000))
print(system.non_bonded_inter[0, 0].lennard_jones)
if not args.visualizer:
# print initial energies
energies = system.analysis.energy()
print(energies)
# time integration loop
print("Timing every {} steps".format(measurement_steps))
main_tick = time()
all_t = []
for i in range(30):
tick = time()
system.integrator.run(measurement_steps)
tock = time()
t = (tock - tick) / measurement_steps
print("step {}, time = {:.2e}, verlet: {:.2f}"
.format(i, t, system.cell_system.get_state()["verlet_reuse"]))
all_t.append(t)
main_tock = time()
# average time
all_t = np.array(all_t)
avg = np.average(all_t)
ci = 1.96 * np.std(all_t) / np.sqrt(len(all_t) - 1)
print("average: {:.3e} +/- {:.3e} (95% C.I.)".format(avg, ci))
# print final energies
energies = system.analysis.energy()
print(energies)
# write report
cmd = " ".join(x for x in sys.argv[1:] if not x.startswith("--output"))
report = ('"{script}","{arguments}",{cores},"{mpi}",{mean:.3e},'
'{ci:.3e},{n},{dur:.1f},{E1:.5e},{E2:.5e},{E3:.5e}\n'.format(
script=os.path.basename(sys.argv[0]), arguments=cmd,
cores=n_proc, dur=main_tock - main_tick, n=measurement_steps,
mpi="OMPI_COMM_WORLD_SIZE" in os.environ, mean=avg, ci=ci,
E1=system.analysis.energy()["total"],
E2=system.analysis.energy()["kinetic"],
E3=system.analysis.energy()["non_bonded"]))
if not os.path.isfile(args.output):
report = ('"script","arguments","cores","MPI","mean","ci",'
'"steps_per_tick","duration","E1","E2","E3"\n' + report)
with open(args.output, "a") as f:
f.write(report)
else:
# use visualizer
visualizer = visualization.openGLLive(system)
def main_thread():
while True:
system.integrator.run(1)
visualizer.update()
sleep(1 / 60.) # limit framerate to at most 60 FPS
t = Thread(target=main_thread)
t.daemon = True
t.start()
visualizer.start()
#
# Copyright (C) 2013-2018 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 <http://www.gnu.org/licenses/>.
#
from __future__ import print_function
import os
import sys
import numpy as np
from time import time
import argparse
parser = argparse.ArgumentParser(description="Benchmark P3M simulations. "
"Save the results to a CSV file.")
parser.add_argument("--particles_per_core", metavar="N", action="store",
type=int, default=1000, required=False,
help="Number of particles in the simulation box")
parser.add_argument("--volume_fraction", metavar="FRAC", action="store",
type=float, default=0.25, required=False,
help="Fraction of the simulation box volume occupied by "
"particles (range: [0.01-0.74], default: 0.25)")
parser.add_argument("--bjerrum_length", metavar="LENGTH", action="store",
type=float, default=4., required=False,
help="Bjerrum length (default: 4)")
group = parser.add_mutually_exclusive_group()
group.add_argument("--output", metavar="FILEPATH", action="store",
type=str, required=False, default="benchmarks.csv",
help="Output file (default: benchmarks.csv)")
group.add_argument("--visualizer", action="store_true",
help="Starts the visualizer (for debugging purposes)")
args = parser.parse_args()
# process and check arguments
n_proc = int(os.environ.get("OMPI_COMM_WORLD_SIZE", 1))
n_part = n_proc * args.particles_per_core
measurement_steps = int(np.round(5e5 / args.particles_per_core, -1))
assert args.bjerrum_length > 0, "bjerrum_length must be a positive number"
assert args.volume_fraction > 0, "volume_fraction must be a positive number"
assert args.volume_fraction < np.pi / (3 * np.sqrt(2)), \
"volume_fraction exceeds the physical limit of sphere packing (~0.74)"
if not args.visualizer:
assert(measurement_steps >= 50), \
"{} steps per tick are too short".format(measurement_steps)
import espressomd
from espressomd import thermostat
from espressomd import electrostatics
if args.visualizer:
from espressomd import visualization
from threading import Thread
required_features = ["ELECTROSTATICS", "LENNARD_JONES", "MASS"]
espressomd.assert_features(required_features)
print(espressomd.features())
# Interaction parameters (Lennard-Jones, Coulomb)
#############################################################
species = ["anion", "cation"]
types = {"anion": 0, "cation": 0}
charges = {"anion": -1.0, "cation": 1.0}
lj_sigmas = {"anion": 1.0, "cation": 1.0}
lj_epsilons = {"anion": 1.0, "cation": 1.0}
WCA_cut = 2.**(1. / 6.)
lj_cuts = {"anion": WCA_cut * lj_sigmas["anion"],
"cation": WCA_cut * lj_sigmas["cation"]}
masses = {"anion": 1.0, "cation": 1.0}
# System parameters
#############################################################
# volume of N spheres with radius r: N * (4/3*pi*r^3)
lj_sig = (lj_sigmas["cation"] + lj_sigmas["anion"]) / 2
box_l = (n_part * 4. / 3. * np.pi * (lj_sig / 2.)**3
/ args.volume_fraction)**(1. / 3.)
# System
#############################################################
system = espressomd.System(box_l=3 * (box_l,))
system.cell_system.set_domain_decomposition(use_verlet_lists=True)
# PRNG seeds
#############################################################
system.random_number_generator_state = list(range(
n_proc * (system._get_PRNG_state_size() + 1)))
# Integration parameters
#############################################################
system.time_step = 0.01
system.cell_system.skin = .4
system.thermostat.turn_off()
#############################################################
# Setup System #
#############################################################
# Interaction setup
#############################################################
for i in range(len(species)):
ion1 = species[i]
for j in range(i, len(species)):
ion2 = species[j]
lj_sig = (lj_sigmas[ion1] + lj_sigmas[ion2]) / 2
lj_cut = (lj_cuts[ion1] + lj_cuts[ion2]) / 2
lj_eps = (lj_epsilons[ion1] * lj_epsilons[ion2])**(1. / 2.)
system.non_bonded_inter[types[ion1],
types[ion2]].lennard_jones.set_params(
epsilon=lj_eps, sigma=lj_sig, cutoff=lj_cut, shift="auto")
# Particle setup
#############################################################
for i in range(0, n_part, len(species)):
for t in species:
system.part.add(pos=np.random.random(3) * system.box_l,
q=charges[t], type=types[t], mass=masses[t])
#############################################################
# Warmup Integration #
#############################################################
energy = system.analysis.energy()
print("Before Minimization: E_total = {}".format(energy["total"]))
system.minimize_energy.init(f_max=1000, gamma=30.0,
max_steps=1000, max_displacement=0.05)
system.minimize_energy.minimize()