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
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_image = 5, &
59 box_cgal = 6, &
60 box_usdef = 77
61
62contains
63
69 function box_factory_create(namespace, space, latt, n_sites, site_position) result(box)
70 type(namespace_t), intent(in) :: namespace
71 class(space_t), intent(in) :: space
72 type(lattice_vectors_t), optional, intent(in) :: latt
73 integer, optional, intent(in) :: n_sites
74 real(real64), optional, intent(in) :: site_position(:,:)
76 class(box_t), pointer :: box
77
78 type(block_t) :: blk
79 integer :: default_boxshape, idir, box_shape
80 real(real64) :: center(space%dim), axes(space%dim, space%dim), rsize, xsize, lsize(space%dim)
81 character(len=1024) :: filename
82 character(len=1024) :: user_def
83 real(real64), parameter :: tol = 1.0e-13_real64
84
85 push_sub(box_factory_create)
86
87 ! We must have both n_sites and site_position or none.
88 assert(present(n_sites) .eqv. present(site_position))
89
90 !%Variable BoxShape
91 !%Type integer
92 !%Section Mesh::Simulation Box
93 !%Description
94 !% This variable decides the shape of the simulation box.
95 !% The default is <tt>minimum</tt> for finite systems and <tt>parallelepiped</tt> for periodic systems.
96 !% Note that some incompatibilities apply:
97 !% <ul><li>Spherical or minimum mesh is not allowed for periodic systems.
98 !% <li>Cylindrical mesh is not allowed for systems that are periodic in more than one dimension.
99 !% <li><tt>box_image</tt> is only allowed in 2D.</ul>
100 !%Option sphere 1
101 !% The simulation box will be a sphere of radius <tt>Radius</tt>. (In 2D, this is a circle.)
102 !%Option cylinder 2
103 !% The simulation box will be a cylinder with radius <tt>Radius</tt> and height (in the <i>x</i>-direction)
104 !% of 2 <tt>Xlength</tt>.
105 !%Option minimum 3
106 !% The simulation box will be constructed by adding spheres created around each
107 !% atom (or user-defined potential), of radius <tt>Radius</tt>.
108 !%Option parallelepiped 4
109 !% The simulation box will be a parallelepiped whose dimensions are taken from
110 !% the variable <tt>Lsize</tt>.
111 !%Option box_image 5
112 !% The simulation box will be defined through an image, specified with <tt>BoxShapeImage</tt>.
113 !% White (RGB = 255,255,255) means that the point
114 !% is contained in the simulation box, while any other color means that the point is out.
115 !% The image will be scaled to fit <tt>Lsize</tt>, while its resolution will define the default <tt>Spacing</tt>.
116 !% The actual box may be slightly larger than <tt>Lsize</tt> to ensure one grid point = one pixel for
117 !% default <tt>Spacing</tt>.
118 !%Option box_cgal 6
119 !% The simulation box will be defined by a file read using the CGAL library.
120 !% The file name needs to be specified with <tt>BoxCgalFile</tt>.
121 !% <tt>Lsize</tt> needs to be large enough to contain the shape defined in the file.
122 !%Option user_defined 77
123 !% The shape of the simulation box will be read from the variable <tt>BoxShapeUsDef</tt>.
124 !%End
125
126 if (space%is_periodic()) then
127 default_boxshape = parallelepiped
128 if(.not. present(latt)) then
129 message(1) = "Periodic system box is trying to be generated without lattice vectors given."
130 call messages_fatal(1, namespace=namespace)
131 endif
132 else
133 if (present(site_position)) then
134 default_boxshape = minimum
135 else
136 default_boxshape = parallelepiped
137 endif
138 end if
139 call parse_variable(namespace, 'BoxShape', default_boxshape, box_shape)
140 if (.not. varinfo_valid_option('BoxShape', box_shape)) call messages_input_error(namespace, 'BoxShape')
141 select case (box_shape)
142 case (sphere, minimum, box_usdef)
143 if (space%dim > 1 .and. space%is_periodic()) call messages_input_error(namespace, 'BoxShape')
144 case (cylinder)
145 if (space%dim == 2) then
146 message(1) = "BoxShape = cylinder is not meaningful in 2D. Use sphere if you want a circle."
147 call messages_fatal(1, namespace=namespace)
148 end if
149 if (space%periodic_dim > 1) call messages_input_error(namespace, 'BoxShape')
150 end select
151
152 ! ignore box_shape in 1D
153 if (space%dim == 1 .and. box_shape /= parallelepiped) then
154 box_shape = sphere
155 end if
156
157 ! Cannot use images in 1D or 3D
158 if (space%dim /= 2 .and. box_shape == box_image) call messages_input_error(namespace, 'BoxShape')
159
160 if (space%dim > 3 .and. box_shape /= parallelepiped) then
161 message(1) = "For more than 3 dimensions, you can only use the parallelepiped box."
162 call messages_fatal(1, namespace=namespace)
163 ! FIXME: why not a hypersphere as another option?
164 end if
165
166 !%Variable Radius
167 !%Type float
168 !%Section Mesh::Simulation Box
169 !%Description
170 !% Defines the radius for <tt>BoxShape</tt> = <tt>sphere</tt>,
171 !% <tt>cylinder</tt>, or <tt>minimum</tt>. Must be a positive
172 !% number.
173 !%End
174 if (box_shape == sphere .or. box_shape == cylinder .or. box_shape == minimum) then
175 if (.not. parse_is_defined(namespace, 'Radius')) then
176 message(1) = "BoxShape = sphere, cylinder and minimum require the Radius variable to be defined."
177 call messages_fatal(1,namespace=namespace)
178 else
179 call parse_variable(namespace, 'Radius', -m_one, rsize, units_inp%length)
180 end if
181 if (rsize < m_zero) call messages_input_error(namespace, 'Radius')
182 end if
183
184 if (box_shape == minimum .and. .not. present(site_position)) then
185 ! We should only be here if ions are present, something has gone wrong
186 message(1) = "BoxShape = minimum only makes sense when the calculation includes atomic sites."
187 call messages_fatal(1, namespace=namespace)
188 end if
189
190 if (box_shape == cylinder) then
191 !%Variable Xlength
192 !%Default <tt>Radius</tt>
193 !%Type float
194 !%Section Mesh::Simulation Box
195 !%Description
196 !% If <tt>BoxShape</tt> is <tt>cylinder</tt>, the total length of the cylinder is twice <tt>Xlength</tt>.
197 !% Note that when PeriodicDimensions = 1, then the length of the cylinder is determined from the lattice vectors.
198 !%End
199 if (space%is_periodic()) then
200 xsize = norm2(latt%rlattice(1:space%periodic_dim, 1))/m_two
201 else
202 call parse_variable(namespace, 'Xlength', rsize, xsize, units_inp%length)
203 end if
204 end if
205
206 lsize = m_zero
207 if (box_shape == parallelepiped .or. box_shape == box_image .or. &
208 box_shape == box_usdef .or. box_shape == box_cgal) then
209
210 !%Variable Lsize
211 !%Type block
212 !%Section Mesh::Simulation Box
213 !%Description
214 !% If <tt>BoxShape</tt> is <tt>parallelepiped</tt>, <tt>box_image</tt>,
215 !% or <tt>user_defined</tt>, this is a block of the form:
216 !%
217 !% <tt>%Lsize
218 !% <br>&nbsp;&nbsp;sizex | sizey | sizez | ...
219 !% <br>%</tt>
220 !%
221 !% where the <tt>size*</tt> are half the lengths of the box in each direction.
222 !%
223 !% The number of columns must match the dimensionality of the
224 !% calculation. If you want a cube you can also set <tt>Lsize</tt> as a
225 !% single variable.
226 !%End
227 if (present(latt)) then
228 ! lattice should only be passed if periodic
229 ! lsize along the periodic dimensions must always be set from the norm of the lattice vectors
230 do idir = 1, space%periodic_dim
231 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
232 end do
233 endif
234
235 if (space%is_periodic()) then
236 ! For mixed-periodicity, lsize along the non-periodic dimensions is
237 ! by default set from the lattice parameters (this can still be
238 ! overriden by setting Lsize, see bellow).
239 do idir = space%periodic_dim + 1, space%dim
240 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
241 end do
242 else
243 ! Lsize must be set for finite systems, as in that case we do not have the lattice parameters
244 if (.not. parse_is_defined(namespace, 'Lsize')) then
245 call messages_input_error(namespace, 'Lsize', 'Lsize is required for finite systems')
246 end if
247 end if
248
249 ! Note that for cases with mixed-periodicidy, the user still has the
250 ! option to set Lsize to override the size of the box along the
251 ! non-periodic dimensions given by the lattice parameters. This
252 ! requires the user to also set Lsize for the periodic dimensions,
253 ! which at the moment must match exactly the corresponding values
254 ! given by the lattice vectors.
255 if (parse_block(namespace, 'Lsize', blk) == 0) then
256 ! Lsize is specified as a block
257 if (parse_block_cols(blk, 0) < space%dim) then
258 call messages_input_error(namespace, 'Lsize')
259 end if
260
261 do idir = 1, space%dim
262 call parse_block_float(blk, 0, idir - 1, lsize(idir), units_inp%length)
263 end do
264 call parse_block_end(blk)
265
266 else if (parse_is_defined(namespace, 'Lsize')) then
267 ! Lsize is specified as a scalar
268 call parse_variable(namespace, 'Lsize', -m_one, lsize(1), units_inp%length)
269 if (abs(lsize(1) + m_one) <= m_epsilon) then
270 call messages_input_error(namespace, 'Lsize')
271 end if
272 do idir = 2, space%dim
273 lsize(idir) = lsize(1)
274 end do
275
276 end if
277
278 ! Check that lsize is consistent with the lattice vectors along the periodic dimensions
279 do idir = 1, space%periodic_dim
280 if (abs(m_two*lsize(idir) - norm2(latt%rlattice(1:space%dim, idir))) > tol) then
281 call messages_input_error(namespace, 'Lsize', &
282 'Lsize must be exactly half the length of the lattice vectors along periodic dimensions')
283 end if
284 end do
285 end if
286
287 ! read in image for box_image
288 if (box_shape == box_image) then
289
290 !%Variable BoxShapeImage
291 !%Type string
292 !%Section Mesh::Simulation Box
293 !%Description
294 !% Name of the file that contains the image that defines the simulation box
295 !% when <tt>BoxShape = box_image</tt>. No default. Will search in current
296 !% directory and <tt>OCTOPUS-HOME/share/</tt>.
297 !%End
298#if defined(HAVE_GDLIB)
299 call parse_variable(namespace, 'BoxShapeImage', '', filename)
300 if (trim(filename) == "") then
301 message(1) = "Must specify BoxShapeImage if BoxShape = box_image."
302 call messages_fatal(1, namespace=namespace)
303 end if
304#else
305 message(1) = "To use 'BoxShape = box_image', you have to compile Octopus"
306 message(2) = "with GD library support."
307 call messages_fatal(2, namespace=namespace)
308#endif
309 end if
310
311 ! read in box shape for user-defined boxes
312 if (box_shape == box_usdef) then
313
314 !%Variable BoxShapeUsDef
315 !%Type string
316 !%Section Mesh::Simulation Box
317 !%Description
318 !% Boolean expression that defines the interior of the simulation box. For example,
319 !% <tt>BoxShapeUsDef = "(sqrt(x^2+y^2) <= 4) && z>-2 && z<2"</tt> defines a cylinder
320 !% with axis parallel to the <i>z</i>-axis.
321 !%End
322
323 call parse_variable(namespace, 'BoxShapeUsDef', 'x^2+y^2+z^2 < 4', user_def)
324 end if
325
326 ! get filename for cgal boxes
327 if (box_shape == box_cgal) then
328#ifndef HAVE_CGAL
329 message(1) = "To use 'BoxShape = box_cgal', you have to compile Octopus"
330 message(2) = "with CGAL library support."
331 call messages_fatal(2, namespace=namespace)
332#endif
333 !%Variable BoxCgalFile
334 !%Type string
335 !%Section Mesh::Simulation Box
336 !%Description
337 !% Filename to be read in by the cgal library. It should describe a shape that
338 !% is used for the simulation box
339 !%End
340 if (.not. parse_is_defined(namespace, 'BoxCgalFile')) then
341 message(1) = "Must specify BoxCgalFile if BoxShape = box_cgal."
342 call messages_fatal(1, namespace=namespace)
343 end if
344 call parse_variable(namespace, 'BoxCgalFile', '', filename)
345 end if
346
347 call messages_obsolete_variable(namespace, 'BoxOffset')
348
349 !%Variable BoxCenter
350 !%Type float
351 !%Section Mesh::Simulation Box
352 !%Description
353 !% This block defines the coordinate center of the simulation box
354 !%End
355 if(parse_block(namespace, 'BoxCenter', blk) == 0) then
356 if(parse_block_cols(blk, 0) < space%dim) call messages_input_error(namespace, 'BoxCenter')
357 do idir = 1, space%dim
358 call parse_block_float(blk, 0, idir - 1, center(idir), units_inp%length)
359 end do
360 call parse_block_end(blk)
361 else
362 center = m_zero ! In case no BoxCenter is explicitly defined in the input file the default is the origin
363 end if
364
365 if (present(latt)) then
366 ! Use the lattice vectors
367 axes = latt%rlattice
368 else
369 ! Use Cartesian axes (instead, we could read this from the input file here)
370 axes = diagonal_matrix(space%dim, m_one)
371 end if
372
373 ! Now generate the box
374 select case (box_shape)
375 case (sphere)
376 box => box_sphere_t(space%dim, center, rsize, namespace)
377 case (cylinder)
378 box => box_cylinder_t(space%dim, center, axes, rsize, m_two * xsize, namespace, periodic_boundaries=space%is_periodic())
379 case (parallelepiped)
380 box => box_parallelepiped_t(space%dim, center, axes, m_two * lsize(1:space%dim), namespace, &
381 n_periodic_boundaries=space%periodic_dim)
382 case (box_usdef)
383 box => box_user_defined_t(space%dim, center, axes, user_def, m_two*lsize(1:space%dim), namespace)
384 case (box_cgal)
385 box => box_cgal_t(space%dim, center, filename, m_two*lsize(1:space%dim), namespace)
386 case (minimum)
387 box => box_minimum_t(space%dim, rsize, n_sites, site_position, namespace)
388 case (box_image)
389 box => box_image_t(center, axes, lsize, filename, space%periodic_dim, namespace)
390 end select
391
392 pop_sub(box_factory_create)
393 end function box_factory_create
394
395end 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 box_image
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:189
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_epsilon
Definition: global.F90:203
real(real64), parameter, public m_one
Definition: global.F90:188
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1057
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_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
logical function, public parse_is_defined(namespace, name)
Definition: parser.F90:502
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
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:135
Class implementing a cylinder box. The cylinder axis is always along the first direction defined by t...
Class implementing a box generated from a 2D image.
Definition: box_image.F90:133
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:132
Class implementing a box defined by a mathematical expression. This box needs to be inside a parallel...