Octopus
maxwell_function.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 R. Jestaedt, H. Appel, F. Bonafe, M. Oliveira, N. Tancogne-Dejean
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
26 use iso_c_binding
27 use debug_oct_m
28 use fft_oct_m
29 use global_oct_m
30 use io_oct_m
32 use math_oct_m
33 use mpi_oct_m
34 use parser_oct_m
37 use string_oct_m
38 use unit_oct_m
41
42 implicit none
43
44 public :: &
45 mxf_t, &
46 mxf_init, &
52 mxf, &
53 mxf_read, &
55
56 integer, public, parameter :: &
57 MXF_EMPTY = 10001, &
58 mxf_const_wave = 10002, &
59 mxf_const_phase = 10004, &
60 mxf_gaussian_wave = 10005, &
61 mxf_cosinoidal_wave = 10006, &
62 mxf_logistic_wave = 10007, &
63 mxf_trapezoidal_wave = 10008, &
64 mxf_from_file = 10009, &
65 mxf_numerical = 10010, &
66 mxf_from_expr = 10011, &
67 mxf_fourier_series = 10012, &
68 mxf_zero_fourier = 10013
69
70 type mxf_t
71 integer :: mode = mxf_empty
72 real(real64) :: k_vector(3) = m_zero
73 real(real64) :: r0(3) = m_zero
74 real(real64) :: width = m_zero
75 real(real64) :: a0 = m_zero
76 real(real64) :: dx = m_zero
77 real(real64) :: init_x = m_zero
78 real(real64) :: final_x = m_zero
79 real(real64) :: growth = m_zero
80 integer :: niter = 0
81 integer :: nfreqs = 0
82
83 type(spline_t) :: amplitude
84 character(len=200) :: expression
85 type(fft_t) :: fft_handler
86 end type mxf_t
87
88 interface mxf
89 module procedure mxf_eval
90 end interface mxf
91
92contains
93
94 !------------------------------------------------------------
96 subroutine mxf_read(f, namespace, function_name, ierr)
97 type(mxf_t), intent(inout) :: f
98 type(namespace_t), intent(in) :: namespace
99 character(len=*), intent(in) :: function_name
100 integer, intent(out) :: ierr
101
102 type(block_t) :: blk
103 integer :: nrows, ncols, i, function_type, idim
104 character(len=100) :: row_name, function_expression
105 real(real64) :: a0, r0(3), growth, width, k_vector(3)
106
107 push_sub(mxf_read)
108
109 !%Variable MaxwellFunctions
110 !%Type block
111 !%Section Maxwell
112 !%Description
113 !% This block specifies the shape of a "spatial-dependent function", such as the
114 !% envelope needed when using the <tt>MaxwellFunctions</tt> block. Each line in the block
115 !% specifies one function. The first element of each line will be a string
116 !% that defines the name of the function. The second element specifies which type
117 !% of function we are using; in the following we provide an example for each of the
118 !% possible types:
119 !%
120 !%Option mxf_const_wave 10002
121 !%
122 !% <tt>%MaxwellFunctions
123 !% <br>&nbsp;&nbsp; "function-name" | mxf_const_wave | kx | ky | kz | x0 | y0 | z0
124 !% <br>%</tt>
125 !%
126 !% The function is constant plane wave <math> f(x,y,z) = a0 * \cos( kx*(x-x0) + ky*(y-y0) + kz*(z-z0) ) </math>
127 !%
128 !%Option mxf_const_phase 10004
129 !%
130 !% <tt>%MaxwellFunctions
131 !% <br>&nbsp;&nbsp; "function-name" | mxf_const_phase | kx | ky | kz | x0 | y0 | z0
132 !% <br>%</tt>
133 !%
134 !% The function is a constant phase of <math> f(x,y,z) = a0 * (kx * x0 + ky * y0 + kz * z0) </math>
135 !%
136 !%Option mxf_gaussian_wave 10005
137 !%
138 !% <tt>%MaxwellFunctions
139 !% <br>&nbsp;&nbsp; "function-name" | mxf_gaussian_wave | kx | ky | kz | x0 | y0 | z0 | width
140 !% <br>%</tt>
141 !%
142 !% The function is a Gaussian, <math> f(x,y,z) = a0 * \exp( -( kx*(x-x0) + ky*(y-y0) + kz*(z-z0) )^2 / (2 width^2) ) </math>
143 !%
144 !%Option mxf_cosinoidal_wave 10006
145 !%
146 !% <tt>%MaxwellFunctions
147 !% <br>&nbsp;&nbsp; "function-name" | mxf_cosinoidal_wave | kx | ky | kz | x0 | y0 | z0 | width
148 !% <br>%</tt>
149 !%
150 !% <math> f(x,y,z) = \cos( \frac{\pi}{2} \frac{kx*(x-x0)+ky*(y-y0)+kz*(z-z0)-2 width}{width} + \pi ) </math>
151 !%
152 !% If <math> | kx*x + ky*y + kz*z - x0 | > \xi\_0 </math>, then <math> f(x,y,z) = 0 </math>.
153 !%
154 !%Option mxf_logistic_wave 10007
155 !%
156 !% <tt>%MaxwellFunctions
157 !% <br>&nbsp;&nbsp; "function-name" | mxf_logistic_wave | kx | ky | kz | x0 | y0 | z0 | growth | width
158 !% <br>%</tt>
159 !%
160 !% The function is a logistic function, <math> f(x,y,z) = a0 * 1/(1+\exp(growth*(kx*(x-x0)+ky*(y-y0)+kz*(kz*(z-z0))+width/2))) * 1/(1+\exp(-growth*(kx*(x-x0)+ky*(y-y0)+kz*(kz*(z-z0))-width/2))) </math>
161 !%
162 !%Option mxf_trapezoidal_wave 10008
163 !%
164 !% <tt>%MaxwellFunctions
165 !% <br>&nbsp;&nbsp; "function-name" | mxf_trapezoidal_wave | kx | ky | kz | x0 | y0 | z0 | growth | width
166 !% <br>%</tt>
167 !%
168 !% The function is a logistic function,
169 !% <br> <math> f(x,y,z) = a0 * ( ( 1-growth*(k*(r-r0)-width/2)*\Theta(k*(r-r0)-width/2))*\Theta(-(k*(r-r0)+width/2+1/growth)) </math>
170 !% <br> <math> \qquad \qquad \qquad + (-1+growth*(k*(r-r0)+width/2)*\Theta(k*(r-r0)+width/2))*\Theta(-(k*(r-r0)-width/2+1/growth)) ) </math>
171 !%
172 !%Option mxf_from_expr 10011
173 !%
174 !% <tt>%MaxwellFunctions
175 !% <br>&nbsp;&nbsp; "function-name" | mxf_from_expr | kx | ky | kz | "expression"
176 !% <br>%</tt>
177 !%
178 !% The temporal shape of the field is given as an expression (e.g., <tt>cos(2.0*x-3*y+4*z)</tt>. The
179 !% letter <i>x</i>, <i>y</i>, <i>z</i> means spatial coordinates, obviously.
180 !% The expression is used to construct the function <i>f</i>
181 !% that defines the field.
182 !%End
183 ierr = -3
184 if (parse_block(namespace, 'MaxwellFunctions', blk) /= 0) then
185 ierr = -1
186 pop_sub(mxf_read)
187 return
188 end if
190 nrows = parse_block_n(blk)
191 row_loop: do i = 1, nrows
192 call parse_block_string(blk, i-1, 0, row_name)
193 if (trim(row_name) == trim(function_name)) then
194
195 ncols = parse_block_cols(blk, i-1)
196 call parse_block_integer(blk, i-1, 1, function_type)
197
198 a0 = m_one
199 r0 = m_zero
200 width = m_zero
201 k_vector = m_zero
202 select case (function_type)
203 case (mxf_const_wave)
204 do idim = 1, 3
205 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
206 end do
207 do idim = 1, 3
208 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
209 end do
210 call mxf_init_const_wave(f, a0, k_vector, r0)
211 case (mxf_const_phase)
212 do idim = 1, 3
213 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
214 end do
215 do idim = 1, 3
216 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
217 end do
218 call mxf_init_const_phase(f, a0, k_vector, r0)
219 case (mxf_gaussian_wave)
220 do idim = 1, 3
221 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
222 end do
223 do idim = 1, 3
224 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
225 end do
226 call parse_block_float(blk, i-1, 8, width, units_inp%length)
227 call mxf_init_gaussian_wave(f, a0, k_vector, r0, width)
229 do idim = 1, 3
230 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
231 end do
232 do idim = 1, 3
233 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
234 end do
235 call parse_block_float(blk, i-1, 8, width, units_inp%length)
236 call mxf_init_cosinoidal_wave(f, a0, k_vector, r0, width)
237 case (mxf_logistic_wave)
238 do idim = 1, 3
239 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
240 end do
241 do idim = 1, 3
242 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
243 end do
244 call parse_block_float(blk, i-1, 8, growth, units_inp%length)
245 call parse_block_float(blk, i-1, 9, width, units_inp%length)
246 call mxf_init_logistic_wave(f, a0, k_vector, r0, growth, width)
248 do idim = 1, 3
249 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
250 end do
251 do idim = 1, 3
252 call parse_block_float(blk, i-1, 4+idim, r0(idim), units_inp%length)
253 end do
254 call parse_block_float(blk, i-1, 8, growth, units_inp%length)
255 call parse_block_float(blk, i-1, 9, width, units_inp%length)
256 call mxf_init_trapezoidal_wave(f, a0, k_vector, r0, growth, width)
257 case (mxf_from_expr)
258 do idim = 1, 3
259 call parse_block_float(blk, i-1, 1+idim, k_vector(idim), unit_one/units_inp%length)
260 end do
261 call parse_block_string(blk, i-1, 5, function_expression)
262 call conv_to_c_string(function_expression)
263 call mxf_init_fromexpr(f, k_vector, trim(function_expression))
264 case default
265 ierr = -2
266 call parse_block_end(blk)
267 pop_sub(mxf_read)
268 return
269 end select
270
271 ierr = 0
272 exit row_loop
273 end if
274 end do row_loop
275
276 call parse_block_end(blk)
277
278 pop_sub(mxf_read)
279 end subroutine mxf_read
280 !------------------------------------------------------------
281
282
283 !------------------------------------------------------------
284 subroutine mxf_init(f)
285 type(mxf_t), intent(inout) :: f
286
287 push_sub(mxf_init)
288
289 f%mode = mxf_empty
290 f%niter = 0
291 f%dx = m_zero
292
293 pop_sub(mxf_init)
294 end subroutine mxf_init
295 !------------------------------------------------------------
296
297
298 !------------------------------------------------------------
299 logical function mxf_is_empty(f)
300 type(mxf_t), intent(in) :: f
301
302 push_sub(mxf_is_empty)
303 mxf_is_empty = (f%mode == mxf_empty)
304
305 pop_sub(mxf_is_empty)
306 end function mxf_is_empty
307 !------------------------------------------------------------
308
309
310 !------------------------------------------------------------
311 subroutine mxf_init_const_wave(f, a0, k_vector, r0)
312 type(mxf_t), intent(inout) :: f
313 real(real64), intent(in) :: a0, k_vector(3), r0(3)
314
315 push_sub(mxf_init_const_wave)
316
317 f%mode = mxf_const_wave
318 f%a0 = a0
319 f%k_vector = k_vector
320 f%r0 = r0
321
322 pop_sub(mxf_init_const_wave)
323 end subroutine mxf_init_const_wave
324 !------------------------------------------------------------
325
326
327 !------------------------------------------------------------
328 subroutine mxf_init_const_phase(f, a0, k_vector, r0)
329 type(mxf_t), intent(inout) :: f
330 real(real64), intent(in) :: a0, k_vector(3), r0(3)
331
332 push_sub(mxf_init_const_phase)
333
334 f%mode = mxf_const_phase
335 f%a0 = a0
336 f%k_vector = k_vector
337 f%r0 = r0
338
339 pop_sub(mxf_init_const_phase)
340 end subroutine mxf_init_const_phase
341 !------------------------------------------------------------
342
343
344 !------------------------------------------------------------
345 subroutine mxf_init_gaussian_wave(f, a0, k_vector, r0, width)
346 type(mxf_t), intent(inout) :: f
347 real(real64), intent(in) :: a0, k_vector(3), r0(3), width
348
349 push_sub(mxf_init_gaussian_wave)
350
351 f%mode = mxf_gaussian_wave
352 f%a0 = a0
353 f%k_vector = k_vector
354 f%r0 = r0
355 f%width = width
356
358 end subroutine mxf_init_gaussian_wave
359 !------------------------------------------------------------
360
361
362 !------------------------------------------------------------
363 subroutine mxf_init_cosinoidal_wave(f, a0, k_vector, r0, width)
364 type(mxf_t), intent(inout) :: f
365 real(real64), intent(in) :: a0, k_vector(3), r0(3), width
366
368
369 f%mode = mxf_cosinoidal_wave
370 f%a0 = a0
371 f%k_vector = k_vector
372 f%r0 = r0
373 f%width = width
374
376 end subroutine mxf_init_cosinoidal_wave
377 !------------------------------------------------------------
378
379
380 !------------------------------------------------------------
381 subroutine mxf_init_logistic_wave(f, a0, k_vector, r0, growth, width)
382 type(mxf_t), intent(inout) :: f
383 real(real64), intent(in) :: a0, k_vector(3), r0(3), growth, width
384
385 push_sub(mxf_init_logistic_wave)
386
387 f%mode = mxf_logistic_wave
388 f%a0 = a0
389 f%k_vector = k_vector
390 f%r0 = r0
391 f%growth = growth
392 f%width = width
393
395 end subroutine
396 !------------------------------------------------------------
397
398
399 !------------------------------------------------------------
400 subroutine mxf_init_trapezoidal_wave(f, a0, k_vector, r0, growth, width)
401 type(mxf_t), intent(inout) :: f
402 real(real64), intent(in) :: a0, k_vector(3), r0(3), growth, width
403
405
406 f%mode = mxf_trapezoidal_wave
407 f%a0 = a0
408 f%k_vector = k_vector
409 f%r0 = r0
410 f%growth = growth
411 f%width = width
412
414 end subroutine
415 !------------------------------------------------------------
416
417
418 !------------------------------------------------------------
419 subroutine mxf_init_fromexpr(f, k_vector, expression)
420 type(mxf_t), intent(inout) :: f
421 real(real64), intent(in) :: k_vector(3)
422 character(len=*), intent(in) :: expression
423
424 push_sub(mxf_init_fromexpr)
425
426 f%mode = mxf_from_expr
427 f%k_vector = k_vector
428 f%expression = trim(expression)
429
430 pop_sub(mxf_init_fromexpr)
431 end subroutine mxf_init_fromexpr
432 !------------------------------------------------------------
433
438 !------------------------------------------------------------
439 complex(real64) function mxf_envelope_eval(f, x) result(env)
440 type(mxf_t), intent(in) :: f
441 real(real64), intent(in) :: x(:)
442 real(real64) :: xx, limit_1, limit_2, limit_3, limit_4, r_re, r_im, rr
443 complex(real64) :: r
444 integer :: xdim
445
446 xdim = size(x)
447
448 select case (f%mode)
449 case (mxf_const_wave)
450
451 env = f%a0
452
453 case (mxf_const_phase)
454
455 env = f%a0 * sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim)))
457 case (mxf_gaussian_wave)
458
459 r = exp(-((sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) &
460 / norm2(f%k_vector(1:xdim)) )**2 / (m_two*f%width**2)))
461 env = f%a0 * r
462
464
465 r = m_zero
466 if (abs( sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))/norm2(f%k_vector(1:xdim)))) <= f%width) then
467 r = - cos((m_pi/m_two) * ((sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) &
468 / norm2(f%k_vector(1:xdim)) - m_two*f%width) / f%width))
469 end if
470 env = f%a0 * r
471
472 case (mxf_logistic_wave)
473
474 r = m_one/(m_one + exp(f%growth*(sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) &
475 / norm2(f%k_vector(1:xdim)) - f%width/m_two))) &
476 + m_one/(m_one + exp(-f%growth*(sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) &
477 / norm2(f%k_vector(1:xdim)) + f%width/m_two))) - m_one
478 env = f%a0 * r
479
481
482 xx = sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) / norm2(f%k_vector(1:xdim))
483 limit_1 = - f%width/m_two - m_one/f%growth
484 limit_2 = - f%width/m_two
485 limit_3 = f%width/m_two
486 limit_4 = f%width/m_two + m_one/f%growth
487 if ((xx > limit_1) .and. (xx <= limit_2)) then
488 r = m_one + f%growth * (sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim)))/norm2(f%k_vector(1:xdim)) + f%width/m_two)
489 else if ((xx > limit_2) .and. (xx <= limit_3)) then
490 r = m_one
491 else if ((xx > limit_3) .and. (xx <= limit_4)) then
492 r = m_one - f%growth * (sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim)))/norm2(f%k_vector(1:xdim)) - f%width/m_two)
493 else
494 r = m_zero
495 end if
496 env = f%a0 * r
497
498 case (mxf_from_expr)
499 ! here x(:) is actually x(:) - v(:)*t
500 rr = norm2(x)
501 call parse_expression(r_re, r_im, 3, x(:), rr, m_zero, trim(f%expression))
502 env = r_re + m_zi*r_im
503
504 case default
505
506 env = m_zero
507
508 end select
509
510 end function mxf_envelope_eval
511 !------------------------------------------------------------
519 !------------------------------------------------------------
520 complex(real64) function mxf_eval(f, x, phi) result(y)
521 type(mxf_t), intent(in) :: f
522 real(real64), intent(in) :: x(:)
523 real(real64), optional, intent(in) :: phi
524
525 real(real64) :: phi_
526 integer :: xdim
527
528 ! no push_sub because it is called too frequently
529
530 phi_ = optional_default(phi, m_zero)
531
532 xdim = size(x)
533
534 y = mxf_envelope_eval(f, x)
535 if (f%mode /= mxf_const_phase) then
536 y = y * exp(m_zi * (sum(f%k_vector(1:xdim)*(x(:) - f%r0(1:xdim))) + phi_))
537 endif
538
539 end function mxf_eval
540 !------------------------------------------------------------
541
542end module maxwell_function_oct_m
543
544!! Local Variables:
545!! mode: f90
546!! coding: utf-8
547!! End:
double exp(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
Fast Fourier Transform module. This module provides a single interface that works with different FFT ...
Definition: fft.F90:118
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_pi
some mathematical constants
Definition: global.F90:185
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public m_one
Definition: global.F90:188
Definition: io.F90:114
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
integer, parameter, public mxf_fourier_series
integer, parameter, public mxf_logistic_wave
complex(real64) function mxf_envelope_eval(f, x)
Evaluation of envelope itself.
complex(real64) function mxf_eval(f, x, phi)
Evaluation of spatial envelope Functions.
integer, parameter, public mxf_trapezoidal_wave
subroutine, public mxf_read(f, namespace, function_name, ierr)
This function initializes "f" from the MXFunctions block.
integer, parameter, public mxf_from_file
integer, parameter, public mxf_cosinoidal_wave
integer, parameter, public mxf_zero_fourier
subroutine, public mxf_init_const_wave(f, a0, k_vector, r0)
subroutine, public mxf_init(f)
integer, parameter, public mxf_numerical
subroutine mxf_init_trapezoidal_wave(f, a0, k_vector, r0, growth, width)
subroutine, public mxf_init_const_phase(f, a0, k_vector, r0)
integer, parameter, public mxf_gaussian_wave
integer, parameter, public mxf_const_wave
subroutine, public mxf_init_gaussian_wave(f, a0, k_vector, r0, width)
logical function, public mxf_is_empty(f)
subroutine, public mxf_init_fromexpr(f, k_vector, expression)
integer, parameter, public mxf_const_phase
subroutine, public mxf_init_cosinoidal_wave(f, a0, k_vector, r0, width)
integer, parameter, public mxf_from_expr
subroutine mxf_init_logistic_wave(f, a0, k_vector, r0, growth, width)
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public conv_to_c_string(str)
converts to c string
Definition: string.F90:252
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
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
type(unit_t), public unit_one
some special units required for particular quantities