Octopus
box_factory.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2013,2021 M. Oliveira
3!! Copyright (C) 2021 K. Lively, A. Obzhirov, I. Albar
4!!
5!! This program is free software; you can redistribute it and/or modify
6!! it under the terms of the GNU General Public License as published by
7!! the Free Software Foundation; either version 2, or (at your option)
8!! any later version.
9!!
10!! This program is distributed in the hope that it will be useful,
11!! but WITHOUT ANY WARRANTY; without even the implied warranty of
12!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13!! GNU General Public License for more details.
14!!
15!! You should have received a copy of the GNU General Public License
16!! along with this program; if not, write to the Free Software
17!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18!! 02110-1301, USA.
19!!
20
21#include "global.h"
22
28 use box_oct_m
31 use debug_oct_m
36 use global_oct_m
38 use math_oct_m
41 use parser_oct_m
43 use space_oct_m
46
47 implicit none
48
49 private
50 public :: &
52
53 integer, parameter, public :: &
54 SPHERE = 1, &
55 cylinder = 2, &
56 minimum = 3, &
57 parallelepiped = 4, &
58 box_cgal = 5, &
59 box_usdef = 77
60
61contains
62
68 function box_factory_create(namespace, space, latt, n_sites, site_position) result(box)
69 type(namespace_t), intent(in) :: namespace
70 class(space_t), intent(in) :: space
71 type(lattice_vectors_t), optional, intent(in) :: latt
72 integer, optional, intent(in) :: n_sites
73 real(real64), optional, intent(in) :: site_position(:,:)
75 class(box_t), pointer :: box
76
77 type(block_t) :: blk
78 integer :: default_boxshape, idir, box_shape
79 real(real64) :: center(space%dim), axes(space%dim, space%dim), rsize, xsize, lsize(space%dim)
80 character(len=1024) :: filename
81 character(len=1024) :: user_def
82 real(real64), parameter :: tol = 1.0e-13_real64
83
84 push_sub(box_factory_create)
85
86 ! We must have both n_sites and site_position or none.
87 assert(present(n_sites) .eqv. present(site_position))
88
89 !%Variable BoxShape
90 !%Type integer
91 !%Section Mesh::Simulation Box
92 !%Description
93 !% This variable decides the shape of the simulation box.
94 !% The default is <tt>minimum</tt> for finite systems and <tt>parallelepiped</tt> for periodic systems.
95 !% Note that some incompatibilities apply:
96 !% <ul><li>Spherical or minimum mesh is not allowed for periodic systems.
97 !% <li>Cylindrical mesh is not allowed for systems that are periodic in more than one dimension.</ul>
98 !%Option sphere 1
99 !% The simulation box will be a sphere of radius <tt>Radius</tt>. (In 2D, this is a circle.)
100 !%Option cylinder 2
101 !% The simulation box will be a cylinder with radius <tt>Radius</tt> and height (in the <i>x</i>-direction)
102 !% of 2 <tt>Xlength</tt>.
103 !%Option minimum 3
104 !% The simulation box will be constructed by adding spheres created around each
105 !% atom (or user-defined potential), of radius <tt>Radius</tt>.
106 !%Option parallelepiped 4
107 !% The simulation box will be a parallelepiped whose dimensions are taken from
108 !% the variable <tt>Lsize</tt>.
109 !%Option box_cgal 5
110 !% The simulation box will be defined by a file read using the CGAL library.
111 !% The file name needs to be specified with <tt>BoxCgalFile</tt>.
112 !% <tt>Lsize</tt> needs to be large enough to contain the shape defined in the file.
113 !%Option user_defined 77
114 !% The shape of the simulation box will be read from the variable <tt>BoxShapeUsDef</tt>.
115 !%End
116
117 if (space%is_periodic()) then
118 default_boxshape = parallelepiped
119 if(.not. present(latt)) then
120 message(1) = "Periodic system box is trying to be generated without lattice vectors given."
121 call messages_fatal(1, namespace=namespace)
122 endif
123 else
124 if (present(site_position)) then
125 default_boxshape = minimum
126 else
127 default_boxshape = parallelepiped
128 endif
129 end if
130 call parse_variable(namespace, 'BoxShape', default_boxshape, box_shape)
131 if (.not. varinfo_valid_option('BoxShape', box_shape)) call messages_input_error(namespace, 'BoxShape')
132 select case (box_shape)
133 case (sphere, minimum, box_usdef)
134 if (space%dim > 1 .and. space%is_periodic()) call messages_input_error(namespace, 'BoxShape')
135 case (cylinder)
136 if (space%dim == 2) then
137 message(1) = "BoxShape = cylinder is not meaningful in 2D. Use sphere if you want a circle."
138 call messages_fatal(1, namespace=namespace)
139 end if
140 if (space%periodic_dim > 1) call messages_input_error(namespace, 'BoxShape')
141 end select
142
143 ! ignore box_shape in 1D
144 if (space%dim == 1 .and. box_shape /= parallelepiped) then
145 if (space%is_periodic()) then
146 ! Periodic systems should not use spherical boxes.
147 box_shape = parallelepiped
148 else
149 box_shape = sphere
150 end if
151 end if
152
153 if (space%dim > 3 .and. box_shape /= parallelepiped) then
154 message(1) = "For more than 3 dimensions, you can only use the parallelepiped box."
155 call messages_fatal(1, namespace=namespace)
156 ! FIXME: why not a hypersphere as another option?
157 end if
158
159 !%Variable Radius
160 !%Type float
161 !%Section Mesh::Simulation Box
162 !%Description
163 !% Defines the radius for <tt>BoxShape</tt> = <tt>sphere</tt>,
164 !% <tt>cylinder</tt>, or <tt>minimum</tt>. Must be a positive
165 !% number.
166 !%End
167 if (box_shape == sphere .or. box_shape == cylinder .or. box_shape == minimum) then
168 if (.not. parse_is_defined(namespace, 'Radius')) then
169 message(1) = "BoxShape = sphere, cylinder and minimum require the Radius variable to be defined."
170 call messages_fatal(1,namespace=namespace)
171 else
172 call parse_variable(namespace, 'Radius', -m_one, rsize, units_inp%length)
173 end if
174 if (rsize < m_zero) call messages_input_error(namespace, 'Radius')
175 end if
176
177 if (box_shape == minimum .and. .not. present(site_position)) then
178 ! We should only be here if ions are present, something has gone wrong
179 message(1) = "BoxShape = minimum only makes sense when the calculation includes atomic sites."
180 call messages_fatal(1, namespace=namespace)
181 end if
182
183 if (box_shape == cylinder) then
184 !%Variable Xlength
185 !%Default <tt>Radius</tt>
186 !%Type float
187 !%Section Mesh::Simulation Box
188 !%Description
189 !% If <tt>BoxShape</tt> is <tt>cylinder</tt>, the total length of the cylinder is twice <tt>Xlength</tt>.
190 !% Note that when PeriodicDimensions = 1, then the length of the cylinder is determined from the lattice vectors.
191 !%End
192 if (space%is_periodic()) then
193 xsize = norm2(latt%rlattice(1:space%periodic_dim, 1))/m_two
194 else
195 call parse_variable(namespace, 'Xlength', rsize, xsize, units_inp%length)
196 end if
197 end if
198
199 lsize = m_zero
200 if (box_shape == parallelepiped .or. box_shape == box_usdef .or. box_shape == box_cgal) then
201
202 !%Variable Lsize
203 !%Type block
204 !%Section Mesh::Simulation Box
205 !%Description
206 !% If <tt>BoxShape</tt> is <tt>parallelepiped</tt> or <tt>user_defined</tt>, this is a block of the form:
207 !%
208 !% <tt>%Lsize
209 !% <br>&nbsp;&nbsp;sizex | sizey | sizez | ...
210 !% <br>%</tt>
211 !%
212 !% where the <tt>size*</tt> are half the lengths of the box in each direction.
213 !%
214 !% The number of columns must match the dimensionality of the
215 !% calculation. If you want a cube you can also set <tt>Lsize</tt> as a
216 !% single variable.
217 !%End
218 if (present(latt)) then
219 ! lattice should only be passed if periodic
220 ! lsize along the periodic dimensions must always be set from the norm of the lattice vectors
221 do idir = 1, space%periodic_dim
222 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
223 end do
224 endif
225
226 if (space%is_periodic()) then
227 ! For mixed-periodicity, lsize along the non-periodic dimensions is
228 ! by default set from the lattice parameters (this can still be
229 ! overriden by setting Lsize, see bellow).
230 do idir = space%periodic_dim + 1, space%dim
231 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
232 end do
233 else
234 ! Lsize must be set for finite systems, as in that case we do not have the lattice parameters
235 if (.not. parse_is_defined(namespace, 'Lsize')) then
236 call messages_input_error(namespace, 'Lsize', 'Lsize is required for finite systems')
237 end if
238 end if
239
240 ! Note that for cases with mixed-periodicidy, the user still has the
241 ! option to set Lsize to override the size of the box along the
242 ! non-periodic dimensions given by the lattice parameters. This
243 ! requires the user to also set Lsize for the periodic dimensions,
244 ! which at the moment must match exactly the corresponding values
245 ! given by the lattice vectors.
246 if (parse_block(namespace, 'Lsize', blk) == 0) then
247 ! Lsize is specified as a block
248 if (parse_block_cols(blk, 0) < space%dim) then
249 call messages_input_error(namespace, 'Lsize')
250 end if
251
252 do idir = 1, space%dim
253 call parse_block_float(blk, 0, idir - 1, lsize(idir), units_inp%length)
254 end do
255 call parse_block_end(blk)
256
257 else if (parse_is_defined(namespace, 'Lsize')) then
258 ! Lsize is specified as a scalar
259 call parse_variable(namespace, 'Lsize', -m_one, lsize(1), units_inp%length)
260 if (abs(lsize(1) + m_one) <= m_epsilon) then
261 call messages_input_error(namespace, 'Lsize')
262 end if
263 do idir = 2, space%dim
264 lsize(idir) = lsize(1)
265 end do
266
267 end if
268
269 ! Check that lsize is consistent with the lattice vectors along the periodic dimensions
270 do idir = 1, space%periodic_dim
271 if (abs(m_two*lsize(idir) - norm2(latt%rlattice(1:space%dim, idir))) > tol) then
272 call messages_input_error(namespace, 'Lsize', &
273 'Lsize must be exactly half the length of the lattice vectors along periodic dimensions')
274 end if
275 end do
276 end if
277
278 ! read in box shape for user-defined boxes
279 if (box_shape == box_usdef) then
280
281 !%Variable BoxShapeUsDef
282 !%Type string
283 !%Section Mesh::Simulation Box
284 !%Description
285 !% Boolean expression that defines the interior of the simulation box. For example,
286 !% <tt>BoxShapeUsDef = "(sqrt(x^2+y^2) <= 4) && z>-2 && z<2"</tt> defines a cylinder
287 !% with axis parallel to the <i>z</i>-axis.
288 !%End
289
290 call parse_variable(namespace, 'BoxShapeUsDef', 'x^2+y^2+z^2 < 4', user_def)
291 end if
292
293 ! get filename for cgal boxes
294 if (box_shape == box_cgal) then
295#ifndef HAVE_CGAL
296 message(1) = "To use 'BoxShape = box_cgal', you have to compile Octopus"
297 message(2) = "with CGAL library support."
298 call messages_fatal(2, namespace=namespace)
299#endif
300 !%Variable BoxCgalFile
301 !%Type string
302 !%Section Mesh::Simulation Box
303 !%Description
304 !% Filename to be read in by the cgal library. It should describe a shape that
305 !% is used for the simulation box
306 !%End
307 if (.not. parse_is_defined(namespace, 'BoxCgalFile')) then
308 message(1) = "Must specify BoxCgalFile if BoxShape = box_cgal."
309 call messages_fatal(1, namespace=namespace)
310 end if
311 call parse_variable(namespace, 'BoxCgalFile', '', filename)
312 end if
313
314 call messages_obsolete_variable(namespace, 'BoxOffset')
315
316 !%Variable BoxCenter
317 !%Type float
318 !%Section Mesh::Simulation Box
319 !%Description
320 !% This block defines the coordinate center of the simulation box
321 !%End
322 if(parse_block(namespace, 'BoxCenter', blk) == 0) then
323 if(parse_block_cols(blk, 0) < space%dim) call messages_input_error(namespace, 'BoxCenter')
324 do idir = 1, space%dim
325 call parse_block_float(blk, 0, idir - 1, center(idir), units_inp%length)
326 end do
327 call parse_block_end(blk)
328 else
329 center = m_zero ! In case no BoxCenter is explicitly defined in the input file the default is the origin
330 end if
331
332 if (present(latt)) then
333 ! Use the lattice vectors
334 axes = latt%rlattice
335 else
336 ! Use Cartesian axes (instead, we could read this from the input file here)
337 axes = diagonal_matrix(space%dim, m_one)
338 end if
339
340 ! Now generate the box
341 select case (box_shape)
342 case (sphere)
343 box => box_sphere_t(space%dim, center, rsize, namespace)
344 case (cylinder)
345 box => box_cylinder_t(space%dim, center, axes, rsize, m_two * xsize, namespace, periodic_boundaries=space%is_periodic())
346 case (parallelepiped)
347 box => box_parallelepiped_t(space%dim, center, axes, m_two * lsize(1:space%dim), namespace, &
348 n_periodic_boundaries=space%periodic_dim)
349 case (box_usdef)
350 box => box_user_defined_t(space%dim, center, axes, user_def, m_two*lsize(1:space%dim), namespace)
351 case (box_cgal)
352 box => box_cgal_t(space%dim, center, filename, m_two*lsize(1:space%dim), namespace)
353 case (minimum)
354 box => box_minimum_t(space%dim, rsize, n_sites, site_position, namespace)
355 end select
356
357 pop_sub(box_factory_create)
358 end function box_factory_create
359
360end module box_factory_oct_m
Module, implementing a factory for boxes.
integer, parameter, public minimum
integer, parameter, public box_cgal
integer, parameter, public parallelepiped
integer, parameter, public cylinder
class(box_t) function, pointer, public box_factory_create(namespace, space, latt, n_sites, site_position)
initialize a box of any type
integer, parameter, public box_usdef
real(real64), parameter, public m_two
Definition: global.F90:202
real(real64), parameter, public m_zero
Definition: global.F90:200
real(real64), parameter, public m_epsilon
Definition: global.F90:216
real(real64), parameter, public m_one
Definition: global.F90:201
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1000
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
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:463
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
This module defines the unit system, used for input and output.
type(unit_system_t), public units_inp
the units systems for reading and writing
Class implementing a box defined by a file read using the cgal library.
Definition: box_cgal.F90:137
Class implementing a cylinder box. The cylinder axis is always along the first direction defined by t...
Class implementing a box that is a union of spheres. We do this in a specific class instead of using ...
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 defined by a mathematical expression. This box needs to be inside a parallel...