Octopus
local_multipoles.F90
Go to the documentation of this file.
1!! Copyright (C) 2014 M. Oliveira, J. Jornet-Somoza
2!! Copyright (C) 2020-2021 M. Oliveira, K. Lively, A. Obzhirov, I. Albar
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
23 use atom_oct_m
24 use basins_oct_m
27 use box_oct_m
32 use comm_oct_m
33 use debug_oct_m
34 use global_oct_m
36 use io_oct_m
38 use ions_oct_m
39 use kick_oct_m
40 use, intrinsic :: iso_fortran_env
41 use loct_oct_m
43 use mesh_oct_m
45 use mpi_oct_m
48 use parser_oct_m
52 use space_oct_m
56 use string_oct_m
57 use unit_oct_m
59 use utils_oct_m
61 use xc_oct_m
62
63 implicit none
64
66 class(box_t), pointer :: box
67 character(len=500) :: clist
68 character(len=15) :: lab
69 integer :: dshape
70 logical, allocatable :: mesh_mask(:)
71 logical, allocatable :: ions_mask(:)
72 type(local_write_t) :: writ
73 end type local_domain_t
74
75 type(electrons_t), pointer :: sys
76 integer, parameter :: BADER = 9 ! should be = OPTION__OUTPUT__BADER
77
78 ! Initialize stuff
79 call global_init()
80
81 call parser_init()
82
83 call messages_init()
84
85 call io_init()
87
88 call print_header()
89 call messages_print_with_emphasis(msg="Local Domains mode", namespace=global_namespace)
91
92 call messages_experimental("oct-local_multipoles utility")
93
95
96 call calc_mode_par%set_parallelization(p_strategy_states, default = .false.)
98
99 call local_domains()
100
101 safe_deallocate_p(sys)
103 call io_end()
104 call print_date("Calculation ended on ")
105 call messages_end()
106 call parser_end()
107 call global_end()
108
109contains
110 ! -------------
114 subroutine local_domains()
115 integer :: nd
116 type(local_domain_t), allocatable :: loc_domains(:)
117 integer :: err, iter, l_start, l_end, l_step, id
118 integer :: ia, n_spec_def, read_data, iunit, ispec
119 integer :: length, folder_index
120 real(real64) :: default_dt, dt
121 character(len=MAX_PATH_LEN) :: filename, folder, folder_default, radiifile
122 character(len=MAX_PATH_LEN) :: in_folder, restart_folder, basename, frmt, ldrestart_folder
123 character(len=15) :: lab
124 logical :: iterate, ldupdate, ldoverwrite, ldrestart, ld_need_hm
125 type(kick_t) :: kick
126 type(restart_t) :: restart, restart_ld
127
128 push_sub(local_domains)
129
130 message(1) = 'Info: Creating local domains'
131 message(2) = ''
132 call messages_info(2)
133
134 write(folder_default,'(a)') 'restart/gs/'
135
136 !%Variable LDFolder
137 !%Type string
138 !%Section Utilities::oct-local_multipoles
139 !%Description
140 !% The folder name where the density used as input file is.
141 !%End
142 call parse_variable(global_namespace, 'LDFolder', folder_default, folder)
143
144 ! Check if the folder is finished by an /
145 if (index(folder, '/', back = .true.) /= len_trim(folder)) then
146 folder = trim(folder)//'/'
147 end if
148
149 default_dt = m_zero
150 call parse_variable(global_namespace, 'TDTimeStep', default_dt, dt, unit = units_inp%time)
151 if (dt < m_zero) then
152 write(message(1),'(a)') 'Input: TDTimeStep must be positive.'
153 write(message(2),'(a)') 'Input: TDTimeStep reset to 0. Check input file.'
154 call messages_info(2)
155 end if
156
157 !%Variable LDFilename
158 !%Type string
159 !%Default 'density'
160 !%Section Utilities::oct-local_multipoles
161 !%Description
162 !% Input filename. The original filename for the density which is going to be
163 !% fragmented into domains.
164 !%End
165 call parse_variable(global_namespace, 'LDFilename', 'density', basename)
166 if (basename == " ") basename = ""
167 ! Delete the extension if present
168 length = len_trim(basename)
169 if (length > 4) then
170 if (basename(length-3:length) == '.obf') then
171 basename = trim(basename(1:length-4))
172 end if
173 end if
174
175 !%Variable LDUpdate
176 !%Type logical
177 !%Default false
178 !%Section Utilities::oct-local_multipoles
179 !%Description
180 !% Controls if the calculation of the local domains is desired at each iteration.
181 !%End
182 call parse_variable(global_namespace, 'LDUpdate', .false., ldupdate)
183
184 !%Variable LDOverWrite
185 !%Type logical
186 !%Default true
187 !%Section Utilities::oct-local_multipoles
188 !%Description
189 !% Controls whether to over-write existing files.
190 !%End
191 call parse_variable(global_namespace, 'LDOverWrite', .true., ldoverwrite)
192
193 !%Variable LDRadiiFile
194 !%Type string
195 !%Default 'default'
196 !%Section Utilities::oct-local_multipoles
197 !%Description
198 !% Full path for the radii file. If set, def_rsize will be reset to the new values.
199 !% This file should have the same format as share/PP/default.
200 !%End
201 call parse_variable(global_namespace, 'LDRadiiFile', 'default', radiifile)
202
203 if (trim(radiifile) /= "default") then
204 n_spec_def = max(0, loct_number_of_lines(string_f_to_c(radiifile)))
205 if (n_spec_def > 0) n_spec_def = n_spec_def - 1 ! First line is a comment
206
207 ! get parameters from file
208 do ia = 1, sys%ions%nspecies
209 read_data = 0
210 iunit = io_open(radiifile, global_namespace, action='read', status='old', die=.false.)
211 if (iunit /= -1) then
212 if (ia == 1) then
213 write(message(1),'(a,a)') 'Redefining def_rsize from file:', trim(radiifile)
214 call messages_info(1)
215 end if
216 read(iunit,*)
217 default_file: do ispec = 1, n_spec_def
218 read(iunit,*) lab
219 if (trim(lab) == trim(sys%ions%species(ia)%s%get_label())) then
220 select type(spec=>sys%ions%species(ia)%s)
221 class is(pseudopotential_t)
222 call read_from_default_file(iunit, read_data, spec)
223 end select
224 exit default_file
225 end if
226 end do default_file
227 call io_close(iunit)
228 else
229 write(message(1),'(a,a)') 'Octopus could not open then file:', trim(radiifile)
230 call messages_warning(1)
231 end if
232 end do
233 end if
234
235 !TODO: use standart FromSratch and %RestartOptions
236 !%Variable LDRestart
237 !%Type logical
238 !%Default false
239 !%Section Utilities::oct-local_multipoles
240 !%Description
241 !% Restart information will be read from <tt>LDRestartFolder</tt>.
242 !%End
243 call parse_variable(global_namespace, 'LDRestart', .false., ldrestart)
244
245 if (ldrestart) then
246 write(folder_default,'(a)')'ld.general'
247
248 !%Variable LDRestartFolder
249 !%Type string
250 !%Default "ld.general"
251 !%Section Utilities::oct-local_multipoles
252 !%Description
253 !% The folder name where the density used as input file is.
254 !%End
255 call parse_variable(global_namespace, 'LDRestartFolder', folder_default, ldrestart_folder)
256
257 ! Check if the folder is finished by an /
258 if (index(ldrestart_folder, '/', .true.) /= len_trim(ldrestart_folder)) then
259 write(ldrestart_folder,'(a,a1)') trim(ldrestart_folder), '/'
260 end if
261 end if
262
263
264 !%Variable LDIterateFolder
265 !%Type logical
266 !%Default false
267 !%Section Utilities::oct-local_multipoles
268 !%Description
269 !% This variable decides if a folder is going to be iterated.
270 !%End
271 call parse_variable(global_namespace, 'LDIterateFolder', .false., iterate)
272
273 !%Variable LDStart
274 !%Type integer
275 !%Default 0
276 !%Section Utilities::oct-local_multipoles
277 !%Description
278 !% The starting number of the filename or folder.
279 !%End
280 call parse_variable(global_namespace, 'LDStart', 0, l_start)
281
282 !%Variable LDEnd
283 !%Type integer
284 !%Default 0
285 !%Section Utilities::oct-local_multipoles
286 !%Description
287 !% The last number of the filename or folder.
288 !%End
289 call parse_variable(global_namespace, 'LDEnd', 0, l_end)
290
291 !%Variable LDStep
292 !%Type integer
293 !%Default 1
294 !%Section Utilities::oct-local_multipoles
295 !%Description
296 !% The padding between the filenames or folder.
297 !%End
298 call parse_variable(global_namespace, 'LDStep', 1, l_step)
299
300 message(1) = 'Info: Computing local multipoles'
301 message(2) = ''
302 call messages_info(2)
303
304 call local_init(sys%space, sys%gr, sys%ions, nd, loc_domains)
305
306 ! Starting loop over selected densities.
307 if (any(loc_domains(:)%dshape == bader)) then
308 call messages_experimental('Bader volumes in oct-local_multipoles')
309 end if
310
311 call kick_init(kick, global_namespace, sys%space, sys%kpoints, sys%st%d%ispin)
312 ld_need_hm = .false.
313 do id = 1, nd
314 call local_write_init(loc_domains(id)%writ, global_namespace, loc_domains(id)%lab, 0, dt)
315 ld_need_hm = ld_need_hm .or. local_write_check_hm(loc_domains(id)%writ)
316 end do
317
318 if (ld_need_hm) then
319 message(1) = 'Info: Local domains output includes local potential and/or local energy.'
320 call messages_info(1)
321
322 call hamiltonian_elec_epot_generate(sys%hm, global_namespace, sys%space, sys%gr, sys%ions, &
323 sys%ext_partners, sys%st, time=m_zero)
324 call sys%hm%update(sys%gr, global_namespace, sys%space, sys%ext_partners, time=m_zero)
325 end if
326
327 if (ldrestart) then
328 !TODO: check for domains & mesh compatibility
329 call restart_ld%init(global_namespace, restart_undefined, restart_type_load, sys%mc, err, &
330 dir=trim(ldrestart_folder), mesh = sys%gr)
331 call local_restart_read(sys%space, sys%gr, sys%ions, nd, loc_domains, restart_ld)
332 call restart_ld%end()
333 end if
334
335 ! Initialize the restart directory from <tt>LDFolder</tt> value.
336 ! This directory has to have the files 'grid', 'mesh' and 'lxyz.obf'
337 ! and the files that are going to be used, must be inside this folder
338 if (iterate) then
339 ! Delete the last / and find the previous /, if any
340 in_folder = folder(1:len_trim(folder)-1)
341 folder_index = index(in_folder, '/', .true.)
342 restart_folder = in_folder(1:folder_index)
343 else
344 restart_folder = folder
345 end if
346 call restart%init(global_namespace, restart_undefined, restart_type_load, sys%mc, err, &
347 dir=trim(restart_folder), mesh = sys%gr)
348
349!!$ call loct_progress_bar(-1, l_end-l_start)
350 do iter = l_start, l_end, l_step
351 if (iterate) then
352 ! Delete the last / and add the corresponding folder number
353 write(in_folder,'(a,i0.7,a)') folder(folder_index+1:len_trim(folder)-1),iter, "/"
354 write(filename, '(a,a,a)') trim(in_folder), trim(basename)
355 else
356 in_folder = "."
357 if (l_start /= l_end) then
358 ! Here, we are only considering 10 character long filenames.
359 ! Subtract the initial part given at 'ConvertFilename' from the format and pad
360 ! with zeros.
361 write(frmt,'(a,i0,a)')"(a,i0.",10-len_trim(basename),")"
362 write(filename, fmt=trim(frmt)) trim(basename), iter
363 else
364 ! Assuming filename is given complete in the 'LDFilename'
365 write(filename, '(a,a,a,a)') trim(in_folder),"/", trim(basename)
366 filename = basename
367 end if
368 end if
369 ! FIXME: there is a special function for reading the density. Why not use that?
370 ! TODO: Find the function that reads the density. Which one?
371 ! FIXME: why only real functions? Please generalize.
372 ! TODO: up to know the local_multipoles utlity acts over density functions, which are real.
373 if (err == 0) then
374 call restart%read_mesh_function(trim(filename), sys%gr, sys%st%rho(:,1), err)
375 end if
376 if (err /= 0) then
377 write(message(1),*) 'While reading density: "', trim(filename), '", error code:', err
378 call messages_fatal(1)
379 end if
380
381 ! Look for the mesh points inside local domains
382 if ((iter == l_start .and. .not. ldrestart) .or. ldupdate) then
383 call local_inside_domain(sys%space, sys%gr, sys%ions, nd, loc_domains, global_namespace, sys%st%rho(:,1))
384 call local_restart_write(global_namespace, sys%space, sys%gr, sys%mc, nd, loc_domains)
385 end if
386
387 do id = 1, nd
388 call local_write_iter(loc_domains(id)%writ, global_namespace, sys%space, loc_domains(id)%lab, loc_domains(id)%ions_mask, &
389 loc_domains(id)%mesh_mask, sys%gr, sys%st, sys%hm, sys%ks, sys%ions, &
390 sys%ext_partners, kick, iter, l_start, ldoverwrite)
391 end do
392 call loct_progress_bar(iter-l_start, l_end-l_start)
393 end do
394
395 call restart%end()
396 call kick_end(kick)
397
398 do id = 1, nd
399 call local_end(loc_domains(id))
400 end do
401 safe_deallocate_a(loc_domains)
402
403 message(1) = 'Info: Exiting local domains'
404 message(2) = ''
405 call messages_info(2)
406
407 pop_sub(local_domains)
408 end subroutine local_domains
409
410 ! ---------------------------------------------------------
413 ! ---------------------------------------------------------
414 subroutine local_init(space, mesh, ions, nd, loc_domains)
415 class(space_t), intent(in) :: space
416 class(mesh_t), intent(in) :: mesh
417 type(ions_t), intent(in) :: ions
418 integer, intent(out) :: nd
419 type(local_domain_t), allocatable, intent(out) :: loc_domains(:)
420
421 integer :: id
422 type(block_t) :: blk
423
424 push_sub(local_init)
425
426 !TODO: use same strategy used in %Species block to define variables
427 !%Variable LocalDomains
428 !%Type block
429 !%Section Utilities::oct-local_multipoles
430 !%Description
431 !% The LocalDomains are by definition part of the global grid. The domains are defined by
432 !% selecting a type shape. The domain box will be constructed using the given parameters.
433 !% A local domain could be construct by addition of several box centered on the ions.
434 !% The grid points inside this box will belong to the local domain.
435 !%
436 !% The format of this block is the following:<br>
437 !% <tt> 'Label' | Shape | %< | Shape dependencies >% </tt>
438 !% <br>The first field is the label of the domain.
439 !% Label = string with the name of the new local domain.
440 !% The second is the shape type of the box used to define the domain.
441 !% Shape = SPHERE, CYLINDER, PARALLELEPIPED, MINIMUM, BADER.
442 !% Some types may need some parameters given in the remaining fields of the row.
443 !% (the valid options are detailed below).
444 !%
445 !% <tt>%LocalDomains
446 !% <br>case (SPHERE): | rsize | %<dim origin coordinates>
447 !% <br>case (CYLINDER): | rsize | xsize | %<origin coordinates>
448 !% <br>case (PARALLELEPIPED): | %<lsize> | %<origin coordinates>
449 !% <br>case (MINIMUM): | rsize | 'center_list'
450 !% <br>case (BADER): | 'center_list'
451 !% <br>%</tt>
452 !% <br>rsize: Radius in input length units
453 !% <br>xsize: the length of the cylinder in the x-direction
454 !% <br>origin coordinates: in input length units separated by |, where the box is centered.
455 !% <br>lsize: half of the length of the parallelepiped in each direction.
456 !% <br>center_list: string containing the list of atoms in xyz file for each domain in the form "2,16-23"
457 !%End
458
459 ! First, find out if there is a LocalDomains block.
460 nd = 0
461 if (parse_block(global_namespace, 'LocalDomains', blk) == 0) then
462 nd = parse_block_n(blk)
463 end if
464
465 safe_allocate(loc_domains(1:nd))
466
467 block: do id = 1, nd
468 safe_allocate(loc_domains(id)%mesh_mask(1:mesh%np))
469 safe_allocate(loc_domains(id)%ions_mask(1:ions%natoms))
470 call parse_block_string(blk, id-1, 0, loc_domains(id)%lab)
471 call local_read_from_block(loc_domains(id), space, ions, blk, id-1, global_namespace)
472 end do block
473 call parse_block_end(blk)
474 message(1) = ''
475 call messages_info(1)
476
477 pop_sub(local_init)
478 end subroutine local_init
479
480 ! ---------------------------------------------------------
483 ! ---------------------------------------------------------
484 subroutine local_end(domain)
485 type(local_domain_t), intent(inout) :: domain
486
487 class(box_t), pointer :: box
488
489 push_sub(local_end)
490
491 if (domain%dshape /= bader) then
492 box => domain%box
493 safe_deallocate_p(box)
494 end if
495 call local_write_end(domain%writ)
496 safe_deallocate_a(domain%mesh_mask)
497 safe_deallocate_a(domain%ions_mask)
498
499 pop_sub(local_end)
500 end subroutine local_end
501
502 ! ---------------------------------------------------------
503 subroutine local_read_from_block(domain, space, ions, blk, row, namespace)
504 type(local_domain_t), intent(inout) :: domain
505 class(space_t), intent(in) :: space
506 type(ions_t), intent(in) :: ions
507 type(block_t), intent(in) :: blk
508 integer, intent(in) :: row
509 type(namespace_t), intent(in) :: namespace
510
511 integer :: ic, ia
512 real(real64) :: radius, center(space%dim), half_length(space%dim)
513 class(box_union_t), pointer :: minimum_box
514
515 push_sub(local_read_from_block)
516
517 call parse_block_integer(blk, row, 1, domain%dshape)
518
519 select case (domain%dshape)
520 case (minimum)
521 call parse_block_float(blk, row, 2, radius, unit = units_inp%length)
522 if (radius < m_zero) call messages_input_error(namespace, 'radius', row=row, column=2)
523 call parse_block_string(blk, row, 3, domain%clist)
524
525 minimum_box => box_union_t(space%dim)
526 do ia = 1, ions%natoms
527 if (loct_isinstringlist(ia, domain%clist)) then
528 call minimum_box%add_box(box_sphere_t(space%dim, ions%pos(:, ia), radius, namespace))
529 end if
530 end do
531 domain%box => minimum_box
532
533 ic = 0
534 do ia = 1, ions%natoms
535 if (domain%box%contains_point(ions%pos(:, ia)) .and. .not. loct_isinstringlist(ia, domain%clist)) then
536 ic = ic + 1
537 if (ic <= 20) write(message(ic),'(a,a,I0,a,a)')'Atom: ',trim(ions%atom(ia)%species%get_label()), ia, &
538 ' is inside the union box BUT not in list: ', trim(domain%clist)
539 end if
540 end do
541 if (ic > 0) then
542 if (ic > 20) ic = 20
543 call messages_warning(ic)
544 message(1) = ' THIS COULD GIVE INCORRECT RESULTS '
545 call messages_warning(1)
546 if (ic == 20) then
547 message(1) = ' AT LEAST 19 ATOMS ARE NOT PRESENT IN THE LIST'
548 call messages_warning(1)
549 end if
550 end if
551
552 case (sphere)
553 call parse_block_float(blk, row, 2, radius, unit = units_inp%length)
554 if (radius < m_zero) call messages_input_error(namespace, 'radius', row=row, column=2)
555 do ic = 1, space%dim
556 call parse_block_float(blk, row, 2 + ic, center(ic), unit = units_inp%length)
557 end do
558
559 domain%box => box_sphere_t(space%dim, center, radius, namespace)
560
561 case (cylinder)
562 call parse_block_float(blk, row, 2, radius, unit = units_inp%length)
563 if (radius < m_zero) then
564 call messages_input_error(namespace, 'radius', row=row, column=2)
565 end if
566 call parse_block_float(blk, row, 3, half_length(1), unit = units_inp%length)
567 do ic = 1, space%dim
568 call parse_block_float(blk, row, 3 + ic, center(ic), unit = units_inp%length)
569 end do
570
571 domain%box => box_cylinder_t(space%dim, center, ions%latt%rlattice, radius, half_length(1)*m_two, namespace)
572
573 case (parallelepiped)
574 do ic = 1, space%dim
575 call parse_block_float(blk, row, 1 + ic, half_length(ic), unit = units_inp%length)
576 end do
577 do ic = 1, space%dim
578 call parse_block_float(blk, row, 1 + space%dim + ic, center(ic), unit = units_inp%length)
579 end do
580
581 domain%box => box_parallelepiped_t(space%dim, center, ions%latt%rlattice, half_length*m_two, namespace)
582
583 case (bader)
584 call parse_block_string(blk, row, 2, domain%clist)
585 pop_sub(local_read_from_block)
586 return
587 end select
588
589 pop_sub(local_read_from_block)
590 end subroutine local_read_from_block
591
592 ! ---------------------------------------------------------
594 subroutine local_restart_write(namespace, space, mesh, mc, nd, loc_domains)
595 type(namespace_t), intent(in) :: namespace
596 class(space_t), intent(in) :: space
597 class(mesh_t), intent(in) :: mesh
598 type(multicomm_t), intent(in) :: mc
599 integer, intent(in) :: nd
600 type(local_domain_t), intent(in) :: loc_domains(:)
601
602 integer :: id, ip, iunit, ierr
603 character(len=MAX_PATH_LEN) :: dirname
604 character(len=140), allocatable :: lines(:)
605 real(real64), allocatable :: ff(:,:)
606 type(restart_t) :: restart
607
608 push_sub(local_restart_write)
609
610 dirname = "./restart/ld"
611 write(message(1),'(a,a)')'Info: Writing restart info to ', trim(dirname)
612 call messages_info(1)
613
614 call restart%init(namespace, restart_undefined, restart_type_dump, mc, ierr, mesh=mesh, dir=trim(dirname))
615
616 safe_allocate(lines(1:nd+2))
617 write(lines(1),'(a,1x,i5)') 'Number of local domains =', nd
618 write(lines(2),'(a3,1x,a15,1x,a5,1x)') '#id', 'label', 'shape'
619 do id = 1, nd
620 write(lines(id+2), '(i3,1x,a15,1x,i5)') id, trim(loc_domains(id)%lab), loc_domains(id)%dshape
621 end do
622 iunit = restart%open("ldomains.info")
623 call restart%write(iunit, lines, nd+2, ierr)
624 call io_close(iunit)
625 safe_deallocate_a(lines)
626
627 safe_allocate(ff(1:mesh%np, 1))
628 ff = m_zero
629 do id = 1, nd
630 do ip = 1, mesh%np
631 if (loc_domains(id)%mesh_mask(ip)) ff(ip, 1) = ff(ip, 1) + 2**real(id, real64)
632 end do
633 end do
634 call restart%write_mesh_function("ldomains", mesh, ff(1:mesh%np, 1), ierr)
635 safe_deallocate_a(ff)
636
637 call restart%end()
638
639 pop_sub(local_restart_write)
640 end subroutine local_restart_write
641
642 ! ---------------------------------------------------------
643 subroutine local_restart_read(space, mesh, ions, nd, loc_domains, restart)
644 class(space_t), intent(in) :: space
645 class(mesh_t), intent(in) :: mesh
646 type(ions_t), intent(in) :: ions
647 integer, intent(in) :: nd
648 type(local_domain_t), intent(inout) :: loc_domains(:)
649 type(restart_t), intent(in) :: restart
650
651 integer :: id, ip, iunit, ierr
652 character(len=31) :: line(1), tmp
653 real(real64), allocatable :: mask(:)
654
655 push_sub(local_restart_read)
656
657 message(1) = 'Info: Reading mesh points inside each local domain'
658 call messages_info(1)
659
660 safe_allocate(mask(1:mesh%np))
661
662 !Read local domain information from ldomains.info
663 iunit = restart%open("ldomains.info", status='old')
664 call restart%read(iunit, line, 1, ierr)
665 read(line(1),'(a25,1x,i5)') tmp, ierr
666 call restart%close(iunit)
667
668 call restart%read_mesh_function("ldomains", mesh, mask, ierr)
669
670 do id = 1, nd
671 loc_domains(id)%mesh_mask = .false.
672 do ip = 1 , mesh%np
673 if (bitand(int(mask(ip)), 2**id) /= 0) loc_domains(id)%mesh_mask(ip) = .true.
674 end do
675
676 !Check for atom list inside each domain
677 call local_ions_mask(loc_domains(id)%mesh_mask, ions, mesh, loc_domains(id)%ions_mask)
678 end do
679
680 safe_deallocate_a(mask)
681
682 pop_sub(local_restart_read)
683 end subroutine local_restart_read
684
685 ! ---------------------------------------------------------
686 subroutine local_inside_domain(space, mesh, ions, nd, loc_domains, namespace, ff)
687 class(space_t), intent(in) :: space
688 class(mesh_t), intent(in) :: mesh
689 type(ions_t), intent(in) :: ions
690 integer, intent(in) :: nd
691 type(local_domain_t), intent(inout) :: loc_domains(:)
692 type(namespace_t), intent(in) :: namespace
693 real(real64), intent(in) :: ff(:)
694
695 integer(int64) :: how
696 integer :: id, ip, ierr
697 type(basins_t) :: basins
698 character(len=MAX_PATH_LEN) :: filename
699 real(real64), allocatable :: dble_domain_map(:), domain_mesh(:)
700
701 push_sub(local_inside_domain)
702
703 !TODO: find a parallel algorithm to perform the charge-density fragmentation.
704 message(1) = 'Info: Assigning mesh points inside each local domain'
705 call messages_info(1)
706
707 ! If we have Bader domains, then we need to get the basins
708 if (any(loc_domains(:)%dshape == bader)) then
709 if (mesh%parallel_in_domains) then
710 write(message(1),'(a)') 'Bader volumes can only be computed in serial'
711 call messages_fatal(1)
712 end if
713 call create_basins(namespace, space, mesh, ions, ff, basins)
714 end if
715
716 do id = 1, nd
717 ! Create the mask that tells which mesh points are inside the domain
718 select case (loc_domains(id)%dshape)
719 case (bader)
720 call bader_domain_create_mask(loc_domains(id), basins, mesh, ions)
721 case default
722 call box_domain_create_mask(loc_domains(id), mesh)
723 end select
724
725 !Check for atom list inside each domain
726 call local_ions_mask(loc_domains(id)%mesh_mask, ions, mesh, loc_domains(id)%ions_mask)
727 end do
728
729 if (any(loc_domains(:)%dshape == bader)) then
730 call basins_end(basins)
731 end if
732
733 if (debug%info) then
734 call parse_variable(namespace, 'LDOutputFormat', 0, how)
735 if (.not. varinfo_valid_option('OutputFormat', how, is_flag=.true.)) then
736 call messages_input_error(namespace, 'LDOutputFormat')
737 end if
739 ! Write extra information about domains
740 safe_allocate(dble_domain_map(1:mesh%np))
741 safe_allocate(domain_mesh(1:mesh%np))
742
743 domain_mesh = m_zero
744 do id = 1, nd
745 dble_domain_map = m_zero
746 do ip = 1, mesh%np
747 if (loc_domains(id)%mesh_mask(ip)) then
748 dble_domain_map(ip) = real(id, real64)
749 domain_mesh(ip) = domain_mesh(ip) + dble_domain_map(ip)
750 end if
751 end do
752
753 write(filename,'(a,a)') 'domain.', trim(loc_domains(id)%lab)
754 call dio_function_output(how, 'local.general', trim(filename), namespace, space, mesh, dble_domain_map, unit_one, ierr, &
755 pos=ions%pos, atoms=ions%atom)
756 end do
757
758 call dio_function_output(how, 'local.general', 'domain.mesh', namespace, space, mesh, domain_mesh, unit_one, ierr, &
759 pos=ions%pos, atoms=ions%atom)
760
761 safe_deallocate_a(dble_domain_map)
762 safe_deallocate_a(domain_mesh)
763 end if
764
765 pop_sub(local_inside_domain)
766 end subroutine local_inside_domain
767
768 ! ---------------------------------------------------------
769 subroutine create_basins(namespace, space, mesh, ions, ff, basins)
770 type(namespace_t), intent(in) :: namespace
771 class(space_t), intent(in) :: space
772 class(mesh_t), intent(in) :: mesh
773 type(ions_t), intent(in) :: ions
774 real(real64), intent(in) :: ff(:)
775 type(basins_t), intent(inout) :: basins
776
777 logical :: use_atomic_radii
778 integer :: ip, ierr, ia, is, rankmin
779 integer(int64) :: how
780 real(real64) :: bader_threshold, dmin, dd
781 integer, allocatable :: ion_map(:)
782 real(real64), allocatable :: ff2(:,:), ffs(:)
783
784 push_sub(create_basins)
785
786 !%Variable LDBaderThreshold
787 !%Type float
788 !%Default 0.01
789 !%Section Utilities::oct-local_multipoles
790 !%Description
791 !% This variable sets the threshold for the basins calculations. Recommended values:
792 !% 0.01 -> intramolecular volumes; 0.2 -> intermolecular volumes.
793 !%End
794 call parse_variable(namespace, 'LDBaderThreshold', 0.01_real64, bader_threshold)
795
796 ! Copy function used to construct the basins, as we need to modify it
797 safe_allocate(ff2(1:mesh%np,1))
798 ff2(1:mesh%np,1) = ff(1:mesh%np)
799
800 ! Add long range density from atoms
801 safe_allocate(ffs(1:mesh%np))
802 do ia = 1, ions%natoms
803 call species_get_long_range_density(ions%atom(ia)%species, ions%namespace, ions%space, ions%latt, &
804 ions%pos(:, ia), mesh, ffs)
805 do is = 1, ubound(ff2, dim=2)
806 ff2(1:mesh%np, is) = ff2(1:mesh%np, is) - ffs(1:mesh%np)
807 end do
808 end do
809 safe_deallocate_a(ffs)
810
811 call basins_init(basins, namespace, mesh)
812 call basins_analyze(basins, namespace, mesh, ff2(:,1), ff2, bader_threshold)
813
814 if (debug%info) then
815 call parse_variable(namespace, 'LDOutputFormat', 0, how)
816 if (.not. varinfo_valid_option('OutputFormat', how, is_flag=.true.)) then
817 call messages_input_error(namespace, 'LDOutputFormat')
818 end if
819
820 call dio_function_output(how, 'local.general', 'basinsmap', namespace, space, mesh, real(basins%map(1:mesh%np), real64) , &
821 unit_one, ierr, pos=ions%pos, atoms=ions%atom)
822 call dio_function_output(how, 'local.general', 'dens_ff2', namespace, space, mesh, ff2(:,1), &
823 unit_one, ierr, pos=ions%pos, atoms=ions%atom)
824 end if
825 safe_deallocate_a(ff2)
826
827 !%Variable LDUseAtomicRadii
828 !%Type logical
829 !%Default false
830 !%Section Utilities::oct-local_multipoles
831 !%Description
832 !% If set, atomic radii will be used to assign lone pairs to ion.
833 !%End
834 call parse_variable(global_namespace, 'LDUseAtomicRadii', .false., use_atomic_radii)
835
836 if (use_atomic_radii) then
837 safe_allocate(ion_map(1:ions%natoms))
838 ion_map = 0
839 do ia = 1, ions%natoms
840 ion_map(ia) = basins%map(mesh_nearest_point(mesh, ions%pos(:, ia), dmin, rankmin))
841 end do
842
843 do ip = 1, mesh%np
844 ! Check if lonely pair has no ions assigned to it
845 if (all(ion_map(:) /= basins%map(ip))) then
846 ! Assign lonely pair to ion in a atomic radii distance
847 do ia = 1, ions%natoms
848 dd = norm2(mesh%x(:, ip) - ions%pos(:, ia))
849 if (dd <= ions%atom(ia)%species%get_vdw_radius()) basins%map(ip) = ion_map(ia)
850 end do
851 end if
852 end do
853
854 safe_deallocate_a(ion_map)
855 end if
856
857 pop_sub(create_basins)
858 end subroutine create_basins
859
860 ! ---------------------------------------------------------
861 subroutine box_domain_create_mask(domain, mesh)
862 class(local_domain_t), intent(inout) :: domain
863 class(mesh_t), intent(in) :: mesh
865 push_sub(box_domain_create_mask)
866
867 domain%mesh_mask = domain%box%contains_points(mesh%np, mesh%x_t)
868
870 end subroutine box_domain_create_mask
871
872 ! ---------------------------------------------------------
873 subroutine bader_domain_create_mask(domain, basins, mesh, ions)
874 class(local_domain_t), intent(inout) :: domain
875 type(basins_t), intent(in) :: basins
876 class(mesh_t), intent(in) :: mesh
877 type(ions_t), intent(in) :: ions
878
879 integer :: ia, ib, ip, ix, n_basins, rankmin
880 real(real64) :: dmin
881 integer, allocatable :: domain_map(:)
882
884
885 ! Count then number of basins to consider. That is the number of ions specified in the input by the user
886 n_basins = 0
887 do ia = 1, ions%natoms
888 if (loct_isinstringlist(ia, domain%clist)) n_basins = n_basins + 1
889 end do
890
891 safe_allocate(domain_map(1:n_basins))
892
893 ! Assign basins to ions
894 domain_map = 0
895 ib = 0
896 do ia = 1, ions%natoms
897 if (.not. loct_isinstringlist(ia, domain%clist)) cycle
898 ib = ib + 1
899 ix = mesh_nearest_point(mesh, ions%pos(:, ia), dmin, rankmin)
900 domain_map(ib) = basins%map(ix)
901 end do
902
903 ! Now construct the mask: a point belongs to this Bader domain if it is part
904 ! of at least one basin that is part of this domain
905 do ip = 1, mesh%np
906 domain%mesh_mask(ip) = any(domain_map(1:n_basins) == basins%map(ip))
907 end do
908
909 safe_deallocate_a(domain_map)
910
912 end subroutine bader_domain_create_mask
913
914 ! ---------------------------------------------------------
915 !Check for the ions inside each local domain.
916 subroutine local_ions_mask(mesh_mask, ions, mesh, ions_mask)
917 logical, intent(in) :: mesh_mask(:)
918 type(ions_t), intent(in) :: ions
919 class(mesh_t), intent(in) :: mesh
920 logical, intent(out) :: ions_mask(:)
921
922 integer :: ia, ix
923 integer, allocatable :: mask_tmp(:)
924 integer :: rankmin
925 real(real64) :: dmin
926
927 push_sub(local_ions_mask)
928
929 safe_allocate(mask_tmp(1:ions%natoms))
930 mask_tmp = 0
931
932 do ia = 1, ions%natoms
933 ix = mesh_nearest_point(mesh, ions%pos(:, ia), dmin, rankmin)
934 if (rankmin /= mesh%mpi_grp%rank) cycle
935 if (mesh_mask(ix)) mask_tmp(ia) = 1
936 end do
937
938 call mesh%allreduce(mask_tmp, ions%natoms)
939 ions_mask = mask_tmp == 1
940
941 safe_deallocate_a(mask_tmp)
942
943 pop_sub(local_ions_mask)
944 end subroutine local_ions_mask
945
946end program oct_local_multipoles
947
948!! Local Variables:
949!! mode: f90
950!! coding: utf-8
951!! End:
subroutine create_basins(namespace, space, mesh, ions, ff, basins)
program oct_local_multipoles
subroutine local_restart_read(space, mesh, ions, nd, loc_domains, restart)
subroutine local_ions_mask(mesh_mask, ions, mesh, ions_mask)
subroutine local_restart_write(namespace, space, mesh, mc, nd, loc_domains)
Write restart files for local domains.
subroutine local_inside_domain(space, mesh, ions, nd, loc_domains, namespace, ff)
subroutine bader_domain_create_mask(domain, basins, mesh, ions)
subroutine local_read_from_block(domain, space, ions, blk, row, namespace)
subroutine local_domains()
Reads a global grid and density and make local domains This is a high-level interface that reads the ...
subroutine local_init(space, mesh, ions, nd, loc_domains)
Initialize local_domain_t variable, allocating variable and reading parameters from input file.
subroutine local_end(domain)
Ending local_domain_t variable, allocating variable and reading parameters from input file.
subroutine box_domain_create_mask(domain, mesh)
subroutine, public basins_init(this, namespace, mesh)
Definition: basins.F90:153
subroutine, public basins_analyze(this, namespace, mesh, f, rho, threshold)
Definition: basins.F90:190
subroutine, public basins_end(this)
Definition: basins.F90:172
Module, implementing a factory for boxes.
integer, parameter, public sphere
integer, parameter, public minimum
integer, parameter, public parallelepiped
integer, parameter, public cylinder
This module handles the calculation mode.
type(calc_mode_par_t), public calc_mode_par
Singleton instance of parallel calculation mode.
integer, parameter, public p_strategy_states
parallelization in states
type(debug_t), save, public debug
Definition: debug.F90:158
real(real64), parameter, public m_two
Definition: global.F90:202
subroutine, public global_end()
Finalise parser varinfo file, and MPI.
Definition: global.F90:494
real(real64), parameter, public m_zero
Definition: global.F90:200
subroutine, public global_init(communicator)
Initialise Octopus.
Definition: global.F90:375
integer, parameter, public length
subroutine, public hamiltonian_elec_epot_generate(this, namespace, space, gr, ions, ext_partners, st, time)
subroutine, public dio_function_output(how, dir, fname, namespace, space, mesh, ff, unit, ierr, pos, atoms, grp, root)
Top-level IO routine for functions defined on the mesh.
Definition: io.F90:116
subroutine, public io_init(defaults)
If the argument defaults is present and set to true, then the routine will not try to read anything f...
Definition: io.F90:165
subroutine, public io_close(iunit, grp)
Definition: io.F90:467
subroutine, public io_end()
Definition: io.F90:271
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:402
subroutine, public kick_end(kick)
Definition: kick.F90:796
subroutine, public kick_init(kick, namespace, space, kpoints, nspin)
Definition: kick.F90:225
subroutine, public local_write_init(writ, namespace, lab, iter, dt)
subroutine, public local_write_end(writ)
logical function, public local_write_check_hm(writ)
subroutine, public local_write_iter(writ, namespace, space, lab, ions_mask, mesh_mask, mesh, st, hm, ks, ions, ext_partners, kick, iter, l_start, ldoverwrite)
System information (time, memory, sysname)
Definition: loct.F90:117
logical function, public loct_isinstringlist(a, s)
Definition: loct.F90:288
subroutine, public loct_progress_bar(a, maxcount)
A wrapper around the progress bar, such that it can be silenced without needing to dress the call wit...
Definition: loct.F90:276
character(kind=c_char, len=1) function, dimension(len_trim(f_string)+1), private string_f_to_c(f_string)
convert a Fortran string to a C string
Definition: loct.F90:240
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
integer function, public mesh_nearest_point(mesh, pos, dmin, rankmin)
Returns the index of the point which is nearest to a given vector position pos.
Definition: mesh.F90:386
subroutine, public messages_end()
Definition: messages.F90:273
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
character(len=512), private msg
Definition: messages.F90:167
subroutine, public messages_init(output_dir)
Definition: messages.F90:220
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
subroutine, public print_date(str)
Definition: messages.F90:983
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:272
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
type(namespace_t), public global_namespace
Definition: namespace.F90:135
subroutine, public parse_block_string(blk, l, c, res, convert_to_c)
Definition: parser.F90:818
subroutine, public parser_init()
Initialise the Octopus parser.
Definition: parser.F90:410
subroutine, public parser_end()
End the Octopus parser.
Definition: parser.F90:442
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
subroutine, public profiling_end(namespace)
Definition: profiling.F90:415
subroutine, public profiling_init(namespace)
Create profiling subdirectory.
Definition: profiling.F90:257
subroutine, public read_from_default_file(iunit, read_data, spec)
integer, parameter, public restart_undefined
Definition: restart.F90:156
integer, parameter, public restart_type_dump
Definition: restart.F90:184
integer, parameter, public restart_type_load
Definition: restart.F90:184
subroutine, public species_get_long_range_density(species, namespace, space, latt, pos, mesh, rho, sphere_inout, nlr_x)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
This module defines the unit system, used for input and output.
subroutine, public unit_system_init(namespace)
type(unit_system_t), public units_inp
the units systems for reading and writing
type(unit_t), public unit_one
some special units required for particular quantities
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:120
subroutine, public print_header()
This subroutine prints the logo followed by information about the compilation and the system....
Definition: utils.F90:304
Definition: xc.F90:120
Class implementing a cylinder box. The cylinder axis is always along the first direction defined by t...
class to tell whether a point is inside or outside
Definition: box.F90:143
Class implementing a parallelepiped box. Currently this is restricted to a rectangular cuboid (all th...
Class implementing a spherical box.
Definition: box_sphere.F90:134
Class implementing a box that is an union other boxes.
Definition: box_union.F90:134
Class describing the electron system.
Definition: electrons.F90:223
Describes mesh distribution to nodes.
Definition: mesh.F90:187
Stores all communicators and groups.
Definition: multicomm.F90:208
int true(void)