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