Using SIONlib (parallel I/O library) to write/read HISTORY files in DL_MESO_DPD

Purpose of Module

This module proposes to use the SIONlib library to write/read the trajectory (HISTORY) files in DL_MESO_DPD, the Dissipative Particle Dynamics (DPD) code from the DL_MESO package. In the last release (2.6, dating November 2015), the MPI version of DL_MESO_DPD generates multiple trajectory files, one for each MPI task. The use of SIONlib allows to minimally modify the writing so that just one physical file (history.sion) is produced. An analogous modification has to be implemented in the post-processing utilities that read the HISTORY files. As an example, here the modifications are implemented for one specific utility, format_history_sion.f90, a formatting tool analogous to format_history.f90 (see Formatting the HISTORY files of DL_MESO_DPD). Beside showing how to adapt the reading, this allows a robust check of the implementation, since the output is human readable, contains the full trajectories, and can be readily compared with that obtained using format_history.f90 with the standard version of DL_MESO_DPD.

Notice that the next released version of DL_MESO_DPD (in development) will tackle the writing of files differently, producing a single trajectory file from the start. However, the interface proposed here provides this feature to the users of version 2.6, and represents an alternative solution for the handling of the trajectories.

The implementation presented here is meant to show the feasibility of the interfacing, not to deal with all the possible cases. We therefore restrict in this module to the relevant case in which: i) the simulation is run in parallel using MPI, ii) a single SIONlib-type physical file is produced, and iii) the post-processing is done by a single process.

Finally, we would like to underline that, while SIONlib is optimized for a large number of MPI tasks, the reduction from several output files to just one is in any case a benefit, for example when it comes to the maintenance of the simulation output.

Background Information

The base code for this module is DL_MESO_DPD, the Dissipative Particle Dynamics code from the mesoscopic simulation package DL_MESO, developed by M. Seaton at Daresbury Laboratory. This open source code is available from STFC under both academic (free) and commercial (paid) licenses. The module is to be used with DL_MESO in its last released version, version 2.6 (dating November 2015).

The present module requires the SIONlib library to be installed. Its last released version is number 1.7.1 (dating November 2016).

Testing

The version of DL_MESO_DPD including SIONlib (see below) is compiled using the corresponding makefile (Makefile-MPI). Two pre-processing flags can be used when compiling: -D DEBUG, to print information for any SIONlib-related action, and -D STDTRAJ, to recover the standard printing of trajectories as HISTORY* files.

The utility format_history_sion.f90 is compiled with the available Fortran90+MPI compiler, and using appropriate flags for the SIONlib library, e.g:

mpifort -c -cpp format_history_sion.f90 `/home/user/sionlib/bin/sionconfig --cflags --f77 --mpi --threadsafe --64`
mpifort -o format_history_sion.exe format_history_sion.o `/home/user/sionlib/bin/sionconfig --libs --f77 --mpi --threadsafe --64`

and the executable must be in the same directory of the history.sion file. It is assumed that SIONlib has been installed in the /home/user/sionlib/ directory, where of course the user name has to be adapted. If the pre-processing flag -D DEBUG is used when compiling, the result of each read statement is printed to the standard output and an eventual mismatch in the number of read elements is signaled.

To test the writing/reading of the trajectories, the user can choose any simulation run using DL_MESO_DPD, then analyze the trajectories with both format_history.f90 (which reads standard DL_MESO_DPD binary HISTORY* files) and format_history_sion.f90 (which reads the SIONlib-type history.sion file): the formatted files so obtained, HISTORY*-F and sion*-F, respectively, should coincide.

However, for completeness, we provide the input files for a possible test: the CONTROL file

Simple test

vol 1000.0
temperature 1.0
cutoff 1.0

timestep 0.01
steps 1000
equilibration steps 0
traj  0  100  0
stats every 100
stack size 100
print every 100
job time 1000.0
close time 10.0

ensemble nvt mdvv

nfold  1  1  1
global bonds

finish

and the FIELD file

Simple example

SPECIES 2
A  1.0  0.0  0  
B  1.0  0.0  0  

MOLECULES 1
AB
nummols 1500
beads 2
A  0.0 0.0 0.0
B  0.1 0.0 0.0
bonds 1
harm  1 2 10.0 0.0
finish

INTERACTIONS 2
A  A dpd   25.0 1.0 4.0
B  B dpd   25.0 1.0 4.0

CLOSE

Source Code

A number of DL_MESO_DPD modules have to be slightly modified to use SIONlib when writing the trajectories, namely: variables.f90, constants.f90, start_module.f90, dlmesodpd.f90, error_module.f90 and the Makefile-MPI. As an example of the post-processing of a SIONlib-type trajectory, we provide the formatting utility format_history_sion.f90, analogous to format_history.f90 (see Formatting the HISTORY files of DL_MESO_DPD): it reads the SIONlib trajectory file (history.sion) and produces multiple formatted trajectory files (sion*-F).

In the following we give the needed changes in the form of patches [1]: in the git diff, a is the branch with the standard version (version 2.6, revision 15 [2]), b the SIONlib one.

The patch for Makefile-MPI is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
diff --git a/Makefile-MPI b/Makefile-MPI
index 462de59..0078f94 100644
--- a/Makefile-MPI
+++ b/Makefile-MPI
@@ -1,10 +1,13 @@
 MF=      Makefile
 
+SCFLAGS = `/home/user/sionlib/bin/sionconfig --cflags --f77 --mpi --threadsafe --64`
+SLFLAGS = `/home/user/sionlib/bin/sionconfig --libs --f77 --mpi --threadsafe --64`
+
 FC=      mpifort
-FFLAGS=  -O3
+FFLAGS=  -O3 -cpp
 LFLAGS=  $(FFLAGS)
 
-EXE=     dpd.exe
+EXE=     dpd-MPI-sion.exe
 
 VPATH=   ../DPD/
 
@@ -38,12 +41,12 @@ SRC= \
 OBJ=	$(SRC:.f90=.o)
 
 .f90.o:
-	$(FC) $(FFLAGS) -c $<
+	$(FC) $(FFLAGS) -c $< $(SCFLAGS)
 
 all:	$(EXE)
 
 $(EXE):	$(OBJ)
-	$(FC) $(LFLAGS) -o $@ $(OBJ)
+	$(FC) $(LFLAGS) -o $@ $(OBJ) $(SLFLAGS)
 
 $(OBJ):	$(MF)
 

The patch for variables.f90 is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
diff --git a/variables.f90 b/variables.f90
index 3aef25a..3f6a109 100644
--- a/variables.f90
+++ b/variables.f90
@@ -326,4 +326,18 @@ MODULE variables
 !         Allocated in config_module.f90          
       REAL(KIND=dp), ALLOCATABLE, SAVE, TARGET :: commsinbuf(:,:), commsoutbuf(:,:)
 
+!     variables needed by SIONlib 
+      INTEGER*8 sierr
+      CHARACTER(len=255) :: filename 
+      CHARACTER(len=255) :: newfname
+      INTEGER:: nfiles
+      INTEGER:: gComm, lComm, sid
+      INTEGER:: fsblksize
+      INTEGER*8 :: chunksize
+      INTEGER*8 :: size, nelem
+      INTEGER :: seof
+      INTEGER :: buffer_i(6)
+      REAL(KIND=dp) :: buffer_r(10)
+      CHARACTER(LEN=8) :: buffer_c
+      
 END MODULE

The patch for constants.f90 is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
diff --git a/constants.f90 b/constants.f90
index 65bbee4..82c2641 100644
--- a/constants.f90
+++ b/constants.f90
@@ -13,5 +13,7 @@ MODULE constants
       REAL(KIND=dp), PARAMETER :: fkt=2.0_dp/3.0_dp
       REAL(KIND=dp), PARAMETER :: rt12=3.464101615377546_dp
       REAL(KIND=dp), PARAMETER :: langepsilon=1.0e-6_dp
+!     for SIONlib
+      INTEGER, PARAMETER :: nsion = 13
       
 END MODULE

The patch for dlmesodpd.f90 is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
diff --git a/dlmesodpd.f90 b/dlmesodpd.f90
index 062c26c..90600f2 100644
--- a/dlmesodpd.f90
+++ b/dlmesodpd.f90
@@ -189,8 +189,15 @@ PROGRAM dlmesodpd
       END IF
 
 !     close files, deallocate arrays and close down MPI
-
+#ifdef STDTRAJ
       IF (ltraj) CLOSE (nhist)
+#endif
+!!! SIONlib 3: close SIONlib file  
+      IF (ltraj) call fsion_parclose_mpi(sid,sierr)
+#ifdef DEBUG
+      WRITE (nprint, *) "sierr=", sierr , "on idnode=", idnode
+#endif
+!!!
       CALL free_memory
       IF (.NOT. l_scr) CLOSE (nprint)
       CALL exitcomms ()

The patch for error_module.f90 is

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
diff --git a/error_module.f90 b/error_module.f90
index cb19b28..f8c3c3b 100644
--- a/error_module.f90
+++ b/error_module.f90
@@ -589,6 +589,11 @@ CONTAINS
         CASE (1198)
           WRITE (nprint,"(/,1x,'error: deallocation failure in field_module -> plcfor_stoyanov')")
 
+!      sionlib          
+       CASE (1500) 
+          WRITE (nprint,"(/,1x,'error: this version (using sionlib) does not support restart')")
+       CASE (1501)
+          WRITE (nprint,"(/,1x,'error: problem in writing SIONfile, mismatched number of items',i10)") value
           
         CASE DEFAULT
           WRITE (nprint,"(/,1x,'error: undefined error code found')") 
@@ -605,7 +610,12 @@ CONTAINS
 !     close all i/o channels
 
         IF (idnode==0) CLOSE (nprint)
+#ifdef STDTRAJ
         CLOSE (nhist)
+#endif
+!!! SIONlib: close file
+        IF (ltraj) call fsion_parclose_mpi(sid,sierr)
+!!!
         IF (idnode==0) CLOSE (nsave)
 
 !     shut down MPI and stop program

The patch for start_module.f90 is

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
diff --git a/start_module.f90 b/start_module.f90
index a7f0233..81c3b24 100644
--- a/start_module.f90
+++ b/start_module.f90
@@ -95,6 +95,9 @@ CONTAINS
       INTEGER :: fail (4)
       INTEGER, ALLOCATABLE :: localmolmap(:)
 
+!     SIONlib 0: set sionlib filename
+      filename = 'history.sion'
+
 !     set restart filename
 
       WRITE (chan, '(i6.6)') idnode
@@ -296,6 +299,10 @@ CONTAINS
 
         IF (nstep>0) THEN
            
+!!! SIONlib 1a: give error for resart
+           CALL error (idnode, 1500, 1)
+!!!
+#ifdef STDTRAJ           
            IF (nodes>1) THEN
               OPEN (nhist, file='HISTORY'//chan, access = 'sequential', form = 'unformatted', status = 'unknown',&
                    & position = 'append')
@@ -303,45 +310,184 @@ CONTAINS
               OPEN (nhist, file='HISTORY', access = 'sequential', form = 'unformatted', status = 'unknown',&
                    & position = 'append')
            END IF
-
+#endif          
         ELSE
 
+!!! SIONlib 1b: define and open
+           gcomm = MPI_COMM_WORLD
+           lcomm = MPI_COMM_WORLD 
+           fsblksize = -1
+           chunksize = 100
+           nfiles = 1
+           call fsion_paropen_mpi(trim(filename),'bw',nfiles, gComm,lComm, &
+                chunksize,fsblksize,idnode,newfname,sid)
+#ifdef DEBUG
+           WRITE (6,*) "opened sionfile on node=",idnode ,"; sid=",sid
+           WRITE (6,*) "input chunksize (if needed, will be internally corrected)=", chunksize, "; fsblksize=", fsblksize
+#endif
+!!!
+#ifdef STDTRAJ           
           IF (nodes>1) THEN
             OPEN (nhist, file='HISTORY'//chan, access = 'sequential', form = 'unformatted', status = 'unknown')
           ELSE
             OPEN (nhist, file='HISTORY', access = 'sequential', form = 'unformatted', status = 'unknown')
           END IF
-
-
+#endif          
           IF (lgbnd .AND. idnode>0) THEN
+#ifdef STDTRAJ
              WRITE (nhist) nspe, nmoldef, nusyst, nsyst, nbeads, 0
+#endif
+!!! SIONlib 2a: write into SION file
+            nelem=6
+            size=4
+            buffer_i (1:6) = (/ nspe, nmoldef, nusyst, nsyst, nbeads, 0 /)
+            call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "a written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!            
           ELSE
+#ifdef STDTRAJ
              WRITE (nhist) nspe, nmoldef, nusyst, nsyst, nbeads, nbonds
-          END IF
-
+#endif
+!!! SIONlib 2b: write into SION file
+            nelem=6
+            size=4
+            buffer_i (1:6) = (/ nspe, nmoldef, nusyst, nsyst, nbeads, nbonds /)
+            call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "b written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!            
+         END IF
+#ifdef STDTRAJ
          WRITE (nhist) dimx, dimy, dimz, volm
+#endif
+!!! SIONlib 2c: write into SION file
+         nelem=4
+         size=8
+         buffer_r (1:4) = (/ dimx, dimy, dimz, volm /)
+         call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+         IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+         WRITE (6,*) "c written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!
+#ifdef STDTRAJ
          WRITE (nhist) keytrj, srftype*srfx, srftype*srfy, srftype*srfz
+#endif
+!!! SIONlib 2d: write into SION file
+         nelem=4
+         size=4
+         buffer_i (1:4) = (/ keytrj, srftype*srfx, srftype*srfy, srftype*srfz /)
+         call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+         IF (sierr.ne.nelem)  CALL error (idnode, 1501, INT (sierr - nelem))
+         WRITE (6,*) "d written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!
        
 !      write species information
           DO i = 1, nspe
             k = (i * (i + 1)) / 2
             SELECT CASE (ktype (k))
             CASE (0:2)
+#ifdef STDTRAJ
                WRITE (nhist) namspe (i), amass (i), vvv (2, k), lfrzn (i)
+#endif
+!!! SIONlib 2e: write into SION file
+              nelem=1
+              size=8
+              buffer_c = namspe (i)
+              call fsion_write(buffer_c,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "e1 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+              nelem=2
+              size=8
+              buffer_r (1:2) = (/ amass (i), vvv (2, k) /)              
+              call fsion_write(buffer_r,size,nelem,sid,sierr)              
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "e2 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif              
+              nelem=1
+              size=4
+              buffer_i (1) = lfrzn (i)
+              call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "e3 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!                        
            CASE (3)
+#ifdef STDTRAJ
               WRITE (nhist) namspe (i), amass (i), vvv (6, k), lfrzn (i)
+#endif
+!!! SIONlib 2f: write into SION file
+              nelem=1
+              size=8
+              buffer_c = namspe (i)
+              call fsion_write(buffer_c,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "f1 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif              
+              nelem=2
+              size=8
+              buffer_r (1:2) = (/ amass (i), vvv (6, k) /)              
+              call fsion_write(buffer_r,size,nelem,sid,sierr)              
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "f2 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif              
+              nelem=1
+              size=4
+              buffer_i (1) = lfrzn (i)
+              call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "f3 written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!                        
            END SELECT
           END DO
 
 !      write molecule names
           IF (nmoldef>0) THEN
             DO i = 1, nmoldef
+#ifdef STDTRAJ
                WRITE (nhist) nammol (i)
+#endif
+!!! SIONlib 2g: write into SION file
+              nelem=1
+              size=8
+              buffer_c = nammol (i)
+              call fsion_write(buffer_c,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "g written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!
            END DO
           END IF
 
 !      write name of calculation
+#ifdef STDTRAJ
           WRITE (nhist) text
+#endif
+!!! SIONlib 2h: write into SION file
+              nelem=1
+              size=80
+              call fsion_write(text,size,nelem,sid,sierr)
+#ifdef DEBUG
+              IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+              WRITE (6,*) "h written in sionfile on node=",idnode ,"; # elements",sierr
+#endif              
+!!!
           
 !      create map of local bead numbers to molecule numbers
           ALLOCATE (localmolmap (nbeads), STAT=fail(1))
@@ -351,7 +497,19 @@ CONTAINS
 !      write bead information (including molecule numbers)
           DO i = 1, nbeads
             imol = localmolmap(i)
+#ifdef STDTRAJ
             WRITE (nhist) lab (i), ltp (i), ltm (i), imol
+#endif
+!!! SIONlib 2i: write into SION file
+            nelem=4
+            size=4
+            buffer_i (1:4) = (/ lab (i), ltp (i), ltm (i), imol /)
+            call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "i written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!            
          END DO
 
           DEALLOCATE (localmolmap, STAT=fail(1))
@@ -360,7 +518,19 @@ CONTAINS
 !      write bonds between beads
           IF (nbonds>0 .AND. ((.NOT. lgbnd) .OR. idnode==0)) THEN
             DO j = 1, nbonds
+#ifdef STDTRAJ
                WRITE (nhist) bndtbl (j, 1), bndtbl (j, 2)
+#endif
+!!! SIONlib 2j: write into SION file
+            nelem=2
+            size=4
+            buffer_i (1:2) = (/ bndtbl (j, 1), bndtbl (j, 2) /)
+            call fsion_write(buffer_i,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "j written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!            
            END DO
           END IF
 

These changes only affect one subroutine (start) within the start_module.f90. The user can either implement the changes shown above, or replace the second part of the subroutine start with the file provided (downloadable version of the second part of subroutine start).

The patch for statistics_module.f90 is

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
diff --git a/statistics_module.f90 b/statistics_module.f90
index e2d5e79..e283d16 100644
--- a/statistics_module.f90
+++ b/statistics_module.f90
@@ -11,6 +11,7 @@ MODULE statistics_module
 
       USE constants
       USE variables
+      USE error_module
       IMPLICIT none
 
 CONTAINS
@@ -621,41 +622,103 @@ CONTAINS
       REAL(KIND=dp) :: time
 
 !     write out data
-
+#ifdef STDTRAJ
       WRITE (nhist) time, REAL (nbeads, KIND=dp), dimx, dimy, dimz, shrdx, shrdy, shrdz
+#endif
+!!! SIONlib 2k: write into SION file
+      nelem=8
+      size=8
+      buffer_r (1:8) = (/ time, REAL (nbeads, KIND=dp), dimx, dimy, dimz, shrdx, shrdy, shrdz /)
+      call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+      IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+      WRITE (6,*) "k written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!             
 
       SELECT CASE (keytrj)
       CASE (0)
         ! positions
         DO i = 1, nbeads
+#ifdef STDTRAJ
            WRITE (nhist) REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz
+#endif
+!!! SIONlib 2l: write into SION file
+          nelem=4
+          size=8
+          buffer_r (1:4) = (/ REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz /)
+          call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+          IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+          WRITE (6,*) "l written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!             
         END DO
       CASE (1)
         ! positions and velocities
         DO i = 1, nbeads
+#ifdef STDTRAJ
            WRITE (nhist) REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
                &vxx (i), vyy (i), vzz (i)
+#endif
+!!! SIONlib 2m: write into SION file
+          nelem=7
+          size=8
+          buffer_r (1:7) = (/ REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
+               &vxx (i), vyy (i), vzz (i) /)
+          call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+          IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+          WRITE (6,*) "m written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!          
         END DO
       CASE (2)
         ! positions, velocities and forces
         IF (itype==1) THEN
           DO i = 1, nbeads
+#ifdef STDTRAJ
              WRITE (nhist) REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
                  &vxx (i), vyy (i), vzz (i), (fxx(i)+fvx(i)), (fyy(i)+fvy(i)), (fzz(i)+fvz(i))
+#endif
+!!! SIONlib 2n: write into SION file
+            nelem=10
+            size=8
+            buffer_r (1:10) = (/ REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
+                 &vxx (i), vyy (i), vzz (i), (fxx(i)+fvx(i)), (fyy(i)+fvy(i)), (fzz(i)+fvz(i))  /)
+            call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "n written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!                         
           END DO
         ELSE
           DO i = 1, nbeads
+#ifdef STDTRAJ
              WRITE (nhist) REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
                   &vxx (i), vyy (i), vzz (i), fxx (i), fyy (i), fzz (i)
+#endif
+!!! SIONlib 2p: write into SION file
+            nelem=10
+            size=8
+            buffer_r (1:10) = (/ REAL (lab(i), KIND=dp), xxx (i) + delx, yyy (i) + dely, zzz (i) + delz, &
+                         &vxx (i), vyy (i), vzz (i), fxx (i), fyy (i), fzz (i)  /)
+            call fsion_write(buffer_r,size,nelem,sid,sierr)
+#ifdef DEBUG
+            IF (sierr.ne.nelem) CALL error (idnode, 1501, INT (sierr - nelem))
+            WRITE (6,*) "p written in sionfile on node=",idnode ,"; # elements",sierr
+#endif
+!!!                         
          END DO
         END IF
       END SELECT
 
 !     clear buffers in case of job failure
-
+#ifdef STDTRAJ
       ENDFILE (nhist)
       BACKSPACE (nhist)
-
+#endif
       RETURN
       END SUBROUTINE histout
 

Also here the changes only affect one subroutine (histout) within the statistics_module.f90. The user can either implement the changes shown above, or replace the subroutine histout with the file provided (downloadable version of the subroutine histout).

Finally, the formatting utility format_history_sion.f90 is

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
PROGRAM format_history_sion
!***********************************************************************************
!
! module to format dl_meso HISTORY files written using SIONlib library
!
! authors - m. a. seaton & s. chiacchiera, february 2017
! adapted to use SIONlib: march 2018
!**********************************************************************************
  
IMPLICIT none
INCLUDE "mpif.h"
  
      INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND (15, 307)
      INTEGER, PARAMETER :: ntraj=10,nuser=5

      CHARACTER(80) :: text
      CHARACTER(8), ALLOCATABLE :: namspe (:), nammol (:)
      CHARACTER(6) :: chan
      
      INTEGER, ALLOCATABLE :: ltp (:), ltm (:), mole (:),  beads (:), bonds (:), bndtbl (:,:)
      INTEGER, ALLOCATABLE :: nbdmol (:), nbomol (:)
      INTEGER :: chain, imol, ioerror, i, k, j, nmoldef, ibond
      INTEGER :: nspe, nbeads, nusyst, nsyst, nbonds, global, species, molecule, numnodes, numbond
      INTEGER :: nummol, lfrzn, rnmol, keytrj, srfx, srfy, srfz
      INTEGER :: bead1, bead2
      INTEGER :: nform
      
      REAL(KIND=dp), ALLOCATABLE :: nmol (:)
      REAL(KIND=dp) :: volm, dimx, dimy, dimz, shrdx, shrdy, shrdz
      REAL(KIND=dp) :: amass, rcii
      REAL(KIND=dp) :: time, mbeads, mglobal, x, y, z, vx, vy, vz, fx, fy, fz
      
      LOGICAL :: eof, lcomm, lmcheck
!     for SIONlib
      CHARACTER*(*) :: fname, file_mode
      INTEGER :: numfiles, ntasks, fsblksize, sid
      INTEGER, ALLOCATABLE :: globalranks (:)
      INTEGER*8, ALLOCATABLE :: chunksizes (:)
      INTEGER*8 :: chunksize_input
      INTEGER*8 :: sierr
      INTEGER :: nformsion
      INTEGER*8 :: size, nelem
      INTEGER :: buffer_i(6)
      REAL(KIND=dp) :: buffer_r(10)
      CHARACTER(LEN=8) :: buffer_c
      INTEGER :: rank, chunknum
      INTEGER*8 :: posinchunk
      INTEGER*8, ALLOCATABLE :: pos_d (:)
      INTEGER, ALLOCATABLE :: chun_d (:)
      INTEGER :: seof
      PARAMETER (fname = 'history.sion')
      PARAMETER (file_mode= 'br')
      
      ! Switches for commenting and checking molecules
      
      lcomm =   .TRUE.
      lmcheck = .TRUE.
      
      ! Get number of nodes 

      WRITE (*,*) "Number of nodes used in calculations ?"
      READ (*,*) numnodes

      ! Get chunksize used to write
      WRITE (*,*) "Chunksize used to write history.sion?"
      READ (*,*) chunksize_input
      
      ALLOCATE (beads (numnodes), bonds (numnodes))

! SIONlib: Determine if history.sion file exists
      INQUIRE (file = fname, EXIST = eof)
      IF (.NOT. eof) THEN
         WRITE (*,*) "ERROR: cannot find history.sion file"
         STOP
      END IF

! SIONlib: serial open
      numfiles = 1
      fsblksize = -1
      ALLOCATE (chunksizes (numnodes), globalranks (numnodes)) 
      chunksizes (:) = -1
      globalranks (:) = -1
      call FSION_OPEN (fname, file_mode, ntasks, numfiles, &
           chunksizes, fsblksize, globalranks, sid)
      IF(ntasks.ne.numnodes) THEN
         WRITE (6,*) "Number of tasks used to write is different from given! -", ntasks   
         STOP
      END IF
!      WRITE(6,*) "chunksizes=", chunksizes !not read as it should. Why?
      WRITE(6,*) "fsblksize=", fsblksize
!      WRITE(6,*) "globalranks=",globalranks !not read as it should. Why?
      WRITE(6,*) "sid=", sid
      ! Set *by hand* the values of chunksizes and globalranks
      DO j = 1, ntasks
         globalranks (j) = j-1
         chunksizes (j) = 0
         DO WHILE (chunksizes (j) < chunksize_input) 
            chunksizes (j) = chunksizes (j) + fsblksize
         END DO
      END DO
      WRITE(6,*) "(set by hand) chunksizes=", chunksizes
      WRITE(6,*) "(set by hand) globalranks=", globalranks

!     variables to track positions within the .sion file      
      ALLOCATE (pos_d (numnodes), chun_d (numnodes))      
      
      ! Open the output files
      nform = ntraj + numnodes
      nformsion = nform + numnodes       
      DO j = 1, numnodes
         IF (numnodes>1)THEN
            WRITE (chan, '(i6.6)') j-1
            OPEN (nformsion+j-1, file = 'sion'//chan//'-F', status = 'replace')
         ELSE
            OPEN (nformsion+j-1, file = 'sion-F', status = 'replace')
         END IF
      END DO
      
! SIONlib:  reading the header of history.sion
      ! Here the number of beads, molecules and bonds are determined
      ! Arrays are filled with names of particles and molecules

      numbond = 0

      DO j = 1, numnodes
         seof = 0
         call fsion_feof (sid, seof)
         IF (seof /= 0) THEN
#ifdef DEBUG
            WRITE (6,*) "rank ", j-1, ": End of file !"
#endif
            CYCLE
         END IF
         
         rank = j - 1
         chunknum = 0
         posinchunk = 0
         CALL FSION_SEEK (sid, rank, chunknum, posinchunk, sierr)
         
!     lines a and b
         nelem=6
         size=4
         buffer_i (1:6) = 0
         CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
         WRITE (6,*) "(a/b) in sion file, rank ", rank, ": buffer_i=",buffer_i
         CALL READ_CHECK (sierr, nelem)
#endif
         CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk)
         IF (j==1) THEN
            nspe = buffer_i (1)
            nmoldef = buffer_i (2)
            nusyst = buffer_i (3)
            nsyst = buffer_i (4)
         END IF
         nbeads = buffer_i (5)
         nbonds = buffer_i (6)
         !     line c
         nelem=4
         size=8
         buffer_r (1:4) = 0
         CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
         WRITE (6,*) "(c) in sion file, rank ", rank, ": buffer_r(1:4)=",buffer_r(1:4)
         CALL READ_CHECK (sierr, nelem)
#endif
         CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk)
         IF (j==1) THEN
            dimx = buffer_r (1)
            dimy = buffer_r (2)
            dimz = buffer_r (3)
            volm = buffer_r (4)
         END IF
         !     line d
         nelem=4
         size=4
         buffer_i (1:4) = 0
         CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
         WRITE (6,*) "(d) in sion file, rank ", rank, ": buffer_i(1:4)=",buffer_i(1:4)
         CALL READ_CHECK (sierr, nelem)
#endif
         CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
         IF (j==1) THEN
            keytrj = buffer_i (1)
            srfx = buffer_i (2)
            srfy = buffer_i (3)
            srfz = buffer_i (4)
         END IF
         beads (j) = nbeads
         bonds (j) = nbonds
         numbond = numbond + nbonds
         
         IF (lcomm) WRITE (nformsion+j-1,*) "# nspe, nmoldef, nusyst, nsyst, nbeads, nbonds"
         WRITE (nformsion+j-1,*) nspe, nmoldef, nusyst, nsyst, nbeads, nbonds
         IF (lcomm) WRITE (nformsion+j-1,*) "# dimx, dimy, dimz, volm"
         WRITE (nformsion+j-1,97) dimx, dimy, dimz, volm
         IF (lcomm) WRITE (nformsion+j-1,*) "# keytrj, srfx, srfy, srfz"
         WRITE (nformsion+j-1,*) keytrj, srfx, srfy, srfz

         chun_d (j) = chunknum
         pos_d (j) = posinchunk
      END DO ! end of loop over nodes
!!!
      ALLOCATE (namspe (nspe), nammol (nmoldef))
      IF (lmcheck) THEN 
         ALLOCATE (ltp (1:nsyst), ltm (1:nsyst), mole (1:nsyst))
         ALLOCATE (nmol (1:nmoldef), nbdmol (1:nmoldef), nbomol (1:nmoldef))
         ALLOCATE (bndtbl (numbond, 2))
      ENDIF
      
      DO j = 1, numnodes
         rank = j - 1
         chunknum = chun_d (j)
         posinchunk = pos_d (j)
         CALL FSION_SEEK (sid, rank, chunknum, posinchunk, sierr)
!!! 
         IF (lcomm) WRITE (nformsion+j-1,*) "# SPECIES:"
         IF (lcomm) WRITE (nformsion+j-1,*) "# namspe, amass, rcii, lfrzn"
         
         DO i = 1, nspe
            !     line e
            nelem = 1
            size = 8
            buffer_c = '        '
            CALL FSION_READ(buffer_c,size,nelem,sid,sierr)
#ifdef DEBUG
            WRITE (6,*) "(e1) in sion file, rank ", rank, ": buffer_c=",buffer_c
            CALL READ_CHECK (sierr, nelem)
#endif               
            CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
            IF (j==1) THEN
               namspe (i) = buffer_c
            END IF
               
            nelem=2
            size=8
            buffer_r (1:2) = 0
            CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
            WRITE (6,*) "(e2) in sion file, rank ", rank, ": buffer_r (1:2)=",buffer_r (1:2)
            CALL READ_CHECK (sierr, nelem)
#endif
            CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
            amass = buffer_r (1)
            rcii = buffer_r (2)
            
            nelem=1
            size=4
            buffer_i (1) = 0
            CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
            WRITE (6,*) "(e3) in sion file, rank ", rank, ": buffer_i (1)=",buffer_i (1)
            CALL READ_CHECK (sierr, nelem)
#endif
            CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
            lfrzn = buffer_i (1)
            WRITE (nformsion+j-1,96) namspe (i), amass, rcii, lfrzn
         END DO
         
         IF (nmoldef>0) THEN
            IF (lcomm) WRITE (nformsion+j-1,*) "# MOLECULES:"
            IF (lcomm) WRITE (nformsion+j-1,*) "# nammol"

            DO i = 1, nmoldef
               !     line g
               nelem=1
               size=8
               buffer_c = '        '
               CALL FSION_READ(buffer_c,size,nelem,sid,sierr)
               IF (j==1) THEN
                  nammol (i) = buffer_c
               END IF
#ifdef DEBUG
               WRITE (6,*) "(g) in sion file, rank ", rank, ": buffer_c=",buffer_c
               CALL READ_CHECK (sierr, nelem)
#endif
               CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
               WRITE (nformsion+j-1,*) nammol (i)
            END DO
         END IF

         !     line h
         nelem=1
         size=80
         text = '                                                                                '
         CALL FSION_READ(text,size,nelem,sid,sierr)
#ifdef DEBUG
         WRITE (6,*) "(h) in sion file, rank ", rank, ": text=", text
         CALL READ_CHECK (sierr, nelem)
#endif
         CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
         
         IF (lcomm) WRITE (nformsion+j-1,*) "# Simulation name:"
         WRITE (nformsion+j-1,*) text

         IF (j==1) THEN
            nummol = 0 !counter for number of molecules      
            ibond = 0  !counter for bonds
         END IF

         ! Here one could close and open again the loop over nodes, as in the std 
         ! version of the utility: in case, pos_d and chunk_d must be updated too
         
      !     fill in arrays for beads and bonds
         rank = j - 1

         IF (lcomm) WRITE (nformsion+j-1,*) "# BEADS:"
         IF (lcomm) WRITE (nformsion+j-1,*) "# global, species, molecule, chain"

         IF (lmcheck) THEN
            !Build ltp, ltm, mole
            DO i = 1, beads (j)
               !     line i
               nelem = 4
               size=4
               buffer_i (1:4) = 0
               CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
               WRITE (6,*) "(i) in sion file, rank ", rank, ": buffer_i(1:4)=",buffer_i(1:4)
               CALL READ_CHECK (sierr, nelem)
#endif 
               CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 

               global = buffer_i (1)
               species = buffer_i (2)
               molecule = buffer_i (3)
               chain = buffer_i (4)

               ltp (global) = species
               ltm (global) = molecule
               mole (global) = chain
               nummol = MAX (nummol, chain)
               WRITE (nformsion+j-1,*) global, species, molecule, chain 
            END DO
         ELSE
            DO i = 1, beads (j)
               !     line i
               nelem = 4
               size=4
               buffer_i (1:4) = 0
               CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
               WRITE (6,*) "(i) in sion file, rank ", rank, ": buffer_i(1:4)=",buffer_i(1:4)
               CALL READ_CHECK (sierr, nelem)
#endif
               CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
               global = buffer_i (1)
               species = buffer_i (2)
               molecule = buffer_i (3)
               chain = buffer_i (4)
               WRITE (nformsion+j-1,*) global, species, molecule, chain 
            END DO
         ENDIF
         
         IF (bonds (j)>0) THEN
            IF (lcomm) WRITE (nformsion+j-1,*) "# BONDS:"
            IF (lcomm) WRITE (nformsion+j-1,*) "# extremes of the bond"

            IF (lmcheck) THEN
               ! Build bndtbl
               DO i = 1, bonds (j)
                  ibond = ibond + 1
                  !     line j
                  nelem=2
                  size=4
                  buffer_i (1:2) = 0 
                  CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
                  WRITE (6,*) "(j) in sion file, rank ", rank, ": buffer_i(1:2)=",buffer_i(1:2)
                  CALL READ_CHECK (sierr, nelem)
#endif
                  CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
                  bead1 = buffer_i (1)
                  bead2 = buffer_i (2)
                  bndtbl (ibond, 1) = bead1
                  bndtbl (ibond, 2) = bead2
                  WRITE (nformsion+j-1,*) bead1, bead2
               END DO
            ELSE
               DO i = 1, bonds (j)
                  !     line j
                  nelem=2
                  size=4
                  buffer_i (1:2) = 0 
                  CALL FSION_READ(buffer_i,size,nelem,sid,sierr)
#ifdef DEBUG
                  WRITE (6,*) "(j) in sion file, rank ", rank, ": buffer_i(1:2)=",buffer_i(1:2)
                  CALL READ_CHECK (sierr, nelem)
#endif
                  CALL DETERMINE_POS (rank, nelem*size, chunknum, posinchunk) 
                  bead1 = buffer_i (1)
                  bead2 = buffer_i (2)
                  WRITE (nformsion+j-1,*) bead1, bead2
               END DO
            END IF
         END IF
         chun_d (j) = chunknum
         pos_d (j) = posinchunk
         
      END DO ! over nodes

      IF (lmcheck) THEN
      ! determine numbers of molecules, beads and bonds per molecule type
         nmol = 0.0_dp
         nbdmol = 0
         nbomol = 0 
         chain = 0
         imol = 0 !necessary to avoid out of bounds
         
         DO i = 1, nsyst
            IF (mole (i) /= chain) THEN
               chain = mole (i)
               imol = ltm (i)
               nmol (imol) = nmol (imol) + 1.0_dp
            END IF
            IF (imol > 0) nbdmol (imol) = nbdmol (imol) + 1
         END DO

         DO i = 1, numbond
            imol = ltm (bndtbl (i,1))
            nbomol (imol) = nbomol (imol) + 1
         END DO
            
         DO i = 1, nmoldef
            rnmol = NINT (nmol (i))
            IF (rnmol>0) THEN
               nbdmol (i) = nbdmol (i) / rnmol
               nbomol (i) = nbomol (i) / rnmol
            END IF
         END DO

         ! Write to std output the arrays built
         WRITE (*,*) "# Check of beads: i, ltp(i), ltm(i), mole(i)"
         DO i = 1, nsyst
            WRITE(*,*) i, ltp (i), ltm (i), mole (i)
         END DO

         !Check of molecule beads and numbers
         IF (nmoldef>0) THEN
            WRITE (*,*) "# Check of molecules: nammol(i), nbdmol(i), nbomol(i), nmol(i)"
            DO i = 1, nmoldef
               WRITE (*,*) nammol (i), nbdmol (i), nbomol (i), NINT(nmol(i))
            END DO
            WRITE (*,*) "# Total number of molecules = ",nummol
         END IF

         ! Write to std output bndtbl
         IF (numbond > 0) THEN
            WRITE (*,*) "# Check of bonds: bndbtl(i,1), bndbtl(i,2)"
            DO i = 1, numbond
               WRITE (*,*) bndtbl (i,1), bndtbl (i,2)
            END DO
         END IF
      END IF

      !reading trajectories 
      DO j = 1, numnodes

         seof = 0
         k = 0
         
         IF (lcomm) WRITE (nformsion+j-1,*) "# --- TRAJECTORIES --- (key =", keytrj,")"
         SELECT CASE (keytrj)
         CASE (0)
            IF (lcomm) WRITE (nformsion+j-1,*) "# mglobal, x, y, z"
         CASE(1)
            IF (lcomm) WRITE (nformsion+j-1,*) "# mglobal, x, y, z, vx, vy, vz"
         CASE(2) 
            IF (lcomm) WRITE (nformsion+j-1,*) "# mglobal, x, y, z, vx, vy, vz, fx, fy, fz"
         END SELECT
         
         rank = j - 1
         chunknum = chun_d (j)
         posinchunk = pos_d (j)         
         CALL FSION_SEEK (sid, rank, chunknum, posinchunk, sierr)
!!!         
         DO WHILE (.true.)

            call fsion_feof (sid, seof)
            IF (seof /= 0) THEN
#ifdef DEBUG
               WRITE (6,*) "rank ", rank, ": End of file !"
#endif
               IF (k==0) THEN
                  PRINT *, 'ERROR: cannot find trajectory data in history.sion file'
                  STOP
               END IF
               EXIT
            END IF
            
            ! line k 
            nelem=8
            size=8
            buffer_r (1:8) = 0
            CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
            WRITE (6,*) "(k) in sion file, rank ", rank, ": buffer_r(1:8)=",buffer_r(1:8)
            CALL READ_CHECK (sierr, nelem)
#endif
            time = buffer_r (1)
            mbeads = buffer_r (2)
            dimx = buffer_r (3)
            dimy = buffer_r (4)
            dimz = buffer_r (5)
            shrdx = buffer_r (6)
            shrdy = buffer_r (7)
            shrdz = buffer_r (8)
            !
            IF (lcomm) WRITE (nformsion+j-1,*) "# time, mbeads, dimx, dimy, dimz, shrdx, shrdy, shrdz"
            WRITE (nformsion+j-1,98) time, mbeads, dimx, dimy, dimz, shrdx, shrdy, shrdz
                        
            k = k + 1
            
            IF (lcomm) WRITE (nformsion+j-1,*) "# snapshot number:", k
            
            nbeads = NINT (mbeads)
            
            SELECT CASE (keytrj)
            CASE (0)
               DO i = 1, nbeads
                  ! line l
                  nelem=4
                  size=8
                  buffer_r (1:4) = 0
                  CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
                  WRITE (6,*) "(l) in sion file, rank ", rank, ": buffer_r(1:4)=",buffer_r(1:4)
                  CALL READ_CHECK (sierr, nelem)
#endif
                  mglobal = buffer_r (1)
                  x = buffer_r (2)
                  y = buffer_r (3)
                  z = buffer_r (4)
                  !
                  WRITE (nformsion+j-1,99) mglobal, x, y, z
               END DO
            CASE (1)
               DO i = 1, nbeads
                  ! line m
                  nelem=7
                  size=8
                  buffer_r (1:7) = 0
                  CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
                  WRITE (6,*) "(m) in sion file, rank ", rank, ": buffer_r(1:7)=",buffer_r(1:7)
                  CALL READ_CHECK (sierr, nelem)
#endif
                  mglobal = buffer_r (1)
                  x = buffer_r (2)
                  y = buffer_r (3)
                  z = buffer_r (4)
                  vx = buffer_r (5)
                  vy = buffer_r (6)
                  vz = buffer_r (7)
                  !
                  WRITE (nformsion+j-1,99) mglobal, x, y, z, vx, vy, vz
               END DO
            CASE (2)
               DO i = 1, nbeads
                  ! line n and p
                  nelem=10
                  size=8
                  buffer_r (1:10) = 0
                  CALL FSION_READ(buffer_r,size,nelem,sid,sierr)
#ifdef DEBUG
                  WRITE (6,*) "(l) in sion file, rank ", rank, ": buffer_r(1:10)=",buffer_r(1:10)
                  CALL READ_CHECK (sierr, nelem)
#endif
                  mglobal = buffer_r (1)
                  x = buffer_r (2)
                  y = buffer_r (3)
                  z = buffer_r (4)
                  vx = buffer_r (5)
                  vy = buffer_r (6)
                  vz = buffer_r (7)
                  fx = buffer_r (8)
                  fy = buffer_r (9)
                  fz = buffer_r (10)
                  !
                  WRITE (nformsion+j-1,99) mglobal, x, y, z, vx, vy, vz, fx, fy, fz
               END DO
            END SELECT
            
         END DO
      END DO
      
      ! close the output files
      DO j = 1, numnodes
         CLOSE (nformsion+j-1)
      END DO

! SIONlib serial close
      call FSION_CLOSE (sid, sierr)
      CLOSE (nformsion)

#ifdef DEBUG
      WRITE (*,*) "The final chunknumbers and positions within chunks are:"
      WRITE (*,*) "chun_d=", chun_d
      WRITE (*,*) "pos_d=", pos_d
#endif
      
      DEALLOCATE (beads, bonds)
      DEALLOCATE (namspe, nammol)
      IF (lmcheck) DEALLOCATE (ltp, ltm, mole, nmol, nbdmol, bndtbl, nbomol)
! SIONlib related quantities
      DEALLOCATE (chunksizes, globalranks, pos_d, chun_d)

99    FORMAT(f10.1,2x,1p,9(e13.6,3x))
98    FORMAT(8(f10.3,3x))
97    FORMAT(4(f10.3,3x))
96    FORMAT(A9,3x,2(f10.3,3x),I2)

    CONTAINS

      SUBROUTINE DETERMINE_POS (rank, nbytes, chunk, pos)
!***********************************************************************************
! routine to determine the position in the .sion file at each write statement 
!
! author - s. chiacchiera, march 2018
!***********************************************************************************
! It is assumed that each rank has its chunks numbered as 0, 1, etc
        IMPLICIT none
        INTEGER, INTENT (OUT) :: rank
        INTEGER, INTENT (INOUT) :: chunk
        INTEGER*8, INTENT (INOUT) :: pos
        INTEGER*8, INTENT(IN) :: nbytes
        INTEGER*8 :: pos_try
        IF (nbytes > chunksizes (rank + 1)) THEN
           WRITE (*,*) "error: too large record (hint: increase chunksize)"
           STOP
        END IF
        pos_try = pos + nbytes
        IF (pos_try <= chunksizes (rank + 1)) THEN 
           pos = pos_try
        ELSE
           chunk = chunk + 1
           pos = nbytes
        END IF
        RETURN
      END SUBROUTINE DETERMINE_POS

      SUBROUTINE READ_CHECK (sierr, nelem)
!***********************************************************************************
! routine to signal eventual mismatch when reading the .sion file
!
! author - s. chiacchiera, march 2018
!***********************************************************************************

        IMPLICIT none
        INTEGER*8, INTENT (IN) :: sierr, nelem
        IF (sierr.ne.nelem) THEN
           WRITE (6,*) "error: number of elements read differs from expected! mismatch is ", sierr-nelem
           STOP
        END IF
      END SUBROUTINE READ_CHECK
     
END PROGRAM format_history_sion

Additional information

Using the modifications proposed above, the trajectories will be written by DL_MESO_DPD in the SIONlib format (history.sion file). For comparison purposes, the standard HISTORY* files can be also written at the same time, using the -D STDTRAJ flag for compilation in Makefile-MPI.

To be able to use SIONlib, the writing statements for which the records are formed by inhomogeneous items (e.g., two 8-byte strings and a 4-byte integer) have to be split into different records, hence the increased number of write/read statements. To help the reader, comments have been added to label all the SIONlib-related commands, namely: “SIONlib 0, 1a, 1b, 2a, 2b, …, 2p, 3”. The writing statements are labelled “2a, 2b, etc”, and each one corresponds to the writing of single record in the standard version of DL_MESO_DPD. The SIONlib file definition, opening and closing statements have been labelled 0, 1 and 3 in the comments.

Important SIONlib variables:

  • fsblksize: file system block size in bytes. If set to -1, it is read by SIONlib. (Typically, this value is 4096.)
  • chunksize: size in bytes of the data written by a task in a single write call. It is internally increased by SIONlib to the next multiple of the filesystem block size. (For DL_MESO_DPD, the largest record has size 80 bytes, hence we choose chunksize = 100, which, typically, will be internally increased to 4096.)
  • nfiles: number of physical files produced by SIONlib (set to 1 here).

Acknowledgements

We are very grateful to Dr. Wolfgang Frings for kind support concerning the usage of the Fortran version of SIONlib.

[1]If patching is done with GNU patch command, the -l option (ignoring whitespaces) has to be active.
[2]On CCPForge, a software development framework where, in particular, the different versions of DL_MESO_DPD are stored, version 2.6 in its revision 15 corresponds to the commit number 48e9a42a51f4cb450eb9c39dcbf6eb4a38c7cd32.