(git:98357aa)
Loading...
Searching...
No Matches
realspace_grid_openpmd.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 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! **************************************************************************************************
12
13#ifdef __OPENPMD
14 USE cp_files, ONLY: close_file, &
19 USE kinds, ONLY: default_string_length, &
20 dp
21 USE message_passing, ONLY: &
25 USE physcon, ONLY: a_bohr, e_charge, seconds
26#if defined(__parallel)
27#if defined(__MPI_F08)
28 USE mpi_f08, ONLY: mpi_allreduce, mpi_integer, mpi_bxor, mpi_allgather
29#else
30 USE mpi, ONLY: mpi_allreduce, mpi_integer, mpi_bxor, mpi_allgather
31#endif
32#endif
33
34 USE openpmd_api, ONLY: &
35 openpmd_attributable_type, &
36 openpmd_dynamic_memory_view_type_1d, &
37 openpmd_dynamic_memory_view_type_3d, &
38 openpmd_mesh_type, &
39 openpmd_particle_species_type, &
40 openpmd_record_component_type, &
41 openpmd_record_type, openpmd_type_double, openpmd_type_int
43 USE pw_types, ONLY: pw_r3d_rs_type
44 USE util, ONLY: sort_unique
45
46#else
47
48 USE pw_types, ONLY: pw_r3d_rs_type
49 USE kinds, ONLY: dp
50
51#endif
52
53#include "../base/base_uses.f90"
54
55 IMPLICIT NONE
56
57 PRIVATE
58
59 PUBLIC ::pw_to_openpmd
60
61#ifdef __OPENPMD
62 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'realspace_grid_openpmd'
63 LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .false.
64 LOGICAL, PRIVATE :: parses_linebreaks = .false., &
65 parse_test = .true.
66
67 TYPE cp_openpmd_write_buffer_1d
68 REAL(KIND=dp), POINTER :: buffer(:)
69 END TYPE cp_openpmd_write_buffer_1d
70#endif
71
72CONTAINS
73
74#ifdef __OPENPMD
75! **************************************************************************************************
76!> \brief ...
77!> \param particles_z ...
78!> \param res_atom_types ...
79!> \param res_atom_counts ...
80!> \param res_len ...
81! **************************************************************************************************
82 SUBROUTINE pw_get_atom_types(particles_z, res_atom_types, res_atom_counts, res_len)
83 INTEGER, DIMENSION(:), INTENT(IN) :: particles_z
84 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: res_atom_types, res_atom_counts
85 INTEGER, INTENT(OUT) :: res_len
86
87 INTEGER :: current_atom_number, i
88 INTEGER, ALLOCATABLE, DIMENSION(:) :: particles_z_sorted
89 LOGICAL :: unique
90
91 ALLOCATE (particles_z_sorted(SIZE(particles_z)))
92 particles_z_sorted(:) = particles_z(:)
93 CALL sort_unique(particles_z_sorted, unique)
94
95 ALLOCATE (res_atom_types(min(118, SIZE(particles_z))))
96 ALLOCATE (res_atom_counts(min(118, SIZE(particles_z))))
97 current_atom_number = -1
98 res_len = 0
99 DO i = 1, SIZE(particles_z_sorted)
100 IF (particles_z_sorted(i) /= current_atom_number) THEN
101 res_len = res_len + 1
102 current_atom_number = particles_z_sorted(i)
103 res_atom_types(res_len) = current_atom_number
104 res_atom_counts(res_len) = 1
105 ELSE
106 res_atom_counts(res_len) = res_atom_counts(res_len) + 1
107 END IF
108 END DO
109
110 END SUBROUTINE pw_get_atom_types
111
112! **************************************************************************************************
113!> \brief ...
114!> \param particles_z ...
115!> \param particles_r ...
116!> \param particles_zeff ...
117!> \param atom_type ...
118!> \param atom_count ...
119!> \param openpmd_data ...
120!> \param do_write_data ...
121! **************************************************************************************************
122 SUBROUTINE pw_write_particle_species( &
123 particles_z, &
124 particles_r, &
125 particles_zeff, &
126 atom_type, &
127 atom_count, &
128 openpmd_data, &
129 do_write_data &
130 )
131 INTEGER, DIMENSION(:), INTENT(IN) :: particles_z
132 REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: particles_r
133 REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
134 INTEGER, INTENT(IN) :: atom_type, atom_count
135 TYPE(cp_openpmd_per_call_value_type) :: openpmd_data
136 LOGICAL :: do_write_data
137
138 CHARACTER(len=1), DIMENSION(3), PARAMETER :: dims = ["x", "y", "z"]
139
140 CHARACTER(len=3) :: atom_type_as_string
141 CHARACTER(len=default_string_length) :: species_name
142 INTEGER :: i, j, k
143 INTEGER, DIMENSION(1) :: global_extent, global_offset, &
144 local_extent
145 TYPE(cp_openpmd_write_buffer_1d) :: charge_write_buffer
146 TYPE(cp_openpmd_write_buffer_1d), DIMENSION(3) :: write_buffers
147 TYPE(openpmd_attributable_type) :: attr
148 TYPE(openpmd_dynamic_memory_view_type_1d) :: unresolved_charge_write_buffer
149 TYPE(openpmd_dynamic_memory_view_type_1d), &
150 DIMENSION(3) :: unresolved_write_buffers
151 TYPE(openpmd_particle_species_type) :: species
152 TYPE(openpmd_record_component_type) :: charge_component, position_component, &
153 position_offset_component
154 TYPE(openpmd_record_type) :: charge, position, position_offset
155
156! TODO: The charge is probably constant per species?
157! If yes, we could use a constant component and save storage space
158
159 global_extent(1) = atom_count
160 IF (do_write_data) THEN
161 global_offset(1) = 0
162 local_extent(1) = atom_count
163 ELSE
164 global_offset(1) = 0
165 local_extent(1) = 0
166 END IF
167
168 WRITE (atom_type_as_string, '(I3)') atom_type
169 species_name = trim(openpmd_data%name_prefix)//"-"//adjustl(atom_type_as_string)
170
171 CALL openpmd_data%iteration%open()
172 species = openpmd_data%iteration%get_particle_species(trim(species_name))
173
174 position_offset = species%get_record("positionOffset")
175 position = species%get_record("position")
176 ! length
177 CALL position%set_unit_dimension([1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp])
178 DO k = 1, SIZE(dims)
179 position_offset_component = position_offset%get_component(dims(k))
180 CALL position_offset_component%make_constant_zero(openpmd_type_int, global_extent)
181 CALL position_offset_component%set_unit_SI(a_bohr) ! doesnt really matter as it is zero
182 position_component = position%get_component(dims(k))
183 CALL position_component%reset_dataset(openpmd_type_double, global_extent)
184 CALL position_component%set_unit_SI(a_bohr)
185 unresolved_write_buffers(k) = &
186 position_component%store_chunk_span_1d_double(global_offset, local_extent)
187 write_buffers(k)%buffer => unresolved_write_buffers(k)%resolve_double(deallocate=.false.)
188 END DO
189
190 IF (PRESENT(particles_zeff)) THEN
191 charge = species%get_record("charge")
192 charge_component = charge%as_record_component()
193 ! charge ~ time x current
194 CALL charge%set_unit_dimension([0.0_dp, 0.0_dp, 1.0_dp, 1.0_dp, 0.0_dp, 0.0_dp, 0.0_dp])
195 CALL charge_component%reset_dataset(openpmd_type_double, global_extent)
196 CALL charge_component%set_unit_SI(e_charge)
197 unresolved_charge_write_buffer = charge_component%store_chunk_span_1d_double(global_offset, local_extent)
198 charge_write_buffer%buffer => unresolved_charge_write_buffer%resolve_double(deallocate=.false.)
199 END IF
200
201 ! Resolve Spans for a second time to allow for internal reallocations in BP4 engine of ADIOS2
202 DO k = 1, SIZE(dims)
203 write_buffers(k)%buffer = unresolved_write_buffers(k)%resolve_double(deallocate=.true.)
204 END DO
205 IF (PRESENT(particles_zeff)) THEN
206 charge_write_buffer%buffer = unresolved_charge_write_buffer%resolve_double(deallocate=.true.)
207 END IF
208 IF (do_write_data) THEN
209 j = 1
210 DO i = 1, SIZE(particles_z)
211 IF (particles_z(i) == atom_type) THEN
212 DO k = 1, 3
213 write_buffers(k)%buffer(j) = particles_r(k, i)
214 END DO
215 IF (PRESENT(particles_zeff)) THEN
216 charge_write_buffer%buffer(j) = particles_zeff(i)
217 END IF
218 j = j + 1
219 END IF
220 END DO
221 END IF
222 attr = openpmd_data%iteration%as_attributable()
223 CALL attr%series_flush("hdf5.independent_stores = true")
224 END SUBROUTINE pw_write_particle_species
225
226! **************************************************************************************************
227!> \brief ...
228!> \param particles_z ...
229!> \param particles_r ...
230!> \param particles_zeff ...
231!> \param atom_types ...
232!> \param atom_counts ...
233!> \param num_atom_types ...
234!> \param openpmd_data ...
235!> \param gid ...
236! **************************************************************************************************
237 SUBROUTINE pw_write_particles( &
238 particles_z, &
239 particles_r, &
240 particles_zeff, &
241 atom_types, &
242 atom_counts, &
243 num_atom_types, &
244 openpmd_data, &
245 gid &
246 )
247 INTEGER, DIMENSION(:), INTENT(IN) :: particles_z
248 REAL(KIND=dp), DIMENSION(:, :), INTENT(IN) :: particles_r
249 REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
250 INTEGER, DIMENSION(:), INTENT(IN) :: atom_types, atom_counts
251 INTEGER, INTENT(IN), TARGET :: num_atom_types
252 TYPE(cp_openpmd_per_call_value_type) :: openpmd_data
253 TYPE(mp_comm_type), OPTIONAL :: gid
254
255 INTEGER :: i, mpi_rank
256 LOGICAL :: do_write_data
257
258 IF (PRESENT(gid)) THEN
259 CALL gid%get_rank(mpi_rank)
260 do_write_data = mpi_rank == 0
261 ELSE
262 do_write_data = .true.
263 END IF
264 DO i = 1, num_atom_types
265 CALL pw_write_particle_species( &
266 particles_z, &
267 particles_r, &
268 particles_zeff, &
269 atom_types(i), &
270 atom_counts(i), &
271 openpmd_data, &
272 do_write_data &
273 )
274 END DO
275 END SUBROUTINE pw_write_particles
276
277! **************************************************************************************************
278!> \brief ...
279!> \param pw ...
280!> \param unit_nr ...
281!> \param title ...
282!> \param particles_r ...
283!> \param particles_z ...
284!> \param particles_zeff ...
285!> \param stride ...
286!> \param zero_tails ...
287!> \param silent ...
288!> \param mpi_io ...
289! **************************************************************************************************
290 SUBROUTINE pw_to_openpmd( &
291 pw, &
292 unit_nr, &
293 title, &
294 particles_r, &
295 particles_z, &
296 particles_zeff, &
297 stride, &
298 zero_tails, &
299 silent, &
300 mpi_io &
301 )
302 TYPE(pw_r3d_rs_type), INTENT(IN) :: pw
303 INTEGER :: unit_nr
304 CHARACTER(*), INTENT(IN), OPTIONAL :: title
305 REAL(KIND=dp), DIMENSION(:, :), INTENT(IN), &
306 OPTIONAL :: particles_r
307 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: particles_z
308 REAL(KIND=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
309 INTEGER, DIMENSION(:), OPTIONAL, POINTER :: stride
310 LOGICAL, INTENT(IN), OPTIONAL :: zero_tails, silent, mpi_io
311
312 CHARACTER(len=*), PARAMETER :: routineN = 'pw_to_openpmd'
313
314 CHARACTER(LEN=default_string_length) :: my_title
315 INTEGER :: count1, count2, count3, handle, i, I1, &
316 I2, I3, iat, L1, L2, L3, my_rank, &
317 my_stride(3), np, num_atom_types, &
318 num_pe, U1, U2, U3
319 INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_counts, atom_types
320 INTEGER, DIMENSION(3) :: global_extent, local_extent, offset
321 LOGICAL :: be_silent, my_zero_tails, parallel_write
322 REAL(KIND=dp), DIMENSION(3) :: grid_spacing
323 REAL(KIND=dp), POINTER :: write_buffer(:, :, :)
324 TYPE(cp_openpmd_per_call_value_type) :: openpmd_data
325 TYPE(mp_comm_type) :: gid
326 TYPE(openpmd_attributable_type) :: attr
327 TYPE(openpmd_dynamic_memory_view_type_3d) :: unresolved_write_buffer
328 TYPE(openpmd_mesh_type) :: mesh
329 TYPE(openpmd_record_component_type) :: scalar_mesh
330
331 CALL timeset(routinen, handle)
332
333 my_zero_tails = .false.
334 be_silent = .false.
335 parallel_write = .false.
336 gid = pw%pw_grid%para%group
337 IF (PRESENT(title)) my_title = trim(title)
338 IF (PRESENT(zero_tails)) my_zero_tails = zero_tails
339 IF (PRESENT(silent)) be_silent = silent
340 IF (PRESENT(mpi_io)) parallel_write = mpi_io
341 my_stride = 1
342 IF (PRESENT(stride)) THEN
343 IF (SIZE(stride) /= 1 .AND. SIZE(stride) /= 3) THEN
344 CALL cp_abort(__location__, "STRIDE keyword can accept only 1 "// &
345 "(the same for X,Y,Z) or 3 values. Correct your input file.")
346 END IF
347 IF (SIZE(stride) == 1) THEN
348 DO i = 1, 3
349 my_stride(i) = stride(1)
350 END DO
351 ELSE
352 my_stride = stride(1:3)
353 END IF
354 cpassert(my_stride(1) > 0)
355 cpassert(my_stride(2) > 0)
356 cpassert(my_stride(3) > 0)
357 END IF
358
359 openpmd_data = cp_openpmd_get_value_unit_nr(unit_nr)
360
361 cpassert(PRESENT(particles_z) .EQV. PRESENT(particles_r))
362 np = 0
363 IF (PRESENT(particles_z)) THEN
364 CALL pw_get_atom_types(particles_z, atom_types, atom_counts, num_atom_types)
365 cpassert(SIZE(particles_z) == SIZE(particles_r, dim=2))
366 np = SIZE(particles_z)
367 END IF
368
369 DO i = 1, 3
370 ! Notes:
371 ! 1. This loses information on the rotation of the mesh, the mesh is stored
372 ! without reference to a global coordinate system
373 ! 2. This assumes that the coordinate system is not sheared
374 grid_spacing(i) = sqrt(sum(pw%pw_grid%dh(:, i)**2))*real(my_stride(i), dp)
375 END DO
376
377 IF (PRESENT(particles_z)) THEN
378 IF (parallel_write) THEN
379 CALL pw_write_particles( &
380 particles_z, &
381 particles_r, &
382 particles_zeff, &
383 atom_types, &
384 atom_counts, &
385 num_atom_types, &
386 openpmd_data, &
387 gid &
388 )
389 ELSE
390 CALL pw_write_particles( &
391 particles_z, &
392 particles_r, &
393 particles_zeff, &
394 atom_types, &
395 atom_counts, &
396 num_atom_types, &
397 openpmd_data &
398 )
399 END IF
400 END IF
401
402 DO iat = 1, 3
403 global_extent(iat) = (pw%pw_grid%npts(iat) + my_stride(iat) - 1)/my_stride(iat)
404 ! '- 1' for upper gaussian bracket
405 offset(iat) = ((pw%pw_grid%bounds_local(1, iat) - pw%pw_grid%bounds(1, iat) + my_stride(iat) - 1)/my_stride(iat))
406 ! '+ 1' because upper end is inclusive, '- 1' for upper gaussian bracket
407 ! refer local_extent to the global offset first in order to have consistent rounding
408 local_extent(iat) = ((pw%pw_grid%bounds_local(2, iat) + 1 - pw%pw_grid%bounds(1, iat) + my_stride(iat) - 1)/my_stride(iat))
409 END DO
410 local_extent = local_extent - offset
411
412 mesh = openpmd_data%iteration%get_mesh(trim(openpmd_data%name_prefix))
413 CALL mesh%set_axis_labels(["x", "y", "z"])
414 CALL mesh%set_position([0.5_dp, 0.5_dp, 0.5_dp])
415 CALL mesh%set_grid_global_offset([ &
416 pw%pw_grid%bounds(1, 1)*grid_spacing(1), &
417 pw%pw_grid%bounds(1, 2)*grid_spacing(2), &
418 pw%pw_grid%bounds(1, 3)*grid_spacing(3)])
419 CALL mesh%set_grid_spacing(grid_spacing)
420 CALL mesh%set_grid_unit_SI(a_bohr)
421 CALL mesh%set_unit_dimension(openpmd_data%unit_dimension)
422 scalar_mesh = mesh%as_record_component()
423 CALL scalar_mesh%set_unit_SI(openpmd_data%unit_si)
424 CALL scalar_mesh%reset_dataset(openpmd_type_double, global_extent)
425
426 ! shortcut
427 ! need to adjust L1/U1 for uneven distributions across MPI ranks
428 ! (when working with a stride, we might have to skip the first n values)
429 ! so keep this consistent with the offset and local_extent computed above
430 ! L1 = pw%pw_grid%bounds_local(1, 1)
431 l1 = pw%pw_grid%bounds(1, 1) + offset(1)*my_stride(1)
432 l2 = pw%pw_grid%bounds_local(1, 2)
433 l3 = pw%pw_grid%bounds_local(1, 3)
434 ! offset + local_extent is the start index for the next rank already
435 ! since the indexes are inclusive, subtract 1 from the boundary index
436 u1 = pw%pw_grid%bounds(1, 1) + (offset(1) + local_extent(1) - 1)*my_stride(1)
437 u2 = pw%pw_grid%bounds_local(2, 2)
438 u3 = pw%pw_grid%bounds_local(2, 3)
439
440 my_rank = pw%pw_grid%para%group%mepos
441 num_pe = pw%pw_grid%para%group%num_pe
442
443 IF (all(my_stride == 1)) THEN
444 CALL scalar_mesh%store_chunk(pw%array(l1:u1, l2:u2, l3:u3), offset)
445 ! Are there some conditions under which we can skip this flush?
446 attr = openpmd_data%iteration%as_attributable()
447 CALL attr%series_flush("hdf5.independent_stores = false")
448 ELSE
449 count3 = 0
450 DO i3 = l3, u3, my_stride(3)
451 ! maybe add an overload to provide `buf` here for HDF5, might have better performance
452 ! for intermittent flushing
453 ! or just call the buffer in the outer function if memory is no problem...
454 unresolved_write_buffer = scalar_mesh%store_chunk_span_3d_double( &
455 [offset(1), offset(2), offset(3) + count3], &
456 [local_extent(1), local_extent(2), 1])
457 write_buffer => unresolved_write_buffer%resolve_double(deallocate=.true.)
458
459 ! Sanity checks: ensure buffer is associated and matches expected shape
460 cpassert(ASSOCIATED(write_buffer))
461 cpassert(SIZE(write_buffer, 1) == local_extent(1))
462 cpassert(SIZE(write_buffer, 2) == local_extent(2))
463 cpassert(SIZE(write_buffer, 3) == 1)
464
465 count2 = 0
466 DO i2 = l2, u2, my_stride(2)
467 ! This loop deals with ray (:, count2, count3) of the local subspace
468 ! The write buffer itself has been allocated for slice (:, :, count3)
469 count1 = 0
470 DO i1 = l1, u1, my_stride(1)
471 write_buffer(count1 + 1, count2 + 1, 1) = pw%array(i1, i2, i3)
472 ! Debug: print the target indices in write_buffer to the command line
473 ! WRITE(*,*) 'write_buffer index:', count1 + 1, ',', count2 + 1, ',', 1
474 count1 = count1 + 1
475 END DO
476 count2 = count2 + 1
477 END DO
478 count3 = count3 + 1
479 END DO
480 END IF
481
482 CALL timestop(handle)
483
484 END SUBROUTINE pw_to_openpmd
485
486#else
487
488! **************************************************************************************************
489!> \brief ...
490!> \param pw ...
491!> \param unit_nr ...
492!> \param title ...
493!> \param particles_r ...
494!> \param particles_z ...
495!> \param particles_zeff ...
496!> \param stride ...
497!> \param zero_tails ...
498!> \param silent ...
499!> \param mpi_io ...
500! **************************************************************************************************
501 SUBROUTINE pw_to_openpmd( &
502 pw, &
503 unit_nr, &
504 title, &
505 particles_r, &
506 particles_z, &
507 particles_zeff, &
508 stride, &
509 zero_tails, &
510 silent, &
511 mpi_io &
512 )
513 TYPE(pw_r3d_rs_type), INTENT(IN) :: pw
514 INTEGER :: unit_nr
515 CHARACTER(*), INTENT(IN), OPTIONAL :: title
516 REAL(kind=dp), DIMENSION(:, :), INTENT(IN), &
517 OPTIONAL :: particles_r
518 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: particles_z
519 REAL(kind=dp), DIMENSION(:), INTENT(IN), OPTIONAL :: particles_zeff
520 INTEGER, DIMENSION(:), OPTIONAL, POINTER :: stride
521 LOGICAL, INTENT(IN), OPTIONAL :: zero_tails, silent, mpi_io
522
523 mark_used(pw)
524 mark_used(unit_nr)
525 mark_used(title)
526 mark_used(particles_r)
527 mark_used(particles_z)
528 mark_used(particles_zeff)
529 mark_used(stride)
530 mark_used(zero_tails)
531 mark_used(silent)
532 mark_used(mpi_io)
533 cpabort("CP2K compiled without the openPMD-api")
534
535 END SUBROUTINE pw_to_openpmd
536
537#endif
538
539END MODULE realspace_grid_openpmd
Define the atom type and its sub types.
Definition atom_types.F:15
Utility routines to open and close files. Tracking of preconnections.
Definition cp_files.F:16
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
Definition cp_files.F:311
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Definition cp_files.F:122
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
type(cp_openpmd_per_call_value_type) function, public cp_openpmd_get_value_unit_nr(key)
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
Interface to the message passing library MPI.
type(mp_file_descriptor_type) function, public mp_file_type_hindexed_make_chv(count, lengths, displs)
Creates an indexed MPI type for arrays of strings using bytes for spacing (hindexed type)
subroutine, public mp_file_type_free(type_descriptor)
Releases the type used for MPI I/O.
integer, parameter, public mpi_character_size
integer, parameter, public file_offset
integer, parameter, public file_amode_rdonly
subroutine, public mp_file_type_set_view_chv(fh, offset, type_descriptor)
Uses a previously created indexed MPI character type to tell the MPI processes how to partition (set_...
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public a_bohr
Definition physcon.F:136
real(kind=dp), parameter, public e_charge
Definition physcon.F:106
real(kind=dp), parameter, public seconds
Definition physcon.F:150
integer, parameter, public pw_mode_local
Generate Gaussian cube files.
subroutine, public pw_to_openpmd(pw, unit_nr, title, particles_r, particles_z, particles_zeff, stride, zero_tails, silent, mpi_io)
...
All kind of helpful little routines.
Definition util.F:14