Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2025 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Generate Gaussian cube files
10 : ! **************************************************************************************************
11 : MODULE realspace_grid_cube
12 : USE cp_files, ONLY: close_file,&
13 : open_file
14 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
15 : USE kinds, ONLY: dp
16 : USE message_passing, ONLY: &
17 : file_amode_rdonly, file_offset, mp_comm_type, mp_file_descriptor_type, mp_file_type, &
18 : mp_file_type_free, mp_file_type_hindexed_make_chv, mp_file_type_set_view_chv, &
19 : mpi_character_size
20 : USE pw_grid_types, ONLY: PW_MODE_LOCAL
21 : USE pw_types, ONLY: pw_r3d_rs_type
22 : #include "../base/base_uses.f90"
23 :
24 : IMPLICIT NONE
25 :
26 : PRIVATE
27 :
28 : PUBLIC :: pw_to_cube, cube_to_pw, pw_to_simple_volumetric
29 :
30 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'realspace_grid_cube'
31 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .FALSE.
32 : LOGICAL, PRIVATE :: parses_linebreaks = .FALSE., &
33 : parse_test = .TRUE.
34 :
35 : CONTAINS
36 :
37 : ! **************************************************************************************************
38 : !> \brief ...
39 : !> \param pw ...
40 : !> \param unit_nr ...
41 : !> \param title ...
42 : !> \param particles_r ...
43 : !> \param particles_z ...
44 : !> \param particles_zeff ...
45 : !> \param stride ...
46 : !> \param max_file_size_mb ...
47 : !> \param zero_tails ...
48 : !> \param silent ...
49 : !> \param mpi_io ...
50 : ! **************************************************************************************************
51 1928 : SUBROUTINE pw_to_cube(pw, unit_nr, title, particles_r, particles_z, particles_zeff, &
52 : stride, max_file_size_mb, zero_tails, silent, mpi_io)
53 : TYPE(pw_r3d_rs_type), INTENT(IN) :: pw
54 : INTEGER, INTENT(IN) :: unit_nr
55 : CHARACTER(*), INTENT(IN), OPTIONAL :: title
56 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
57 : OPTIONAL :: particles_r
58 : INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: particles_z
59 : REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
60 : INTEGER, DIMENSION(:), OPTIONAL, POINTER :: stride
61 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: max_file_size_mb
62 : LOGICAL, INTENT(IN), OPTIONAL :: zero_tails, silent, mpi_io
63 :
64 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_to_cube'
65 : INTEGER, PARAMETER :: entry_len = 13, num_entries_line = 6
66 :
67 : INTEGER :: checksum, dest, handle, i, I1, I2, I3, iat, ip, L1, L2, L3, msglen, my_rank, &
68 : my_stride(3), np, num_linebreak, num_pe, rank(2), size_of_z, source, tag, U1, U2, U3
69 : LOGICAL :: be_silent, my_zero_tails, parallel_write
70 : REAL(KIND=dp) :: compression_factor, my_max_file_size_mb
71 1928 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: buf
72 : TYPE(mp_comm_type) :: gid
73 : TYPE(mp_file_type) :: mp_unit
74 :
75 1928 : CALL timeset(routineN, handle)
76 :
77 1928 : my_zero_tails = .FALSE.
78 1928 : be_silent = .FALSE.
79 1928 : parallel_write = .FALSE.
80 1928 : my_max_file_size_mb = 0.0_dp
81 1928 : IF (PRESENT(zero_tails)) my_zero_tails = zero_tails
82 1928 : IF (PRESENT(silent)) be_silent = silent
83 1928 : IF (PRESENT(mpi_io)) parallel_write = mpi_io
84 1928 : IF (PRESENT(max_file_size_mb)) my_max_file_size_mb = max_file_size_mb
85 1928 : CPASSERT(my_max_file_size_mb >= 0)
86 :
87 7712 : my_stride = 1
88 1928 : IF (PRESENT(stride)) THEN
89 1880 : IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) &
90 : CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 "// &
91 1880 : "(the same for X,Y,Z) or 3 values. Correct your input file.")
92 1880 : IF (SIZE(stride) == 1) THEN
93 88 : DO i = 1, 3
94 88 : my_stride(i) = stride(1)
95 : END DO
96 : ELSE
97 7432 : my_stride = stride(1:3)
98 : END IF
99 : END IF
100 :
101 1928 : IF (my_max_file_size_mb > 0) THEN
102 : ! A single grid point takes up 13 bytes, which is 1.3e-05 MB.
103 32 : compression_factor = 1.3e-05_dp*PRODUCT(REAL(pw%pw_grid%npts, dp))/max_file_size_mb
104 32 : my_stride(:) = INT(compression_factor**(1.0/3.0)) + 1
105 : END IF
106 :
107 1928 : CPASSERT(my_stride(1) > 0)
108 1928 : CPASSERT(my_stride(2) > 0)
109 1928 : CPASSERT(my_stride(3) > 0)
110 :
111 1928 : IF (.NOT. parallel_write) THEN
112 70 : IF (unit_nr > 0) THEN
113 : ! this format seems to work for e.g. molekel and gOpenmol
114 : ! latest version of VMD can read non orthorhombic cells
115 35 : WRITE (unit_nr, '(a11)') "-Quickstep-"
116 35 : IF (PRESENT(title)) THEN
117 35 : WRITE (unit_nr, *) TRIM(title)
118 : ELSE
119 0 : WRITE (unit_nr, *) "No Title"
120 : END IF
121 :
122 35 : CPASSERT(PRESENT(particles_z) .EQV. PRESENT(particles_r))
123 35 : np = 0
124 35 : IF (PRESENT(particles_z)) THEN
125 35 : CPASSERT(SIZE(particles_z) == SIZE(particles_r, dim=2))
126 : ! cube files can only be written for 99999 particles due to a format limitation (I5)
127 : ! so we limit the number of particles written.
128 35 : np = MIN(99999, SIZE(particles_z))
129 : END IF
130 :
131 35 : WRITE (unit_nr, '(I5,3f12.6)') np, 0.0_dp, 0._dp, 0._dp !start of cube
132 :
133 35 : WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(1) + my_stride(1) - 1)/my_stride(1), &
134 35 : pw%pw_grid%dh(1, 1)*REAL(my_stride(1), dp), pw%pw_grid%dh(2, 1)*REAL(my_stride(1), dp), &
135 70 : pw%pw_grid%dh(3, 1)*REAL(my_stride(1), dp)
136 35 : WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(2) + my_stride(2) - 1)/my_stride(2), &
137 35 : pw%pw_grid%dh(1, 2)*REAL(my_stride(2), dp), pw%pw_grid%dh(2, 2)*REAL(my_stride(2), dp), &
138 70 : pw%pw_grid%dh(3, 2)*REAL(my_stride(2), dp)
139 35 : WRITE (unit_nr, '(I5,3f12.6)') (pw%pw_grid%npts(3) + my_stride(3) - 1)/my_stride(3), &
140 35 : pw%pw_grid%dh(1, 3)*REAL(my_stride(3), dp), pw%pw_grid%dh(2, 3)*REAL(my_stride(3), dp), &
141 70 : pw%pw_grid%dh(3, 3)*REAL(my_stride(3), dp)
142 :
143 35 : IF (PRESENT(particles_z)) THEN
144 35 : IF (PRESENT(particles_zeff)) THEN
145 0 : DO iat = 1, np
146 0 : WRITE (unit_nr, '(I5,4f12.6)') particles_z(iat), particles_zeff(iat), particles_r(:, iat)
147 : END DO
148 : ELSE
149 165 : DO iat = 1, np
150 165 : WRITE (unit_nr, '(I5,4f12.6)') particles_z(iat), 0._dp, particles_r(:, iat)
151 : END DO
152 : END IF
153 : END IF
154 : END IF
155 :
156 : ! shortcut
157 70 : L1 = pw%pw_grid%bounds(1, 1)
158 70 : L2 = pw%pw_grid%bounds(1, 2)
159 70 : L3 = pw%pw_grid%bounds(1, 3)
160 70 : U1 = pw%pw_grid%bounds(2, 1)
161 70 : U2 = pw%pw_grid%bounds(2, 2)
162 70 : U3 = pw%pw_grid%bounds(2, 3)
163 :
164 210 : ALLOCATE (buf(L3:U3))
165 :
166 70 : my_rank = pw%pw_grid%para%group%mepos
167 70 : gid = pw%pw_grid%para%group
168 70 : num_pe = pw%pw_grid%para%group%num_pe
169 70 : tag = 1
170 :
171 70 : rank (1) = unit_nr
172 70 : rank (2) = my_rank
173 70 : checksum = 0
174 70 : IF (unit_nr > 0) checksum = 1
175 :
176 70 : CALL gid%sum(checksum)
177 70 : CPASSERT(checksum == 1)
178 :
179 70 : CALL gid%maxloc(rank)
180 70 : CPASSERT(rank(1) > 0)
181 :
182 70 : dest = rank(2)
183 2110 : DO I1 = L1, U1, my_stride(1)
184 66146 : DO I2 = L2, U2, my_stride(2)
185 :
186 : ! cycling through the CPUs, check if the current ray (I1,I2) is local to that CPU
187 64036 : IF (pw%pw_grid%para%mode /= PW_MODE_LOCAL) THEN
188 192108 : DO ip = 0, num_pe - 1
189 : IF (pw%pw_grid%para%bo(1, 1, ip, 1) <= I1 - L1 + 1 .AND. pw%pw_grid%para%bo(2, 1, ip, 1) >= I1 - L1 + 1 .AND. &
190 192108 : pw%pw_grid%para%bo(1, 2, ip, 1) <= I2 - L2 + 1 .AND. pw%pw_grid%para%bo(2, 2, ip, 1) >= I2 - L2 + 1) THEN
191 64036 : source = ip
192 : END IF
193 : END DO
194 : ELSE
195 0 : source = dest
196 : END IF
197 :
198 64036 : IF (source == dest) THEN
199 32216 : IF (my_rank == source) THEN
200 717159 : buf(:) = pw%array(I1, I2, :)
201 : END IF
202 : ELSE
203 31820 : IF (my_rank == source) THEN
204 703236 : buf(:) = pw%array(I1, I2, :)
205 15910 : CALL gid%send(buf, dest, tag)
206 : END IF
207 31820 : IF (my_rank == dest) THEN
208 15910 : CALL gid%recv(buf, source, tag)
209 : END IF
210 : END IF
211 :
212 64036 : IF (unit_nr > 0) THEN
213 32018 : IF (my_zero_tails) THEN
214 0 : DO I3 = L3, U3
215 0 : IF (buf(I3) < 1.E-7_dp) buf(I3) = 0.0_dp
216 : END DO
217 : END IF
218 32018 : WRITE (unit_nr, '(6E13.5)') (buf(I3), I3=L3, U3, my_stride(3))
219 : END IF
220 :
221 : ! this double loop generates so many messages that it can overload
222 : ! the message passing system, e.g. on XT3
223 : ! we therefore put a barrier here that limits the amount of message
224 : ! that flies around at any given time.
225 : ! if ever this routine becomes a bottleneck, we should go for a
226 : ! more complicated rewrite
227 66076 : CALL gid%sync()
228 :
229 : END DO
230 : END DO
231 :
232 70 : DEALLOCATE (buf)
233 : ELSE
234 1858 : size_of_z = CEILING(REAL(pw%pw_grid%bounds(2, 3) - pw%pw_grid%bounds(1, 3) + 1, dp)/REAL(my_stride(3), dp))
235 1858 : num_linebreak = size_of_z/num_entries_line
236 1858 : IF (MODULO(size_of_z, num_entries_line) /= 0) &
237 1552 : num_linebreak = num_linebreak + 1
238 1858 : msglen = (size_of_z*entry_len + num_linebreak)*mpi_character_size
239 1858 : CALL mp_unit%set_handle(unit_nr)
240 : CALL pw_to_cube_parallel(pw, mp_unit, title, particles_r, particles_z, particles_zeff, &
241 3016 : my_stride, my_zero_tails, msglen)
242 : END IF
243 :
244 1928 : CALL timestop(handle)
245 :
246 3856 : END SUBROUTINE pw_to_cube
247 :
248 : ! **************************************************************************************************
249 : !> \brief Computes the external density on the grid
250 : !> hacked from external_read_density
251 : !> \param grid pw to read from cube file
252 : !> \param filename name of cube file
253 : !> \param scaling scale values before storing
254 : !> \param parallel_read ...
255 : !> \param silent ...
256 : !> \par History
257 : !> Created [M.Watkins] (01.2014)
258 : !> Use blocking, collective MPI read for parallel simulations [Nico Holmberg] (05.2017)
259 : ! **************************************************************************************************
260 38 : SUBROUTINE cube_to_pw(grid, filename, scaling, parallel_read, silent)
261 :
262 : TYPE(pw_r3d_rs_type), INTENT(IN) :: grid
263 : CHARACTER(len=*), INTENT(in) :: filename
264 : REAL(kind=dp), INTENT(in) :: scaling
265 : LOGICAL, INTENT(in) :: parallel_read
266 : LOGICAL, INTENT(in), OPTIONAL :: silent
267 :
268 : CHARACTER(len=*), PARAMETER :: routineN = 'cube_to_pw'
269 : INTEGER, PARAMETER :: entry_len = 13, num_entries_line = 6
270 :
271 : INTEGER :: extunit, handle, i, j, k, msglen, &
272 : my_rank, nat, ndum, num_linebreak, &
273 : num_pe, output_unit, size_of_z, tag
274 : INTEGER, DIMENSION(3) :: lbounds, lbounds_local, npoints, &
275 : npoints_local, ubounds, ubounds_local
276 : LOGICAL :: be_silent
277 38 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: buffer
278 : REAL(kind=dp), DIMENSION(3) :: dr, rdum
279 : TYPE(mp_comm_type) :: gid
280 :
281 76 : output_unit = cp_logger_get_default_io_unit()
282 :
283 38 : CALL timeset(routineN, handle)
284 :
285 38 : be_silent = .FALSE.
286 38 : IF (PRESENT(silent)) THEN
287 0 : be_silent = silent
288 : END IF
289 : !get rs grids and parallel environment
290 38 : gid = grid%pw_grid%para%group
291 38 : my_rank = grid%pw_grid%para%group%mepos
292 38 : num_pe = grid%pw_grid%para%group%num_pe
293 38 : tag = 1
294 :
295 152 : lbounds_local = grid%pw_grid%bounds_local(1, :)
296 152 : ubounds_local = grid%pw_grid%bounds_local(2, :)
297 38 : size_of_z = ubounds_local(3) - lbounds_local(3) + 1
298 :
299 38 : IF (.NOT. parallel_read) THEN
300 0 : npoints = grid%pw_grid%npts
301 0 : lbounds = grid%pw_grid%bounds(1, :)
302 0 : ubounds = grid%pw_grid%bounds(2, :)
303 :
304 0 : DO i = 1, 3
305 0 : dr(i) = grid%pw_grid%dh(i, i)
306 : END DO
307 :
308 0 : npoints_local = grid%pw_grid%npts_local
309 : !pw grids at most pencils - all processors have a full set of z data for x,y
310 0 : ALLOCATE (buffer(lbounds(3):ubounds(3)))
311 :
312 0 : IF (my_rank == 0) THEN
313 0 : IF (output_unit > 0 .AND. .NOT. be_silent) THEN
314 0 : WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A,/)") "Reading the cube file: ", TRIM(filename)
315 : END IF
316 :
317 : CALL open_file(file_name=filename, &
318 : file_status="OLD", &
319 : file_form="FORMATTED", &
320 : file_action="READ", &
321 0 : unit_number=extunit)
322 :
323 : !skip header comments
324 0 : DO i = 1, 2
325 0 : READ (extunit, *)
326 : END DO
327 0 : READ (extunit, *) nat, rdum
328 0 : DO i = 1, 3
329 0 : READ (extunit, *) ndum, rdum
330 0 : IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
331 0 : output_unit > 0) THEN
332 0 : WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
333 0 : WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
334 0 : WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
335 : END IF
336 : END DO
337 : !ignore atomic position data - read from coord or topology instead
338 0 : DO i = 1, nat
339 0 : READ (extunit, *)
340 : END DO
341 : END IF
342 :
343 : !master sends all data to everyone
344 0 : DO i = lbounds(1), ubounds(1)
345 0 : DO j = lbounds(2), ubounds(2)
346 0 : IF (my_rank == 0) THEN
347 0 : READ (extunit, *) (buffer(k), k=lbounds(3), ubounds(3))
348 : END IF
349 0 : CALL gid%bcast(buffer(lbounds(3):ubounds(3)), 0)
350 :
351 : !only use data that is local to me - i.e. in slice of pencil I own
352 : IF ((lbounds_local(1) <= i) .AND. (i <= ubounds_local(1)) .AND. (lbounds_local(2) <= j) &
353 0 : .AND. (j <= ubounds_local(2))) THEN
354 : !allow scaling of external potential values by factor 'scaling' (SCALING_FACTOR in input file)
355 0 : grid%array(i, j, lbounds(3):ubounds(3)) = buffer(lbounds(3):ubounds(3))*scaling
356 : END IF
357 :
358 : END DO
359 : END DO
360 :
361 0 : IF (my_rank == 0) CALL close_file(unit_number=extunit)
362 :
363 0 : CALL gid%sync()
364 : ELSE
365 : ! Parallel routine needs as input the byte size of each grid z-slice
366 : ! This is a hack to prevent compilation errors with gcc -Wall (up to versions 6.3)
367 : ! related to allocatable-length string declaration CHARACTER(LEN=:), ALLOCATABLE, DIMENSION(:) :: string
368 : ! Each data line of a Gaussian cube contains max 6 entries with last line potentially containing less if nz % 6 /= 0
369 : ! Thus, this size is simply the number of entries multiplied by the entry size + the number of line breaks
370 38 : num_linebreak = size_of_z/num_entries_line
371 38 : IF (MODULO(size_of_z, num_entries_line) /= 0) &
372 36 : num_linebreak = num_linebreak + 1
373 38 : msglen = (size_of_z*entry_len + num_linebreak)*mpi_character_size
374 38 : CALL cube_to_pw_parallel(grid, filename, scaling, msglen, silent=silent)
375 : END IF
376 :
377 38 : CALL timestop(handle)
378 :
379 76 : END SUBROUTINE cube_to_pw
380 :
381 : ! **************************************************************************************************
382 : !> \brief Reads a realspace potential/density from a cube file using collective MPI I/O and
383 : !> stores it in grid.
384 : !> \param grid pw to read from cube file
385 : !> \param filename name of cube file
386 : !> \param scaling scale values before storing
387 : !> \param msglen the size of each grid slice along z-axis in bytes
388 : !> \param silent ...
389 : !> \par History
390 : !> Created [Nico Holmberg] (05.2017)
391 : ! **************************************************************************************************
392 38 : SUBROUTINE cube_to_pw_parallel(grid, filename, scaling, msglen, silent)
393 :
394 : TYPE(pw_r3d_rs_type), INTENT(IN) :: grid
395 : CHARACTER(len=*), INTENT(in) :: filename
396 : REAL(kind=dp), INTENT(in) :: scaling
397 : INTEGER, INTENT(in) :: msglen
398 : LOGICAL, INTENT(in), OPTIONAL :: silent
399 :
400 : INTEGER, PARAMETER :: entry_len = 13, num_entries_line = 6
401 :
402 : INTEGER, DIMENSION(3) :: lbounds, lbounds_local, npoints, &
403 : npoints_local, ubounds, ubounds_local
404 38 : INTEGER, ALLOCATABLE, DIMENSION(:), TARGET :: blocklengths
405 : INTEGER(kind=file_offset), ALLOCATABLE, &
406 38 : DIMENSION(:), TARGET :: displacements
407 : INTEGER(kind=file_offset) :: BOF
408 : INTEGER :: extunit_handle, i, ientry, islice, j, k, my_rank, nat, ndum, nslices, num_pe, &
409 : offset_global, output_unit, pos, readstat, size_of_z, tag
410 38 : CHARACTER(LEN=msglen), ALLOCATABLE, DIMENSION(:) :: readbuffer
411 38 : CHARACTER(LEN=msglen) :: tmp
412 : LOGICAL :: be_silent, should_read(2)
413 38 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: buffer
414 : REAL(kind=dp), DIMENSION(3) :: dr, rdum
415 : TYPE(mp_comm_type) :: gid
416 : TYPE(mp_file_descriptor_type) :: mp_file_desc
417 : TYPE(mp_file_type) :: extunit
418 :
419 76 : output_unit = cp_logger_get_default_io_unit()
420 :
421 38 : be_silent = .FALSE.
422 38 : IF (PRESENT(silent)) THEN
423 0 : be_silent = silent
424 : END IF
425 :
426 : !get rs grids and parallel envnment
427 38 : gid = grid%pw_grid%para%group
428 38 : my_rank = grid%pw_grid%para%group%mepos
429 38 : num_pe = grid%pw_grid%para%group%num_pe
430 38 : tag = 1
431 :
432 152 : DO i = 1, 3
433 152 : dr(i) = grid%pw_grid%dh(i, i)
434 : END DO
435 :
436 152 : npoints = grid%pw_grid%npts
437 152 : lbounds = grid%pw_grid%bounds(1, :)
438 152 : ubounds = grid%pw_grid%bounds(2, :)
439 :
440 152 : npoints_local = grid%pw_grid%npts_local
441 152 : lbounds_local = grid%pw_grid%bounds_local(1, :)
442 152 : ubounds_local = grid%pw_grid%bounds_local(2, :)
443 38 : size_of_z = ubounds_local(3) - lbounds_local(3) + 1
444 38 : nslices = (ubounds_local(1) - lbounds_local(1) + 1)*(ubounds_local(2) - lbounds_local(2) + 1)
445 38 : islice = 1
446 :
447 : ! Read header information and determine byte offset of cube data on master process
448 38 : IF (my_rank == 0) THEN
449 19 : IF (output_unit > 0 .AND. .NOT. be_silent) THEN
450 19 : WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A,/)") "Reading the cube file: ", TRIM(filename)
451 : END IF
452 :
453 : CALL open_file(file_name=filename, &
454 : file_status="OLD", &
455 : file_form="FORMATTED", &
456 : file_action="READ", &
457 : file_access="STREAM", &
458 19 : unit_number=extunit_handle)
459 :
460 : !skip header comments
461 57 : DO i = 1, 2
462 57 : READ (extunit_handle, *)
463 : END DO
464 19 : READ (extunit_handle, *) nat, rdum
465 76 : DO i = 1, 3
466 57 : READ (extunit_handle, *) ndum, rdum
467 57 : IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
468 19 : output_unit > 0) THEN
469 0 : WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
470 0 : WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
471 0 : WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
472 : END IF
473 : END DO
474 : !ignore atomic position data - read from coord or topology instead
475 44 : DO i = 1, nat
476 44 : READ (extunit_handle, *)
477 : END DO
478 : ! Get byte offset
479 19 : INQUIRE (extunit_handle, POS=offset_global)
480 19 : CALL close_file(unit_number=extunit_handle)
481 : END IF
482 : ! Sync offset and start parallel read
483 38 : CALL gid%bcast(offset_global, grid%pw_grid%para%group%source)
484 38 : BOF = offset_global
485 38 : CALL extunit%open(groupid=gid, filepath=filename, amode_status=file_amode_rdonly)
486 : ! Determine byte offsets for each grid z-slice which are local to a process
487 114 : ALLOCATE (displacements(nslices))
488 29450 : displacements = 0
489 1151 : DO i = lbounds(1), ubounds(1)
490 3396 : should_read(:) = .TRUE.
491 1132 : IF (i < lbounds_local(1)) THEN
492 371 : should_read(1) = .FALSE.
493 761 : ELSE IF (i > ubounds_local(1)) THEN
494 : EXIT
495 : END IF
496 45269 : DO j = lbounds(2), ubounds(2)
497 44118 : should_read(2) = .TRUE.
498 44118 : IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
499 0 : should_read(2) = .FALSE.
500 : END IF
501 102942 : IF (ALL(should_read .EQV. .TRUE.)) THEN
502 29412 : IF (islice > nslices) CPABORT("Index out of bounds.")
503 29412 : displacements(islice) = BOF
504 29412 : islice = islice + 1
505 : END IF
506 : ! Update global byte offset
507 45231 : BOF = BOF + msglen
508 : END DO
509 : END DO
510 : ! Size of each z-slice is msglen
511 114 : ALLOCATE (blocklengths(nslices))
512 29450 : blocklengths(:) = msglen
513 : ! Create indexed MPI type using calculated byte offsets as displacements and use it as a file view
514 38 : mp_file_desc = mp_file_type_hindexed_make_chv(nslices, blocklengths, displacements)
515 38 : BOF = 0
516 38 : CALL mp_file_type_set_view_chv(extunit, BOF, mp_file_desc)
517 : ! Collective read of cube
518 114 : ALLOCATE (readbuffer(nslices))
519 29450 : readbuffer(:) = ''
520 38 : CALL extunit%read_all(msglen, nslices, readbuffer, mp_file_desc)
521 38 : CALL mp_file_type_free(mp_file_desc)
522 38 : CALL extunit%close()
523 : ! Convert cube values string -> real
524 38 : i = lbounds_local(1)
525 38 : j = lbounds_local(2)
526 114 : ALLOCATE (buffer(lbounds(3):ubounds(3)))
527 1522 : buffer = 0.0_dp
528 : ! Test if the compiler supports parsing lines with line breaks in them
529 38 : IF (parse_test) THEN
530 16 : READ (readbuffer(1), *, IOSTAT=readstat) (buffer(k), k=lbounds(3), ubounds(3))
531 16 : IF (readstat == 0) THEN
532 16 : parses_linebreaks = .TRUE.
533 : ELSE
534 0 : parses_linebreaks = .FALSE.
535 : END IF
536 16 : parse_test = .FALSE.
537 652 : buffer = 0.0_dp
538 : END IF
539 29450 : DO islice = 1, nslices
540 29412 : IF (parses_linebreaks) THEN
541 : ! Use list-directed conversion if supported
542 : ! Produces faster code, but maybe the latter method could be optimized
543 29412 : READ (readbuffer(islice), *) (buffer(k), k=lbounds(3), ubounds(3))
544 : ELSE
545 : ! Convert values by going through the z-slice one value at a time
546 0 : tmp = readbuffer(islice)
547 : pos = 1
548 : ientry = 1
549 0 : DO k = lbounds_local(3), ubounds_local(3)
550 0 : IF (MODULO(ientry, num_entries_line) == 0 .OR. k == ubounds_local(3)) THEN
551 : ! Last value on line, dont read line break
552 0 : READ (tmp(pos:pos + (entry_len - 2)), '(E12.5)') buffer(k)
553 0 : pos = pos + (entry_len + 1)
554 : ELSE
555 0 : READ (tmp(pos:pos + (entry_len - 1)), '(E13.5)') buffer(k)
556 0 : pos = pos + entry_len
557 : END IF
558 0 : ientry = ientry + 1
559 : END DO
560 : END IF
561 : ! Optionally scale cube file values
562 1213948 : grid%array(i, j, lbounds(3):ubounds(3)) = scaling*buffer(lbounds(3):ubounds(3))
563 29412 : j = j + 1
564 29450 : IF (j > ubounds_local(2)) THEN
565 742 : j = lbounds_local(2)
566 742 : i = i + 1
567 : END IF
568 : END DO
569 38 : DEALLOCATE (readbuffer)
570 38 : DEALLOCATE (blocklengths, displacements)
571 : IF (debug_this_module) THEN
572 : ! Check that cube was correctly read using intrinsic read on master who sends data to everyone
573 : buffer = 0.0_dp
574 : IF (my_rank == 0) THEN
575 : IF (output_unit > 0 .AND. .NOT. be_silent) THEN
576 : WRITE (output_unit, FMT="(/,T2,A,/,/,T2,A)") "Reading the cube file: ", filename
577 : END IF
578 :
579 : CALL open_file(file_name=filename, &
580 : file_status="OLD", &
581 : file_form="FORMATTED", &
582 : file_action="READ", &
583 : unit_number=extunit_handle)
584 :
585 : !skip header comments
586 : DO i = 1, 2
587 : READ (extunit_handle, *)
588 : END DO
589 : READ (extunit_handle, *) nat, rdum
590 : DO i = 1, 3
591 : READ (extunit_handle, *) ndum, rdum
592 : IF ((ndum /= npoints(i) .OR. (ABS(rdum(i) - dr(i)) > 1e-4)) .AND. &
593 : output_unit > 0) THEN
594 : WRITE (output_unit, *) "Restart from density | ERROR! | CUBE FILE NOT COINCIDENT WITH INTERNAL GRID ", i
595 : WRITE (output_unit, *) "Restart from density | ", ndum, " DIFFERS FROM ", npoints(i)
596 : WRITE (output_unit, *) "Restart from density | ", rdum, " DIFFERS FROM ", dr(i)
597 : END IF
598 : END DO
599 : !ignore atomic position data - read from coord or topology instead
600 : DO i = 1, nat
601 : READ (extunit_handle, *)
602 : END DO
603 : END IF
604 :
605 : !master sends all data to everyone
606 : DO i = lbounds(1), ubounds(1)
607 : DO j = lbounds(2), ubounds(2)
608 : IF (my_rank == 0) THEN
609 : READ (extunit_handle, *) (buffer(k), k=lbounds(3), ubounds(3))
610 : END IF
611 : CALL gid%bcast(buffer(lbounds(3):ubounds(3)), 0)
612 :
613 : !only use data that is local to me - i.e. in slice of pencil I own
614 : IF ((lbounds_local(1) <= i) .AND. (i <= ubounds_local(1)) .AND. (lbounds_local(2) <= j) &
615 : .AND. (j <= ubounds_local(2))) THEN
616 : !allow scaling of external potential values by factor 'scaling' (SCALING_FACTOR in input file)
617 : IF (ANY(grid%array(i, j, lbounds(3):ubounds(3)) /= buffer(lbounds(3):ubounds(3))*scaling)) &
618 : CALL cp_abort(__LOCATION__, &
619 : "Error in parallel read of input cube file.")
620 : END IF
621 :
622 : END DO
623 : END DO
624 :
625 : IF (my_rank == 0) CALL close_file(unit_number=extunit_handle)
626 :
627 : CALL gid%sync()
628 : END IF
629 38 : DEALLOCATE (buffer)
630 :
631 38 : END SUBROUTINE cube_to_pw_parallel
632 :
633 : ! **************************************************************************************************
634 : !> \brief Writes a realspace potential to a cube file using collective MPI I/O.
635 : !> \param grid the pw to output to the cube file
636 : !> \param unit_nr the handle associated with the cube file
637 : !> \param title title of the cube file
638 : !> \param particles_r Cartersian coordinates of the system
639 : !> \param particles_z atomic masses of atoms in the system
640 : !> \param particles_zeff effective atomic charges of atoms in the system
641 : !> \param stride every stride(i)th value of the potential is outputted (i=x,y,z)
642 : !> \param zero_tails flag that determines if small values of the potential should be zeroed
643 : !> \param msglen the size of each grid slice along z-axis in bytes
644 : !> \par History
645 : !> Created [Nico Holmberg] (11.2017)
646 : ! **************************************************************************************************
647 1858 : SUBROUTINE pw_to_cube_parallel(grid, unit_nr, title, particles_r, particles_z, particles_zeff, &
648 : stride, zero_tails, msglen)
649 :
650 : TYPE(pw_r3d_rs_type), INTENT(IN) :: grid
651 : TYPE(mp_file_type), INTENT(IN) :: unit_nr
652 : CHARACTER(*), INTENT(IN), OPTIONAL :: title
653 : REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
654 : OPTIONAL :: particles_r
655 : INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: particles_z
656 : REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
657 : INTEGER, INTENT(IN) :: stride(3)
658 : LOGICAL, INTENT(IN) :: zero_tails
659 : INTEGER, INTENT(IN) :: msglen
660 :
661 : INTEGER, PARAMETER :: entry_len = 13, header_len = 41, &
662 : header_len_z = 53, num_entries_line = 6
663 :
664 : CHARACTER(LEN=entry_len) :: value
665 : CHARACTER(LEN=header_len) :: header
666 : CHARACTER(LEN=header_len_z) :: header_z
667 : INTEGER, DIMENSION(3) :: lbounds, lbounds_local, ubounds, &
668 : ubounds_local
669 1858 : INTEGER, ALLOCATABLE, DIMENSION(:), TARGET :: blocklengths
670 : INTEGER(kind=file_offset), ALLOCATABLE, &
671 1858 : DIMENSION(:), TARGET :: displacements
672 : INTEGER(kind=file_offset) :: BOF
673 : INTEGER :: counter, i, islice, j, k, last_z, &
674 : my_rank, np, nslices, size_of_z
675 1858 : CHARACTER(LEN=msglen), ALLOCATABLE, DIMENSION(:) :: writebuffer
676 1858 : CHARACTER(LEN=msglen) :: tmp
677 : LOGICAL :: should_write(2)
678 : TYPE(mp_comm_type) :: gid
679 : TYPE(mp_file_descriptor_type) :: mp_desc
680 :
681 : !get rs grids and parallel envnment
682 1858 : gid = grid%pw_grid%para%group
683 1858 : my_rank = grid%pw_grid%para%group%mepos
684 :
685 : ! Shortcut
686 7432 : lbounds = grid%pw_grid%bounds(1, :)
687 7432 : ubounds = grid%pw_grid%bounds(2, :)
688 7432 : lbounds_local = grid%pw_grid%bounds_local(1, :)
689 7432 : ubounds_local = grid%pw_grid%bounds_local(2, :)
690 : ! Determine the total number of z-slices and the number of values per slice
691 1858 : size_of_z = CEILING(REAL(ubounds_local(3) - lbounds_local(3) + 1, dp)/REAL(stride(3), dp))
692 1858 : islice = 1
693 28431 : DO i = lbounds(1), ubounds(1), stride(1)
694 82506 : should_write(:) = .TRUE.
695 27502 : IF (i < lbounds_local(1)) THEN
696 8972 : should_write(1) = .FALSE.
697 18530 : ELSE IF (i > ubounds_local(1)) THEN
698 : EXIT
699 : END IF
700 593770 : DO j = lbounds(2), ubounds(2), stride(2)
701 565339 : should_write(2) = .TRUE.
702 565339 : IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
703 0 : should_write(2) = .FALSE.
704 : END IF
705 1341748 : IF (ALL(should_write .EQV. .TRUE.)) THEN
706 374918 : islice = islice + 1
707 : END IF
708 : END DO
709 : END DO
710 1858 : nslices = islice - 1
711 37670 : DO k = lbounds(3), ubounds(3), stride(3)
712 37670 : IF (k + stride(3) > ubounds(3)) last_z = k
713 : END DO
714 1858 : islice = 1
715 : ! Determine initial byte offset (0 or EOF if data is appended)
716 1858 : CALL unit_nr%get_position(BOF)
717 : ! Write header information on master process and update byte offset accordingly
718 1858 : IF (my_rank == 0) THEN
719 : ! this format seems to work for e.g. molekel and gOpenmol
720 : ! latest version of VMD can read non orthorhombic cells
721 929 : CALL unit_nr%write_at(BOF, "-Quickstep-"//NEW_LINE("C"))
722 929 : BOF = BOF + LEN("-Quickstep-"//NEW_LINE("C"))*mpi_character_size
723 929 : IF (PRESENT(title)) THEN
724 929 : CALL unit_nr%write_at(BOF, TRIM(title)//NEW_LINE("C"))
725 929 : BOF = BOF + LEN(TRIM(title)//NEW_LINE("C"))*mpi_character_size
726 : ELSE
727 0 : CALL unit_nr%write_at(BOF, "No Title"//NEW_LINE("C"))
728 0 : BOF = BOF + LEN("No Title"//NEW_LINE("C"))*mpi_character_size
729 : END IF
730 :
731 929 : CPASSERT(PRESENT(particles_z) .EQV. PRESENT(particles_r))
732 929 : np = 0
733 929 : IF (PRESENT(particles_z)) THEN
734 929 : CPASSERT(SIZE(particles_z) == SIZE(particles_r, dim=2))
735 : ! cube files can only be written for 99999 particles due to a format limitation (I5)
736 : ! so we limit the number of particles written.
737 929 : np = MIN(99999, SIZE(particles_z))
738 : END IF
739 :
740 929 : WRITE (header, '(I5,3f12.6)') np, 0.0_dp, 0._dp, 0._dp !start of cube
741 929 : CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
742 929 : BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
743 :
744 929 : WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(1) + stride(1) - 1)/stride(1), &
745 929 : grid%pw_grid%dh(1, 1)*REAL(stride(1), dp), grid%pw_grid%dh(2, 1)*REAL(stride(1), dp), &
746 1858 : grid%pw_grid%dh(3, 1)*REAL(stride(1), dp)
747 929 : CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
748 929 : BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
749 :
750 929 : WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(2) + stride(2) - 1)/stride(2), &
751 929 : grid%pw_grid%dh(1, 2)*REAL(stride(2), dp), grid%pw_grid%dh(2, 2)*REAL(stride(2), dp), &
752 1858 : grid%pw_grid%dh(3, 2)*REAL(stride(2), dp)
753 929 : CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
754 929 : BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
755 :
756 929 : WRITE (header, '(I5,3f12.6)') (grid%pw_grid%npts(3) + stride(3) - 1)/stride(3), &
757 929 : grid%pw_grid%dh(1, 3)*REAL(stride(3), dp), grid%pw_grid%dh(2, 3)*REAL(stride(3), dp), &
758 1858 : grid%pw_grid%dh(3, 3)*REAL(stride(3), dp)
759 929 : CALL unit_nr%write_at(BOF, header//NEW_LINE("C"))
760 929 : BOF = BOF + LEN(header//NEW_LINE("C"))*mpi_character_size
761 :
762 929 : IF (PRESENT(particles_z)) THEN
763 929 : IF (PRESENT(particles_zeff)) THEN
764 1516 : DO i = 1, np
765 1166 : WRITE (header_z, '(I5,4f12.6)') particles_z(i), particles_zeff(i), particles_r(:, i)
766 1166 : CALL unit_nr%write_at(BOF, header_z//NEW_LINE("C"))
767 1516 : BOF = BOF + LEN(header_z//NEW_LINE("C"))*mpi_character_size
768 : END DO
769 : ELSE
770 2587 : DO i = 1, np
771 2008 : WRITE (header_z, '(I5,4f12.6)') particles_z(i), 0._dp, particles_r(:, i)
772 2008 : CALL unit_nr%write_at(BOF, header_z//NEW_LINE("C"))
773 2587 : BOF = BOF + LEN(header_z//NEW_LINE("C"))*mpi_character_size
774 : END DO
775 : END IF
776 : END IF
777 : END IF
778 : ! Sync offset
779 1858 : CALL gid%bcast(BOF, grid%pw_grid%para%group%source)
780 : ! Determine byte offsets for each grid z-slice which are local to a process
781 : ! and convert z-slices to cube format compatible strings
782 5574 : ALLOCATE (displacements(nslices))
783 376776 : displacements = 0
784 5574 : ALLOCATE (writebuffer(nslices))
785 376776 : writebuffer(:) = ''
786 28431 : DO i = lbounds(1), ubounds(1), stride(1)
787 82506 : should_write(:) = .TRUE.
788 27502 : IF (i < lbounds_local(1)) THEN
789 8972 : should_write(1) = .FALSE.
790 18530 : ELSE IF (i > ubounds_local(1)) THEN
791 : EXIT
792 : END IF
793 28431 : DO j = lbounds(2), ubounds(2), stride(2)
794 565339 : should_write(2) = .TRUE.
795 565339 : IF (j < lbounds_local(2) .OR. j > ubounds_local(2)) THEN
796 0 : should_write(2) = .FALSE.
797 : END IF
798 1315175 : IF (ALL(should_write .EQV. .TRUE.)) THEN
799 374918 : IF (islice > nslices) CPABORT("Index out of bounds.")
800 374918 : displacements(islice) = BOF
801 374918 : tmp = ''
802 374918 : counter = 0
803 9698589 : DO k = lbounds(3), ubounds(3), stride(3)
804 9323671 : IF (zero_tails .AND. grid%array(i, j, k) < 1.E-7_dp) THEN
805 54882 : WRITE (value, '(E13.5)') 0.0_dp
806 : ELSE
807 9268789 : WRITE (value, '(E13.5)') grid%array(i, j, k)
808 : END IF
809 9323671 : tmp = TRIM(tmp)//TRIM(value)
810 9323671 : counter = counter + 1
811 9323671 : IF (MODULO(counter, num_entries_line) == 0 .OR. k == last_z) &
812 2070617 : tmp = TRIM(tmp)//NEW_LINE('C')
813 : END DO
814 374918 : writebuffer(islice) = tmp
815 374918 : islice = islice + 1
816 : END IF
817 : ! Update global byte offset
818 565339 : BOF = BOF + msglen
819 : END DO
820 : END DO
821 : ! Create indexed MPI type using calculated byte offsets as displacements
822 : ! Size of each z-slice is msglen
823 5574 : ALLOCATE (blocklengths(nslices))
824 376776 : blocklengths(:) = msglen
825 1858 : mp_desc = mp_file_type_hindexed_make_chv(nslices, blocklengths, displacements)
826 : ! Use the created type as a file view
827 : ! NB. The vector 'displacements' contains the absolute offsets of each z-slice i.e.
828 : ! they are given relative to the beginning of the file. The global offset to
829 : ! set_view must therefore be set to 0
830 1858 : BOF = 0
831 1858 : CALL mp_file_type_set_view_chv(unit_nr, BOF, mp_desc)
832 : ! Collective write of cube
833 1858 : CALL unit_nr%write_all(msglen, nslices, writebuffer, mp_desc)
834 : ! Clean up
835 1858 : CALL mp_file_type_free(mp_desc)
836 1858 : DEALLOCATE (writebuffer)
837 1858 : DEALLOCATE (blocklengths, displacements)
838 :
839 1858 : END SUBROUTINE pw_to_cube_parallel
840 :
841 : ! **************************************************************************************************
842 : !> \brief Prints a simple grid file: X Y Z value
843 : !> \param pw ...
844 : !> \param unit_nr ...
845 : !> \param stride ...
846 : !> \param pw2 ...
847 : !> \par History
848 : !> Created [Vladimir Rybkin] (08.2018)
849 : !> \author Vladimir Rybkin
850 : ! **************************************************************************************************
851 16 : SUBROUTINE pw_to_simple_volumetric(pw, unit_nr, stride, pw2)
852 : TYPE(pw_r3d_rs_type), INTENT(IN) :: pw
853 : INTEGER, INTENT(IN) :: unit_nr
854 : INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: stride
855 : TYPE(pw_r3d_rs_type), INTENT(IN), OPTIONAL :: pw2
856 :
857 : CHARACTER(len=*), PARAMETER :: routineN = 'pw_to_simple_volumetric'
858 :
859 : INTEGER :: checksum, dest, handle, i, I1, I2, I3, &
860 : ip, L1, L2, L3, my_rank, my_stride(3), &
861 : ngrids, npoints, num_pe, rank(2), &
862 : source, tag, U1, U2, U3
863 : LOGICAL :: DOUBLE
864 : REAL(KIND=dp) :: x, y, z
865 16 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: buf, buf2
866 : TYPE(mp_comm_type) :: gid
867 :
868 16 : CALL timeset(routineN, handle)
869 :
870 : ! Check if we write two grids
871 16 : DOUBLE = .FALSE.
872 16 : IF (PRESENT(pw2)) DOUBLE = .TRUE.
873 :
874 64 : my_stride = 1
875 16 : IF (PRESENT(stride)) THEN
876 16 : IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) &
877 : CALL cp_abort(__LOCATION__, "STRIDE keyword can accept only 1 "// &
878 16 : "(the same for X,Y,Z) or 3 values. Correct your input file.")
879 16 : IF (SIZE(stride) == 1) THEN
880 0 : DO i = 1, 3
881 0 : my_stride(i) = stride(1)
882 : END DO
883 : ELSE
884 64 : my_stride = stride(1:3)
885 : END IF
886 16 : CPASSERT(my_stride(1) > 0)
887 16 : CPASSERT(my_stride(2) > 0)
888 16 : CPASSERT(my_stride(3) > 0)
889 : END IF
890 :
891 : ! shortcut
892 16 : L1 = pw%pw_grid%bounds(1, 1)
893 16 : L2 = pw%pw_grid%bounds(1, 2)
894 16 : L3 = pw%pw_grid%bounds(1, 3)
895 16 : U1 = pw%pw_grid%bounds(2, 1)
896 16 : U2 = pw%pw_grid%bounds(2, 2)
897 16 : U3 = pw%pw_grid%bounds(2, 3)
898 :
899 : ! Write the header: number of points and number of spins
900 16 : ngrids = 1
901 16 : IF (DOUBLE) ngrids = 2
902 : npoints = ((pw%pw_grid%npts(1) + my_stride(1) - 1)/my_stride(1))* &
903 : ((pw%pw_grid%npts(2) + my_stride(2) - 1)/my_stride(1))* &
904 16 : ((pw%pw_grid%npts(3) + my_stride(3) - 1)/my_stride(1))
905 16 : IF (unit_nr > 1) WRITE (unit_nr, '(I7,I5)') npoints, ngrids
906 :
907 48 : ALLOCATE (buf(L3:U3))
908 16 : IF (DOUBLE) ALLOCATE (buf2(L3:U3))
909 :
910 16 : my_rank = pw%pw_grid%para%group%mepos
911 16 : gid = pw%pw_grid%para%group
912 16 : num_pe = pw%pw_grid%para%group%num_pe
913 16 : tag = 1
914 :
915 16 : rank (1) = unit_nr
916 16 : rank (2) = my_rank
917 16 : checksum = 0
918 16 : IF (unit_nr > 0) checksum = 1
919 :
920 16 : CALL gid%sum(checksum)
921 16 : CPASSERT(checksum == 1)
922 :
923 16 : CALL gid%maxloc(rank)
924 16 : CPASSERT(rank(1) > 0)
925 :
926 16 : dest = rank(2)
927 500 : DO I1 = L1, U1, my_stride(1)
928 15288 : DO I2 = L2, U2, my_stride(2)
929 :
930 : ! cycling through the CPUs, check if the current ray (I1,I2) is local to that CPU
931 14788 : IF (pw%pw_grid%para%mode /= PW_MODE_LOCAL) THEN
932 44364 : DO ip = 0, num_pe - 1
933 : IF (pw%pw_grid%para%bo(1, 1, ip, 1) <= I1 - L1 + 1 .AND. pw%pw_grid%para%bo(2, 1, ip, 1) >= I1 - L1 + 1 .AND. &
934 44364 : pw%pw_grid%para%bo(1, 2, ip, 1) <= I2 - L2 + 1 .AND. pw%pw_grid%para%bo(2, 2, ip, 1) >= I2 - L2 + 1) THEN
935 14788 : source = ip
936 : END IF
937 : END DO
938 : ELSE
939 0 : source = dest
940 : END IF
941 :
942 14788 : IF (source == dest) THEN
943 7444 : IF (my_rank == source) THEN
944 118276 : buf(:) = pw%array(I1, I2, :)
945 3722 : IF (DOUBLE) buf2(:) = pw2%array(I1, I2, :)
946 : END IF
947 : ELSE
948 7344 : IF (my_rank == source) THEN
949 116976 : buf(:) = pw%array(I1, I2, :)
950 3672 : CALL gid%send(buf, dest, tag)
951 3672 : IF (DOUBLE) THEN
952 0 : buf2(:) = pw2%array(I1, I2, :)
953 0 : CALL gid%send(buf2, dest, tag)
954 : END IF
955 : END IF
956 7344 : IF (my_rank == dest) THEN
957 3672 : CALL gid%recv(buf, source, tag)
958 3672 : IF (DOUBLE) CALL gid%recv(buf2, source, tag)
959 : END IF
960 : END IF
961 :
962 7394 : IF (.NOT. DOUBLE) THEN
963 470504 : DO I3 = L3, U3, my_stride(3)
964 : x = pw%pw_grid%dh(1, 1)*I1 + &
965 : pw%pw_grid%dh(2, 1)*I2 + &
966 455716 : pw%pw_grid%dh(3, 1)*I3
967 :
968 : y = pw%pw_grid%dh(1, 2)*I1 + &
969 : pw%pw_grid%dh(2, 2)*I2 + &
970 455716 : pw%pw_grid%dh(3, 2)*I3
971 :
972 : z = pw%pw_grid%dh(1, 3)*I1 + &
973 : pw%pw_grid%dh(2, 3)*I2 + &
974 455716 : pw%pw_grid%dh(3, 3)*I3
975 :
976 470504 : IF (unit_nr > 0) THEN
977 227858 : WRITE (unit_nr, '(6E13.5, 6E13.5, 6E13.5, 6E13.5)') x, y, z, buf(I3)
978 : END IF
979 : END DO
980 :
981 : ELSE
982 :
983 0 : DO I3 = L3, U3, my_stride(3)
984 : x = pw%pw_grid%dh(1, 1)*I1 + &
985 : pw%pw_grid%dh(2, 1)*I2 + &
986 0 : pw%pw_grid%dh(3, 1)*I3
987 :
988 : y = pw%pw_grid%dh(1, 2)*I1 + &
989 : pw%pw_grid%dh(2, 2)*I2 + &
990 0 : pw%pw_grid%dh(3, 2)*I3
991 :
992 : z = pw%pw_grid%dh(1, 3)*I1 + &
993 : pw%pw_grid%dh(2, 3)*I2 + &
994 0 : pw%pw_grid%dh(3, 3)*I3
995 :
996 0 : IF (unit_nr > 0) THEN
997 0 : WRITE (unit_nr, '(6E13.5, 6E13.5, 6E13.5, 6E13.5)') x, y, z, buf(I3), buf2(I3)
998 : END IF
999 : END DO
1000 :
1001 : END IF ! Double
1002 :
1003 : ! this double loop generates so many messages that it can overload
1004 : ! the message passing system, e.g. on XT3
1005 : ! we therefore put a barrier here that limits the amount of message
1006 : ! that flies around at any given time.
1007 : ! if ever this routine becomes a bottleneck, we should go for a
1008 : ! more complicated rewrite
1009 15272 : CALL gid%sync()
1010 :
1011 : END DO
1012 : END DO
1013 :
1014 16 : DEALLOCATE (buf)
1015 16 : IF (DOUBLE) DEALLOCATE (buf2)
1016 :
1017 16 : CALL timestop(handle)
1018 :
1019 32 : END SUBROUTINE pw_to_simple_volumetric
1020 :
1021 : END MODULE realspace_grid_cube
|