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