Octopus
hamiltonian_mxll.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
22 use accel_oct_m
23 use batch_oct_m
26 use cube_oct_m
27 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
34 use, intrinsic :: iso_fortran_env
36 use math_oct_m
39 use mesh_oct_m
43 use parser_oct_m
49
50 implicit none
51
52 private
53 public :: &
72
74 integer :: dim
76 logical :: adjoint = .false.
77
78 real(real64) :: current_time
79 logical :: apply_packed
80
81 logical :: time_zero
82
83 type(nl_operator_t), pointer :: operators(:)
84
85 type(bc_mxll_t) :: bc
86 type(derivatives_t), pointer, private :: der
87 type(states_mxll_t), pointer :: st
88
89 integer :: rs_sign
90
91 logical :: propagation_apply = .false.
92
93 integer, pointer :: rs_state_fft_map(:,:,:)
94 integer, pointer :: rs_state_fft_map_inv(:,:)
95
96 logical :: mx_ma_coupling = .false.
97 logical :: mx_ma_coupling_apply = .false.
98 integer :: mx_ma_trans_field_calc_method
99 logical :: mx_ma_trans_field_calc_corr = .false.
100 integer :: mx_ma_coupling_points_number
101 real(real64), allocatable :: mx_ma_coupling_points(:,:)
102 integer, allocatable :: mx_ma_coupling_points_map(:)
103 integer :: mx_ma_coupling_order
104 logical :: ma_mx_coupling = .false.
105 logical :: ma_mx_coupling_apply = .false.
106
107 logical :: bc_add_ab_region = .false.
108 logical :: bc_zero = .false.
109 logical :: bc_constant = .false.
110 logical :: bc_mirror_pec = .false.
111 logical :: bc_mirror_pmc = .false.
112 logical :: bc_periodic = .false.
113 logical :: bc_plane_waves = .false.
114 logical :: bc_medium = .false.
115
116 logical :: plane_waves = .false.
117 logical :: plane_waves_apply = .false.
118 logical :: spatial_constant = .false.
119 logical :: spatial_constant_apply = .false.
120 logical :: spatial_constant_propagate = .false.
121
122 logical :: calc_medium_box = .false.
123 type(single_medium_box_t), allocatable :: medium_boxes(:)
124 logical :: medium_boxes_initialized = .false.
125
127 integer :: operator
128 logical :: current_density_ext_flag = .false.
129 logical :: current_density_from_medium = .false.
130
131 type(energy_mxll_t) :: energy
132
133 logical :: cpml_hamiltonian = .false.
134
135 logical :: diamag_current = .false.
136 real(real64) :: c_factor
137 real(real64) :: current_factor
138
139 type(cube_t) :: cube
140 type(mesh_cube_parallel_map_t) :: mesh_cube_map
141
142 contains
143 procedure :: update_span => hamiltonian_mxll_span
144 procedure :: dapply => dhamiltonian_mxll_apply
145 procedure :: zapply => zhamiltonian_mxll_apply
146 procedure :: dmagnus_apply => dhamiltonian_mxll_magnus_apply
147 procedure :: zmagnus_apply => zhamiltonian_mxll_magnus_apply
148 procedure :: is_hermitian => hamiltonian_mxll_hermitian
149 end type hamiltonian_mxll_t
150
151 integer, public, parameter :: &
152 FARADAY_AMPERE = 1, &
154 mxll_simple = 3
155
156contains
157
158 ! ---------------------------------------------------------
160 subroutine hamiltonian_mxll_init(hm, namespace, gr, st)
161 type(hamiltonian_mxll_t), intent(inout) :: hm
162 type(namespace_t), intent(in) :: namespace
163 type(grid_t), target, intent(inout) :: gr
164 type(states_mxll_t), target, intent(inout) :: st
165
168
169 call profiling_in('HAMILTONIAN_INIT')
170
171 hm%dim = st%dim
172 hm%st => st
173
174 assert(associated(gr%der%lapl))
175
176 hm%operators(1:3) => gr%der%grad(1:3) ! cross product for Maxwell calculation needs dimension >= 2
177 hm%der => gr%der
178 hm%rs_sign = st%rs_sign
180 hm%mx_ma_coupling_apply = .false.
181 hm%mx_ma_coupling = .false.
182 hm%ma_mx_coupling_apply = .false.
183 hm%ma_mx_coupling = .false.
185 !%Variable MaxwellHamiltonianOperator
186 !%Type integer
187 !%Default faraday_ampere
188 !%Section Maxwell
189 !%Description
190 !% With this variable the the Maxwell Hamiltonian operator can be selected
191 !%Option faraday_ampere 1
192 !% The propagation operation in vacuum with Spin 1 matrices without Gauss law condition.
193 !%Option faraday_ampere_medium 2
194 !% The propagation operation in medium with Spin 1 matrices without Gauss law condition
195 !%Option simple 3
196 !% A simpler implementation of the Hamiltonian, including PML. It does not use an extra
197 !% transformation to (potentially) 6-element vectors, but uses directly the Riemann-Silberstein
198 !% vector as a variable.
199 !%End
200 call parse_variable(namespace, 'MaxwellHamiltonianOperator', faraday_ampere, hm%operator)
202 if (hm%operator == faraday_ampere_medium) then
203 ! TODO: define this operator automatically if there is a linear medium system present
204 hm%dim = 2*hm%dim
205 hm%calc_medium_box = .true.
206 end if
208 !%Variable ExternalCurrent
209 !%Type logical
210 !%Default no
211 !%Section Maxwell
212 !%Description
213 !% If an external current density will be used.
214 !%End
215 call parse_variable(namespace, 'ExternalCurrent', .false., hm%current_density_ext_flag)
217 hm%plane_waves_apply = .false.
218 hm%spatial_constant_apply = .false.
219 hm%spatial_constant_propagate = .true. ! only used if spatially constant field is used
221 hm%propagation_apply = .false.
223 !%Variable SpeedOfLightFactor
224 !%Type float
225 !%Default 1.0
226 !%Section Maxwell
227 !%Description
228 !% Fictitous factor to modify the speed of light in vacuum.
229 !% Note: the proper way to handle linear media with a certain refractive index
230 !% is by the user of the linear_medium system.
231 !%End
232 call parse_variable(namespace, 'SpeedOfLightFactor', m_one, hm%c_factor)
234 !%Variable CurrentDensityFactor
235 !%Type float
236 !%Default 1.0
237 !%Section Maxwell
238 !%Description
239 !% Fictitous factor to modify the current density coming from partner systems.
240 !% Note: This factor does not affect the external current density prescribed by the
241 !% <tt>UserDefinedMaxwellExternalCurrent</tt> block.
242 !%End
243 call parse_variable(namespace, 'CurrentDensityFactor', m_one, hm%current_factor)
245 hm%rs_state_fft_map => st%rs_state_fft_map
246 hm%rs_state_fft_map_inv => st%rs_state_fft_map_inv
247
248 call parse_variable(namespace, 'StatesPack', .true., hm%apply_packed)
249
250 call parse_variable(namespace, 'TimeZero', .false., hm%time_zero)
251 if (hm%time_zero) call messages_experimental('TimeZero')
252
253 call hm%update_span(gr%spacing(1:gr%der%dim), m_zero, namespace)
254
255 call profiling_out('HAMILTONIAN_INIT')
256 pop_sub(hamiltonian_mxll_init)
257 end subroutine hamiltonian_mxll_init
258
259
260 ! ---------------------------------------------------------
261 subroutine hamiltonian_mxll_end(hm)
262 type(hamiltonian_mxll_t), intent(inout) :: hm
263
264 integer :: il
265
266 push_sub(hamiltonian_mxll_end)
267
268 call profiling_in("HAMILTONIAN_MXLL_END")
269
270 nullify(hm%operators)
271
272 call bc_mxll_end(hm%bc)
273
274 if (allocated(hm%medium_boxes)) then
275 do il = 1, size(hm%medium_boxes)
276 call single_medium_box_end(hm%medium_boxes(il))
277 end do
278 end if
279
280 call profiling_out("HAMILTONIAN_MXLL_END")
281
282 pop_sub(hamiltonian_mxll_end)
283 end subroutine hamiltonian_mxll_end
284
285
286 ! ---------------------------------------------------------
287 logical function hamiltonian_mxll_hermitian(hm)
288 class(hamiltonian_mxll_t), intent(in) :: hm
289
291
292 if (any(hm%bc%bc_ab_type == option__maxwellabsorbingboundaries__cpml)) then
293 ! With PML, the Hamiltonian is not purely Hermitian
295 else
297 end if
298
300 end function hamiltonian_mxll_hermitian
301
302
303 ! ---------------------------------------------------------
304 subroutine hamiltonian_mxll_span(hm, delta, emin, namespace)
305 class(hamiltonian_mxll_t), intent(inout) :: hm
306 real(real64), intent(in) :: delta(:)
307 real(real64), intent(in) :: emin
308 type(namespace_t), intent(in) :: namespace
309
310 integer :: i
311 real(real64) :: emax, fd_factor
312 real(real64), parameter :: fd_factors(4) = [1.0_real64, 1.3723_real64, 1.5861_real64, 1.7307_real64]
313
314 push_sub(hamiltonian_mxll_span)
315
316 ! the discretization of the gradient operator with finite differences of different order
317 ! gives different prefactors, they can be obtained by Fourier transform of the stencil
318 ! and taking the maximum of the resulting expressions
319 if (hm%der%stencil_type == der_star .and. hm%der%order <= 4) then
320 fd_factor = fd_factors(hm%der%order)
321 else
322 ! if we use a different stencil, use pi as an upper bound from the continuous solution
323 fd_factor = m_pi
324 end if
325
326 emax = m_zero
327 do i = 1, size(delta)
328 emax = emax + m_one / delta(i)**2
329 end do
330 emax = p_c * fd_factor * sqrt(emax/m_three)
331
332 hm%spectral_middle_point = m_zero
333 hm%spectral_half_span = emax
334
335 pop_sub(hamiltonian_mxll_span)
336 end subroutine hamiltonian_mxll_span
337
338
339 ! ---------------------------------------------------------
340 subroutine hamiltonian_mxll_adjoint(hm)
341 type(hamiltonian_mxll_t), intent(inout) :: hm
342
344
345 if (.not. hm%adjoint) then
346 hm%adjoint = .true.
347 end if
348
350 end subroutine hamiltonian_mxll_adjoint
351
352
353 ! ---------------------------------------------------------
355 type(hamiltonian_mxll_t), intent(inout) :: hm
356
358
359 if (hm%adjoint) then
360 hm%adjoint = .false.
361 end if
362
364 end subroutine hamiltonian_mxll_not_adjoint
365
366
367 ! ---------------------------------------------------------
369 subroutine hamiltonian_mxll_update(this, time)
370 type(hamiltonian_mxll_t), intent(inout) :: this
371 real(real64), optional, intent(in) :: time
372
374
375 this%current_time = m_zero
376 if (present(time)) this%current_time = time
377
379 end subroutine hamiltonian_mxll_update
381 ! -----------------------------------------------------------------
382
383 real(real64) function hamiltonian_mxll_get_time(this) result(time)
384 type(hamiltonian_mxll_t), intent(inout) :: this
385
386 time = this%current_time
387
388 end function hamiltonian_mxll_get_time
389
390 ! -----------------------------------------------------------------
391
392 logical pure function hamiltonian_mxll_apply_packed(this, mesh) result(apply)
393 type(hamiltonian_mxll_t), intent(in) :: this
394 class(mesh_t), intent(in) :: mesh
395
396 apply = this%apply_packed
397 if (mesh%use_curvilinear) apply = .false.
398
400
401 ! ---------------------------------------------------------
402 subroutine hamiltonian_mxll_apply_batch(hm, namespace, der, psib, hpsib, time, terms, set_bc)
403 type(hamiltonian_mxll_t), intent(in) :: hm
404 type(namespace_t), intent(in) :: namespace
405 type(derivatives_t), intent(in) :: der
406 type(batch_t), target, intent(inout) :: psib
407 type(batch_t), target, intent(inout) :: hpsib
408 real(real64), optional, intent(in) :: time
409 integer, optional, intent(in) :: terms
410 logical, optional, intent(in) :: set_bc
411
412 type(batch_t) :: gradb(der%dim)
413 integer :: idir, ifield, field_dir, pml_dir, rs_sign
414 integer :: ip, ip_in, il
415 real(real64) :: pml_a, pml_b, pml_c
416 complex(real64) :: pml_g, grad
417 integer, parameter :: field_dirs(3, 2) = reshape([2, 3, 1, 3, 1, 2], [3, 2])
418 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m, ff_real(3), ff_imag(3), coeff_real, coeff_imag
419 complex(real64) :: ff_plus(3), ff_minus(3), hpsi(6)
420 integer, parameter :: sign_medium(6) = [1, 1, 1, -1, -1, -1]
421 logical :: with_medium
422 real(real64) :: p_c_
423
425 call profiling_in("H_MXLL_APPLY_BATCH")
426 assert(psib%status() == hpsib%status())
427
428 assert(psib%nst == hpsib%nst)
429 assert(hm%st%dim == 3)
430 p_c_ = p_c * hm%c_factor
431
432 !Not implemented at the moment
433 assert(.not. present(terms))
434 with_medium = hm%operator == faraday_ampere_medium
435
436 if (present(time)) then
437 if (abs(time - hm%current_time) > 1e-10_real64) then
438 write(message(1),'(a)') 'hamiltonian_apply_batch time assertion failed.'
439 write(message(2),'(a,f12.6,a,f12.6)') 'time = ', time, '; hm%current_time = ', hm%current_time
440 call messages_fatal(2, namespace=namespace)
441 end if
442 end if
443
444 if (hm%operator == mxll_simple) then
445 call hamiltonian_mxll_apply_simple(hm, namespace, der%mesh, psib, hpsib, terms, set_bc)
446 call profiling_out("H_MXLL_APPLY_BATCH")
448 return
449 end if
450
451 call zderivatives_batch_grad(der, psib, gradb, set_bc=set_bc)
452
453 if (hm%cpml_hamiltonian) then
454 call apply_pml_boundary(gradb)
455 end if
456
457 call zderivatives_batch_curl_from_gradient(der, hpsib, gradb)
458
459 call scale_after_curl()
460
461 if (hm%bc_constant .and. .not. with_medium) then
463 end if
464
465 if (with_medium) then
466 do idir = 1, 3
467 if ((hm%bc%bc_type(idir) == mxll_bc_medium)) then
468 call apply_medium_box(hm%bc%medium(idir))
469 end if
470 end do
471
472 if (hm%calc_medium_box) then
473 do il = 1, size(hm%medium_boxes)
474 call apply_medium_box(hm%medium_boxes(il))
475 end do
476 end if
477 end if
478
479 do idir = 1, der%dim
480 call gradb(idir)%end()
481 end do
482
483 call profiling_out("H_MXLL_APPLY_BATCH")
486 contains
487 subroutine apply_pml_boundary(gradb)
488 type(batch_t) :: gradb(:)
489 type(accel_kernel_t), save :: ker_pml
490 integer :: wgsize
492 call profiling_in("APPLY_PML_BOUNDARY")
493
494 if (with_medium) then
495 rs_sign = 1
496 else
497 rs_sign = hm%rs_sign
498 end if
499 do idir = 1, der%dim
500 call batch_scal(der%mesh%np, rs_sign * p_c_, gradb(idir))
501 end do
502
503 do pml_dir = 1, hm%st%dim
504 if (hm%bc%bc_ab_type(pml_dir) == mxll_ab_cpml) then
505 select case (gradb(pml_dir)%status())
506 case (batch_not_packed)
507 do ifield = 1, 2
508 field_dir = field_dirs(pml_dir, ifield)
509 !$omp parallel do private(ip, pml_c, pml_a, pml_b, pml_g, grad)
510 do ip_in = 1, hm%bc%pml%points_number
511 ip = hm%bc%pml%points_map(ip_in)
512 pml_c = hm%bc%pml%c(ip_in, pml_dir)
513 pml_a = hm%bc%pml%a(ip_in, pml_dir)
514 pml_b = hm%bc%pml%b(ip_in, pml_dir)
515 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
516 grad = gradb(pml_dir)%zff_linear(ip, field_dir)
517 gradb(pml_dir)%zff_linear(ip, field_dir) = pml_c * ((m_one + pml_a)*grad/p_c_ &
518 + rs_sign * pml_b*pml_g)
519 if (with_medium) then
520 pml_g = hm%bc%pml%conv_minus(ip_in, pml_dir, field_dir)
521 grad = gradb(pml_dir)%zff_linear(ip, field_dir+3)
522 gradb(pml_dir)%zff_linear(ip, field_dir+3) = pml_c * ((m_one + pml_a)*grad/p_c_ &
523 + rs_sign * pml_b*pml_g)
524 end if
525 end do
526 end do
527 case (batch_packed)
528 !$omp parallel do private(ip, field_dir, pml_c, pml_a, pml_b, pml_g, grad, ifield)
529 do ip_in = 1, hm%bc%pml%points_number
530 ip = hm%bc%pml%points_map(ip_in)
531 pml_c = hm%bc%pml%c(ip_in, pml_dir)
532 pml_a = hm%bc%pml%a(ip_in, pml_dir)
533 pml_b = hm%bc%pml%b(ip_in, pml_dir)
534 do ifield = 1, 2
535 field_dir = field_dirs(pml_dir, ifield)
536 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
537 grad = gradb(pml_dir)%zff_pack(field_dir, ip)
538 gradb(pml_dir)%zff_pack(field_dir, ip) = pml_c * ((m_one + pml_a)*grad/p_c_ &
539 + rs_sign * pml_b*pml_g)
540 if (with_medium) then
541 pml_g = hm%bc%pml%conv_minus(ip_in, pml_dir, field_dir)
542 grad = gradb(pml_dir)%zff_pack(field_dir+3, ip)
543 gradb(pml_dir)%zff_pack(field_dir+3, ip) = pml_c * ((m_one + pml_a)*grad/p_c_ &
544 + rs_sign * pml_b*pml_g)
545 end if
546 end do
547 end do
548 case (batch_device_packed)
549 call accel_kernel_start_call(ker_pml, 'pml.cl', 'pml_apply')
550
551 if (with_medium) then
552 call accel_set_kernel_arg(ker_pml, 0, 1_int32)
553 else
554 call accel_set_kernel_arg(ker_pml, 0, 0_int32)
555 end if
556 call accel_set_kernel_arg(ker_pml, 1, hm%bc%pml%points_number)
557 call accel_set_kernel_arg(ker_pml, 2, pml_dir-1)
558 call accel_set_kernel_arg(ker_pml, 3, p_c_)
559 call accel_set_kernel_arg(ker_pml, 4, rs_sign)
560 call accel_set_kernel_arg(ker_pml, 5, hm%bc%pml%buff_map)
561 call accel_set_kernel_arg(ker_pml, 6, gradb(pml_dir)%ff_device)
562 call accel_set_kernel_arg(ker_pml, 7, log2(int(gradb(pml_dir)%pack_size(1), int32)))
563 call accel_set_kernel_arg(ker_pml, 8, hm%bc%pml%buff_a)
564 call accel_set_kernel_arg(ker_pml, 9, hm%bc%pml%buff_b)
565 call accel_set_kernel_arg(ker_pml, 10, hm%bc%pml%buff_c)
566 call accel_set_kernel_arg(ker_pml, 11, hm%bc%pml%buff_conv_plus)
567 call accel_set_kernel_arg(ker_pml, 12, hm%bc%pml%buff_conv_minus)
568
569 wgsize = accel_max_workgroup_size()
570 call accel_kernel_run(ker_pml, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
571 end select
572 end if
573 end do
574
575 if (accel_is_enabled()) then
576 call accel_finish()
577 end if
578
579 call profiling_out("APPLY_PML_BOUNDARY")
581 end subroutine apply_pml_boundary
582
583 subroutine scale_after_curl
585 call profiling_in("SCALE_AFTER_CURL")
586 if (.not. hm%cpml_hamiltonian) then
587 ! if we do not need pml, scale after the curl because it is cheaper
588 if (with_medium) then
589 ! in case of a medium, multiply first 3 components with +, others with -
590 call batch_scal(der%mesh%np, sign_medium * p_c_, hpsib)
591 else
592 call batch_scal(der%mesh%np, hm%rs_sign * p_c_, hpsib)
593 end if
594 else
595 ! this is needed for PML computations with medium
596 if (with_medium) then
597 ! in case of a medium, multiply first 3 components with +, others with -
598 call batch_scal(der%mesh%np, sign_medium * m_one, hpsib)
599 end if
600 end if
601 call profiling_out("SCALE_AFTER_CURL")
603 end subroutine scale_after_curl
604
605 subroutine apply_constant_boundary
607 call profiling_in('APPLY_CONSTANT_BC')
608 select case (hpsib%status())
609 case (batch_not_packed)
610 do field_dir = 1, hm%st%dim
611 do ip_in = 1, hm%bc%constant_points_number
612 ip = hm%bc%constant_points_map(ip_in)
613 hpsib%zff_linear(ip, field_dir) = hm%st%rs_state_const(field_dir)
614 end do
615 end do
616 case (batch_packed)
617 do ip_in = 1, hm%bc%constant_points_number
618 ip = hm%bc%constant_points_map(ip_in)
619 do field_dir = 1, hm%st%dim
620 hpsib%zff_pack(field_dir, ip) = hm%st%rs_state_const(field_dir)
621 end do
622 end do
623 case (batch_device_packed)
624 call messages_not_implemented("Maxwell constant boundary on GPU", namespace=namespace)
625 end select
626 call profiling_out('APPLY_CONSTANT_BC')
628 end subroutine apply_constant_boundary
629
630 subroutine apply_medium_box(medium)
631 type(single_medium_box_t), intent(in) :: medium
632
633 integer :: ifield
634
636 call profiling_in("MEDIUM_BOX")
637 assert(.not. medium%has_mapping)
638 !$omp parallel do private(ip, cc, aux_ep, aux_mu, sigma_e, sigma_m, &
639 !$omp ff_plus, ff_minus, hpsi, ff_real, ff_imag, ifield, coeff_real, coeff_imag)
640 do ip = 1, medium%points_number
641 cc = medium%c(ip)/p_c
642 if (abs(cc) <= m_epsilon) cycle
643 aux_ep(1:3) = medium%aux_ep(ip, 1:3)
644 aux_mu(1:3) = medium%aux_mu(ip, 1:3)
645 sigma_e = medium%sigma_e(ip)
646 sigma_m = medium%sigma_m(ip)
647 select case (hpsib%status())
648 case (batch_not_packed)
649 ff_plus(1:3) = psib%zff_linear(ip, 1:3)
650 ff_minus(1:3) = psib%zff_linear(ip, 4:6)
651 hpsi(1:6) = hpsib%zff_linear(ip, 1:6)
652 case (batch_packed)
653 ff_plus(1:3) = psib%zff_pack(1:3, ip)
654 ff_minus(1:3) = psib%zff_pack(4:6, ip)
655 hpsi(1:6) = hpsib%zff_pack(1:6, ip)
656 case (batch_device_packed)
657 call messages_not_implemented("Maxwell Medium on GPU", namespace=namespace)
658 end select
659 ff_real = real(ff_plus+ff_minus, real64)
660 ff_imag = aimag(ff_plus-ff_minus)
661 aux_ep = dcross_product(aux_ep, ff_real)
662 aux_mu = dcross_product(aux_mu, ff_imag)
663 do ifield = 1, 3
664 coeff_real = - cc * aux_ep(ifield) + sigma_m * ff_imag(ifield)
665 coeff_imag = - cc * aux_mu(ifield) - sigma_e * ff_real(ifield)
666 hpsi(ifield) = cc * hpsi(ifield) + cmplx(coeff_real, coeff_imag, real64)
667 hpsi(ifield+3) = cc * hpsi(ifield+3) + cmplx(-coeff_real, coeff_imag, real64)
668 end do
669 select case (hpsib%status())
670 case (batch_not_packed)
671 hpsib%zff_linear(ip, 1:6) = hpsi(1:6)
672 case (batch_packed)
673 hpsib%zff_pack(1:6, ip) = hpsi(1:6)
674 end select
675 end do
676 call profiling_out("MEDIUM_BOX")
678 end subroutine apply_medium_box
679
680 end subroutine hamiltonian_mxll_apply_batch
681
682 ! ---------------------------------------------------------
683 subroutine hamiltonian_mxll_apply_simple(hm, namespace, mesh, psib, hpsib, terms, set_bc)
684 type(hamiltonian_mxll_t), intent(in) :: hm
685 type(namespace_t), intent(in) :: namespace
686 class(mesh_t), intent(in) :: mesh
687 type(batch_t), target, intent(inout) :: psib
688 type(batch_t), target, intent(inout) :: hpsib
689 integer, optional, intent(in) :: terms
690 logical, optional, intent(in) :: set_bc
691
692 type(batch_t) :: gradb(hm%der%dim)
693 integer :: idir
694
696 call profiling_in("MXLL_HAMILTONIAN_SIMPLE")
697
698 call zderivatives_batch_grad(hm%der, psib, gradb, set_bc=set_bc)
699
700 if (any(hm%bc%bc_ab_type == option__maxwellabsorbingboundaries__cpml)) then
701 ! in the pml layer, the gradient is modified
702 call mxll_apply_pml_simple(hm, gradb)
703 end if
704
705 ! compute the curl from the gradient
706 call zderivatives_batch_curl_from_gradient(hm%der, hpsib, gradb)
707
708 if (hm%calc_medium_box) then
709 ! as the speed of light depends on space, hpsib is already scaled correctly
710 call mxll_linear_medium_terms_simple(hm, hpsib)
711 else
712 ! scale rs_state_tmpb (prefactor of curl)
713 call batch_scal(mesh%np, p_c*hm%c_factor, hpsib)
714 end if
715
716 do idir = 1, hm%der%dim
717 call gradb(idir)%end()
718 end do
719
720 call profiling_out("MXLL_HAMILTONIAN_SIMPLE")
722 end subroutine hamiltonian_mxll_apply_simple
724 ! ---------------------------------------------------------
725 subroutine mxll_apply_pml_simple(hm, gradb)
726 type(hamiltonian_mxll_t), target, intent(in) :: hm
727 type(batch_t), intent(inout) :: gradb(1:hm%st%dim)
728
729 integer :: idir, jdir, ip_in, ip, wgsize
730 type(accel_kernel_t), save :: ker_pml
731
732
733 push_sub(mxll_apply_pml_simple)
734 call profiling_in("APPLY_PML_SIMPLE")
735 ! update pml values
736 ! loop over gradient direction
737 do jdir = 1, hm%st%dim
738 select case (gradb(1)%status())
739 case (batch_not_packed)
740 ! loop over space direction
741 do idir = 1, hm%st%dim
742 if (idir == jdir) cycle
743 do ip_in = 1, hm%bc%pml%points_number
744 ip = hm%bc%pml%points_map(ip_in)
745 ! update gradient to take pml into account when computing the curl
746 gradb(jdir)%zff_linear(ip, idir) = gradb(jdir)%zff_linear(ip, idir) * (m_one + hm%bc%pml%c(ip_in, jdir)) + &
747 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
748 end do
749 end do
750 case (batch_packed)
751 do ip_in = 1, hm%bc%pml%points_number
752 ip = hm%bc%pml%points_map(ip_in)
753 ! loop over space direction
754 do idir = 1, hm%st%dim
755 if (idir == jdir) cycle
756 ! update gradient to take pml into account when computing the curl
757 gradb(jdir)%zff_pack(idir, ip) = gradb(jdir)%zff_pack(idir, ip) * (m_one + hm%bc%pml%c(ip_in, jdir)) +&
758 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
759 end do
760 end do
761 case (batch_device_packed)
762 call accel_kernel_start_call(ker_pml, 'pml.cl', 'pml_apply_new')
763
764 call accel_set_kernel_arg(ker_pml, 0, hm%bc%pml%points_number)
765 call accel_set_kernel_arg(ker_pml, 1, jdir-1)
766 call accel_set_kernel_arg(ker_pml, 2, hm%bc%pml%buff_map)
767 call accel_set_kernel_arg(ker_pml, 3, gradb(jdir)%ff_device)
768 call accel_set_kernel_arg(ker_pml, 4, log2(int(gradb(jdir)%pack_size(1), int32)))
769 call accel_set_kernel_arg(ker_pml, 5, hm%bc%pml%buff_b)
770 call accel_set_kernel_arg(ker_pml, 6, hm%bc%pml%buff_c)
771 call accel_set_kernel_arg(ker_pml, 7, hm%bc%pml%buff_conv_plus_old)
772
773 wgsize = accel_max_workgroup_size()
774 call accel_kernel_run(ker_pml, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
775 end select
776 end do
777 call profiling_out("APPLY_PML_SIMPLE")
778 pop_sub(mxll_apply_pml_simple)
779 end subroutine mxll_apply_pml_simple
780
781 ! ---------------------------------------------------------
782 subroutine mxll_update_pml_simple(hm, rs_stateb)
783 type(hamiltonian_mxll_t),intent(inout) :: hm
784 type(batch_t), intent(inout) :: rs_stateb
785
786 integer :: wgsize, idir, jdir, ip, ip_in
787 type(accel_kernel_t), save :: ker_pml_update
788 type(batch_t) :: gradb(1:hm%st%dim)
789
790 push_sub(mxll_update_pml_simple)
791 call profiling_in("UPDATE_PML_SIMPLE")
792
793 call zderivatives_batch_grad(hm%der, rs_stateb, gradb)
794
795 do jdir = 1, hm%st%dim
796 call rs_stateb%check_compatibility_with(gradb(jdir))
797 select case (gradb(jdir)%status())
798 case (batch_not_packed)
799 ! loop over space direction
800 do idir = 1, hm%st%dim
801 if (idir == jdir) cycle
802 do ip_in = 1, hm%bc%pml%points_number
803 ip = hm%bc%pml%points_map(ip_in)
804 hm%bc%pml%conv_plus(ip_in, jdir, idir) = hm%bc%pml%c(ip_in, jdir) * gradb(jdir)%zff_linear(ip, idir) +&
805 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
806 end do
807 end do
808 case (batch_packed)
809 do ip_in = 1, hm%bc%pml%points_number
810 ip = hm%bc%pml%points_map(ip_in)
811 ! loop over space direction
812 do idir = 1, hm%st%dim
813 if (idir == jdir) cycle
814 hm%bc%pml%conv_plus(ip_in, jdir, idir) = hm%bc%pml%c(ip_in, jdir) * gradb(jdir)%zff_pack(idir, ip) +&
815 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
816 end do
817 end do
818 case (batch_device_packed)
819 call accel_kernel_start_call(ker_pml_update, 'pml.cl', 'pml_update_new')
820
821 call accel_set_kernel_arg(ker_pml_update, 0, hm%bc%pml%points_number)
822 call accel_set_kernel_arg(ker_pml_update, 1, jdir-1)
823 call accel_set_kernel_arg(ker_pml_update, 2, hm%bc%pml%buff_map)
824 call accel_set_kernel_arg(ker_pml_update, 3, gradb(jdir)%ff_device)
825 call accel_set_kernel_arg(ker_pml_update, 4, log2(int(gradb(jdir)%pack_size(1), int32)))
826 call accel_set_kernel_arg(ker_pml_update, 5, hm%bc%pml%buff_b)
827 call accel_set_kernel_arg(ker_pml_update, 6, hm%bc%pml%buff_c)
828 call accel_set_kernel_arg(ker_pml_update, 7, hm%bc%pml%buff_conv_plus)
829 call accel_set_kernel_arg(ker_pml_update, 8, hm%bc%pml%buff_conv_plus_old)
830
831 wgsize = accel_max_workgroup_size()
832 call accel_kernel_run(ker_pml_update, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
833 end select
834 call gradb(jdir)%end()
835 end do
836 call profiling_out("UPDATE_PML_SIMPLE")
838 end subroutine mxll_update_pml_simple
839
840 ! ---------------------------------------------------------
841 subroutine mxll_copy_pml_simple(hm, rs_stateb)
842 type(hamiltonian_mxll_t),intent(inout) :: hm
843 type(batch_t), intent(inout) :: rs_stateb
844
845 integer :: wgsize, idir, jdir, ip, ip_in
846 type(accel_kernel_t), save :: ker_pml_copy
847
848 push_sub(mxll_copy_pml_simple)
849 call profiling_in("COPY_PML_SIMPLE")
850
851 select case (rs_stateb%status())
852 case (batch_packed, batch_not_packed)
853 do jdir = 1, hm%st%dim
854 ! loop over space direction
855 do idir = 1, hm%st%dim
856 if (idir == jdir) cycle
857 do ip_in = 1, hm%bc%pml%points_number
858 ip = hm%bc%pml%points_map(ip_in)
859 hm%bc%pml%conv_plus_old(ip_in, jdir, idir) = hm%bc%pml%conv_plus(ip_in, jdir, idir)
860 end do
861 end do
862 end do
863 case (batch_device_packed)
864 call accel_kernel_start_call(ker_pml_copy, 'pml.cl', 'pml_copy')
865
866 call accel_set_kernel_arg(ker_pml_copy, 0, hm%bc%pml%points_number*9)
867 call accel_set_kernel_arg(ker_pml_copy, 1, hm%bc%pml%buff_conv_plus)
868 call accel_set_kernel_arg(ker_pml_copy, 2, hm%bc%pml%buff_conv_plus_old)
869
870 wgsize = accel_max_workgroup_size()
871 call accel_kernel_run(ker_pml_copy, (/ accel_padded_size(hm%bc%pml%points_number*9) /), (/ wgsize /))
872 end select
873 call profiling_out("COPY_PML_SIMPLE")
874 pop_sub(mxll_copy_pml_simple)
875 end subroutine mxll_copy_pml_simple
876
877 ! ---------------------------------------------------------
878 subroutine mxll_linear_medium_terms_simple(hm, rs_stateb)
879 type(hamiltonian_mxll_t),intent(in) :: hm
880 type(batch_t), intent(inout) :: rs_stateb
881
882 integer :: il, ip
883 logical :: need_to_pack
884
886 call profiling_in("LINEAR_MEDIUM_SIMPLE")
887
888 do il = 1, size(hm%medium_boxes)
889 assert(.not. hm%medium_boxes(il)%has_mapping)
890 need_to_pack = .false.
891 ! copy to the CPU for GPU runs
892 if(rs_stateb%status() == batch_device_packed) then
893 call rs_stateb%do_unpack(force=.true.)
894 need_to_pack = .true.
895 end if
896 select case (rs_stateb%status())
897 case (batch_not_packed)
898 do ip = 1, hm%medium_boxes(il)%points_number
899 if (abs(hm%medium_boxes(il)%c(ip)) <= m_epsilon) then
900 ! Hamiltonian without medium
901 rs_stateb%zff_linear(ip, 1:3) = p_c*hm%c_factor*rs_stateb%zff_linear(ip, 1:3)
902 else
903 ! Hamiltonian with medium terms
904 rs_stateb%zff_linear(ip, 1:3) = hm%medium_boxes(il)%c(ip)*(rs_stateb%zff_linear(ip, 1:3) + &
905 cmplx( &
906 -dcross_product(hm%medium_boxes(il)%aux_ep(ip, 1:3)*m_two, &
907 real(rs_stateb%zff_linear(ip, 1:3), real64)), &
908 -dcross_product(hm%medium_boxes(il)%aux_mu(ip, 1:3)*m_two, &
909 aimag(rs_stateb%zff_linear(ip, 1:3))), real64)) + &
910 cmplx(&
911 hm%medium_boxes(il)%sigma_m(ip)*aimag(rs_stateb%zff_linear(ip, 1:3)), &
912 -hm%medium_boxes(il)%sigma_e(ip)*real(rs_stateb%zff_linear(ip, 1:3), real64), real64)
913 end if
914 end do
915 case (batch_packed)
916 do ip = 1, hm%medium_boxes(il)%points_number
917 if (abs(hm%medium_boxes(il)%c(ip)) <= m_epsilon) then
918 ! Hamiltonian without medium
919 rs_stateb%zff_pack(1:3, ip) = p_c*hm%c_factor*rs_stateb%zff_pack(1:3, ip)
920 else
921 ! Hamiltonian with medium terms
922 rs_stateb%zff_pack(1:3, ip) = hm%medium_boxes(il)%c(ip)*(rs_stateb%zff_pack(1:3, ip) + &
923 cmplx( &
924 -dcross_product(hm%medium_boxes(il)%aux_ep(ip, 1:3)*m_two, &
925 real(rs_stateb%zff_pack(1:3, ip), real64)), &
926 -dcross_product(hm%medium_boxes(il)%aux_mu(ip, 1:3)*m_two, &
927 aimag(rs_stateb%zff_pack(1:3, ip))), real64)) + &
928 cmplx(&
929 hm%medium_boxes(il)%sigma_m(ip)*aimag(rs_stateb%zff_pack(1:3, ip)), &
930 -hm%medium_boxes(il)%sigma_e(ip)*real(rs_stateb%zff_pack(1:3, ip), real64), real64)
931 end if
932 end do
933 end select
934 if(need_to_pack) then
935 call rs_stateb%do_pack()
936 end if
937 end do
938
939 call profiling_out("LINEAR_MEDIUM_SIMPLE")
942
943 ! --------------------------------------------------------
945 subroutine dhamiltonian_mxll_apply(hm, namespace, mesh, psib, hpsib, terms, set_bc)
946 class(hamiltonian_mxll_t), intent(in) :: hm
947 type(namespace_t), intent(in) :: namespace
948 class(mesh_t), intent(in) :: mesh
949 class(batch_t), target, intent(inout) :: psib
950 class(batch_t), target, intent(inout) :: hpsib
951 integer, optional, intent(in) :: terms
952 logical, optional, intent(in) :: set_bc
953
954 write(message(1),'(a)') 'dhamiltonian_mxll_apply not implemented (states are complex).'
955 call messages_fatal(1, namespace=namespace)
956
957 end subroutine dhamiltonian_mxll_apply
958
959 ! ---------------------------------------------------------
961 subroutine zhamiltonian_mxll_apply(hm, namespace, mesh, psib, hpsib, terms, set_bc)
962 class(hamiltonian_mxll_t), intent(in) :: hm
963 type(namespace_t), intent(in) :: namespace
964 class(mesh_t), intent(in) :: mesh
965 class(batch_t), target, intent(inout) :: psib
966 class(batch_t), target, intent(inout) :: hpsib
967 integer, optional, intent(in) :: terms
968 logical, optional, intent(in) :: set_bc
969
970 complex(real64), allocatable :: rs_aux_in(:,:), rs_aux_out(:,:)
971 integer :: ii
972 logical :: on_gpu
973
975
976 call profiling_in('ZHAMILTONIAN_MXLL_APPLY')
977
978 on_gpu = psib%status() == batch_device_packed
979 if (hm%operator == faraday_ampere_medium .and. on_gpu) then
980 ! legacy code, keep for the moment
981 safe_allocate(rs_aux_in(1:mesh%np_part, 1:hm%dim))
982 safe_allocate(rs_aux_out(1:mesh%np, 1:hm%dim))
983 call boundaries_set(hm%der%boundaries, mesh, psib)
984 do ii = 1, hm%dim
985 call batch_get_state(psib, ii,mesh%np_part, rs_aux_in(:, ii))
986 end do
987 ! This uses the old non-batch implementation
988 call maxwell_hamiltonian_apply_fd(hm, hm%der, rs_aux_in, rs_aux_out)
989 do ii = 1, hm%dim
990 call batch_set_state(hpsib, ii, mesh%np, rs_aux_out(:, ii))
991 end do
992 safe_deallocate_a(rs_aux_in)
993 safe_deallocate_a(rs_aux_out)
994 else
995 ! default branch, should be the only one at some point
996 call hamiltonian_mxll_apply_batch(hm, namespace, hm%der, psib, hpsib, set_bc=set_bc)
997 end if
998
999 call profiling_out('ZHAMILTONIAN_MXLL_APPLY')
1000
1002 end subroutine zhamiltonian_mxll_apply
1003
1004
1005 ! ---------------------------------------------------------
1007 subroutine maxwell_hamiltonian_apply_fd(hm, der, psi, oppsi)
1008 type(hamiltonian_mxll_t), intent(in) :: hm
1009 type(derivatives_t), intent(in) :: der
1010 complex(real64), intent(inout) :: psi(:,:)
1011 complex(real64), intent(inout) :: oppsi(:,:)
1012
1013 real(real64), pointer :: mx_rho(:,:)
1014 complex(real64), allocatable :: tmp(:,:)
1015 complex(real64), pointer :: kappa_psi(:,:)
1016 integer :: np, np_part, ip, ip_in, rs_sign
1017 real(real64) :: P_c_
1018
1020
1021 call profiling_in('MAXWELL_HAMILTONIAN_APPLY_FD')
1022
1023 np = der%mesh%np
1024 np_part = der%mesh%np_part
1025 rs_sign = hm%rs_sign
1026 p_c_ = p_c * hm%c_factor
1027
1028 select case (hm%operator)
1029
1030 !=================================================================================================
1031 ! Maxwell Hamiltonian - Hamiltonian operation in vacuum via partial derivatives:
1032
1033 case (faraday_ampere)
1034 call profiling_in('MXLL_HAM_APPLY_FD_FARADAY_AMP')
1035
1036 safe_allocate(tmp(1:np,1:2))
1037 oppsi = m_z0
1039 if (hm%diamag_current) then
1040 mx_rho => hm%st%grid_rho
1041 kappa_psi => hm%st%kappa_psi
1042 end if
1043
1044 !-----------------------------------------------------------------------------------------------
1045 ! Riemann-Silberstein vector component 1 calculation:
1046 tmp = m_z0
1047 call zderivatives_partial(der, psi(:,3), tmp(:,1), 2, set_bc = .false.)
1048 call zderivatives_partial(der, psi(:,2), tmp(:,2), 3, set_bc = .false.)
1049 tmp = rs_sign * p_c_ * tmp
1050 call maxwell_pml_hamiltonian(hm, der, psi, 2, 3, tmp(:,1))
1051 call maxwell_pml_hamiltonian(hm, der, psi, 3, 2, tmp(:,2))
1052 oppsi(1:np,1) = ( tmp(1:np,1)-tmp(1:np,2))
1053
1054 !-----------------------------------------------------------------------------------------------
1055 ! Riemann-Silberstein vector component 2 calculation:
1056 tmp = m_z0
1057 call zderivatives_partial(der, psi(:,1), tmp(:,1), 3, set_bc = .false.)
1058 call zderivatives_partial(der, psi(:,3), tmp(:,2), 1, set_bc = .false.)
1059 tmp = rs_sign * p_c_ * tmp
1060 call maxwell_pml_hamiltonian(hm, der, psi, 3, 1, tmp(:,1))
1061 call maxwell_pml_hamiltonian(hm, der, psi, 1, 3, tmp(:,2))
1062 oppsi(1:np,2) = ( tmp(1:np,1)-tmp(1:np,2))
1063
1064 !-----------------------------------------------------------------------------------------------
1065 ! Riemann-Silberstein vector component 3 calculation:
1066 tmp = m_z0
1067 call zderivatives_partial(der, psi(:,2), tmp(:,1), 1, set_bc = .false.)
1068 call zderivatives_partial(der, psi(:,1), tmp(:,2), 2, set_bc = .false.)
1069 tmp = rs_sign * p_c_ * tmp
1070 call maxwell_pml_hamiltonian(hm, der, psi, 1, 2, tmp(:,1))
1071 call maxwell_pml_hamiltonian(hm, der, psi, 2, 1, tmp(:,2))
1072 oppsi(1:np,3) = ( tmp(1:np,1)-tmp(1:np,2))
1073
1074 if (hm%bc_constant) then
1075 do ip_in = 1, hm%bc%constant_points_number
1076 ip = hm%bc%constant_points_map(ip_in)
1077 oppsi(ip,:) = hm%st%rs_state_const(:)
1078 end do
1079 end if
1080
1081 safe_deallocate_a(tmp)
1082
1083 call profiling_out('MXLL_HAM_APPLY_FD_FARADAY_AMP')
1084 !=================================================================================================
1085 ! Maxwell Hamiltonian - Hamiltonian operation in medium via partial derivatives:
1086
1088 call profiling_in('MXLL_HAM_APP_FAR_AMP_MED')
1089
1090 safe_allocate(tmp(1:np,1:4))
1091 oppsi = m_z0
1092
1093 !-----------------------------------------------------------------------------------------------
1094 ! Riemann-Silberstein vector component 1 calculation:
1095 tmp = m_z0
1096 call zderivatives_partial(der, psi(:,3), tmp(:,1), 2, set_bc = .false.)
1097 call zderivatives_partial(der, psi(:,2), tmp(:,3), 3, set_bc = .false.)
1098 call zderivatives_partial(der, psi(:,6), tmp(:,2), 2, set_bc = .false.)
1099 call zderivatives_partial(der, psi(:,5), tmp(:,4), 3, set_bc = .false.)
1100 tmp = p_c_ * tmp
1101 call maxwell_pml_hamiltonian_medium(hm, der, psi, 2, 3, tmp(:,1:2))
1102 call maxwell_pml_hamiltonian_medium(hm, der, psi, 3, 2, tmp(:,3:4))
1103 oppsi(1:np,1) = (tmp(1:np,1)-tmp(1:np,3))
1104 oppsi(1:np,4) = -(tmp(1:np,2)-tmp(1:np,4))
1105
1106 !-----------------------------------------------------------------------------------------------
1107 ! Riemann-Silberstein vector component 2 calculation:
1108 tmp = m_z0
1109 call zderivatives_partial(der, psi(:,1), tmp(:,1), 3, set_bc = .false.)
1110 call zderivatives_partial(der, psi(:,3), tmp(:,3), 1, set_bc = .false.)
1111 call zderivatives_partial(der, psi(:,4), tmp(:,2), 3, set_bc = .false.)
1112 call zderivatives_partial(der, psi(:,6), tmp(:,4), 1, set_bc = .false.)
1113 tmp = p_c_ * tmp
1114 call maxwell_pml_hamiltonian_medium(hm, der, psi, 3, 1, tmp(:,1:2))
1115 call maxwell_pml_hamiltonian_medium(hm, der, psi, 1, 3, tmp(:,3:4))
1116 oppsi(1:np,2) = (tmp(1:np,1)-tmp(1:np,3))
1117 oppsi(1:np,5) = -(tmp(1:np,2)-tmp(1:np,4))
1118
1119 !-----------------------------------------------------------------------------------------------
1120 ! Riemann-Silberstein vector component 3 calculation:
1121 tmp = m_z0
1122 call zderivatives_partial(der, psi(:,2), tmp(:,1), 1, set_bc = .false.)
1123 call zderivatives_partial(der, psi(:,1), tmp(:,3), 2, set_bc = .false.)
1124 call zderivatives_partial(der, psi(:,5), tmp(:,2), 1, set_bc = .false.)
1125 call zderivatives_partial(der, psi(:,4), tmp(:,4), 2, set_bc = .false.)
1126 tmp = p_c_ * tmp
1127 call maxwell_pml_hamiltonian_medium(hm, der, psi, 1, 2, tmp(:,1:2))
1128 call maxwell_pml_hamiltonian_medium(hm, der, psi, 2, 1, tmp(:,3:4))
1129 oppsi(1:np,3) = (tmp(1:np,1)-tmp(1:np,3))
1130 oppsi(1:np,6) = -(tmp(1:np,2)-tmp(1:np,4))
1131
1132
1133 safe_deallocate_a(tmp)
1134
1135 !-----------------------------------------------------------------------------------------------
1136 ! Riemann-Silberstein vector calculation if medium boundaries is set:
1137 call maxwell_medium_boundaries_calculation(hm, psi, oppsi)
1138
1139 !-----------------------------------------------------------------------------------------------
1140 ! Riemann-Silberstein vector calculation for medium boxes:
1141 call maxwell_medium_boxes_calculation(hm, der, psi, oppsi)
1142
1143 call profiling_out('MXLL_HAM_APP_FAR_AMP_MED')
1144
1145 end select
1146
1147 call profiling_out('MAXWELL_HAMILTONIAN_APPLY_FD')
1148
1150 end subroutine maxwell_hamiltonian_apply_fd
1151
1152
1153 ! ---------------------------------------------------------
1155 subroutine maxwell_pml_hamiltonian(hm, der, psi, dir1, dir2, tmp)
1156 type(hamiltonian_mxll_t), intent(in) :: hm
1157 type(derivatives_t), intent(in) :: der
1158 complex(real64), intent(inout) :: psi(:,:)
1159 integer, intent(in) :: dir1
1160 integer, intent(in) :: dir2
1161 complex(real64), intent(inout) :: tmp(:)
1162
1163
1164 push_sub(maxwell_pml_hamiltonian)
1165
1166 call profiling_in('MAXWELL_PML_HAMILTONIAN')
1167
1168 if ((hm%bc%bc_ab_type(dir1) == mxll_ab_cpml) .and. hm%cpml_hamiltonian) then
1169 call maxwell_pml_calculation_via_riemann_silberstein(hm, der, psi, dir1, dir2, tmp(:))
1170 end if
1171
1172 call profiling_out('MAXWELL_PML_HAMILTONIAN')
1173
1175 end subroutine maxwell_pml_hamiltonian
1176
1177 ! ---------------------------------------------------------
1179 subroutine maxwell_pml_hamiltonian_medium(hm, der, psi, dir1, dir2, tmp)
1180 type(hamiltonian_mxll_t), intent(in) :: hm
1181 type(derivatives_t), intent(in) :: der
1182 complex(real64), intent(inout) :: psi(:,:)
1183 integer, intent(in) :: dir1
1184 integer, intent(in) :: dir2
1185 complex(real64), intent(inout) :: tmp(:,:)
1186
1187
1189
1190 call profiling_in('MAXWELL_PML_HAMILTONIAN_MEDIUM')
1191
1192 if ((hm%bc%bc_ab_type(dir1) == mxll_ab_cpml) .and. hm%cpml_hamiltonian) then
1193 call maxwell_pml_calculation_via_riemann_silberstein_medium(hm, der, psi, dir1, dir2, tmp(:,:))
1194 end if
1195
1196 call profiling_out('MAXWELL_PML_HAMILTONIAN_MEDIUM')
1197
1199 end subroutine maxwell_pml_hamiltonian_medium
1200
1201 ! ---------------------------------------------------------
1203 subroutine maxwell_pml_calculation_via_riemann_silberstein(hm, der, psi, pml_dir, field_dir, pml)
1204 type(hamiltonian_mxll_t), intent(in) :: hm
1205 type(derivatives_t), intent(in) :: der
1206 integer, intent(in) :: pml_dir
1207 complex(real64), intent(inout) :: psi(:,:)
1208 integer, intent(in) :: field_dir
1209 complex(real64), intent(inout) :: pml(:)
1210
1211 integer :: ip, ip_in, rs_sign
1212 real(real64) :: pml_c
1213 complex(real64), allocatable :: tmp_partial(:)
1214 complex(real64) :: pml_a, pml_b, pml_g
1215
1217
1218 if (hm%cpml_hamiltonian) then
1219
1220 rs_sign = hm%rs_sign
1221
1222 safe_allocate(tmp_partial(1:der%mesh%np_part))
1223
1224 call zderivatives_partial(der, psi(:,field_dir), tmp_partial(:), pml_dir, set_bc = .false.)
1225 do ip_in = 1, hm%bc%pml%points_number
1226 ip = hm%bc%pml%points_map(ip_in)
1227 pml_c = hm%bc%pml%c(ip_in, pml_dir)
1228 pml_a = hm%bc%pml%a(ip_in, pml_dir)
1229 pml_b = hm%bc%pml%b(ip_in, pml_dir)
1230 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
1231 pml(ip) = rs_sign * pml_c * ( tmp_partial(ip) &
1232 + real(pml_a, real64) * real(tmp_partial(ip), real64) &
1233 + m_zi * aimag(pml_a) * aimag(tmp_partial(ip)) &
1234 + real(pml_b, real64) * real(pml_g, real64) &
1235 + m_zi * aimag(pml_b) * aimag(pml_g))
1236 end do
1237
1238 safe_deallocate_a(tmp_partial)
1239 end if
1240
1243
1244
1245 ! ---------------------------------------------------------
1248 subroutine maxwell_pml_calculation_via_riemann_silberstein_medium(hm, der, psi, pml_dir, field_dir, pml)
1249 type(hamiltonian_mxll_t), intent(in) :: hm
1250 type(derivatives_t), intent(in) :: der
1251 integer, intent(in) :: pml_dir
1252 complex(real64), intent(inout) :: psi(:,:)
1253 integer, intent(in) :: field_dir
1254 complex(real64), intent(inout) :: pml(:,:)
1255
1256 integer :: ip, ip_in, np
1257 real(real64) :: pml_c(3)
1258 complex(real64), allocatable :: tmp_partial(:,:)
1259 complex(real64) :: pml_a(3), pml_b(3), pml_g_p(3), pml_g_m(3)
1260
1262
1263 if (hm%cpml_hamiltonian) then
1264
1265 np = der%mesh%np
1266 safe_allocate(tmp_partial(1:np,1:2))
1267
1268 call zderivatives_partial(der, psi(:,field_dir ), tmp_partial(:,1), pml_dir, set_bc = .false.)
1269 call zderivatives_partial(der, psi(:,field_dir+3), tmp_partial(:,2), pml_dir, set_bc = .false.)
1270 do ip_in = 1, hm%bc%pml%points_number
1271 ip = hm%bc%pml%points_map(ip_in)
1272 pml_c(1:3) = hm%bc%pml%c(ip_in, 1:3)
1273 pml_a(1:3) = hm%bc%pml%a(ip_in, 1:3)
1274 pml_b(1:3) = hm%bc%pml%b(ip_in, 1:3)
1275 pml_g_p(1:3) = hm%bc%pml%conv_plus(ip_in, pml_dir, 1:3)
1276 pml_g_m(1:3) = hm%bc%pml%conv_minus(ip_in, pml_dir, 1:3)
1277 pml(ip, 1) = pml_c(pml_dir) * tmp_partial(ip, 1) &
1278 + pml_c(pml_dir) * real(pml_a(pml_dir), real64) * real(tmp_partial(ip, 1), real64) &
1279 + m_zi * pml_c(pml_dir) * aimag(pml_a(pml_dir)) * aimag(tmp_partial(ip, 1)) &
1280 + pml_c(pml_dir) * real(pml_b(pml_dir), real64) * real(pml_g_p(field_dir), real64) &
1281 + m_zi * pml_c(pml_dir) * aimag(pml_b(pml_dir)) * aimag(pml_g_p(field_dir))
1282 pml(ip, 2) = pml_c(pml_dir) * tmp_partial(ip, 2) &
1283 + pml_c(pml_dir) * real(pml_a(pml_dir), real64) * real(tmp_partial(ip, 2), real64) &
1284 + m_zi * pml_c(pml_dir) * aimag(pml_a(pml_dir)) * aimag(tmp_partial(ip, 2)) &
1285 + pml_c(pml_dir) * real(pml_b(pml_dir), real64) * real(pml_g_m(field_dir), real64) &
1286 + m_zi * pml_c(pml_dir) * aimag(pml_b(pml_dir)) * aimag(pml_g_m(field_dir))
1287 end do
1288
1289 end if
1290
1291 safe_deallocate_a(tmp_partial)
1292
1295
1297 ! ---------------------------------------------------------
1299 subroutine maxwell_medium_boundaries_calculation(hm, psi, oppsi)
1300 type(hamiltonian_mxll_t), intent(in) :: hm
1301 complex(real64), intent(in) :: psi(:,:)
1302 complex(real64), intent(inout) :: oppsi(:,:)
1303
1304 integer :: ip, ip_in, idim
1305 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m
1306 complex(real64) :: ff_plus(3), ff_minus(3)
1307
1309
1310 do idim = 1, 3
1311 if ((hm%bc%bc_type(idim) == mxll_bc_medium)) then
1312 do ip_in = 1, hm%bc%medium(idim)%points_number
1313 ip = hm%bc%medium(idim)%points_map(ip_in)
1314 cc = hm%bc%medium(idim)%c(ip_in)/p_c
1315 aux_ep(:) = hm%bc%medium(idim)%aux_ep(ip_in, :)
1316 aux_mu(:) = hm%bc%medium(idim)%aux_mu(ip_in, :)
1317 sigma_e = hm%bc%medium(idim)%sigma_e(ip_in)
1318 sigma_m = hm%bc%medium(idim)%sigma_m(ip_in)
1319 ff_plus(1) = psi(ip, 1)
1320 ff_plus(2) = psi(ip, 2)
1321 ff_plus(3) = psi(ip, 3)
1322 ff_minus(1) = psi(ip, 4)
1323 ff_minus(2) = psi(ip, 5)
1324 ff_minus(3) = psi(ip, 6)
1325 aux_ep = dcross_product(aux_ep,real(ff_plus+ff_minus, real64) )
1326 aux_mu = dcross_product(aux_mu,aimag(ff_plus-ff_minus))
1327 oppsi(ip, 1) = oppsi(ip, 1)*cc &
1328 - cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1329 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1330 - m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1331 oppsi(ip, 4) = oppsi(ip, 4)*cc &
1332 + cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1333 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1334 + m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1335 oppsi(ip, 2) = oppsi(ip, 2)*cc &
1336 - cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1337 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1338 - m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1339 oppsi(ip, 5) = oppsi(ip, 5)*cc &
1340 + cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1341 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1342 + m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1343 oppsi(ip, 3) = oppsi(ip, 3)*cc &
1344 - cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1345 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1346 - m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1347 oppsi(ip, 6) = oppsi(ip, 6)*cc &
1348 + cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1349 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1350 + m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1351 end do
1352 end if
1353 end do
1354
1357
1358
1359 ! ---------------------------------------------------------
1360 ! > Maxwell Hamiltonian including medium boxes
1361 subroutine maxwell_medium_boxes_calculation(hm, der, psi, oppsi)
1362 type(hamiltonian_mxll_t), intent(in) :: hm
1363 type(derivatives_t), intent(in) :: der
1364 complex(real64), intent(in) :: psi(:,:)
1365 complex(real64), intent(inout) :: oppsi(:,:)
1366
1367 integer :: ip, il
1368 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m
1369 complex(real64) :: ff_plus(3), ff_minus(3)
1370
1372
1373 if (hm%calc_medium_box) then
1374 do il = 1, size(hm%medium_boxes)
1375 assert(.not. hm%medium_boxes(il)%has_mapping)
1376 do ip = 1, hm%medium_boxes(il)%points_number
1377 cc = hm%medium_boxes(il)%c(ip)/p_c
1378 if (abs(cc) <= m_epsilon) cycle
1379 aux_ep(1:3) = hm%medium_boxes(il)%aux_ep(ip, 1:3)
1380 aux_mu(1:3) = hm%medium_boxes(il)%aux_mu(ip, 1:3)
1381 sigma_e = hm%medium_boxes(il)%sigma_e(ip)
1382 sigma_m = hm%medium_boxes(il)%sigma_m(ip)
1383 ff_plus(1) = psi(ip, 1)
1384 ff_plus(2) = psi(ip, 2)
1385 ff_plus(3) = psi(ip, 3)
1386 ff_minus(1) = psi(ip, 4)
1387 ff_minus(2) = psi(ip, 5)
1388 ff_minus(3) = psi(ip, 6)
1389 aux_ep = dcross_product(aux_ep, real(ff_plus+ff_minus, real64) )
1390 aux_mu = dcross_product(aux_mu, aimag(ff_plus-ff_minus))
1391 oppsi(ip, 1) = oppsi(ip,1)*cc &
1392 - cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1393 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1394 - m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1395 oppsi(ip, 4) = oppsi(ip,4)*cc &
1396 + cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1397 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1398 + m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1399 oppsi(ip, 2) = oppsi(ip,2)*cc &
1400 - cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1401 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1402 - m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1403 oppsi(ip, 5) = oppsi(ip,5)*cc &
1404 + cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1405 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1406 + m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1407 oppsi(ip, 3) = oppsi(ip,3)*cc &
1408 - cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1409 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1410 - m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1411 oppsi(ip, 6) = oppsi(ip,6)*cc &
1412 + cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1413 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1414 + m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1415 end do
1416 end do
1417 end if
1418
1421
1422 ! ---------------------------------------------------------
1424 subroutine dhamiltonian_mxll_magnus_apply(hm, namespace, mesh, psib, hpsib, vmagnus)
1425 class(hamiltonian_mxll_t), intent(in) :: hm
1426 type(namespace_t), intent(in) :: namespace
1427 class(mesh_t), intent(in) :: mesh
1428 class(batch_t), intent(inout) :: psib
1429 class(batch_t), intent(inout) :: hpsib
1430 real(real64), intent(in) :: vmagnus(:, :, :)
1431
1432 call messages_not_implemented ('dhamiltonian_mxll_magnus_apply', namespace=namespace)
1433
1434 end subroutine dhamiltonian_mxll_magnus_apply
1435
1436 ! ---------------------------------------------------------
1438 subroutine zhamiltonian_mxll_magnus_apply(hm, namespace, mesh, psib, hpsib, vmagnus)
1439 class(hamiltonian_mxll_t), intent(in) :: hm
1440 type(namespace_t), intent(in) :: namespace
1441 class(mesh_t), intent(in) :: mesh
1442 class(batch_t), intent(inout) :: psib
1443 class(batch_t), intent(inout) :: hpsib
1444 real(real64), intent(in) :: vmagnus(:, :, :)
1445
1446 call messages_not_implemented ('zhamiltonian_mxll_magnus_apply', namespace=namespace)
1447
1448 end subroutine zhamiltonian_mxll_magnus_apply
1449
1450end module hamiltonian_mxll_oct_m
1451
1452!! Local Variables:
1453!! mode: f90
1454!! coding: utf-8
1455!! End:
subroutine apply_medium_box(medium)
subroutine apply_constant_boundary
subroutine apply_pml_boundary(gradb)
subroutine scale_after_curl
double log2(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:122
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
integer, parameter, public der_star
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
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
real(real64), parameter, public m_three
Definition: global.F90:190
This module implements the underlying real-space grid.
Definition: grid.F90:117
This module defines an abstract class for Hamiltonians.
subroutine mxll_apply_pml_simple(hm, gradb)
subroutine, public hamiltonian_mxll_init(hm, namespace, gr, st)
Initializing the Maxwell Hamiltonian.
subroutine, public zhamiltonian_mxll_apply(hm, namespace, mesh, psib, hpsib, terms, set_bc)
Applying the Maxwell Hamiltonian on Maxwell states.
subroutine, public hamiltonian_mxll_apply_simple(hm, namespace, mesh, psib, hpsib, terms, set_bc)
subroutine, public mxll_update_pml_simple(hm, rs_stateb)
integer, parameter, public faraday_ampere
real(real64) function, public hamiltonian_mxll_get_time(this)
subroutine, public hamiltonian_mxll_end(hm)
subroutine maxwell_hamiltonian_apply_fd(hm, der, psi, oppsi)
Applying the Maxwell Hamiltonian on Maxwell states with finite difference.
subroutine maxwell_medium_boundaries_calculation(hm, psi, oppsi)
Maxwell Hamiltonian for medium boundaries.
subroutine maxwell_pml_calculation_via_riemann_silberstein_medium(hm, der, psi, pml_dir, field_dir, pml)
Maxwell Hamiltonian is updated for the PML calculation via Riemann-Silberstein vector with medium ins...
subroutine, public hamiltonian_mxll_span(hm, delta, emin, namespace)
integer, parameter, public faraday_ampere_medium
integer, parameter, public mxll_simple
subroutine, public dhamiltonian_mxll_apply(hm, namespace, mesh, psib, hpsib, terms, set_bc)
Apply hamiltonian to real states (not possible)
logical function, public hamiltonian_mxll_hermitian(hm)
subroutine maxwell_pml_calculation_via_riemann_silberstein(hm, der, psi, pml_dir, field_dir, pml)
Maxwell Hamiltonian is updated for the PML calculation via Riemann-Silberstein vector.
subroutine, public hamiltonian_mxll_update(this, time)
Maxwell Hamiltonian update (here only the time is updated, can maybe be added to another routine)
subroutine maxwell_pml_hamiltonian(hm, der, psi, dir1, dir2, tmp)
Maxwell Hamiltonian is updated for the PML calculation.
subroutine, public mxll_copy_pml_simple(hm, rs_stateb)
subroutine, public hamiltonian_mxll_apply_batch(hm, namespace, der, psib, hpsib, time, terms, set_bc)
subroutine, public hamiltonian_mxll_not_adjoint(hm)
subroutine, public hamiltonian_mxll_adjoint(hm)
subroutine, public zhamiltonian_mxll_magnus_apply(hm, namespace, mesh, psib, hpsib, vmagnus)
Maxwell hamiltonian Magnus (not implemented)
subroutine maxwell_pml_hamiltonian_medium(hm, der, psi, dir1, dir2, tmp)
Maxwell Hamiltonian is updated for the PML calculation.
logical pure function, public hamiltonian_mxll_apply_packed(this, mesh)
subroutine, public dhamiltonian_mxll_magnus_apply(hm, namespace, mesh, psib, hpsib, vmagnus)
Maxwell hamiltonian Magnus (not implemented)
subroutine mxll_linear_medium_terms_simple(hm, rs_stateb)
subroutine maxwell_medium_boxes_calculation(hm, der, psi, oppsi)
subroutine, public single_medium_box_end(medium_box)
Deallocation of medium_box components.
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public bc_mxll_end(bc)
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
This module defines non-local operators.
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 handles spin dimensions of the states and the k-point distribution.
The abstract Hamiltonian class defines a skeleton for specific implementations.
int true(void)