Octopus
external_waves.F90
Go to the documentation of this file.
1!! Copyright (C) 2023 E.I. Albar, F. Bonafe and Heiko Appel
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#include "global.h"
19
21 use accel_oct_m
24 use clock_oct_m
26 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
32 use index_oct_m
37 use, intrinsic :: iso_fortran_env
39 use io_oct_m
41 use lasers_oct_m
45 use mesh_oct_m
47 use mpi_oct_m
52 use parser_oct_m
56 use string_oct_m
57 use types_oct_m
58 use unit_oct_m
62
63 implicit none
64
65 private
66 public :: &
73
74 type bessel_beam_t
75 integer, allocatable :: helicity(:)
76 integer, allocatable :: m_order(:)
77 real(real64), allocatable :: amp(:)
78 real(real64), allocatable :: theta_k(:)
79 real(real64), allocatable :: omega(:)
80 real(real64), allocatable :: shift(:,:)
81 logical, allocatable :: envelope(:)
82 integer, allocatable :: lin_dir(:)
83 contains
84 procedure :: init => bessel_beam_init
85 procedure :: function => bessel_beam_function
87 end type bessel_beam_t
88
90 integer :: points_number
91 integer, allocatable :: points_map(:)
92 integer :: number
93 integer, allocatable :: modus(:)
94 integer, allocatable :: field_type(:)
95 character(len=1024), allocatable :: e_field_string(:,:)
96 real(real64), allocatable :: k_vector(:,:)
97 real(real64), allocatable :: v_vector(:,:)
98 complex(real64), allocatable :: e_field(:,:)
99 real(real64), allocatable :: pw_phase(:)
100 type(mxf_t), allocatable :: mx_function(:)
101 integer :: out_file
102 logical :: output_from_point = .false.
103 real(real64), allocatable :: selected_point_coordinate(:)
104 real(real64), allocatable :: selected_point_field(:)
105 real(real64) :: c_factor
106 type(accel_mem_t) :: buff_map
107 type(bessel_beam_t) :: bessel
108 contains
109 procedure :: init_interaction_as_partner => external_waves_init_interaction_as_partner
110 procedure :: update_quantity => external_waves_update_quantity
111 procedure :: copy_quantities_to_interaction => external_waves_copy_quantities_to_interaction
112 final :: external_waves_end
114
115 interface external_waves_t
116 module procedure external_waves_constructor
117 end interface external_waves_t
118
119contains
120
121 function external_waves_constructor(namespace) result(this)
122 class(external_waves_t), pointer :: this
123 type(namespace_t), intent(in) :: namespace
124
125 integer :: iq, quantities(3)
126
128
129 safe_allocate(this)
130
131 this%namespace = namespace_t("ExternalSource", parent=namespace)
132
133 message(1) = 'Plane-wave is currently always 3D and non-periodic.'
134 call messages_warning(1)
135 call external_waves_init(this, this%namespace)
136
137 quantities = [ e_field, vector_potential, b_field ]
138
139 do iq = 1, size(quantities)
140 this%quantities(quantities(iq))%always_available = .true.
141 this%quantities(quantities(iq))%updated_on_demand = .true.
142 this%quantities(quantities(iq))%iteration = clock_t()
143 end do
144
145 this%supported_interactions_as_partner = [mxll_e_field_to_matter, mxll_b_field_to_matter, mxll_vec_pot_to_matter]
146
148 end function external_waves_constructor
149
150 ! ---------------------------------------------------------
151 subroutine external_waves_init_interaction_as_partner(partner, interaction)
152 class(external_waves_t), intent(in) :: partner
153 class(interaction_surrogate_t), intent(inout) :: interaction
154
156
157 select type (interaction)
158 type is (lorentz_force_t)
159 ! Nothing to be initialized
161 ! Nothing to be initialized
163 ! Nothing to be initialized
165 ! Nothing to be initialized
166 class default
167 message(1) = "Unsupported interaction."
168 call messages_fatal(1, namespace=partner%namespace)
169 end select
173 ! ---------------------------------------------------------
175 class(external_waves_t), intent(inout) :: this
176 integer, intent(in) :: iq
180 select case (iq)
182 ! We will not update the quantities here because they are computed
183 ! on-the-fly when copying them to the corresponding interaction (see
184 ! copy_quantities_to_interaction routine)
185 case default
186 message(1) = "Incompatible quantity."
187 call messages_fatal(1, namespace=this%namespace)
188 end select
193 ! ---------------------------------------------------------
194 subroutine external_waves_copy_quantities_to_interaction(partner, interaction)
195 class(external_waves_t), intent(inout) :: partner
196 class(interaction_surrogate_t), intent(inout) :: interaction
200 select type(interaction)
201 class is (mxll_e_field_to_matter_t)
202 interaction%system_field = m_zero
203 call external_waves_eval(partner, partner%quantities(e_field)%iteration%value(), interaction%system_gr, e_field, &
204 interaction%system_field)
205 call interaction%do_mapping()
206
207 class is (mxll_vec_pot_to_matter_t)
208 interaction%system_field = m_zero
209 call external_waves_eval(partner, partner%quantities(vector_potential)%iteration%value(), interaction%system_gr, &
210 vector_potential, interaction%system_field)
211 call interaction%do_mapping()
212
213 class is (mxll_b_field_to_matter_t)
214 interaction%system_field = m_zero
215 call external_waves_eval(partner, partner%quantities(b_field)%iteration%value(), interaction%system_gr, b_field, &
216 interaction%system_field, der=interaction%system_gr%der)
217 call interaction%do_mapping()
218
219 class default
220 message(1) = "Incompatible interaction."
221 call messages_fatal(1, namespace=partner%namespace)
222 end select
223
226
227 ! ---------------------------------------------------------
228 ! Load the external source for the multisystem framework
229 subroutine load_external_waves(partners, namespace)
230 class(partner_list_t), intent(inout) :: partners
231 type(namespace_t), intent(in) :: namespace
232
233 logical :: has_source
234
235 push_sub(load_external_waves)
236
237 !%Variable AnalyticalExternalSource
238 !%Type logical
239 !%Default no
240 !%Section Maxwell
241 !%Description
242 !% This means the analytical evaluation of formula will be used, Maxwell propagation will not be used.
243 !%End
244 call parse_variable(namespace, 'AnalyticalExternalSource', .false., has_source)
245
246 if (has_source) then
247 call partners%add(external_waves_t(namespace))
248 end if
249
250 pop_sub(load_external_waves)
251 end subroutine load_external_waves
252
253
255 ! ---------------------------------------------------------
256 subroutine external_waves_init(external_waves, namespace)
257 type(external_waves_t), intent(inout) :: external_waves
258 type(namespace_t), intent(in) :: namespace
259 type(block_t) :: blk
260 integer :: il, nlines, ncols, iex_norm, idim
261 integer, parameter :: sys_dim = 3
262 real(real64) :: k_vector(sys_dim), velocity(sys_dim), x_pos(sys_dim)
263 real(real64) :: x_norm, dummy(sys_dim), k_dot_e , test_limit, k_norm, output_pos(3)
264 complex(real64) :: e_field(sys_dim)
265 character(len=1024) :: k_string(sys_dim)
266 character(len=1), dimension(sys_dim), parameter :: dims = ["x", "y", "z"]
267 character(len=1024) :: mxf_expression
268
269 push_sub(external_waves_init)
270
271 call profiling_in('EXTERNAL_WAVES_INIT')
272
273 test_limit = 10.0e-9_real64
274
275 !%Variable ExternalSourceBesselOutput
276 !%Type block
277 !%Section Maxwell
278 !%Description
279 !% The ExternalSourceBesselOutput block allows to output analytically calculated fields at a
280 !% particular point in space. The columns denote the x, y, and z coordinate of the point.
281 !% Please be aware that ExternalSource lives on the grid of the system that it is applied to.
282 !% Therefore, it might not be evaluated at every point in space. When comparing, please be sure
283 !% to check the log and compare if your required point in space matches the evaluated position.
284 !%
285 !% <tt>%ExternalSourceBesselOutput
286 !% <br>&nbsp;&nbsp; -1.0 | 2.0 | 4.0
287 !% <br>%</tt>
288 !%
289 !%End
290
291 if (parse_block(namespace, 'ExternalSourceBesselOutput', blk) == 0) then
292 nlines = parse_block_n(blk)
293 if (nlines > 1 ) then
294 message(2) = 'ExternalSource output is limited to one point.'
295 call messages_fatal(1, namespace=namespace)
296 end if
297 ncols = parse_block_cols(blk,0)
298 if (ncols /= 3 ) then
299 message(1) = 'ExternalSourceBesselOutput must have 3 columns.'
300 call messages_fatal(1, namespace=namespace)
301 end if
302 external_waves%output_from_point= .true.
303 safe_allocate(external_waves%selected_point_coordinate(1:3))
304 safe_allocate(external_waves%selected_point_field(1:3))
305
306 do idim = 1, 3
307 call parse_block_float(blk, 0, idim-1, output_pos(idim), units_inp%length)
308 end do
309 external_waves%selected_point_coordinate(1:3) = output_pos(1:3)
310 external_waves%selected_point_field(1:3) = m_zero
311
312 call parse_block_end(blk)
313 call io_mkdir('ExternalSource')
314 external_waves%out_file = io_open('bessel_source_at_point', namespace=namespace, action='write')
315 write(external_waves%out_file, '(12a) ') '# Time (a.u.) ' , ' Field-x ' , ' Field-y ' , ' Field-z '
316
317 else
318 external_waves%output_from_point= .false.
319
320 end if
321
322 ! This variable is documented in hamiltonian_mxll.F90
323 call parse_variable(namespace, 'SpeedOfLightFactor', m_one, external_waves%c_factor)
324
325 !%Variable MaxwellIncidentWaves
326 !%Type block
327 !%Section Maxwell
328 !%Description
329 !% The initial electromagnetic fields can be set by the user
330 !% with the <tt>MaxwellIncidentWaves</tt> block variable.
331 !% The electromagnetic fields have to fulfill the
332 !% Maxwells equations in vacuum.
333 !% For a Maxwell propagation, setting the electric field is sufficient,
334 !% the magnetic field (for plane waves) will be calculated from it as 1/(c.|k|) . (k x E).
335 !%
336 !% Example:
337 !%
338 !% <tt>%MaxwellIncidentWaves
339 !% <br>&nbsp;&nbsp; plane_wave_parser | "field_type"| "k1x" | "k1y" | "k1z" | "E1x" | "E1z" | "E1x"
340 !% <br>&nbsp;&nbsp; plane_wave_mx_function | "field_type"| "E4x" | "E4y" | "E4z" | mx_envelope_name | phase
341 !% <br>&nbsp;&nbsp; bessel_function | "field_type"| A_0 | m | omega | helicity | <math>\theta_{k}</math> | mx_envelope_name | lin_dir
342 !% <br>%</tt>
343 !%
344 !% Field type can be "electric_field" or "vector_potential". Note that in order to couple to an
345 !% electronic system, the <tt>MaxwellCouplingMode</tt> variable needs to be set to a coupling type
346 !% compatible with the requested field type ("electric_field" is compatible with length gauge,
347 !% while "vector_potential" is compatible with velocity gauge and full minimal coupling).
348 !% Otherwise, the field will not be calculated or applied to the electronic Hamiltonian.
349 !%
350 !%Option plane_wave_parser 0
351 !% Parser input modus
352 !%Option plane_wave_mx_function 1
353 !% The incident wave envelope is defined by an mx_function
354 !%Option bessel_function 2
355 !% The incident source is a generalized Bessel beam, parametrized by its amplitude, opening angle, helicity, order and frequency.
356 !% This beam is a solution of Maxwell equations, and inherently circularly polarized and is parametrized by its amplitude,
357 !% opening angle, helicity, order and frequency.
358 !% Please keep in mind, if you set linear polarization lin_dir,
359 !% you will obtain a linearly polarized Bessel beam.
360 !%End
361
362 if (parse_block(namespace, 'MaxwellIncidentWaves', blk) == 0) then
363
364 call messages_print_with_emphasis(msg='Substitution of the electromagnetic incident waves', namespace=namespace)
365
366 ! find out how many lines (i.e. states) the block has
367 nlines = parse_block_n(blk)
368
369 external_waves%number = nlines
370 safe_allocate(external_waves%modus(1:nlines))
371 safe_allocate(external_waves%e_field_string(1:3, 1:nlines))
372 safe_allocate(external_waves%e_field(1:3, 1:nlines))
373 safe_allocate(external_waves%k_vector(1:3, 1:nlines))
374 safe_allocate(external_waves%v_vector(1:3, 1:nlines))
375 safe_allocate(external_waves%mx_function(1:nlines))
376 safe_allocate(external_waves%field_type(1:nlines))
377 safe_allocate(external_waves%pw_phase(1:nlines))
378 external_waves%pw_phase = m_zero
379
380 call external_waves%bessel%init(nlines, 3)
381
382 do il = 1, nlines
383 ncols = parse_block_cols(blk, il - 1)
384 if ((ncols < 5) .or. (ncols > 9)) then
385 message(1) = 'Each line in the MaxwellIncidentWaves block must have five to nine columns.'
386 call messages_fatal(1, namespace=namespace)
387 end if
388
389 ! check input modus e.g. parser of defined functions
390 call parse_block_integer(blk, il - 1, 0, external_waves%modus(il))
391 call parse_block_integer(blk, il - 1, 1, external_waves%field_type(il))
392
393 ! parse formula string
394 if (external_waves%modus(il) == option__maxwellincidentwaves__plane_wave_parser) then
395 do idim = 1, 3
396 call parse_block_string( blk, il - 1, idim + 1, k_string(idim))
397 call parse_block_string( blk, il - 1, 3 + idim + 1, external_waves%e_field_string(idim, il))
398 end do
399 write(message(1), '(a,i2,a) ') 'Substituting electromagnetic incident wave ', il, ' with the expressions: '
400 call messages_info(1, namespace=namespace)
401 do idim = 1, 3
402 write(message(idim), '(6a)') ' Wave vector k('//dims(idim)//') = ', trim(k_string(idim))
403 write(message(idim+1), '(2a)') ' E-field('//dims(idim)//') for t_0 = ', trim(external_waves%e_field_string(idim, il))
404 end do
405 call messages_info(6, namespace=namespace)
406
407 do idim = 1, 3
408 call conv_to_c_string(k_string(idim))
409 call conv_to_c_string(external_waves%e_field_string(idim, il))
410 end do
411
412 x_pos(:) = m_zero
413 x_norm = m_zero
414 do idim = 1, 3
415 call parse_expression(k_vector(idim), dummy(idim), idim, x_pos, x_norm, m_zero, k_string(idim))
416 end do
417
418 k_vector = units_to_atomic(unit_one/units_inp%length, k_vector)
419 k_norm = norm2(k_vector)
420
421 velocity(:) = k_vector(:) / k_norm * p_c * external_waves%c_factor
422 external_waves%k_vector(:,il) = k_vector(:)
423 external_waves%v_vector(:,il) = velocity(:)
424
425 else if (external_waves%modus(il) == option__maxwellincidentwaves__plane_wave_mx_function) then
426 do idim = 1, 3
427 call parse_block_cmplx( blk, il - 1, idim + 1, e_field(idim))
428 end do
429 call parse_block_string( blk, il - 1, 3 + 2, mxf_expression)
430
431 write(message(1), '(a,i2) ') 'Substituting electromagnetic incident wave ', il
432 write(message(2), '(a)' ) 'with the expression: '
433 call messages_info(2, namespace=namespace)
434
435 do idim = 1, 3
436 write(message(idim), '(a,f9.4,sp,f9.4,"i")') ' E-field('//trim(dims(idim))//') complex amplitude = ', &
437 real(e_field(idim)), aimag(e_field(idim))
438 end do
439 write(message(4), '(2a)' ) ' Maxwell wave function name = ', trim(mxf_expression)
440 call messages_info(4, namespace=namespace)
441
442 call mxf_read(external_waves%mx_function(il), namespace, trim(mxf_expression), iex_norm)
443 if (iex_norm /= 0) then
444 write(message(1),'(3A)') 'Ex_norm in the ""', trim(mxf_expression), &
445 '"" field defined in the MaxwellIncidentWaves block'
446 call messages_fatal(1, namespace=namespace)
447 end if
448 if (parse_block_cols(blk, il-1) == 7) then
449 call parse_block_float( blk, il - 1, 3 + 3 , external_waves%pw_phase(il))
450 end if
451 e_field = units_to_atomic(units_inp%energy/units_inp%length, e_field)
452 k_vector(1:3) = external_waves%mx_function(il)%k_vector(1:3)
453 k_norm = norm2(k_vector)
454
455 k_dot_e = real(dot_product(k_vector, e_field), real64)
456 if (abs(k_dot_e) > test_limit) then
457 write(message(1), '(a) ') 'The wave vector k or its electric field are not perpendicular. '
458 write(message(2), '(a,f8.3,a)' ) 'Their dot product yields the magnitude', abs(k_dot_e) , ' while'
459 write(message(3), '(a,f8.3,a)' ) 'tolerance is ', test_limit ,'.'
460 call messages_fatal(3, namespace=namespace)
461 end if
462 if (k_norm < 1e-10) then
463 message(1) = 'The k vector is not set correctly: |k|~0 .'
464 call messages_fatal(1, namespace=namespace)
465 end if
466
467 external_waves%e_field(:,il) = e_field(:)
468 external_waves%k_vector(:,il) = k_vector(:)
469 external_waves%v_vector(:,il) = k_vector(:) / k_norm * p_c * external_waves%c_factor
470
471 else if (external_waves%modus(il) == option__maxwellincidentwaves__bessel_function) then
472 call parse_block_float( blk, il - 1, 2 , external_waves%bessel%amp(il))
473 call parse_block_integer( blk, il - 1, 3 , external_waves%bessel%m_order(il))
474 call parse_block_float( blk, il - 1, 4 , external_waves%bessel%omega(il))
475 call parse_block_integer( blk, il - 1, 5 , external_waves%bessel%helicity(il))
476 call parse_block_float( blk, il - 1, 6 , external_waves%bessel%theta_k(il))
477 if (parse_block_cols(blk, il-1) > 7) then
478 call parse_block_string( blk, il - 1, 7 , mxf_expression)
479 external_waves%bessel%envelope(il) = .true.
480 call mxf_read(external_waves%mx_function(il), namespace, trim(mxf_expression), iex_norm)
481 end if
482 if (parse_block_cols(blk, il-1) == 9) then
483 call parse_block_integer( blk, il - 1, 8 , external_waves%bessel%lin_dir(il))
484 end if
485
486 write(message(1), '(a,i2) ') 'Incident Bessel Beam', il
487 call messages_info(1, namespace=namespace)
488
489 if (abs(external_waves%bessel%helicity(il)) /= 1) then
490 write(message(1),'(A)') 'Helicity has to be either +1 or -1 !'
491 call messages_fatal(1, namespace=namespace)
492 end if
493
494 write(message(1), '(a,f5.3)' ) ' Bessel Amplitude ', external_waves%bessel%amp(il)
495 write(message(2), '(a,i2)' ) ' Bessel Order m', external_waves%bessel%m_order(il)
496 write(message(3), '(a,f5.3)' ) ' Bessel Frequency ', external_waves%bessel%omega(il)
497 write(message(4), '(a,i2)' ) ' Bessel Helicity ', external_waves%bessel%helicity(il)
498 write(message(5), '(a,f5.3)' ) ' Bessel Opening Angle ', external_waves%bessel%theta_k(il)
499 call messages_info(4, namespace=namespace)
500
501 if (external_waves%bessel%lin_dir(il)/= 0) then
502 write(message(5), '(a,i2)' ) ' Bessel is Linearly Polarized in Direction : ', external_waves%bessel%lin_dir(il)
503 call messages_info(4, namespace=namespace)
504 end if
505
506 end if
507 end do
508
509 call parse_block_end(blk)
510
511 call messages_print_with_emphasis(namespace=namespace)
512 else
513 external_waves%number = 0
514
515 end if
516
517 !%Variable BesselBeamAxisShift
518 !%Type block
519 !%Section Maxwell
520 !%Description
521 !% The BesselBeamAxisShift block allows to shift the Bessel Beam, which is centered at (0,0,0) as default.
522 !% Selected position point will be used as the new center of the Bessel Beam.
523 !% When defining a BesselBeamAxisShift, please make sure to define a shift for each Bessel source you use,
524 !% then it is possible to tell which source is shifted according to which BesselShift, respectively.
525 !% <tt>%BesselBeamAxisShift
526 !% <br>&nbsp;&nbsp; 0.0 | 2.0 | 5.0
527 !% <br>%</tt>
528 !%
529 !%End
530
531 if (parse_block(namespace, 'BesselBeamAxisShift', blk) == 0) then
532 nlines = parse_block_n(blk)
533 ncols = parse_block_cols(blk,0)
534 if (ncols /= 3 ) then
535 message(1) = 'BesselBeamAxisShift must have 3 columns.'
536 call messages_fatal(1, namespace=namespace)
537 end if
538
539 do il = 1, nlines
540 do idim = 1, 3
541 call parse_block_float(blk, 0, idim-1, external_waves%bessel%shift(il, idim), units_inp%length)
542 end do
543 end do
544
545 call parse_block_end(blk)
546 end if
547
548 call profiling_out('EXTERNAL_WAVES_INIT')
549
550 pop_sub(external_waves_init)
551 end subroutine external_waves_init
552
553 ! ---------------------------------------------------------
554 subroutine external_waves_end(external_waves)
555 type(external_waves_t), intent(inout) :: external_waves
556
557 push_sub(external_waves_end)
558
559 if (external_waves%output_from_point) then
560 call io_close(external_waves%out_file)
561 safe_deallocate_a(external_waves%selected_point_coordinate)
562 safe_deallocate_a(external_waves%selected_point_field)
563 end if
564
565 safe_deallocate_a(external_waves%bessel%shift)
566 safe_deallocate_a(external_waves%points_map)
567 safe_deallocate_a(external_waves%modus)
568 safe_deallocate_a(external_waves%e_field_string)
569 safe_deallocate_a(external_waves%k_vector)
570 safe_deallocate_a(external_waves%v_vector)
571 safe_deallocate_a(external_waves%e_field)
572 safe_deallocate_a(external_waves%mx_function)
573 safe_deallocate_a(external_waves%pw_phase)
574
575 if (accel_is_enabled()) then
576 call accel_release_buffer(external_waves%buff_map)
577 end if
578
579 pop_sub(external_waves_end)
580 end subroutine external_waves_end
581
582 ! ---------------------------------------------------------
584 subroutine external_waves_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
585 type(external_waves_t), intent(inout) :: external_waves
586 real(real64), intent(in) :: time
587 class(mesh_t), intent(in) :: mesh
588 integer, intent(in) :: type_of_field
589 real(real64), intent(out) :: out_field_total(:, :)
590 type(derivatives_t), optional, intent(in):: der
591
592
593 push_sub(external_waves_eval)
594
595 call profiling_in('EXTERNAL_WAVES_EVAL')
596
597 out_field_total = m_zero
598
599 call plane_waves_eval(external_waves, time, mesh, type_of_field, out_field_total, der=der)
600 call bessel_source_eval(external_waves, time, mesh, type_of_field, out_field_total, der=der)
601
602 call profiling_out('EXTERNAL_WAVES_EVAL')
603
604 pop_sub(external_waves_eval)
605 end subroutine external_waves_eval
606
607 ! ---------------------------------------------------------
609 subroutine plane_waves_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
610 type(external_waves_t), intent(inout) :: external_waves
611 real(real64), intent(in) :: time
612 class(mesh_t), intent(in) :: mesh
613 integer, intent(in) :: type_of_field
614 real(real64), intent(out) :: out_field_total(:, :)
615 type(derivatives_t), optional, intent(in):: der
616
617 integer :: wn
618 real(real64), allocatable :: pw_field(:,:), ztmp(:,:), b_field_aux(:,:)
619 real(real64) :: p_c_
620 integer, allocatable :: indices_pw_parser(:)
621 integer, allocatable :: indices_mx_ftc(:)
622 integer :: n_plane_waves, n_points
623
624 push_sub(plane_waves_eval)
625
626 call profiling_in('PLANE_WAVES_EVAL')
627
628 indices_pw_parser = pack([(wn, wn = 1,external_waves%number)], &
629 external_waves%modus == option__maxwellincidentwaves__plane_wave_parser)
630
631 indices_mx_ftc = pack([(wn, wn = 1,external_waves%number)], &
632 external_waves%modus == option__maxwellincidentwaves__plane_wave_mx_function)
633
634 n_plane_waves = size(indices_pw_parser) + size(indices_mx_ftc)
635
636 p_c_ = p_c * external_waves%c_factor
637
638 if (n_plane_waves == 0) then
639 call profiling_out('PLANE_WAVES_EVAL')
640 pop_sub(plane_waves_eval)
641 return
642 end if
643
644 if (type_of_field == b_field .and. any(external_waves%field_type == e_field_vector_potential)) then
645 assert(present(der))
646 safe_allocate(ztmp(mesh%np, size(out_field_total, dim=2)))
647 n_points = mesh%np_part
648 else
649 n_points = mesh%np
650 end if
651 safe_allocate(pw_field(n_points, size(out_field_total, dim=2)))
652 pw_field(:,:) = m_zero
653
654 ! The E_field (or A_field, rescaled later) we calculate always
655 do wn = 1, external_waves%number
656
657 select case(external_waves%modus(wn))
658 case (option__maxwellincidentwaves__plane_wave_parser)
659 call pw_parsed_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
660
661 case (option__maxwellincidentwaves__plane_wave_mx_function)
662 call pw_mx_function_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
663 end select
664
665 select case (external_waves%field_type(wn))
666
667 case(e_field_electric)
668
669 select case (type_of_field)
670 case (e_field)
671 out_field_total(1:mesh%np,:) = out_field_total(1:mesh%np,:) + pw_field(1:mesh%np,:)
672 case (vector_potential)
673 call messages_not_implemented("Calculation of a vector potential from a plane wave specified as electric field")
674 case (b_field)
675 safe_allocate(b_field_aux(1:mesh%np, 1:mesh%box%dim))
676 call get_pw_b_field(external_waves, mesh, wn, pw_field, b_field_aux)
677 out_field_total(:,:) = out_field_total(:,:) + b_field_aux(:,:)
678 safe_deallocate_a(b_field_aux)
679 end select
680
682
683 select case (type_of_field)
684 case (e_field)
685 call messages_not_implemented("Calculation of an electric field from a plane wave specified as vector potential")
686 case (vector_potential)
687 out_field_total(1:mesh%np,:) = out_field_total(1:mesh%np,:) - m_one/p_c_ * pw_field(1:mesh%np,1:3)
688 case (b_field)
689 call dderivatives_curl(der, pw_field(1:mesh%np_part,1:3), ztmp(1:mesh%np,1:3), set_bc = .false.)
690 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) - m_one/p_c_ * ztmp(1:mesh%np, 1:3)
691 end select
692
693 end select
694 end do
695
696 safe_deallocate_a(pw_field)
697 safe_deallocate_a(ztmp)
698 call profiling_out('PLANE_WAVES_EVAL')
699
700 pop_sub(plane_waves_eval)
701
702 end subroutine plane_waves_eval
703
704 ! ---------------------------------------------------------
706 subroutine pw_parsed_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
707 type(external_waves_t), intent(inout) :: external_waves
708 integer, intent(in) :: wn
709 real(real64), intent(in) :: time
710 class(mesh_t), intent(in) :: mesh
711 integer, intent(in) :: n_points
712 real(real64), intent(out) :: pw_field(:,:)
713
714 real(real64) :: x_prop(3), x_norm
715 real(real64) :: velocity_time(3)
716 real(real64) :: parsed_field(3)
717 real(real64) :: dummy(3)
718 integer :: idim, ip
719
720 velocity_time(:) = external_waves%v_vector(1:3, wn) * time
721 do idim = 1, 3
722 call parse_expression(parsed_field(idim), dummy(idim), 3, x_prop, x_norm, m_zero, &
723 external_waves%e_field_string(idim, wn))
724 do ip = 1, n_points
725 x_prop = mesh%x(ip, :) - velocity_time
726 x_norm = norm2(x_prop(1:3))
727 pw_field(ip, idim) = units_to_atomic(units_inp%energy/units_inp%length, parsed_field(idim))
728 end do
729 end do
730
731 end subroutine pw_parsed_evaluation
732
733 ! ---------------------------------------------------------
735 subroutine pw_mx_function_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
736 type(external_waves_t), intent(inout) :: external_waves
737 integer, intent(in) :: wn
738 real(real64), intent(in) :: time
739 class(mesh_t), intent(in) :: mesh
740 integer, intent(in) :: n_points
741 real(real64), intent(out) :: pw_field(:,:)
742
743 real(real64) :: x_prop(3), x_norm
744 real(real64) :: velocity_time(3)
745 complex(real64) :: efield_ip(3)
746 complex(real64) :: e0(3)
747 integer :: ip
748
749 velocity_time(:) = external_waves%v_vector(1:3, wn) * time
750 e0(:) = external_waves%e_field(1:3, wn)
751 do ip = 1, n_points
752 x_prop = mesh%x(ip, :) - velocity_time
753 x_norm = norm2(x_prop(1:3))
754 efield_ip = mxf(external_waves%mx_function(wn), x_prop, external_waves%pw_phase(wn))
755 pw_field(ip, :) = real(e0(1:3) * efield_ip, real64)
756 end do
757
758 end subroutine pw_mx_function_evaluation
759
760 ! ---------------------------------------------------------
762 subroutine get_pw_b_field(external_waves, mesh, pwidx, e_field, b_field)
763 type(external_waves_t), intent(in) :: external_waves
764 class(mesh_t), intent(in) :: mesh
765 real(real64), intent(in) :: e_field(:,:)
766 real(real64), intent(out) :: b_field(:,:)
767 integer, intent(in) :: pwidx
768
769 real(real64) :: k_vector(3), k_vector_abs
770 real(real64) :: velocity(3)
771 real(real64) :: P_c_
772 complex(real64) :: e0(3)
773 integer :: ip
774
775 velocity = external_waves%v_vector(1:3, pwidx)
776 k_vector = external_waves%k_vector(1:3, pwidx)
777 k_vector_abs = norm2(k_vector(1:3))
778 e0 = external_waves%e_field(1:3, pwidx)
779 p_c_ = p_c * external_waves%c_factor
780
781 b_field = m_zero
782 do ip = 1, mesh%np
783 b_field(ip, :) = m_one/(p_c_ * k_vector_abs) * dcross_product(k_vector, e_field(ip, :))
784 end do
785
786 end subroutine get_pw_b_field
787
788 ! ---------------------------------------------------------
790 subroutine bessel_source_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
791 type(external_waves_t), intent(inout) :: external_waves
792 real(real64), intent(in) :: time
793 class(mesh_t), intent(in) :: mesh
794 integer, intent(in) :: type_of_field
795 real(real64), intent(out) :: out_field_total(:, :)
796 type(derivatives_t), optional, intent(in):: der
797
798 real(real64) :: dmin, omega, k_vector(3), c_factor
799 integer :: iline, wn, pos_index, n_points, rankmin
800 real(real64), allocatable :: shift(:,:)
801 complex(real64), allocatable :: bessel_field_total(:,:), ztmp(:,:), vec_pot(:,:)
802 integer, allocatable :: indices_bessel_ftc(:)
803 type(mxf_t) :: envelope_mxf
804
805 push_sub(bessel_source_eval)
806
807 call profiling_in('BESSEL_SOURCE_EVAL')
808
809 indices_bessel_ftc = pack([(wn, wn = 1,external_waves%number)], &
810 external_waves%modus == option__maxwellincidentwaves__bessel_function)
811
812 if (size(indices_bessel_ftc) == 0) then
813 call profiling_out('BESSEL_SOURCE_EVAL')
814 pop_sub(bessel_source_eval)
815 return
816 end if
817
818 ! Check if the BesselBeamAxisShift is defined for every incoming Bessel Beam.
819 if (allocated(external_waves%bessel%shift) .and. &
820 size(external_waves%bessel%shift(:,1)) /= size(indices_bessel_ftc)) then
821 message(1) = 'Number of BesselBeamAxisShift defined in input file'
822 message(2) = 'does not match the number of Bessel beams.'
823 call messages_fatal(2)
824 end if
825
826 safe_allocate(shift(size(indices_bessel_ftc), 3))
827 if (allocated(external_waves%bessel%shift)) then
828 shift = external_waves%bessel%shift
829 else
830 shift = m_zero
831 end if
832
833 if (type_of_field == b_field) then
834 assert(present(der))
835 safe_allocate(vec_pot(mesh%np_part, size(out_field_total, dim=2)))
836 safe_allocate(ztmp(size(out_field_total, dim=1), size(out_field_total, dim=2)))
837 n_points = mesh%np_part ! needed for curl
838 else
839 n_points = mesh%np
840 end if
841
842
843 safe_allocate(bessel_field_total(1:n_points, 1:3))
844 bessel_field_total = m_zero
845
846 do iline = 1, size(indices_bessel_ftc)
847 wn = indices_bessel_ftc(iline)
848 omega = external_waves%bessel%omega(wn)
849 k_vector = external_waves%mx_function(wn)%k_vector
850 c_factor = external_waves%c_factor
851 envelope_mxf = external_waves%mx_function(wn)
852
853 call external_waves%bessel%function(wn, shift, mesh, n_points, time, k_vector, c_factor, envelope_mxf, bessel_field_total)
854
855 select case (external_waves%field_type(wn))
856
858 ! interpreting bessel_field_total as a vector potential (as requested by the user)
859 select case (type_of_field)
860 case (e_field)
861 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) + real(m_zi*omega*bessel_field_total(1:mesh%np,1:3))
862 case (vector_potential)
863 ! For the vector potential, we multiply by -1/c becuase of the electronic Hamiltonian
864 ! being in Gaussian units
865 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) - m_one/p_c * real(bessel_field_total(1:mesh%np,1:3))
866 case (b_field)
867 call zderivatives_curl(der, bessel_field_total(1:mesh%np_part,1:3), ztmp(1:mesh%np,1:3), set_bc = .false.)
868 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) - m_one/p_c * real(ztmp(1:mesh%np, 1:3))
869 end select
870
871 case(e_field_electric)
872 ! interpreting bessel_field_total as an electric field (as requested by the user)
873 select case (type_of_field)
874 case (e_field)
875 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) + real(bessel_field_total(1:mesh%np,1:3))
876 case (vector_potential)
877 ! We calculate the vector potential as real(E/i*omega),
878 ! and convert it to the proper units by multiplying by -1/c
879 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) - m_one/p_c * &
880 real(bessel_field_total(1:mesh%np,1:3)/M_zI/omega)
881 case (b_field)
882 vec_pot(1:mesh%np_part,1:3) = - m_one/p_c * real(bessel_field_total(1:mesh%np_part,1:3)/m_zi/omega)
883 call zderivatives_curl(der, vec_pot(1:mesh%np_part,1:3), ztmp(1:mesh%np,1:3), set_bc = .false.)
884 out_field_total(1:mesh%np,1:3) = out_field_total(1:mesh%np,1:3) - real(ztmp(1:mesh%np, 1:3))
885 end select
886
887 end select
888 end do
889
890 if (external_waves%output_from_point) then
891 pos_index = mesh_nearest_point(mesh, external_waves%selected_point_coordinate(1:3), dmin, rankmin)
892 if (mesh%mpi_grp%rank == rankmin) then
893 external_waves%selected_point_field(:) = out_field_total(pos_index,:)
894 write(external_waves%out_file, "(4F14.8, 4x)") time, external_waves%selected_point_field(:)
895 end if
896 end if
897
898 safe_deallocate_a(shift)
899 safe_deallocate_a(ztmp)
900 safe_deallocate_a(vec_pot)
901 safe_deallocate_a(bessel_field_total)
902 call profiling_out('BESSEL_SOURCE_EVAL')
903
904 pop_sub(bessel_source_eval)
905
906 end subroutine bessel_source_eval
907
908 ! ---------------------------------------------------------
910 subroutine bessel_beam_function(this, iline, shift, mesh, n_points, time, k_vector, c_factor, envelope_mxf, bessel_field)
911 class(bessel_beam_t) :: this
912 integer, intent(in) :: iline
913 real(real64), intent(in) :: shift(:,:), time, k_vector(3), c_factor
914 class(mesh_t), intent(in) :: mesh
915 integer, intent(in) :: n_points
916 type(mxf_t), intent(in) :: envelope_mxf
917 complex(real64), intent(out) :: bessel_field(:,:)
918
919 real(real64) :: pos(3), temp, temp2, temp3, rho, phi_rho, wigner(3)
920 real(real64) :: hel, theta, omega, amp, kappa, proj, k_norm, velocity_time(3), x_prop(3)
921 complex(real64) :: efield_ip(3)
922 real(real64) :: bessel_plus, bessel_minus
923 integer :: ip, mm, pol
924
925 assert(iline <= size(this%omega))
926 hel = real(this%helicity(iline), real64)
927 theta = this%theta_k(iline)
928 mm = this%m_order(iline)
929 amp = this%amp(iline) / sqrt(m_two)
930 omega = this%omega(iline)
931 proj = omega * cos(theta) / p_c ! k_z
932 kappa = sqrt(omega**2 - (proj* p_c)**2) ! parse omega
933 ! Set Wigner Coefficients from theta
934 wigner(1) = hel * sin(theta) / sqrt(m_two) ! mu = 0
935 wigner(2) = 0.5 * (1 + hel * cos(theta)) ! mu = 1
936 wigner(3) = 0.5 * (1 - hel * cos(theta)) ! mu = -1
937 proj = omega * cos(theta) / p_c ! k_z
938 pol = this%lin_dir(iline) ! Incoming polarization corresponding to beam in question
939
940 do ip = 1, n_points
941 pos(:) = mesh%x(ip, :) - shift(iline,:)
942 rho = norm2(pos(1:2))
943 phi_rho = atan2(pos(2) , pos(1))
944 temp = proj * pos(3) + phi_rho * (mm + 1) - omega*time ! temp, temp2 and temp3 should be unitless
945 temp2 = proj * pos(3) + phi_rho * (mm - 1) - omega*time
946 temp3 = proj * pos(3) + phi_rho * mm - omega*time
947 bessel_plus = loct_bessel(mm+1, kappa * rho / p_c)
948 bessel_minus = loct_bessel(mm-1, kappa * rho / p_c)
949
950 ! Calculate complex Ax component, if generalized bessel OR x -polarized bessel
951 if (pol /= 2) then
952 bessel_field(ip, 1) = amp * (exp(m_zi*temp) * wigner(3) * bessel_plus + exp(m_zi*temp2) * wigner(2) * bessel_minus)
953 end if
954 ! Calculate complex Ay component if generalized bessel OR y -polarized bessel
955 if (pol/=1) then
956 bessel_field(ip, 2) = m_zi * amp * (-exp(m_zi*temp) * wigner(3) * bessel_plus + &
957 exp(m_zi*temp2) * wigner(2) * bessel_minus)
958 end if
959 ! Calculate complex Az component, only iff generalized Bessel
960 if (pol == 0) then
961 bessel_field(ip, 3) = - m_zi * amp * sqrt(m_two) * wigner(1) * loct_bessel(mm, kappa * rho / p_c) * exp(m_zi*temp3)
962 end if
963
964 if (this%envelope(iline)) then
965 k_norm = norm2(k_vector)
966 velocity_time = k_vector * p_c * c_factor * time / k_norm
967 x_prop(:) = pos(:) - velocity_time(:)
968 efield_ip = mxf_envelope_eval(envelope_mxf, x_prop)
969 bessel_field(ip, :) = bessel_field(ip, :) * real(efield_ip, real64)
970 end if
971
972 end do
973
974 end subroutine bessel_beam_function
975
977 subroutine bessel_beam_init(this, nlines, dim)
978 class(bessel_beam_t), intent(out) :: this
979 integer, intent(in) :: nlines
980 integer, intent(in) :: dim
981
982 safe_allocate(this%amp(1: nlines))
983 safe_allocate(this%omega(1:nlines))
984 safe_allocate(this%theta_k(1:nlines))
985 safe_allocate(this%m_order(1:nlines))
986 safe_allocate(this%helicity(1:nlines))
987 safe_allocate(this%shift(1:nlines, 1:dim))
988 safe_allocate(this%envelope(1:nlines))
989 safe_allocate(this%lin_dir(1:nlines))
990 this%amp = m_zero
991 this%omega = m_zero
992 this%theta_k = m_zero
993 this%m_order = m_zero
994 this%helicity = m_zero
995 this%shift = m_zero
996 this%lin_dir = m_zero
997 this%envelope = .false.
998
999 end subroutine bessel_beam_init
1000
1002 subroutine bessel_beam_finalize(this)
1003 type(bessel_beam_t), intent(inout) :: this
1004
1005 safe_deallocate_a(this%amp)
1006 safe_deallocate_a(this%omega)
1007 safe_deallocate_a(this%theta_k)
1008 safe_deallocate_a(this%m_order)
1009 safe_deallocate_a(this%helicity)
1010 safe_deallocate_a(this%shift)
1011 safe_deallocate_a(this%lin_dir)
1012 safe_deallocate_a(this%envelope)
1013
1014 end subroutine bessel_beam_finalize
1015
1016end module external_waves_oct_m
1017
1018!! Local Variables:
1019!! mode: f90
1020!! coding: utf-8
1021!! End:
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
double atan2(double __y, double __x) __attribute__((__nothrow__
subroutine, public accel_release_buffer(this)
Definition: accel.F90:1246
pure logical function, public accel_is_enabled()
Definition: accel.F90:400
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public zderivatives_curl(der, ff, op_ff, ghost_update, set_bc)
apply the curl operator to a vector of mesh functions
subroutine, public dderivatives_curl(der, ff, op_ff, ghost_update, set_bc)
apply the curl operator to a vector of mesh functions
subroutine, public load_external_waves(partners, namespace)
subroutine bessel_beam_function(this, iline, shift, mesh, n_points, time, k_vector, c_factor, envelope_mxf, bessel_field)
. Evaluation of the Bessel beam expression
subroutine external_waves_update_quantity(this, iq)
subroutine, public bessel_source_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
Calculation of Bessel beam from parsed formula.
subroutine pw_mx_function_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
Evaluate expression for plane wave that uses predefeined Maxwell function.
subroutine bessel_beam_init(this, nlines, dim)
. Initialization of Bessel beam arrays
subroutine external_waves_copy_quantities_to_interaction(partner, interaction)
subroutine, public external_waves_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
Calculation of external waves from parsed formula.
class(external_waves_t) function, pointer external_waves_constructor(namespace)
subroutine, public external_waves_end(external_waves)
subroutine pw_parsed_evaluation(external_waves, wn, time, mesh, n_points, pw_field)
Evaluate expression for plane wave parsing the provided formula.
subroutine plane_waves_eval(external_waves, time, mesh, type_of_field, out_field_total, der)
Calculation of plane waves from parsed formula.
subroutine get_pw_b_field(external_waves, mesh, pwidx, e_field, b_field)
Calculation of magnetic field for a plane wave.
subroutine external_waves_init_interaction_as_partner(partner, interaction)
subroutine, public external_waves_init(external_waves, namespace)
Here, plane wave is evaluated from analytical formulae on grid.
subroutine bessel_beam_finalize(this)
. Finalize Bessel beam arrays
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_zero
Definition: global.F90:187
complex(real64), parameter, public m_zi
Definition: global.F90:201
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:223
real(real64), parameter, public m_one
Definition: global.F90:188
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module implements the index, used for the mesh points.
Definition: index.F90:122
integer, parameter, public mxll_vec_pot_to_matter
integer, parameter, public mxll_b_field_to_matter
integer, parameter, public mxll_e_field_to_matter
This module defines the abstract interaction_t class, and some auxiliary classes for interactions.
This module defines classes and functions for interaction partners.
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:354
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
integer, parameter, public e_field_electric
Definition: lasers.F90:176
integer, parameter, public e_field_vector_potential
Definition: lasers.F90:176
complex(real64) function mxf_envelope_eval(f, x)
Evaluation of envelope itself.
subroutine, public mxf_read(f, namespace, function_name, ierr)
This function initializes "f" from the MXFunctions block.
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer function, public mesh_nearest_point(mesh, pos, dmin, rankmin)
Returns the index of the point which is nearest to a given vector position pos.
Definition: mesh.F90:380
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:930
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1125
character(len=512), private msg
Definition: messages.F90:165
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:543
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
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
Some general things and nomenclature:
Definition: par_vec.F90:171
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:618
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
Definition: profiling.F90:623
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
Definition: profiling.F90:552
This module defines the quantity_t class and the IDs for quantities, which can be exposed by a system...
Definition: quantity.F90:137
integer, parameter, public b_field
Definition: quantity.F90:146
integer, parameter, public vector_potential
Definition: quantity.F90:146
integer, parameter, public e_field
Definition: quantity.F90:146
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
class representing derivatives
abstract class for general interaction partners
surrogate interaction class to avoid circular dependencies between modules.
Lorenz force between a systems of particles and an electromagnetic field.
Describes mesh distribution to nodes.
Definition: mesh.F90:186
class to transfer a Maxwell B field to a matter system
class to transfer a Maxwell field to a medium
class to transfer a Maxwell vector potential to a medium
int true(void)