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 if (space%is_periodic()) then
155 ! Periodic systems should not use spherical boxes.
156 box_shape = parallelepiped
157 else
158 box_shape = sphere
159 end if
160 end if
161
162 ! Cannot use images in 1D or 3D
163 if (space%dim /= 2 .and. box_shape == box_image) call messages_input_error(namespace, 'BoxShape')
164
165 if (space%dim > 3 .and. box_shape /= parallelepiped) then
166 message(1) = "For more than 3 dimensions, you can only use the parallelepiped box."
167 call messages_fatal(1, namespace=namespace)
168 ! FIXME: why not a hypersphere as another option?
169 end if
170
171 !%Variable Radius
172 !%Type float
173 !%Section Mesh::Simulation Box
174 !%Description
175 !% Defines the radius for <tt>BoxShape</tt> = <tt>sphere</tt>,
176 !% <tt>cylinder</tt>, or <tt>minimum</tt>. Must be a positive
177 !% number.
178 !%End
179 if (box_shape == sphere .or. box_shape == cylinder .or. box_shape == minimum) then
180 if (.not. parse_is_defined(namespace, 'Radius')) then
181 message(1) = "BoxShape = sphere, cylinder and minimum require the Radius variable to be defined."
182 call messages_fatal(1,namespace=namespace)
183 else
184 call parse_variable(namespace, 'Radius', -m_one, rsize, units_inp%length)
185 end if
186 if (rsize < m_zero) call messages_input_error(namespace, 'Radius')
187 end if
188
189 if (box_shape == minimum .and. .not. present(site_position)) then
190 ! We should only be here if ions are present, something has gone wrong
191 message(1) = "BoxShape = minimum only makes sense when the calculation includes atomic sites."
192 call messages_fatal(1, namespace=namespace)
193 end if
194
195 if (box_shape == cylinder) then
196 !%Variable Xlength
197 !%Default <tt>Radius</tt>
198 !%Type float
199 !%Section Mesh::Simulation Box
200 !%Description
201 !% If <tt>BoxShape</tt> is <tt>cylinder</tt>, the total length of the cylinder is twice <tt>Xlength</tt>.
202 !% Note that when PeriodicDimensions = 1, then the length of the cylinder is determined from the lattice vectors.
203 !%End
204 if (space%is_periodic()) then
205 xsize = norm2(latt%rlattice(1:space%periodic_dim, 1))/m_two
206 else
207 call parse_variable(namespace, 'Xlength', rsize, xsize, units_inp%length)
208 end if
209 end if
210
211 lsize = m_zero
212 if (box_shape == parallelepiped .or. box_shape == box_image .or. &
213 box_shape == box_usdef .or. box_shape == box_cgal) then
214
215 !%Variable Lsize
216 !%Type block
217 !%Section Mesh::Simulation Box
218 !%Description
219 !% If <tt>BoxShape</tt> is <tt>parallelepiped</tt>, <tt>box_image</tt>,
220 !% or <tt>user_defined</tt>, this is a block of the form:
221 !%
222 !% <tt>%Lsize
223 !% <br>&nbsp;&nbsp;sizex | sizey | sizez | ...
224 !% <br>%</tt>
225 !%
226 !% where the <tt>size*</tt> are half the lengths of the box in each direction.
227 !%
228 !% The number of columns must match the dimensionality of the
229 !% calculation. If you want a cube you can also set <tt>Lsize</tt> as a
230 !% single variable.
231 !%End
232 if (present(latt)) then
233 ! lattice should only be passed if periodic
234 ! lsize along the periodic dimensions must always be set from the norm of the lattice vectors
235 do idir = 1, space%periodic_dim
236 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
237 end do
238 endif
239
240 if (space%is_periodic()) then
241 ! For mixed-periodicity, lsize along the non-periodic dimensions is
242 ! by default set from the lattice parameters (this can still be
243 ! overriden by setting Lsize, see bellow).
244 do idir = space%periodic_dim + 1, space%dim
245 lsize(idir) = norm2(latt%rlattice(1:space%dim, idir))/m_two
246 end do
247 else
248 ! Lsize must be set for finite systems, as in that case we do not have the lattice parameters
249 if (.not. parse_is_defined(namespace, 'Lsize')) then
250 call messages_input_error(namespace, 'Lsize', 'Lsize is required for finite systems')
251 end if
252 end if
253
254 ! Note that for cases with mixed-periodicidy, the user still has the
255 ! option to set Lsize to override the size of the box along the
256 ! non-periodic dimensions given by the lattice parameters. This
257 ! requires the user to also set Lsize for the periodic dimensions,
258 ! which at the moment must match exactly the corresponding values
259 ! given by the lattice vectors.
260 if (parse_block(namespace, 'Lsize', blk) == 0) then
261 ! Lsize is specified as a block
262 if (parse_block_cols(blk, 0) < space%dim) then
263 call messages_input_error(namespace, 'Lsize')
264 end if
265
266 do idir = 1, space%dim
267 call parse_block_float(blk, 0, idir - 1, lsize(idir), units_inp%length)
268 end do
269 call parse_block_end(blk)
270
271 else if (parse_is_defined(namespace, 'Lsize')) then
272 ! Lsize is specified as a scalar
273 call parse_variable(namespace, 'Lsize', -m_one, lsize(1), units_inp%length)
274 if (abs(lsize(1) + m_one) <= m_epsilon) then
275 call messages_input_error(namespace, 'Lsize')
276 end if
277 do idir = 2, space%dim
278 lsize(idir) = lsize(1)
279 end do
280
281 end if
282
283 ! Check that lsize is consistent with the lattice vectors along the periodic dimensions
284 do idir = 1, space%periodic_dim
285 if (abs(m_two*lsize(idir) - norm2(latt%rlattice(1:space%dim, idir))) > tol) then
286 call messages_input_error(namespace, 'Lsize', &
287 'Lsize must be exactly half the length of the lattice vectors along periodic dimensions')
288 end if
289 end do
290 end if
291
292 ! read in image for box_image
293 if (box_shape == box_image) then
294
295 !%Variable BoxShapeImage
296 !%Type string
297 !%Section Mesh::Simulation Box
298 !%Description
299 !% Name of the file that contains the image that defines the simulation box
300 !% when <tt>BoxShape = box_image</tt>. No default. Will search in current
301 !% directory and <tt>OCTOPUS-HOME/share/</tt>.
302 !%End
303#if defined(HAVE_GDLIB)
304 call parse_variable(namespace, 'BoxShapeImage', '', filename)
305 if (trim(filename) == "") then
306 message(1) = "Must specify BoxShapeImage if BoxShape = box_image."
307 call messages_fatal(1, namespace=namespace)
308 end if
309#else
310 message(1) = "To use 'BoxShape = box_image', you have to compile Octopus"
311 message(2) = "with GD library support."
312 call messages_fatal(2, namespace=namespace)
313#endif
314 end if
315
316 ! read in box shape for user-defined boxes
317 if (box_shape == box_usdef) then
318
319 !%Variable BoxShapeUsDef
320 !%Type string
321 !%Section Mesh::Simulation Box
322 !%Description
323 !% Boolean expression that defines the interior of the simulation box. For example,
324 !% <tt>BoxShapeUsDef = "(sqrt(x^2+y^2) <= 4) && z>-2 && z<2"</tt> defines a cylinder
325 !% with axis parallel to the <i>z</i>-axis.
326 !%End
327
328 call parse_variable(namespace, 'BoxShapeUsDef', 'x^2+y^2+z^2 < 4', user_def)
329 end if
330
331 ! get filename for cgal boxes
332 if (box_shape == box_cgal) then
333#ifndef HAVE_CGAL
334 message(1) = "To use 'BoxShape = box_cgal', you have to compile Octopus"
335 message(2) = "with CGAL library support."
336 call messages_fatal(2, namespace=namespace)
337#endif
338 !%Variable BoxCgalFile
339 !%Type string
340 !%Section Mesh::Simulation Box
341 !%Description
342 !% Filename to be read in by the cgal library. It should describe a shape that
343 !% is used for the simulation box
344 !%End
345 if (.not. parse_is_defined(namespace, 'BoxCgalFile')) then
346 message(1) = "Must specify BoxCgalFile if BoxShape = box_cgal."
347 call messages_fatal(1, namespace=namespace)
348 end if
349 call parse_variable(namespace, 'BoxCgalFile', '', filename)
350 end if
351
352 call messages_obsolete_variable(namespace, 'BoxOffset')
353
354 !%Variable BoxCenter
355 !%Type float
356 !%Section Mesh::Simulation Box
357 !%Description
358 !% This block defines the coordinate center of the simulation box
359 !%End
360 if(parse_block(namespace, 'BoxCenter', blk) == 0) then
361 if(parse_block_cols(blk, 0) < space%dim) call messages_input_error(namespace, 'BoxCenter')
362 do idir = 1, space%dim
363 call parse_block_float(blk, 0, idir - 1, center(idir), units_inp%length)
364 end do
365 call parse_block_end(blk)
366 else
367 center = m_zero ! In case no BoxCenter is explicitly defined in the input file the default is the origin
368 end if
369
370 if (present(latt)) then
371 ! Use the lattice vectors
372 axes = latt%rlattice
373 else
374 ! Use Cartesian axes (instead, we could read this from the input file here)
375 axes = diagonal_matrix(space%dim, m_one)
376 end if
377
378 ! Now generate the box
379 select case (box_shape)
380 case (sphere)
381 box => box_sphere_t(space%dim, center, rsize, namespace)
382 case (cylinder)
383 box => box_cylinder_t(space%dim, center, axes, rsize, m_two * xsize, namespace, periodic_boundaries=space%is_periodic())
384 case (parallelepiped)
385 box => box_parallelepiped_t(space%dim, center, axes, m_two * lsize(1:space%dim), namespace, &
386 n_periodic_boundaries=space%periodic_dim)
387 case (box_usdef)
388 box => box_user_defined_t(space%dim, center, axes, user_def, m_two*lsize(1:space%dim), namespace)
389 case (box_cgal)
390 box => box_cgal_t(space%dim, center, filename, m_two*lsize(1:space%dim), namespace)
391 case (minimum)
392 box => box_minimum_t(space%dim, rsize, n_sites, site_position, namespace)
393 case (box_image)
394 box => box_image_t(center, axes, lsize, filename, space%periodic_dim, namespace)
395 end select
396
397 pop_sub(box_factory_create)
398 end function box_factory_create
399
400end 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:190
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_epsilon
Definition: global.F90:204
real(real64), parameter, public m_one
Definition: global.F90:189
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:1046
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:161
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:415
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:714
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...