Octopus
basins.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21module basins_oct_m
22 use debug_oct_m
23 use global_oct_m
24 use mesh_oct_m
29 use unit_oct_m
31
32 implicit none
33
34 private
35 public :: &
36 basins_t, &
38 basins_end, &
41
42 type basins_t
43 private
44 integer, allocatable, public :: map(:)
45
46 integer :: number
47 integer, allocatable :: position(:)
48 real(real64), allocatable :: val(:)
49 real(real64), allocatable :: volume(:)
50
51 real(real64), allocatable :: population(:)
52 end type basins_t
53
54contains
55
56 !----------------------------------------------------------------
57 subroutine basins_init(this, namespace, mesh)
58 type(basins_t), intent(out) :: this
59 type(namespace_t), intent(in) :: namespace
60 class(mesh_t), intent(in) :: mesh
61
62 push_sub(basins_init)
63
64 if (mesh%parallel_in_domains) then
65 call messages_experimental("Bader basins parallel in domains", namespace=namespace)
66 end if
67
68 safe_allocate(this%map(1:mesh%np))
69 this%map(1:mesh%np) = -1
70
71 pop_sub(basins_init)
72 end subroutine basins_init
73
74
75 !----------------------------------------------------------------
76 subroutine basins_end(this)
77 type(basins_t), intent(inout) :: this
78
79 push_sub(basins_end)
80
81 assert(allocated(this%map))
82 safe_deallocate_a(this%map)
83
84 safe_deallocate_a(this%position)
85 safe_deallocate_a(this%val)
86 safe_deallocate_a(this%volume)
87 safe_deallocate_a(this%population)
88
89 pop_sub(basins_end)
90 end subroutine basins_end
91
92
93 !----------------------------------------------------------------
94 subroutine basins_analyze(this, namespace, mesh, f, rho, threshold)
95 type(basins_t), intent(inout) :: this
96 type(namespace_t), intent(in) :: namespace
97 class(mesh_t), intent(in) :: mesh
98 real(real64), intent(in) :: f(:)
99 real(real64), intent(in) :: rho(:, :)
100 real(real64), intent(in) :: threshold
101
102 integer :: jj, xmax, ymax, zmax
103 integer :: cur_color, dum
104
105 push_sub(basins_analyze)
106
107 assert(allocated(this%map))
108
109 cur_color = 0
110
111 xmax = 1
112 ymax = 1
113 zmax = 1
114 if (mesh%box%dim < 3) zmax = 0
115 if (mesh%box%dim < 2) ymax = 0
116
117 do jj = 1, mesh%np
118 if (this%map(jj) == -1) then
119 dum = steep_fill(jj)
120 end if
121 end do
122
123 call analyze(namespace)
124
125 pop_sub(basins_analyze)
126
127 contains
128
129 !----------------------------------------------------------------
130 recursive integer function steep_fill(ii) result(color)
131 integer, intent(in) :: ii
132
133 integer :: ii_max
134
135 ! No PUSH/POP_SUB in a recursive routine, as the recursion limit of 50 can be reached.
136
137 if (this%map(ii) >= 0) then
138 color = this%map(ii)
139 return
140 end if
141 this%map(ii) = -2
143 ii_max = get_max(ii, m_zero)
144 if (ii_max == -1) then ! this is required to get ring attractors
145 ii_max = get_max(ii, threshold)
146 end if
147
148 if (ii_max /= -1) then
149 color = steep_fill(ii_max)
150 else
151 color = cur_color
152 cur_color = cur_color + 1
153 end if
154 this%map(ii) = color
155
156 end function steep_fill
157
158
159 !----------------------------------------------------------------
160 integer function get_max(ii, threshold)
161 integer, intent(in) :: ii
162 real(real64), intent(in) :: threshold
163
164 real(real64) :: f_max
165 integer :: xx, yy, zz, index
166 integer :: point(3), point2(3)
167
168 push_sub(basins_analyze.get_max)
170 point = 0
171 call mesh_local_index_to_coords(mesh, ii, point)
172
173 f_max = f(ii)
174 get_max = -1
175 do xx = -xmax, xmax
176 do yy = -ymax, ymax
177 do zz = -zmax, zmax
178 if (xx == 0 .and. yy == 0 .and. zz == 0) cycle
179
180 point2 = point
181 point2(1) = point2(1) + xx
182 point2(2) = point2(2) + yy
183 point2(3) = point2(3) + zz
184
185 index = mesh_local_index_from_coords(mesh, point2)
186
187 if (index <= 0 .or. index > mesh%np) cycle
188 if (this%map(index) == -2) cycle
189
190 if (f_max <= f(index) + threshold) then
191 f_max = f(index)
192 get_max = index
193 end if
194
195 end do
196 end do
197 end do
198
199 pop_sub(basins_analyze.get_max)
200 end function get_max
201
202
203 !----------------------------------------------------------------
204 subroutine analyze(namespace)
205 type(namespace_t), intent(in) :: namespace
206
207 integer :: ii, jj, ii_max
208 real(real64) :: f_max
209
210 push_sub(basins_analyze.analyze)
211
212 this%number = maxval(this%map) + 1
213 if (this%number <= 0) then
214 message(1) = "Internal error analysing basins of attraction"
215 call messages_fatal(1, namespace=namespace)
216 end if
217
218 safe_allocate(this%position (1:this%number))
219 safe_allocate(this%val (1:this%number))
220 safe_allocate(this%volume (1:this%number))
221 safe_allocate(this%population(1:this%number))
222
223 this%position(:) = -1
224 this%val(:) = m_zero
225 this%volume(:) = m_zero
226 this%population(:) = m_zero
227 do ii = 1, this%number
228 ii_max = -1
229 f_max = -huge(f_max)
230
231 do jj = 1, mesh%np
232 if (this%map(jj) /= ii-1) cycle
233 if (f_max <= f(jj)) then
234 ii_max = jj
235 f_max = f(jj)
236 end if
237
238 if (mesh%use_curvilinear) then
239 this%volume(ii) = this%volume(ii) + mesh%vol_pp(jj)
240 this%population(ii) = this%population(ii) + mesh%vol_pp(jj)*sum(rho(jj, :))
241 else
242 this%volume(ii) = this%volume(ii) + mesh%volume_element
243 this%population(ii) = this%population(ii) + mesh%volume_element*sum(rho(jj, :))
244 end if
245 end do
246
247 this%position(ii) = ii_max
248 this%val(ii) = f_max
249 end do
250
251 pop_sub(basins_analyze.analyze)
252 end subroutine analyze
254 end subroutine basins_analyze
255
256
257 !----------------------------------------------------------------
258 subroutine basins_write(this, mesh, iunit)
259 type(basins_t), intent(in) :: this
260 class(mesh_t), intent(in) :: mesh
261 integer, intent(in) :: iunit
262
263 integer :: ii
264 type(unit_t) :: unit_vol
265 real(real64) :: xx(1:mesh%box%dim)
266
267 push_sub(basins_write)
268
269 unit_vol = units_out%length**mesh%box%dim
270
271 write(iunit, '(a,i5)') 'Number of basins = ', this%number
272 write(iunit, '(1x)')
273
274 do ii = 1, this%number
275 write(iunit, '(a,i5)') '# ', ii
276 xx = units_from_atomic(units_out%length, mesh%x(this%position(ii), :))
277 write(iunit, '(a,3(f12.6,a), a)') ' position = (', &
278 xx(1), ',', xx(2), ',', xx(3), ') ', units_abbrev(units_out%length)
279 write(iunit, '(a,f12.6)') ' value = ', this%val(ii)
280 write(iunit, '(a,f12.6,a,a)') ' volume = ', units_from_atomic(unit_vol, this%volume(ii)), ' ', units_abbrev(unit_vol)
281 write(iunit, '(a,f12.6)') ' population = ', this%population(ii)
282 end do
283
284 pop_sub(basins_write)
285 end subroutine basins_write
286
287end module basins_oct_m
288
289!! Local Variables:
290!! mode: f90
291!! coding: utf-8
292!! End:
integer function get_max(ii, threshold)
Definition: basins.F90:254
recursive integer function steep_fill(ii)
Definition: basins.F90:224
subroutine analyze(namespace)
Definition: basins.F90:298
subroutine, public basins_write(this, mesh, iunit)
Definition: basins.F90:352
subroutine, public basins_init(this, namespace, mesh)
Definition: basins.F90:151
subroutine, public basins_analyze(this, namespace, mesh, f, rho, threshold)
Definition: basins.F90:188
subroutine, public basins_end(this)
Definition: basins.F90:170
real(real64), parameter, public m_zero
Definition: global.F90:187
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
Definition: mesh.F90:935
subroutine, public mesh_local_index_to_coords(mesh, ip, ix)
Given a local point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:947
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
Some general things and nomenclature:
Definition: par_vec.F90:171
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
Describes mesh distribution to nodes.
Definition: mesh.F90:186