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