jnvance / ljmd-c

Lennard-Jones Molecular Dynamics collaborative project

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

This package contains simplified MD code with multi-threading parallelization for simulating atoms with a Lennard-Jones potential.

The examples directory contains 3 sets of example input decks and the reference directory the corresponding outputs.

Type: make to compile everything and: make clean to remove all compiled objects Project tree

bin – Output executables (targets). The suffix indicates debug version.

obj – Binary objects created during compilation.

src – Source files of the project with subdirectories if needed.

include – Files used by the main executable.

tests – Source files of tests.

serial - serial version of the code.

python - python wrapper for the top level functions

examples - folder for input example files

.gitignore – Prevents adding binary and temporary files to the git repository.

README.md – General information about the project in Markdown format.

Compilation

In the root directory:

make                      #to make the default MD code with Lennard-Jones potential
make morse                #to make the MD with Morse potential
make shared               #to create the shared libraries
make tests                #to create the test executables
make serial               #to make the original serial-version(not optimized)

Usage

Running the executable directly

cd examples
../bin/ljmd.x < [inputfile].inp
../bin/ljmd-morse.x < [inputfile].inp
../bin/ljmd-serial.x < [inputfile].inp

Running from the python script

cd examples
../python/ljmd.py [inputfile].inp

Benchmark

Benchmarks are done with gprof compilation flag -pg added and removed the conflicting flag -fomit-frame-pointer After factorization the program is benchmarked with argon_108 as input the result is as follows.

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  us/call  us/call  name
 76.22      3.60     3.60    10001   359.72   465.94  force
 21.02      4.59     0.99 346714668     0.00     0.00  pbc
  1.49      4.66     0.07    30006     2.34     2.34  azzero
  1.49      4.73     0.07    10000     7.01   472.95  velverlet
  0.00      4.73     0.00    10001     0.00     0.00  ekin
  0.00      4.73     0.00      101     0.00     0.00  output
  0.00      4.73     0.00       12     0.00     0.00  get_a_line

As one can see the pbc function is called many times. One can optimize this using the Newton's Third law thereby calculating the force between 2 pair of atoms only once instead of twice. After that implementation we get a significant performance improvement.

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  us/call  us/call  name    
 75.75      1.92     1.92    10001   192.38   247.49  force
 20.91      2.46     0.53 173357334     0.00     0.00  pbc
  2.76      2.53     0.07    10000     7.01   254.50  velverlet
  0.79      2.55     0.02    30006     0.67     0.67  azzero
  0.00      2.55     0.00    10001     0.00     0.00  ekin
  0.00      2.55     0.00      101     0.00     0.00  output
  0.00      2.55     0.00       12     0.00     0.00  get_a_line

As shown in the table the performance is improved 2x. But this can be improved further by avoiding to calculate expensive operations such as pow() and sqrt() inside the force loop. after this optimization we get the results as

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  us/call  us/call  name    
 73.12      1.35     1.35    10001   135.26   183.36  force
 25.46      1.82     0.47 173357334     0.00     0.00  pbc
  1.08      1.84     0.02    10000     2.00   185.36  velverlet
  0.54      1.85     0.01    30006     0.33     0.33  azzero
  0.00      1.85     0.00    10001     0.00     0.00  ekin
  0.00      1.85     0.00      101     0.00     0.00  output
  0.00      1.85     0.00       12     0.00     0.00  get_a_line

Here the performance is improved by 30% of the original code. But still the calls the program making to pbc is higher we can reduce it by hard coding it into the loop instead of loop calling the function many times. the performance we get after that modification is faster.

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls   s/call   s/call  name
 95.20      1.34     1.34    10001     0.00     0.00  force
  4.97      1.41     0.07    10000     0.00     0.00  velverlet
  0.00      1.41     0.00    30006     0.00     0.00  azzero
  0.00      1.41     0.00    10001     0.00     0.00  ekin
  0.00      1.41     0.00      101     0.00     0.00  output
  0.00      1.41     0.00       12     0.00     0.00  get_a_line
  0.00      1.41     0.00        2     0.00     0.00  seconds
  0.00      1.41     0.00        1     0.00     1.41  mdsim

For improvement: Attempts at OpenMP and MPI implementations were made and are placed in separate branches. Our OpenMP implementation works but does not give adequate improvements. On the other hand, the MPI implementation has a bug that causes a segmentation fault for number of processes > 1.

About

Lennard-Jones Molecular Dynamics collaborative project


Languages

Language:C 87.5%Language:Makefile 7.8%Language:Python 4.6%