Octopus
tdfunction.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
27 use iso_c_binding
28 use debug_oct_m
29 use fft_oct_m
30 use global_oct_m
31 use io_oct_m
33 use math_oct_m
35 use mpi_oct_m
37 use parser_oct_m
40 use unit_oct_m
42
43 implicit none
44
45 private
46 public :: &
47 tdf_t, &
48 tdf_init, &
59 tdf, &
61 tdf_diff, &
69 tdf_write, &
70 tdf_niter, &
71 tdf_nfreqs, &
72 tdf_dt, &
73 tdf_copy, &
74 tdf_read, &
77
78
79 integer, public, parameter :: &
80 TDF_EMPTY = 10001, &
81 tdf_cw = 10002, &
82 tdf_gaussian = 10003, &
83 tdf_cosinoidal = 10004, &
84 tdf_trapezoidal = 10005, &
85 tdf_from_file = 10006, &
86 tdf_numerical = 10007, &
87 tdf_from_expr = 10008, &
88 tdf_fourier_series= 10010, &
89 tdf_zero_fourier = 10011
90
91 type tdf_t
92 private
93 integer :: mode = tdf_empty
94 real(real64) :: t0 = m_zero
95 real(real64) :: tau0 = m_zero
96 real(real64) :: tau1 = m_zero
97 real(real64) :: a0 = m_zero
98 real(real64) :: omega0 = m_zero
99 real(real64) :: dt = m_zero
100 real(real64) :: init_time = m_zero
101 real(real64) :: final_time = m_zero
102 integer :: niter = 0
103 integer :: nfreqs = 0
104
105 type(spline_t) :: amplitude
106 character(len=1024) :: expression
107 real(real64), allocatable :: val(:)
108 real(real64), allocatable :: valww(:)
109 type(fft_t) :: fft_handler
110 end type tdf_t
111
112 interface tdf_set_numerical
114 end interface tdf_set_numerical
115
116 interface tdf
117 module procedure tdfi, tdft
118 end interface tdf
120contains
121
122 !------------------------------------------------------------
124 subroutine tdf_read(f, namespace, function_name, ierr)
125 type(tdf_t), intent(inout) :: f
126 type(namespace_t), intent(in) :: namespace
127 character(len=*), intent(in) :: function_name
128 integer, intent(out) :: ierr
129
130 type(block_t) :: blk
131 integer :: nrows, i, function_type
132 character(len=1024) :: row_name, filename, function_expression
133 real(real64) :: a0, tau0, t0, tau1
134
135 push_sub(tdf_read)
136
137 !%Variable TDFunctions
138 !%Type block
139 !%Section Time-Dependent
140 !%Description
141 !% This block specifies the shape of a "time-dependent function", such as the
142 !% envelope needed when using the <tt>TDExternalFields</tt> block. Each line in the block
143 !% specifies one function. The first element of each line will be a string
144 !% that defines the name of the function. The second element specifies which type
145 !% of function we are using; in the following we provide an example for each of the
146 !% possible types:
147 !%
148 !%Option tdf_cw 10002
149 !%
150 !% <tt>%TDFunctions
151 !% <br>&nbsp;&nbsp; "function-name" | tdf_cw | amplitude
152 !% <br>%</tt>
153 !%
154 !% The function is just a constant of value <tt>amplitude</tt>: <math> f(t) </math> = amplitude
155 !%
156 !%Option tdf_gaussian 10003
157 !%
158 !% <tt>%TDFunctions
159 !% <br>&nbsp;&nbsp; "function-name" | tdf_gaussian | amplitude | tau0 | t0
160 !% <br>%</tt>
161 !%
162 !% The function is a Gaussian, <math> f(t) = F_0 \exp( - (t-t_0)^2/(2\tau_0^2) ) </math>,
163 !% where <math>F_0</math> = amplitude.
164 !%
165 !%Option tdf_cosinoidal 10004
166 !%
167 !% <tt>%TDFunctions
168 !% <br>&nbsp;&nbsp; "function-name" | tdf_cosinoidal | amplitude | tau0 | t0
169 !% <br>%</tt>
170 !%
171 !% <math> f(t) = F_0 \cos( \frac{\pi}{2} \frac{t-2\tau_0-t_0}{\tau0} ) </math>
172 !%
173 !% If <math> | t - t_0 | > \tau_0 </math>, then <math> f(t) = 0 </math>.
174 !%
175 !%Option tdf_trapezoidal 10005
176 !%
177 !% <tt>%TDFunctions
178 !% <br>&nbsp;&nbsp; "function-name" | tdf_trapezoidal | amplitude | tau0 | t0 | tau1
179 !% <br>%</tt>
180 !%
181 !% This function is a trapezoidal centered around <tt>t0</tt>. The
182 !% shape is determined by <tt>tau0</tt> and <tt>tau1</tt>. The
183 !% function ramps linearly for <tt>tau1</tt> time units, stays
184 !% constant for <tt>tau0</tt> time units, and then decays to zero
185 !% linearly again for <tt>tau1</tt> time units.
186 !%
187 !%Option tdf_from_file 10006
188 !%
189 !% <tt>%TDFunctions
190 !% <br>&nbsp;&nbsp; "function-name" | tdf_from_file | "filename"
191 !% <br>%</tt>
192 !%
193 !% The temporal shape of the function is contained in a file called <tt>filename</tt>. This file
194 !% should contain three columns: first column is time, second and third column are the
195 !% real part and the imaginary part of the temporal function <i>f</i>(<i>t</i>).
196 !%
197 !%Option tdf_from_expr 10008
198 !%
199 !% <tt>%TDFunctions
200 !% <br>&nbsp;&nbsp; "function-name" | tdf_from_expr | "expression"
201 !% <br>%</tt>
202 !%
203 !% The temporal shape of the field is given as an expression (e.g., <tt>cos(2.0*t)</tt>. The
204 !% letter <i>t</i> means time, obviously. The expression is used to construct the function <i>f</i>
205 !% that defines the field.
206 !%End
207 ierr = -3
208 if (parse_block(namespace, 'TDFunctions', blk) /= 0) then
209 ierr = -1
210 pop_sub(tdf_read)
211 return
212 end if
213
214 nrows = parse_block_n(blk)
215 row_loop: do i = 1, nrows
216 call parse_block_string(blk, i-1, 0, row_name)
217 if (trim(row_name) == trim(function_name)) then
218
219 call parse_block_integer(blk, i-1, 1, function_type)
220
221 a0 = m_zero
222 tau0 = m_zero
223 t0 = m_zero
224 tau1 = m_zero
225 select case (function_type)
226 case (tdf_cw)
227 call parse_block_float(blk, i-1, 2, a0, units_inp%energy/units_inp%length)
228 call tdf_init_cw(f, a0, m_zero)
229 case (tdf_gaussian)
230 call parse_block_float(blk, i-1, 2, a0, units_inp%energy/units_inp%length)
231 call parse_block_float(blk, i-1, 3, tau0, units_inp%time)
232 call parse_block_float(blk, i-1, 4, t0, units_inp%time)
233 call tdf_init_gaussian(f, a0, m_zero, t0, tau0)
234 case (tdf_cosinoidal)
235 call parse_block_float(blk, i-1, 2, a0, units_inp%energy/units_inp%length)
236 call parse_block_float(blk, i-1, 3, tau0, units_inp%time)
237 call parse_block_float(blk, i-1, 4, t0, units_inp%time)
238 call tdf_init_cosinoidal(f, a0, m_zero, t0, tau0)
239 case (tdf_trapezoidal)
240 call parse_block_float(blk, i-1, 2, a0, units_inp%energy/units_inp%length)
241 call parse_block_float(blk, i-1, 3, tau0, units_inp%time)
242 call parse_block_float(blk, i-1, 4, t0, units_inp%time)
243 call parse_block_float(blk, i-1, 5, tau1, units_inp%time)
244 call tdf_init_trapezoidal(f, a0, m_zero, t0, tau0, tau1)
245 case (tdf_from_file)
246 call parse_block_string(blk, i-1, 2, filename)
247 call tdf_init_fromfile(f, trim(filename), namespace, ierr)
248 case (tdf_from_expr)
249 call parse_block_string(blk, i-1, 2, function_expression)
250 call tdf_init_fromexpr(f, trim(function_expression))
251 case default
252 ierr = -2
253 call parse_block_end(blk)
254 pop_sub(tdf_read)
255 return
256 end select
257
258 ierr = 0
259 exit row_loop
260 end if
261 end do row_loop
262
263 call parse_block_end(blk)
264 pop_sub(tdf_read)
265 end subroutine tdf_read
266 !------------------------------------------------------------
267
268
269 !------------------------------------------------------------
270 integer pure function tdf_niter(f)
271 type(tdf_t), intent(in) :: f
272 tdf_niter = f%niter
273 end function tdf_niter
274 !------------------------------------------------------------
275
276
277 !------------------------------------------------------------
278 integer pure function tdf_nfreqs(f)
279 type(tdf_t), intent(in) :: f
280 tdf_nfreqs = f%nfreqs
281 end function tdf_nfreqs
282 !------------------------------------------------------------
283
284
285 !------------------------------------------------------------
286 real(real64) pure function tdf_dt(f)
287 type(tdf_t), intent(in) :: f
288 tdf_dt = f%dt
289 end function tdf_dt
290 !------------------------------------------------------------
291
292
293 !------------------------------------------------------------
294 subroutine tdf_init(f)
295 type(tdf_t), intent(inout) :: f
296
297 push_sub(tdf_init)
298
299 f%mode = tdf_empty
300 f%niter = 0
301 f%dt = m_zero
302
303 pop_sub(tdf_init)
304 end subroutine tdf_init
305 !------------------------------------------------------------
306
307
308 !------------------------------------------------------------
309 logical function tdf_is_empty(f)
310 type(tdf_t), intent(in) :: f
311
312 push_sub(tdf_is_empty)
313 tdf_is_empty = (f%mode == tdf_empty)
314
315 pop_sub(tdf_is_empty)
316 end function tdf_is_empty
317 !------------------------------------------------------------
318
319
320 !------------------------------------------------------------
321 subroutine tdf_init_cw(f, a0, omega0)
322 type(tdf_t), intent(inout) :: f
323 real(real64), intent(in) :: a0, omega0
324
325 push_sub(tdf_init_cw)
326
327 f%mode = tdf_cw
328 f%a0 = a0
329 f%omega0 = omega0
330
331 pop_sub(tdf_init_cw)
332 end subroutine tdf_init_cw
333 !------------------------------------------------------------
334
335
336 !------------------------------------------------------------
337 subroutine tdf_init_gaussian(f, a0, omega0, t0, tau0)
338 type(tdf_t), intent(inout) :: f
339 real(real64), intent(in) :: a0, omega0, t0, tau0
340
341 push_sub(tdf_init_gaussian)
342
343 f%mode = tdf_gaussian
344 f%a0 = a0
345 f%omega0 = omega0
346 f%t0 = t0
347 f%tau0 = tau0
348
349 pop_sub(tdf_init_gaussian)
350 end subroutine tdf_init_gaussian
351 !------------------------------------------------------------
352
353
354 !------------------------------------------------------------
355 subroutine tdf_init_cosinoidal(f, a0, omega0, t0, tau0)
356 type(tdf_t), intent(inout) :: f
357 real(real64), intent(in) :: a0, omega0, t0, tau0
358
359 push_sub(tdf_init_cosinoidal)
360
361 f%mode = tdf_cosinoidal
362 f%a0 = a0
363 f%omega0 = omega0
364 f%t0 = t0
365 f%tau0 = tau0
366
367 pop_sub(tdf_init_cosinoidal)
368 end subroutine tdf_init_cosinoidal
369 !------------------------------------------------------------
370
372 !------------------------------------------------------------
373 subroutine tdf_init_trapezoidal(f, a0, omega0, t0, tau0, tau1)
374 type(tdf_t), intent(inout) :: f
375 real(real64), intent(in) :: a0, omega0, t0, tau0, tau1
376
377 push_sub(tdf_init_trapezoidal)
378
380 f%a0 = a0
381 f%omega0 = omega0
382 f%t0 = t0
383 f%tau0 = tau0
384 f%tau1 = tau1
385
386 pop_sub(tdf_init_trapezoidal)
387 end subroutine tdf_init_trapezoidal
388 !------------------------------------------------------------
389
390
391 !------------------------------------------------------------
392 subroutine tdf_init_fromexpr(f, expression)
393 type(tdf_t), intent(inout) :: f
394 character(len=*), intent(in) :: expression
395
396 push_sub(tdf_init_fromexpr)
397
398 f%mode = tdf_from_expr
399 f%expression = trim(expression)
400
401 pop_sub(tdf_init_fromexpr)
402 end subroutine tdf_init_fromexpr
403 !------------------------------------------------------------
404
405
406 !------------------------------------------------------------
407 subroutine tdf_init_fromfile(f, filename, namespace, ierr)
408 type(tdf_t), intent(inout) :: f
409 character(len=*), intent(in) :: filename
410 type(namespace_t),intent(in) :: namespace
411 integer, intent(out) :: ierr
412
413 integer :: iunit, lines, j
414 real(real64) :: dummy
415 real(real64), allocatable :: t(:), am(:)
416
417 push_sub(tdf_init_fromfile)
418
419 f%mode = tdf_from_file
420 ierr = 0
421
422 iunit = io_open(trim(filename), namespace, action='read', status='old')
423
424 ! count lines in file
425 call io_skip_header(iunit)
426 lines = 0
427 do
428 read(iunit, *, err=100, end=100) dummy, dummy
429 lines = lines + 1
430 end do
431100 continue
432 rewind(iunit)
433 call io_skip_header(iunit)
434
435 ! allocate and read info
436 safe_allocate( t(1:lines))
437 safe_allocate(am(1:lines))
438 do j = 1, lines
439 read(iunit, *) t(j), am(j)
440 end do
441 call io_close(iunit)
442
443 f%init_time = t(1)
444 f%final_time = t(lines)
445
446 call spline_init(f%amplitude)
447 call spline_fit(lines, t, am, f%amplitude, m_zero)
449 safe_deallocate_a(t)
450 safe_deallocate_a(am)
451
452 pop_sub(tdf_init_fromfile)
453 end subroutine tdf_init_fromfile
454 !------------------------------------------------------------
455
456
457 !------------------------------------------------------------
458 subroutine tdf_init_numerical(f, niter, dt, omegamax, initval, rep)
459 type(tdf_t), intent(inout) :: f
460 integer, intent(in) :: niter
461 real(real64), intent(in) :: dt
462 real(real64), intent(in) :: omegamax
463 real(real64), optional, intent(in) :: initval
464 integer, optional, intent(in) :: rep
465
466 integer :: n(3), optimize_parity(3)
467 logical :: optimize(3)
468 real(real64) :: bigt
469
470 push_sub(tdf_init_numerical)
471
472 f%mode = tdf_numerical
473 f%niter = niter
474 safe_allocate(f%val(1:niter+1))
475 if (present(initval)) then
476 f%val = initval
477 else
478 f%val = m_zero
479 end if
480 f%dt = dt
481
482 f%init_time = m_zero
483 f%final_time = f%dt * f%niter
484
485 if (omegamax > m_zero) then
486 bigt = f%final_time - f%init_time
487 f%nfreqs = int(bigt * omegamax / (m_two * m_pi)) + 1
488 else
489 f%nfreqs = f%niter/2+1
490 end if
491
492 n(1:3) = (/ f%niter, 1, 1 /)
493 optimize(1:3) = .false.
494 optimize_parity(1:3) = -1
495 call fft_init(f%fft_handler, n, 1, fft_real, fftlib_fftw, optimize, optimize_parity)
496
497 if (present(rep)) then
498 select case (rep)
500 safe_allocate(f%valww(1:2*(f%nfreqs-1)+1))
501 f%valww = m_zero
502 safe_deallocate_a(f%val)
503 f%mode = rep
504 end select
505 end if
506
507 pop_sub(tdf_init_numerical)
508 end subroutine tdf_init_numerical
509 !------------------------------------------------------------
510
511
512 !------------------------------------------------------------
513 subroutine tdf_fourier_grid(f, wgrid)
514 type(tdf_t), intent(in) :: f
515 real(real64), intent(inout) :: wgrid(:)
516
517 integer :: i
518 real(real64) :: df
519
520 push_sub(tdf_fourier_grid)
521
522 wgrid = m_zero
523 select case (f%mode)
525 df = m_two * m_pi / (f%final_time-f%init_time)
526 do i = 1, f%nfreqs
527 wgrid(i) = (i-1)*df
528 end do
529 case default
530 message(1) = "Illegal mode in tdf_fourier_grid."
531 call messages_fatal(1)
532 end select
533
534 pop_sub(tdf_fourier_grid)
535 end subroutine tdf_fourier_grid
536 !------------------------------------------------------------
537
538
539 !------------------------------------------------------------
540 subroutine tdf_numerical_to_fourier(f)
541 type(tdf_t), intent(inout) :: f
542
543 integer :: j
544 complex(real64), allocatable :: tmp(:)
545
547
548 safe_allocate(tmp(1:f%niter/2+1))
549 ! Moving to Fourier space implies periodic functions. However, the function on entry
550 ! may not be periodic (f%val(f%niter +1) may not be equal to f%val(1)), so it is
551 ! better if we take the average of those two values.
552 f%val(1) = m_half*(f%val(1)+f%val(f%niter+1))
553 f%val(f%niter+1) = f%val(1)
554 call dfft_forward(f%fft_handler, f%val(1:f%niter), tmp)
555 tmp = tmp * f%dt * sqrt(m_one/(f%final_time-f%init_time))
556 f%mode = tdf_fourier_series
557 safe_allocate(f%valww(1:2*(f%nfreqs-1)+1))
558 f%valww(1) = real(tmp(1), real64)
559 do j = 2, f%nfreqs
560 f%valww(j) = (sqrt(m_two)) * real(tmp(j), real64)
561 end do
562 do j = f%nfreqs+1, 2*f%nfreqs-1
563 f%valww(j) = - (sqrt(m_two)) * aimag(tmp(j-f%nfreqs+1))
564 end do
565
566 safe_deallocate_a(tmp)
567 safe_deallocate_a(f%val)
568
570 end subroutine tdf_numerical_to_fourier
571 !------------------------------------------------------------
572
573
574 !------------------------------------------------------------
575 subroutine tdf_fourier_to_numerical(f)
576 type(tdf_t), intent(inout) :: f
577
578 integer :: j
579 complex(real64), allocatable :: tmp(:)
580
582
583 safe_allocate(tmp(1:f%niter/2+1))
584 tmp = m_z0
585 tmp(1) = f%valww(1)
586 do j = 2, f%nfreqs
587 tmp(j) = cmplx((sqrt(m_two)/m_two)*f%valww(j), -(sqrt(m_two)/m_two)*f%valww(j+f%nfreqs-1), real64)
588 end do
589 safe_allocate(f%val(1:f%niter+1))
590 call dfft_backward(f%fft_handler, tmp, f%val(1:f%niter))
591 f%val(f%niter+1) = f%val(1)
592 f%val = f%val * f%niter * sqrt(m_one/(f%final_time-f%init_time))
593 f%mode = tdf_numerical
594
595 safe_deallocate_a(tmp)
596 safe_deallocate_a(f%valww)
597
599 end subroutine tdf_fourier_to_numerical
600 !------------------------------------------------------------
601
602
603 !------------------------------------------------------------
604 subroutine tdf_numerical_to_zerofourier(f)
605 type(tdf_t), intent(inout) :: f
607 real(real64) :: s
609
611 f%valww(1) = m_zero
612 s = sum(f%valww(2:f%nfreqs))
613 f%valww(2:f%nfreqs) = f%valww(2:f%nfreqs) - s/f%nfreqs
614 f%mode = tdf_zero_fourier
615
617 end subroutine tdf_numerical_to_zerofourier
618 !------------------------------------------------------------
619
620
621 !------------------------------------------------------------
622 subroutine tdf_zerofourier_to_numerical(f)
623 type(tdf_t), intent(inout) :: f
624
626
627 assert(abs(f%valww(1)) <= m_epsilon)
629
631 end subroutine tdf_zerofourier_to_numerical
632 !------------------------------------------------------------
634
635 !------------------------------------------------------------
636 subroutine tdf_set_numericalr(f, values)
637 type(tdf_t), intent(inout) :: f
638 real(real64), intent(in) :: values(:)
639
640 ! no push_sub because it is called too frequently
641
642 select case (f%mode)
643 case (tdf_numerical)
644 f%val(1:f%niter+1) = values(1:f%niter+1)
645 case (tdf_fourier_series)
646 f%valww(1:2*f%nfreqs-1) = values(1:2*f%nfreqs-1)
647 case (tdf_zero_fourier)
648 f%valww(1) = m_zero
649 f%valww(2:2*f%nfreqs-1) = values(1:2*f%nfreqs-2)
650 end select
651
652 end subroutine tdf_set_numericalr
653 !------------------------------------------------------------
654
655
656 !------------------------------------------------------------
657 subroutine tdf_set_numericalr1(f, index, val)
658 type(tdf_t), intent(inout) :: f
659 integer, intent(in) :: index
660 real(real64), intent(in) :: val
661
662 ! no push_sub because it is called too frequently
663
664 select case (f%mode)
665 case (tdf_numerical)
666 f%val(index) = val
667 case (tdf_fourier_series)
668 f%valww(index) = val
669 case (tdf_zero_fourier)
670 f%valww(index+1) = val
671 end select
672
673 end subroutine tdf_set_numericalr1
674 !------------------------------------------------------------
675
676
677 !------------------------------------------------------------
678 subroutine tdf_set_random(f, fdotf)
679 type(tdf_t), intent(inout) :: f
680 real(real64), optional, intent(in) :: fdotf
681
682 type(c_ptr) :: random_gen_pointer
683 integer :: i, n
684 real(real64) :: fdotf_, nrm
685 real(real64), allocatable :: e(:)
686
687 push_sub(tdf_set_random)
688
689 select case (f%mode)
690 case (tdf_fourier_series)
691 n = 2*f%nfreqs-1
692 case (tdf_zero_fourier)
693 n = 2*f%nfreqs-2
694 case default
695 message(1) = "Illegal value for f%mode in tdf_set_random."
696 call messages_fatal(1)
697 end select
698 safe_allocate(e(1:n))
699
700 if (mpi_grp_is_root(mpi_world)) then
701 if (present(fdotf)) then
702 fdotf_ = fdotf
703 else
704 fdotf_ = tdf_dot_product(f, f)
705 end if
706
707 call loct_ran_init(random_gen_pointer)
708
709 do i = 1, n
710 e(i) = loct_ran_gaussian(random_gen_pointer, m_one)
711 end do
712 nrm = norm2(e)
713 e = sqrt(fdotf_) * e/ nrm
714
715 if (f%mode == tdf_zero_fourier) then
716 e(1:f%nfreqs-1) = e(1:f%nfreqs-1) - sum(e(1:f%nfreqs-1))/(f%nfreqs-1)
717 nrm = norm2(e)
718 e = sqrt(fdotf_) * e/ nrm
719 end if
720
721 call loct_ran_end(random_gen_pointer)
722 end if
723
724 call mpi_world%bcast(e(1), n, mpi_double_precision, 0)
725
726 call tdf_set_numerical(f, e)
727 safe_deallocate_a(e)
728 pop_sub(tdf_set_random)
729 end subroutine tdf_set_random
730 !------------------------------------------------------------
731
732
733 !------------------------------------------------------------
734 subroutine tdf_to_numerical(f, niter, dt, omegamax)
735 type(tdf_t), intent(inout) :: f
736 integer, optional, intent(in) :: niter
737 real(real64), optional, intent(in) :: dt
738 real(real64), optional, intent(in) :: omegamax
739
740 real(real64) :: t
741 integer :: j
742 real(real64), allocatable :: val(:)
743
744 if (f%mode == tdf_numerical) return
745 push_sub(tdf_to_numerical)
746
747 select case (f%mode)
748 case (tdf_zero_fourier)
752 case default
753 safe_allocate(val(1:niter+1))
754 do j = 1, niter + 1
755 t = (j-1)*dt
756 val(j) = tdf(f, t)
757 end do
758 call tdf_end(f)
759 assert(present(niter))
760 assert(present(dt))
761 assert(present(omegamax))
762 call tdf_init_numerical(f, niter, dt, omegamax)
763 call tdf_set_numerical(f, val)
764 safe_deallocate_a(val)
765 end select
766
767 pop_sub(tdf_to_numerical)
768 end subroutine tdf_to_numerical
769 !------------------------------------------------------------
770
772 !------------------------------------------------------------
773 real(real64) pure function tdfi(f, i) result(y)
774 type(tdf_t), intent(in) :: f
775 integer, intent(in) :: i
776
777 ! Maybe there should be a grid for any kind of function, so
778 ! that a meaningful number is produced in any case.
779 y = m_zero
780 select case (f%mode)
781 case (tdf_numerical)
782 y = f%val(i)
783 case (tdf_fourier_series)
784 y = f%valww(i)
785 case (tdf_zero_fourier)
786 y = f%valww(i+1)
787 end select
788
789 end function tdfi
790 !------------------------------------------------------------
791
792
793 !------------------------------------------------------------
794 real(real64) function tdft(f, t) result(y)
795 type(tdf_t), intent(in) :: f
796 real(real64), intent(in) :: t
797
798 real(real64), allocatable :: timearray(:), valarray(:)
799 real(real64) :: r, fre, fim, tcu
800 integer :: il, iu
801
802 ! no push_sub because it is called too frequently
803
804 select case (f%mode)
805
806 case (tdf_cw)
807
808 y = f%a0 * cos(f%omega0*t)
809
810 case (tdf_gaussian)
811
812 r = exp(-(t - f%t0)**2 / (m_two*f%tau0**2))
813 y = f%a0 * r * cos(f%omega0 * t)
814
815 case (tdf_cosinoidal)
816
817 r = m_zero
818 if (abs(t - f%t0) <= f%tau0) then
819 r = cos((m_pi / 2) * ((t - 2 * f%tau0 - f%t0) / f%tau0))
820 end if
821 y = f%a0 * r * cos(f%omega0 * t)
822
823 case (tdf_trapezoidal)
824 if (t > f%t0-f%tau0/m_two-f%tau1 .and. t <= f%t0-f%tau0 / m_two) then
825 r = (t - (f%t0 - f%tau0/m_two - f%tau1)) / f%tau1
826 else if (t>f%t0-f%tau0/m_two .and. t <= f%t0+f%tau0 / m_two) then
827 r = m_one
828 else if (t>f%t0+f%tau0/m_two .and. t <= f%t0+f%tau0 / m_two+f%tau1) then
829 r = (f%t0 + f%tau0/m_two + f%tau1 - t) / f%tau1
830 else
831 r = m_zero
832 end if
833 y = f%a0 * r * cos(f%omega0 * t)
834 case (tdf_from_file)
835
836 if (t >= f%init_time .and. t <= f%final_time) then
837 y = spline_eval(f%amplitude, t)
838 else
839 y = m_zero
840 end if
841
842 case (tdf_numerical)
843
844 il = int(t/f%dt)+1; iu = il+1
845
846 safe_allocate(timearray(1:4))
847 safe_allocate(valarray(1:4))
848
849 if (il <= 1) then
850 timearray = (/ m_zero, f%dt, m_two*f%dt, m_three*f%dt /)
851 valarray = (/ f%val(1), f%val(2), f%val(3), f%val(4) /)
852 elseif (il >= f%niter) then
853 timearray = (/ (f%niter-3)*f%dt, (f%niter-2)*f%dt, (f%niter-1)*f%dt, f%niter*f%dt /)
854 valarray = (/ f%val(f%niter-2), f%val(f%niter-1), f%val(f%niter), f%val(f%niter+1) /)
855 else
856 timearray = (/ (il-2)*f%dt, (il-1)*f%dt, il*f%dt, (il+1)*f%dt /)
857 valarray = (/ f%val(il-1), f%val(il), f%val(il+1), f%val(il+2) /)
858 end if
859
860 call interpolate(timearray, valarray, t, y)
861
862 safe_deallocate_a(valarray)
863 safe_deallocate_a(timearray)
864
865 case (tdf_from_expr)
866 tcu = units_from_atomic(units_inp%time, t)
867 call parse_expression(fre, fim, 't', tcu, f%expression)
868 y = fre
869
870 case default
871 y = m_zero
872
873 end select
874
875 end function tdft
876 !------------------------------------------------------------
877
878
879 !------------------------------------------------------------
880 subroutine tdf_end(f)
881 type(tdf_t), intent(inout) :: f
882
883 push_sub(tdf_end)
884
885 select case (f%mode)
886 case (tdf_from_file)
887 call spline_end(f%amplitude)
888 case (tdf_numerical)
889 call fft_end(f%fft_handler)
891 safe_deallocate_a(f%valww)
892 call fft_end(f%fft_handler)
893 end select
894 f%mode = tdf_empty
895 safe_deallocate_a(f%val)
896
897 pop_sub(tdf_end)
898 end subroutine tdf_end
899 !------------------------------------------------------------
900
901
902 !------------------------------------------------------------
903 subroutine tdf_copy(fout, fin)
904 type(tdf_t), intent(inout) :: fout
905 type(tdf_t), intent(in) :: fin
906
907 push_sub(tdf_copy)
908
909 assert((fin%mode >= tdf_empty) .and. (fin%mode <= tdf_zero_fourier))
910
911 call tdf_end(fout)
912 call tdf_init(fout)
913
914 fout%t0 = fin%t0
915 fout%tau0 = fin%tau0
916 fout%tau1 = fin%tau1
917 fout%dt = fin%dt
918 fout%a0 = fin%a0
919 fout%omega0 = fin%omega0
920 fout%niter = fin%niter
921 fout%final_time = fin%final_time
922 fout%init_time = fin%init_time
923 fout%expression = fin%expression
924 fout%nfreqs = fin%nfreqs
925 if (fin%mode == tdf_from_file) then
926 fout%amplitude = fin%amplitude
927 end if
928 if (fin%mode == tdf_numerical) then
929 safe_allocate(fout%val(1:fout%niter+1))
930 fout%val = fin%val
931 call fft_copy(fin%fft_handler, fout%fft_handler)
932 end if
933 if (fin%mode == tdf_fourier_series .or. fin%mode == tdf_zero_fourier) then
934 safe_allocate(fout%valww(1:2*fout%nfreqs-1))
935 fout%valww = fin%valww
936 call fft_copy(fin%fft_handler, fout%fft_handler)
937 end if
938 fout%mode = fin%mode
939
940 pop_sub(tdf_copy)
941 end subroutine tdf_copy
942 !------------------------------------------------------------
943
944
945 !------------------------------------------------------------
946 subroutine tdf_scalar_multiply(alpha, f)
947 real(real64), intent(in) :: alpha
948 type(tdf_t), intent(inout) :: f
949
950 push_sub(tdf_scalar_multiply)
951
952 select case (f%mode)
954 f%a0 = alpha*f%a0
955 case (tdf_numerical)
956 f%val = alpha*f%val
958 f%valww = alpha*f%valww
959 case (tdf_from_file)
960 call spline_times(alpha, f%amplitude, m_zero)
961 end select
962
963 pop_sub(tdf_scalar_multiply)
964 end subroutine tdf_scalar_multiply
965 !------------------------------------------------------------
966
967
968 !------------------------------------------------------------
969 subroutine tdf_cosine_multiply(omega, f)
970 real(real64), intent(in) :: omega
971 type(tdf_t), intent(inout) :: f
972
973 integer :: j
974 real(real64) :: t
975
976 push_sub(tdf_cosine_multiply)
977
978 ! For the moment, we will just assume that f and g are of the same type.
979 assert(f%mode == tdf_numerical)
980
981 do j = 1, f%niter + 1
982 t = f%init_time + (j-1)*f%dt
983 f%val(j) = f%val(j) * cos(omega*t)
984 end do
985
986 pop_sub(tdf_cosine_multiply)
987 end subroutine tdf_cosine_multiply
988 !------------------------------------------------------------
989
990
991 !------------------------------------------------------------
992 subroutine tdf_write(f, iunit, namespace)
993 type(tdf_t), intent(in) :: f
994 integer, optional, intent(in) :: iunit
995 type(namespace_t), optional, intent(in) :: namespace
997 integer :: n_msg
998
999 push_sub(tdf_write)
1000
1001 select case (f%mode)
1002 case (tdf_cw)
1003 write(message(1),'(6x,a)') 'Mode: continuous wave.'
1004 write(message(2),'(6x,a,f10.4,a)') 'Amplitude: ', f%a0, ' [a.u]'
1005 n_msg = 2
1006 case (tdf_gaussian)
1007 write(message(1),'(6x,a)') 'Mode: Gaussian envelope.'
1008 write(message(2),'(6x,a,f10.4,a)') 'Amplitude: ', f%a0, ' [a.u]'
1009 write(message(3),'(6x,a,f10.4,3a)') 'Width: ', units_from_atomic(units_out%time, f%tau0), &
1010 ' [', trim(units_abbrev(units_out%time)), ']'
1011 write(message(4),'(6x,a,f10.4,3a)') 'Middle t: ', units_from_atomic(units_out%time, f%t0), &
1012 ' [', trim(units_abbrev(units_out%time)), ']'
1013 n_msg = 4
1014 case (tdf_cosinoidal)
1015 write(message(1),'(6x,a)') 'Mode: cosinoidal envelope.'
1016 write(message(2),'(6x,a,f10.4,a)') 'Amplitude: ', f%a0, ' [a.u]'
1017 write(message(3),'(6x,a,f10.4,3a)') 'Width: ', units_from_atomic(units_out%time, f%tau0), &
1018 ' [', trim(units_abbrev(units_out%time)), ']'
1019 write(message(4),'(6x,a,f10.4,3a)') 'Middle t: ', units_from_atomic(units_out%time, f%t0), &
1020 ' [', trim(units_abbrev(units_out%time)), ']'
1021 n_msg = 4
1022 case (tdf_trapezoidal)
1023 write(message(1),'(6x,a)') 'Mode: trapezoidal envelope.'
1024 write(message(2),'(6x,a,f10.4,a)') 'Amplitude: ', f%a0, ' [a.u]'
1025 write(message(3),'(6x,a,f10.4,3a)') 'Width: ', units_from_atomic(units_out%time, f%tau0), &
1026 ' [', trim(units_abbrev(units_out%time)), ']'
1027 write(message(4),'(6x,a,f10.4,3a)') 'Middle t: ', units_from_atomic(units_out%time, f%t0), &
1028 ' [', trim(units_abbrev(units_out%time)), ']'
1029 write(message(5),'(6x,a,f10.4,3a)') 'Ramp time: ', units_from_atomic(units_out%time, f%tau1), &
1030 ' [', trim(units_abbrev(units_out%time)), ']'
1031 n_msg = 5
1032 case (tdf_from_file)
1033 write(message(1),'(6x,a)') 'Mode: time-dependent function read from file.'
1034 n_msg = 1
1035 case (tdf_numerical)
1036 write(message(1),'(6x,a)') 'Mode: time-dependent function stored in a numerical array.'
1037 n_msg = 1
1038 case (tdf_from_expr)
1039 write(message(1),'(6x,a)') 'Mode: time-dependent function parsed from the expression:'
1040 write(message(2),'(6x,a)') ' f(t) = '//trim(f%expression)
1041 n_msg = 2
1042 end select
1043
1044 if (abs(f%omega0) > m_epsilon) then
1045 n_msg = n_msg + 1
1046 write(message(n_msg),'(6x,a,f10.4,3a)') 'Frequency: ', units_from_atomic(units_out%energy, f%omega0), &
1047 ' [', trim(units_abbrev(units_out%energy)), ']'
1048 end if
1049
1050 call messages_info(n_msg, iunit=iunit, namespace=namespace)
1051
1052 pop_sub(tdf_write)
1053 end subroutine tdf_write
1054 !------------------------------------------------------------
1055
1056
1057 !------------------------------------------------------------
1058 ! Returns the dot product of f and g, defined as:
1059 ! < f | g > = \int_0^T dt f^*(t) g(t)
1060 ! It assumes that both f and m are in the same mode, otherwise
1061 ! it will fail and stop the code.
1062 !------------------------------------------------------------
1063 real(real64) function tdf_dot_product(f, g) result (fg)
1064 type(tdf_t), intent(in) :: f, g
1065
1066 integer :: i
1067 real(real64) :: t
1068
1069 push_sub(tdf_dot_product)
1070
1071 fg = m_zero
1072
1073 ! For the moment, we will just assume that f and g are of the same type.
1074 assert(f%mode == g%mode)
1075
1076 select case (f%mode)
1077 case (tdf_numerical)
1078 ! We assume that the grid is the same for both functions.
1079 ! We will apply Simpson`s rule. However, note that this rule is only valid if there is an even
1080 ! number of orbitals. So if there is an odd number, we will apply a correction term (that will
1081 ! reduce the error order from 4 to 2, similar to the simple trapezoidal rule).
1082 fg = m_zero
1083 do i = 1, f%niter/2
1084 fg = fg + f%val(2*i-2+1)*g%val(2*i-2+1) + m_four*f%val(2*i-1+1)*g%val(2*i-1+1) + f%val(2*i+1)*g%val(2*i+1)
1085 end do
1086 fg = fg * f%dt / m_three
1087 ! This is the correction term.
1088 if (mod(f%niter, 2).eq.1) then
1089 fg = fg + m_half * (f%val(f%niter)*g%val(f%niter) + f%val(f%niter+1) * g%val(f%niter+1)) * f%dt
1090 end if
1091
1092 case (tdf_fourier_series)
1093 fg = dot_product(f%valww, g%valww)
1094 case (tdf_zero_fourier)
1095 assert(abs(f%valww(1)) <= m_epsilon)
1096 fg = dot_product(f%valww, g%valww)
1097 case default
1098 do i = 1, f%niter + 1
1099 t = (i-1) * f%dt
1100 fg = fg + tdf(f, i) * tdf(g, i)
1101 end do
1102
1103 end select
1104
1105 pop_sub(tdf_dot_product)
1106 end function tdf_dot_product
1107 !------------------------------------------------------------
1108
1109
1110 !------------------------------------------------------------
1111 ! Returns the difference of f and g, defined as:
1112 ! < f-g | f-g > = \int_0^T dt (f^*(t)-g^*(t))*(f(t)-g(t))
1113 ! It assumes that both f and m are in the same mode, otherwise
1114 ! it will fail and stop the code.
1115 !------------------------------------------------------------
1116 real(real64) function tdf_diff(f, g) result (fg)
1117 type(tdf_t), intent(in) :: f, g
1118
1119 integer :: i
1120 type(tdf_t) :: fminusg
1121
1122 push_sub(tdf_diff)
1123
1124 ! For the moment, we will just assume that f and g are of the same type.
1125 assert(f%mode == g%mode)
1126
1127 call tdf_copy(fminusg, f)
1128
1129 select case (f%mode)
1130 case (tdf_numerical)
1131 do i = 1, f%niter
1132 fminusg%val(i) = fminusg%val(i) - g%val(i)
1133 end do
1135 do i = 1, 2*(f%nfreqs-1)+1
1136 fminusg%valww(i) = fminusg%valww(i) - g%valww(i)
1137 end do
1138 case default
1139 message(1) = "Illegal value for f%mode in tdf_diff"
1140 call messages_fatal(1)
1141 end select
1142
1143 fg = tdf_dot_product(fminusg, fminusg)
1144
1145 call tdf_end(fminusg)
1146
1147 pop_sub(tdf_diff)
1148 end function tdf_diff
1149 !------------------------------------------------------------
1150
1151end module tdfunction_oct_m
1152
1153!! Local Variables:
1154!! mode: f90
1155!! coding: utf-8
1156!! End:
subroutine optimize()
double exp(double __x) __attribute__((__nothrow__
double sqrt(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_zero
Definition: global.F90:187
Definition: io.F90:114
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public tdf_numerical_to_fourier(f)
Definition: tdfunction.F90:634
integer, parameter, public tdf_from_file
Definition: tdfunction.F90:172
integer, parameter, public tdf_cosinoidal
Definition: tdfunction.F90:172
subroutine, public tdf_init_cw(f, a0, omega0)
Definition: tdfunction.F90:415
integer pure function, public tdf_nfreqs(f)
Definition: tdfunction.F90:372
logical function, public tdf_is_empty(f)
Definition: tdfunction.F90:403
integer, parameter, public tdf_numerical
Definition: tdfunction.F90:172
subroutine tdf_set_numericalr1(f, index, val)
Definition: tdfunction.F90:751
subroutine tdf_set_numericalr(f, values)
Definition: tdfunction.F90:730
subroutine, public tdf_init_fromfile(f, filename, namespace, ierr)
Definition: tdfunction.F90:501
integer pure function, public tdf_niter(f)
Definition: tdfunction.F90:364
integer, parameter, public tdf_empty
Definition: tdfunction.F90:172
subroutine, public tdf_init_cosinoidal(f, a0, omega0, t0, tau0)
Definition: tdfunction.F90:449
subroutine, public tdf_init_gaussian(f, a0, omega0, t0, tau0)
Definition: tdfunction.F90:431
real(real64) pure function tdfi(f, i)
Definition: tdfunction.F90:867
subroutine, public tdf_numerical_to_zerofourier(f)
Definition: tdfunction.F90:698
subroutine, public tdf_end(f)
Definition: tdfunction.F90:974
integer, parameter, public tdf_zero_fourier
Definition: tdfunction.F90:172
subroutine, public tdf_write(f, iunit, namespace)
subroutine, public tdf_copy(fout, fin)
Definition: tdfunction.F90:997
real(real64) function, public tdf_diff(f, g)
subroutine, public tdf_init_trapezoidal(f, a0, omega0, t0, tau0, tau1)
Definition: tdfunction.F90:467
integer, parameter, public tdf_cw
Definition: tdfunction.F90:172
real(real64) function tdft(f, t)
Definition: tdfunction.F90:888
subroutine, public tdf_cosine_multiply(omega, f)
subroutine, public tdf_set_random(f, fdotf)
Definition: tdfunction.F90:772
subroutine, public tdf_fourier_grid(f, wgrid)
Definition: tdfunction.F90:607
integer, parameter, public tdf_trapezoidal
Definition: tdfunction.F90:172
subroutine, public tdf_init(f)
Definition: tdfunction.F90:388
subroutine, public tdf_init_numerical(f, niter, dt, omegamax, initval, rep)
Definition: tdfunction.F90:552
subroutine, public tdf_to_numerical(f, niter, dt, omegamax)
Definition: tdfunction.F90:828
subroutine, public tdf_fourier_to_numerical(f)
Definition: tdfunction.F90:669
subroutine, public tdf_zerofourier_to_numerical(f)
Definition: tdfunction.F90:716
real(real64) function, public tdf_dot_product(f, g)
integer, parameter, public tdf_gaussian
Definition: tdfunction.F90:172
integer, parameter, public tdf_from_expr
Definition: tdfunction.F90:172
subroutine, public tdf_read(f, namespace, function_name, ierr)
This function initializes "f" from the TDFunctions block.
Definition: tdfunction.F90:218
integer, parameter, public tdf_fourier_series
Definition: tdfunction.F90:172
subroutine, public tdf_scalar_multiply(alpha, f)
real(real64) pure function, public tdf_dt(f)
Definition: tdfunction.F90:380
subroutine, public tdf_init_fromexpr(f, expression)
Definition: tdfunction.F90:486
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
real(real64) function values(xx)
Definition: test.F90:1867