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