34 use,
intrinsic :: iso_fortran_env
74 logical :: adjoint = .false.
76 real(real64) :: current_time
77 logical :: apply_packed
81 type(nl_operator_t),
pointer :: operators(:)
84 type(derivatives_t),
pointer,
private :: der
85 type(states_mxll_t),
pointer :: st
89 logical :: propagation_apply = .false.
91 integer,
pointer :: rs_state_fft_map(:,:,:)
92 integer,
pointer :: rs_state_fft_map_inv(:,:)
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.
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.
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.
119 logical :: calc_medium_box = .false.
120 type(single_medium_box_t),
allocatable :: medium_boxes(:)
121 logical :: medium_boxes_initialized = .false.
125 logical :: current_density_ext_flag = .false.
126 logical :: current_density_from_medium = .false.
128 type(energy_mxll_t) :: energy
130 logical :: cpml_hamiltonian = .false.
132 logical :: diamag_current = .false.
133 real(real64) :: c_factor
134 real(real64) :: current_factor
137 type(mesh_cube_parallel_map_t) :: mesh_cube_map
146 integer,
public,
parameter :: &
147 FARADAY_AMPERE = 1, &
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
169 assert(
associated(gr%der%lapl))
171 hm%operators(1:3) => gr%der%grad(1:3)
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.
195 call parse_variable(namespace,
'MaxwellHamiltonianOperator', faraday_ampere, hm%operator)
210 call parse_variable(namespace,
'ExternalCurrent', .false., hm%current_density_ext_flag)
212 hm%plane_waves_apply = .false.
213 hm%spatial_constant_apply = .false.
214 hm%spatial_constant_propagate = .
true.
216 hm%propagation_apply = .false.
240 hm%rs_state_fft_map => st%rs_state_fft_map
241 hm%rs_state_fft_map_inv => st%rs_state_fft_map_inv
248 call hm%update_span(gr%spacing(1:gr%der%dim),
m_zero, namespace)
265 nullify(hm%operators)
269 if (
allocated(hm%medium_boxes))
then
270 do il = 1,
size(hm%medium_boxes)
287 if (any(hm%bc%bc_ab_type == option__maxwellabsorbingboundaries__cpml))
then
301 real(real64),
intent(in) :: delta(:)
302 real(real64),
intent(in) :: emin
306 real(real64) :: emax, fd_factor
307 real(real64),
parameter :: fd_factors(4) = [1.0_real64, 1.3723_real64, 1.5861_real64, 1.7307_real64]
314 if (hm%der%stencil_type ==
der_star .and. hm%der%order <= 4)
then
315 fd_factor = fd_factors(hm%der%order)
322 do i = 1,
size(delta)
323 emax = emax +
m_one / delta(i)**2
327 hm%spectral_middle_point =
m_zero
328 hm%spectral_half_span = emax
340 if (.not. hm%adjoint)
then
366 real(real64),
optional,
intent(in) :: time
370 this%current_time =
m_zero
371 if (
present(time)) this%current_time = time
381 time = this%current_time
389 class(mesh_t),
intent(in) :: mesh
391 apply = this%apply_packed
392 if (mesh%use_curvilinear) apply = .false.
399 type(namespace_t),
intent(in) :: namespace
400 type(derivatives_t),
intent(in) :: der
401 type(batch_t),
target,
intent(inout) :: psib
402 type(batch_t),
target,
intent(inout) :: hpsib
403 real(real64),
optional,
intent(in) :: time
404 integer,
optional,
intent(in) :: terms
405 logical,
optional,
intent(in) :: set_bc
407 type(batch_t) :: gradb(der%dim)
408 integer :: idir, ifield, field_dir, pml_dir, rs_sign
409 integer :: ip, ip_in, il
410 real(real64) :: pml_a, pml_b, pml_c
411 complex(real64) :: pml_g, grad
412 integer,
parameter :: field_dirs(3, 2) = reshape([2, 3, 1, 3, 1, 2], [3, 2])
413 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m, ff_real(3), ff_imag(3), coeff_real, coeff_imag
414 complex(real64) :: ff_plus(3), ff_minus(3), hpsi(6)
415 integer,
parameter :: sign_medium(6) = [1, 1, 1, -1, -1, -1]
416 logical :: with_medium
420 call profiling_in(
"H_MXLL_APPLY_BATCH")
421 assert(psib%status() == hpsib%status())
423 assert(psib%nst == hpsib%nst)
424 assert(hm%st%dim == 3)
425 p_c_ = p_c * hm%c_factor
428 assert(.not.
present(terms))
431 if (
present(time))
then
432 if (abs(time - hm%current_time) > 1e-10_real64)
then
433 write(message(1),
'(a)')
'hamiltonian_apply_batch time assertion failed.'
434 write(message(2),
'(a,f12.6,a,f12.6)')
'time = ', time,
'; hm%current_time = ', hm%current_time
435 call messages_fatal(2, namespace=namespace)
441 call profiling_out(
"H_MXLL_APPLY_BATCH")
446 call zderivatives_batch_grad(der, psib, gradb, set_bc=set_bc)
448 if (hm%cpml_hamiltonian)
then
452 call zderivatives_batch_curl_from_gradient(der, hpsib, gradb)
456 if (hm%bc_constant .and. .not. with_medium)
then
460 if (with_medium)
then
462 if ((hm%bc%bc_type(idir) == mxll_bc_medium))
then
467 if (hm%calc_medium_box)
then
468 do il = 1,
size(hm%medium_boxes)
475 call gradb(idir)%end()
478 call profiling_out(
"H_MXLL_APPLY_BATCH")
483 type(batch_t) :: gradb(:)
484 type(accel_kernel_t),
save :: ker_pml
487 call profiling_in(
"APPLY_PML_BOUNDARY")
489 if (with_medium)
then
495 call batch_scal(der%mesh%np, rs_sign * p_c_, gradb(idir))
498 do pml_dir = 1, hm%st%dim
499 if (hm%bc%bc_ab_type(pml_dir) == mxll_ab_cpml)
then
500 select case (gradb(pml_dir)%status())
501 case (batch_not_packed)
503 field_dir = field_dirs(pml_dir, ifield)
505 do ip_in = 1, hm%bc%pml%points_number
506 ip = hm%bc%pml%points_map(ip_in)
507 pml_c = hm%bc%pml%c(ip_in, pml_dir)
508 pml_a = hm%bc%pml%a(ip_in, pml_dir)
509 pml_b = hm%bc%pml%b(ip_in, pml_dir)
510 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
511 grad = gradb(pml_dir)%zff_linear(ip, field_dir)
512 gradb(pml_dir)%zff_linear(ip, field_dir) = pml_c * ((m_one + pml_a)*grad/p_c_ &
513 + rs_sign * pml_b*pml_g)
514 if (with_medium)
then
515 pml_g = hm%bc%pml%conv_minus(ip_in, pml_dir, field_dir)
516 grad = gradb(pml_dir)%zff_linear(ip, field_dir+3)
517 gradb(pml_dir)%zff_linear(ip, field_dir+3) = pml_c * ((m_one + pml_a)*grad/p_c_ &
518 + rs_sign * pml_b*pml_g)
524 do ip_in = 1, hm%bc%pml%points_number
525 ip = hm%bc%pml%points_map(ip_in)
526 pml_c = hm%bc%pml%c(ip_in, pml_dir)
527 pml_a = hm%bc%pml%a(ip_in, pml_dir)
528 pml_b = hm%bc%pml%b(ip_in, pml_dir)
530 field_dir = field_dirs(pml_dir, ifield)
531 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
532 grad = gradb(pml_dir)%zff_pack(field_dir, ip)
533 gradb(pml_dir)%zff_pack(field_dir, ip) = pml_c * ((m_one + pml_a)*grad/p_c_ &
534 + rs_sign * pml_b*pml_g)
535 if (with_medium)
then
536 pml_g = hm%bc%pml%conv_minus(ip_in, pml_dir, field_dir)
537 grad = gradb(pml_dir)%zff_pack(field_dir+3, ip)
538 gradb(pml_dir)%zff_pack(field_dir+3, ip) = pml_c * ((m_one + pml_a)*grad/p_c_ &
539 + rs_sign * pml_b*pml_g)
543 case (batch_device_packed)
544 call accel_kernel_start_call(ker_pml,
'pml.cu',
'pml_apply')
546 if (with_medium)
then
547 call accel_set_kernel_arg(ker_pml, 0, 1_int32)
549 call accel_set_kernel_arg(ker_pml, 0, 0_int32)
551 call accel_set_kernel_arg(ker_pml, 1, hm%bc%pml%points_number)
552 call accel_set_kernel_arg(ker_pml, 2, pml_dir-1)
553 call accel_set_kernel_arg(ker_pml, 3, p_c_)
554 call accel_set_kernel_arg(ker_pml, 4, rs_sign)
555 call accel_set_kernel_arg(ker_pml, 5, hm%bc%pml%buff_map)
556 call accel_set_kernel_arg(ker_pml, 6, gradb(pml_dir)%ff_device)
557 call accel_set_kernel_arg(ker_pml, 7,
log2(int(gradb(pml_dir)%pack_size(1), int32)))
558 call accel_set_kernel_arg(ker_pml, 8, hm%bc%pml%buff_a)
559 call accel_set_kernel_arg(ker_pml, 9, hm%bc%pml%buff_b)
560 call accel_set_kernel_arg(ker_pml, 10, hm%bc%pml%buff_c)
561 call accel_set_kernel_arg(ker_pml, 11, hm%bc%pml%buff_conv_plus)
562 call accel_set_kernel_arg(ker_pml, 12, hm%bc%pml%buff_conv_minus)
564 wgsize = accel_max_workgroup_size()
565 call accel_kernel_run(ker_pml, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
570 if (accel_is_enabled())
then
574 call profiling_out(
"APPLY_PML_BOUNDARY")
580 call profiling_in(
"SCALE_AFTER_CURL")
581 if (.not. hm%cpml_hamiltonian)
then
583 if (with_medium)
then
585 call batch_scal(der%mesh%np, sign_medium * p_c_, hpsib)
587 call batch_scal(der%mesh%np, hm%rs_sign * p_c_, hpsib)
591 if (with_medium)
then
593 call batch_scal(der%mesh%np, sign_medium * m_one, hpsib)
596 call profiling_out(
"SCALE_AFTER_CURL")
602 call profiling_in(
'APPLY_CONSTANT_BC')
603 select case (hpsib%status())
604 case (batch_not_packed)
605 do field_dir = 1, hm%st%dim
606 do ip_in = 1, hm%bc%constant_points_number
607 ip = hm%bc%constant_points_map(ip_in)
608 hpsib%zff_linear(ip, field_dir) = hm%st%rs_state_const(field_dir)
612 do ip_in = 1, hm%bc%constant_points_number
613 ip = hm%bc%constant_points_map(ip_in)
614 do field_dir = 1, hm%st%dim
615 hpsib%zff_pack(field_dir, ip) = hm%st%rs_state_const(field_dir)
618 case (batch_device_packed)
619 call messages_not_implemented(
"Maxwell constant boundary on GPU", namespace=namespace)
621 call profiling_out(
'APPLY_CONSTANT_BC')
626 type(single_medium_box_t),
intent(in) :: medium
631 call profiling_in(
"MEDIUM_BOX")
632 assert(.not. medium%has_mapping)
635 do ip = 1, medium%points_number
636 cc = medium%c(ip)/p_c
637 if (abs(cc) <= m_epsilon) cycle
638 aux_ep(1:3) = medium%aux_ep(ip, 1:3)
639 aux_mu(1:3) = medium%aux_mu(ip, 1:3)
640 sigma_e = medium%sigma_e(ip)
641 sigma_m = medium%sigma_m(ip)
642 select case (hpsib%status())
643 case (batch_not_packed)
644 ff_plus(1:3) = psib%zff_linear(ip, 1:3)
645 ff_minus(1:3) = psib%zff_linear(ip, 4:6)
646 hpsi(1:6) = hpsib%zff_linear(ip, 1:6)
648 ff_plus(1:3) = psib%zff_pack(1:3, ip)
649 ff_minus(1:3) = psib%zff_pack(4:6, ip)
650 hpsi(1:6) = hpsib%zff_pack(1:6, ip)
651 case (batch_device_packed)
652 call messages_not_implemented(
"Maxwell Medium on GPU", namespace=namespace)
654 ff_real = real(ff_plus+ff_minus, real64)
655 ff_imag = aimag(ff_plus-ff_minus)
656 aux_ep = dcross_product(aux_ep, ff_real)
657 aux_mu = dcross_product(aux_mu, ff_imag)
659 coeff_real = - cc * aux_ep(ifield) + sigma_m * ff_imag(ifield)
660 coeff_imag = - cc * aux_mu(ifield) - sigma_e * ff_real(ifield)
661 hpsi(ifield) = cc * hpsi(ifield) + cmplx(coeff_real, coeff_imag, real64)
662 hpsi(ifield+3) = cc * hpsi(ifield+3) + cmplx(-coeff_real, coeff_imag, real64)
664 select case (hpsib%status())
665 case (batch_not_packed)
666 hpsib%zff_linear(ip, 1:6) = hpsi(1:6)
668 hpsib%zff_pack(1:6, ip) = hpsi(1:6)
671 call profiling_out(
"MEDIUM_BOX")
680 type(namespace_t),
intent(in) :: namespace
681 class(mesh_t),
intent(in) :: mesh
682 type(batch_t),
target,
intent(inout) :: psib
683 type(batch_t),
target,
intent(inout) :: hpsib
684 integer,
optional,
intent(in) :: terms
685 logical,
optional,
intent(in) :: set_bc
687 type(batch_t) :: gradb(hm%der%dim)
691 call profiling_in(
"MXLL_HAMILTONIAN_SIMPLE")
693 call zderivatives_batch_grad(hm%der, psib, gradb, set_bc=set_bc)
695 if (any(hm%bc%bc_ab_type == option__maxwellabsorbingboundaries__cpml))
then
701 call zderivatives_batch_curl_from_gradient(hm%der, hpsib, gradb)
703 if (hm%calc_medium_box)
then
708 call batch_scal(mesh%np, p_c*hm%c_factor, hpsib)
711 do idir = 1, hm%der%dim
712 call gradb(idir)%end()
715 call profiling_out(
"MXLL_HAMILTONIAN_SIMPLE")
722 type(batch_t),
intent(inout) :: gradb(1:hm%st%dim)
724 integer :: idir, jdir, ip_in, ip, wgsize
725 type(accel_kernel_t),
save :: ker_pml
729 call profiling_in(
"APPLY_PML_SIMPLE")
732 do jdir = 1, hm%st%dim
733 select case (gradb(1)%status())
734 case (batch_not_packed)
736 do idir = 1, hm%st%dim
737 if (idir == jdir) cycle
738 do ip_in = 1, hm%bc%pml%points_number
739 ip = hm%bc%pml%points_map(ip_in)
741 gradb(jdir)%zff_linear(ip, idir) = gradb(jdir)%zff_linear(ip, idir) * (m_one + hm%bc%pml%c(ip_in, jdir)) + &
742 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
746 do ip_in = 1, hm%bc%pml%points_number
747 ip = hm%bc%pml%points_map(ip_in)
749 do idir = 1, hm%st%dim
750 if (idir == jdir) cycle
752 gradb(jdir)%zff_pack(idir, ip) = gradb(jdir)%zff_pack(idir, ip) * (m_one + hm%bc%pml%c(ip_in, jdir)) +&
753 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
756 case (batch_device_packed)
757 call accel_kernel_start_call(ker_pml,
'pml.cu',
'pml_apply_new')
759 call accel_set_kernel_arg(ker_pml, 0, hm%bc%pml%points_number)
760 call accel_set_kernel_arg(ker_pml, 1, jdir-1)
761 call accel_set_kernel_arg(ker_pml, 2, hm%bc%pml%buff_map)
762 call accel_set_kernel_arg(ker_pml, 3, gradb(jdir)%ff_device)
763 call accel_set_kernel_arg(ker_pml, 4,
log2(int(gradb(jdir)%pack_size(1), int32)))
764 call accel_set_kernel_arg(ker_pml, 5, hm%bc%pml%buff_b)
765 call accel_set_kernel_arg(ker_pml, 6, hm%bc%pml%buff_c)
766 call accel_set_kernel_arg(ker_pml, 7, hm%bc%pml%buff_conv_plus_old)
768 wgsize = accel_max_workgroup_size()
769 call accel_kernel_run(ker_pml, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
772 call profiling_out(
"APPLY_PML_SIMPLE")
779 type(batch_t),
intent(inout) :: rs_stateb
781 integer :: wgsize, idir, jdir, ip, ip_in
782 type(accel_kernel_t),
save :: ker_pml_update
783 type(batch_t) :: gradb(1:hm%st%dim)
786 call profiling_in(
"UPDATE_PML_SIMPLE")
788 call zderivatives_batch_grad(hm%der, rs_stateb, gradb)
790 do jdir = 1, hm%st%dim
791 call rs_stateb%check_compatibility_with(gradb(jdir))
792 select case (gradb(jdir)%status())
793 case (batch_not_packed)
795 do idir = 1, hm%st%dim
796 if (idir == jdir) cycle
797 do ip_in = 1, hm%bc%pml%points_number
798 ip = hm%bc%pml%points_map(ip_in)
799 hm%bc%pml%conv_plus(ip_in, jdir, idir) = hm%bc%pml%c(ip_in, jdir) * gradb(jdir)%zff_linear(ip, idir) +&
800 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
804 do ip_in = 1, hm%bc%pml%points_number
805 ip = hm%bc%pml%points_map(ip_in)
807 do idir = 1, hm%st%dim
808 if (idir == jdir) cycle
809 hm%bc%pml%conv_plus(ip_in, jdir, idir) = hm%bc%pml%c(ip_in, jdir) * gradb(jdir)%zff_pack(idir, ip) +&
810 hm%bc%pml%b(ip_in, jdir) * hm%bc%pml%conv_plus_old(ip_in, jdir, idir)
813 case (batch_device_packed)
814 call accel_kernel_start_call(ker_pml_update,
'pml.cu',
'pml_update_new')
816 call accel_set_kernel_arg(ker_pml_update, 0, hm%bc%pml%points_number)
817 call accel_set_kernel_arg(ker_pml_update, 1, jdir-1)
818 call accel_set_kernel_arg(ker_pml_update, 2, hm%bc%pml%buff_map)
819 call accel_set_kernel_arg(ker_pml_update, 3, gradb(jdir)%ff_device)
820 call accel_set_kernel_arg(ker_pml_update, 4,
log2(int(gradb(jdir)%pack_size(1), int32)))
821 call accel_set_kernel_arg(ker_pml_update, 5, hm%bc%pml%buff_b)
822 call accel_set_kernel_arg(ker_pml_update, 6, hm%bc%pml%buff_c)
823 call accel_set_kernel_arg(ker_pml_update, 7, hm%bc%pml%buff_conv_plus)
824 call accel_set_kernel_arg(ker_pml_update, 8, hm%bc%pml%buff_conv_plus_old)
826 wgsize = accel_max_workgroup_size()
827 call accel_kernel_run(ker_pml_update, (/ accel_padded_size(hm%bc%pml%points_number) /), (/ wgsize /))
829 call gradb(jdir)%end()
831 call profiling_out(
"UPDATE_PML_SIMPLE")
838 type(batch_t),
intent(inout) :: rs_stateb
840 integer :: wgsize, idir, jdir, ip, ip_in
841 type(accel_kernel_t),
save :: ker_pml_copy
844 call profiling_in(
"COPY_PML_SIMPLE")
846 select case (rs_stateb%status())
847 case (batch_packed, batch_not_packed)
848 do jdir = 1, hm%st%dim
850 do idir = 1, hm%st%dim
851 if (idir == jdir) cycle
852 do ip_in = 1, hm%bc%pml%points_number
853 ip = hm%bc%pml%points_map(ip_in)
854 hm%bc%pml%conv_plus_old(ip_in, jdir, idir) = hm%bc%pml%conv_plus(ip_in, jdir, idir)
858 case (batch_device_packed)
859 call accel_kernel_start_call(ker_pml_copy,
'pml.cu',
'pml_copy')
861 call accel_set_kernel_arg(ker_pml_copy, 0, hm%bc%pml%points_number*9)
862 call accel_set_kernel_arg(ker_pml_copy, 1, hm%bc%pml%buff_conv_plus)
863 call accel_set_kernel_arg(ker_pml_copy, 2, hm%bc%pml%buff_conv_plus_old)
865 wgsize = accel_max_workgroup_size()
866 call accel_kernel_run(ker_pml_copy, (/ accel_padded_size(hm%bc%pml%points_number*9) /), (/ wgsize /))
868 call profiling_out(
"COPY_PML_SIMPLE")
875 type(batch_t),
intent(inout) :: rs_stateb
878 logical :: need_to_pack
881 call profiling_in(
"LINEAR_MEDIUM_SIMPLE")
883 do il = 1,
size(hm%medium_boxes)
884 assert(.not. hm%medium_boxes(il)%has_mapping)
885 need_to_pack = .false.
887 if(rs_stateb%status() == batch_device_packed)
then
888 call rs_stateb%do_unpack(force=.
true.)
889 need_to_pack = .
true.
891 select case (rs_stateb%status())
892 case (batch_not_packed)
893 do ip = 1, hm%medium_boxes(il)%points_number
894 if (abs(hm%medium_boxes(il)%c(ip)) <= m_epsilon)
then
896 rs_stateb%zff_linear(ip, 1:3) = p_c*hm%c_factor*rs_stateb%zff_linear(ip, 1:3)
899 rs_stateb%zff_linear(ip, 1:3) = hm%medium_boxes(il)%c(ip)*(rs_stateb%zff_linear(ip, 1:3) + &
901 -dcross_product(hm%medium_boxes(il)%aux_ep(ip, 1:3)*m_two, &
902 real(rs_stateb%zff_linear(ip, 1:3), real64)), &
903 -dcross_product(hm%medium_boxes(il)%aux_mu(ip, 1:3)*m_two, &
904 aimag(rs_stateb%zff_linear(ip, 1:3))), real64)) + &
906 hm%medium_boxes(il)%sigma_m(ip)*aimag(rs_stateb%zff_linear(ip, 1:3)), &
907 -hm%medium_boxes(il)%sigma_e(ip)*
real(rs_stateb%zff_linear(ip, 1:3), real64), real64)
911 do ip = 1, hm%medium_boxes(il)%points_number
912 if (abs(hm%medium_boxes(il)%c(ip)) <= m_epsilon)
then
914 rs_stateb%zff_pack(1:3, ip) = p_c*hm%c_factor*rs_stateb%zff_pack(1:3, ip)
917 rs_stateb%zff_pack(1:3, ip) = hm%medium_boxes(il)%c(ip)*(rs_stateb%zff_pack(1:3, ip) + &
919 -dcross_product(hm%medium_boxes(il)%aux_ep(ip, 1:3)*m_two, &
920 real(rs_stateb%zff_pack(1:3, ip), real64)), &
921 -dcross_product(hm%medium_boxes(il)%aux_mu(ip, 1:3)*m_two, &
922 aimag(rs_stateb%zff_pack(1:3, ip))), real64)) + &
924 hm%medium_boxes(il)%sigma_m(ip)*aimag(rs_stateb%zff_pack(1:3, ip)), &
925 -hm%medium_boxes(il)%sigma_e(ip)*
real(rs_stateb%zff_pack(1:3, ip), real64), real64)
929 if(need_to_pack)
then
930 call rs_stateb%do_pack()
934 call profiling_out(
"LINEAR_MEDIUM_SIMPLE")
942 type(namespace_t),
intent(in) :: namespace
943 class(mesh_t),
intent(in) :: mesh
944 class(batch_t),
target,
intent(inout) :: psib
945 class(batch_t),
target,
intent(inout) :: hpsib
946 integer,
optional,
intent(in) :: terms
947 logical,
optional,
intent(in) :: set_bc
949 write(message(1),
'(a)')
'dhamiltonian_mxll_apply not implemented (states are complex).'
950 call messages_fatal(1, namespace=namespace)
958 type(namespace_t),
intent(in) :: namespace
959 class(mesh_t),
intent(in) :: mesh
960 class(batch_t),
target,
intent(inout) :: psib
961 class(batch_t),
target,
intent(inout) :: hpsib
962 integer,
optional,
intent(in) :: terms
963 logical,
optional,
intent(in) :: set_bc
965 complex(real64),
allocatable :: rs_aux_in(:,:), rs_aux_out(:,:)
971 call profiling_in(
'ZHAMILTONIAN_MXLL_APPLY')
973 on_gpu = psib%status() == batch_device_packed
976 safe_allocate(rs_aux_in(1:mesh%np_part, 1:hm%dim))
977 safe_allocate(rs_aux_out(1:mesh%np, 1:hm%dim))
978 call boundaries_set(hm%der%boundaries, mesh, psib)
980 call batch_get_state(psib, ii,mesh%np_part, rs_aux_in(:, ii))
985 call batch_set_state(hpsib, ii, mesh%np, rs_aux_out(:, ii))
987 safe_deallocate_a(rs_aux_in)
988 safe_deallocate_a(rs_aux_out)
994 call profiling_out(
'ZHAMILTONIAN_MXLL_APPLY')
1004 type(derivatives_t),
intent(in) :: der
1005 complex(real64),
contiguous,
intent(inout) :: psi(:,:)
1006 complex(real64),
intent(inout) :: oppsi(:,:)
1008 real(real64),
pointer :: mx_rho(:,:)
1009 complex(real64),
allocatable :: tmp(:,:)
1010 complex(real64),
pointer :: kappa_psi(:,:)
1011 integer :: np, np_part, ip, ip_in, rs_sign
1012 real(real64) :: P_c_
1016 call profiling_in(
'MAXWELL_HAMILTONIAN_APPLY_FD')
1019 np_part = der%mesh%np_part
1020 rs_sign = hm%rs_sign
1021 p_c_ = p_c * hm%c_factor
1023 select case (hm%operator)
1029 call profiling_in(
'MXLL_HAM_APPLY_FD_FARADAY_AMP')
1031 safe_allocate(tmp(1:np,1:2))
1034 if (hm%diamag_current)
then
1035 mx_rho => hm%st%grid_rho
1036 kappa_psi => hm%st%kappa_psi
1042 call zderivatives_partial(der, psi(:,3), tmp(:,1), 2, set_bc = .false.)
1043 call zderivatives_partial(der, psi(:,2), tmp(:,2), 3, set_bc = .false.)
1044 tmp = rs_sign * p_c_ * tmp
1047 oppsi(1:np,1) = ( tmp(1:np,1)-tmp(1:np,2))
1052 call zderivatives_partial(der, psi(:,1), tmp(:,1), 3, set_bc = .false.)
1053 call zderivatives_partial(der, psi(:,3), tmp(:,2), 1, set_bc = .false.)
1054 tmp = rs_sign * p_c_ * tmp
1057 oppsi(1:np,2) = ( tmp(1:np,1)-tmp(1:np,2))
1062 call zderivatives_partial(der, psi(:,2), tmp(:,1), 1, set_bc = .false.)
1063 call zderivatives_partial(der, psi(:,1), tmp(:,2), 2, set_bc = .false.)
1064 tmp = rs_sign * p_c_ * tmp
1067 oppsi(1:np,3) = ( tmp(1:np,1)-tmp(1:np,2))
1069 if (hm%bc_constant)
then
1070 do ip_in = 1, hm%bc%constant_points_number
1071 ip = hm%bc%constant_points_map(ip_in)
1072 oppsi(ip,:) = hm%st%rs_state_const(:)
1076 safe_deallocate_a(tmp)
1078 call profiling_out(
'MXLL_HAM_APPLY_FD_FARADAY_AMP')
1083 call profiling_in(
'MXLL_HAM_APP_FAR_AMP_MED')
1085 safe_allocate(tmp(1:np,1:4))
1091 call zderivatives_partial(der, psi(:,3), tmp(:,1), 2, set_bc = .false.)
1092 call zderivatives_partial(der, psi(:,2), tmp(:,3), 3, set_bc = .false.)
1093 call zderivatives_partial(der, psi(:,6), tmp(:,2), 2, set_bc = .false.)
1094 call zderivatives_partial(der, psi(:,5), tmp(:,4), 3, set_bc = .false.)
1098 oppsi(1:np,1) = (tmp(1:np,1)-tmp(1:np,3))
1099 oppsi(1:np,4) = -(tmp(1:np,2)-tmp(1:np,4))
1104 call zderivatives_partial(der, psi(:,1), tmp(:,1), 3, set_bc = .false.)
1105 call zderivatives_partial(der, psi(:,3), tmp(:,3), 1, set_bc = .false.)
1106 call zderivatives_partial(der, psi(:,4), tmp(:,2), 3, set_bc = .false.)
1107 call zderivatives_partial(der, psi(:,6), tmp(:,4), 1, set_bc = .false.)
1111 oppsi(1:np,2) = (tmp(1:np,1)-tmp(1:np,3))
1112 oppsi(1:np,5) = -(tmp(1:np,2)-tmp(1:np,4))
1117 call zderivatives_partial(der, psi(:,2), tmp(:,1), 1, set_bc = .false.)
1118 call zderivatives_partial(der, psi(:,1), tmp(:,3), 2, set_bc = .false.)
1119 call zderivatives_partial(der, psi(:,5), tmp(:,2), 1, set_bc = .false.)
1120 call zderivatives_partial(der, psi(:,4), tmp(:,4), 2, set_bc = .false.)
1124 oppsi(1:np,3) = (tmp(1:np,1)-tmp(1:np,3))
1125 oppsi(1:np,6) = -(tmp(1:np,2)-tmp(1:np,4))
1128 safe_deallocate_a(tmp)
1138 call profiling_out(
'MXLL_HAM_APP_FAR_AMP_MED')
1142 call profiling_out(
'MAXWELL_HAMILTONIAN_APPLY_FD')
1152 type(derivatives_t),
intent(in) :: der
1153 complex(real64),
intent(inout) :: psi(:,:)
1154 integer,
intent(in) :: dir1
1155 integer,
intent(in) :: dir2
1156 complex(real64),
intent(inout) :: tmp(:)
1161 call profiling_in(
'MAXWELL_PML_HAMILTONIAN')
1163 if ((hm%bc%bc_ab_type(dir1) == mxll_ab_cpml) .and. hm%cpml_hamiltonian)
then
1167 call profiling_out(
'MAXWELL_PML_HAMILTONIAN')
1176 type(derivatives_t),
intent(in) :: der
1177 complex(real64),
intent(inout) :: psi(:,:)
1178 integer,
intent(in) :: dir1
1179 integer,
intent(in) :: dir2
1180 complex(real64),
intent(inout) :: tmp(:,:)
1185 call profiling_in(
'MAXWELL_PML_HAMILTONIAN_MEDIUM')
1187 if ((hm%bc%bc_ab_type(dir1) == mxll_ab_cpml) .and. hm%cpml_hamiltonian)
then
1191 call profiling_out(
'MAXWELL_PML_HAMILTONIAN_MEDIUM')
1200 type(derivatives_t),
intent(in) :: der
1201 integer,
intent(in) :: pml_dir
1202 complex(real64),
intent(inout) :: psi(:,:)
1203 integer,
intent(in) :: field_dir
1204 complex(real64),
intent(inout) :: pml(:)
1206 integer :: ip, ip_in, rs_sign
1207 real(real64) :: pml_c
1208 complex(real64),
allocatable :: tmp_partial(:)
1209 complex(real64) :: pml_a, pml_b, pml_g
1213 if (hm%cpml_hamiltonian)
then
1215 rs_sign = hm%rs_sign
1217 safe_allocate(tmp_partial(1:der%mesh%np_part))
1219 call zderivatives_partial(der, psi(:,field_dir), tmp_partial(:), pml_dir, set_bc = .false.)
1220 do ip_in = 1, hm%bc%pml%points_number
1221 ip = hm%bc%pml%points_map(ip_in)
1222 pml_c = hm%bc%pml%c(ip_in, pml_dir)
1223 pml_a = hm%bc%pml%a(ip_in, pml_dir)
1224 pml_b = hm%bc%pml%b(ip_in, pml_dir)
1225 pml_g = hm%bc%pml%conv_plus(ip_in, pml_dir, field_dir)
1226 pml(ip) = rs_sign * pml_c * ( tmp_partial(ip) &
1227 + real(pml_a, real64) * real(tmp_partial(ip), real64) &
1228 + m_zi * aimag(pml_a) * aimag(tmp_partial(ip)) &
1229 + real(pml_b, real64) * real(pml_g, real64) &
1230 + m_zi * aimag(pml_b) * aimag(pml_g))
1233 safe_deallocate_a(tmp_partial)
1245 type(derivatives_t),
intent(in) :: der
1246 integer,
intent(in) :: pml_dir
1247 complex(real64),
intent(inout) :: psi(:,:)
1248 integer,
intent(in) :: field_dir
1249 complex(real64),
intent(inout) :: pml(:,:)
1251 integer :: ip, ip_in, np
1252 real(real64) :: pml_c(3)
1253 complex(real64),
allocatable :: tmp_partial(:,:)
1254 complex(real64) :: pml_a(3), pml_b(3), pml_g_p(3), pml_g_m(3)
1258 if (hm%cpml_hamiltonian)
then
1261 safe_allocate(tmp_partial(1:np,1:2))
1263 call zderivatives_partial(der, psi(:,field_dir ), tmp_partial(:,1), pml_dir, set_bc = .false.)
1264 call zderivatives_partial(der, psi(:,field_dir+3), tmp_partial(:,2), pml_dir, set_bc = .false.)
1265 do ip_in = 1, hm%bc%pml%points_number
1266 ip = hm%bc%pml%points_map(ip_in)
1267 pml_c(1:3) = hm%bc%pml%c(ip_in, 1:3)
1268 pml_a(1:3) = hm%bc%pml%a(ip_in, 1:3)
1269 pml_b(1:3) = hm%bc%pml%b(ip_in, 1:3)
1270 pml_g_p(1:3) = hm%bc%pml%conv_plus(ip_in, pml_dir, 1:3)
1271 pml_g_m(1:3) = hm%bc%pml%conv_minus(ip_in, pml_dir, 1:3)
1272 pml(ip, 1) = pml_c(pml_dir) * tmp_partial(ip, 1) &
1273 + pml_c(pml_dir) * real(pml_a(pml_dir), real64) * real(tmp_partial(ip, 1), real64) &
1274 + m_zi * pml_c(pml_dir) * aimag(pml_a(pml_dir)) * aimag(tmp_partial(ip, 1)) &
1275 + pml_c(pml_dir) * real(pml_b(pml_dir), real64) * real(pml_g_p(field_dir), real64) &
1276 + m_zi * pml_c(pml_dir) * aimag(pml_b(pml_dir)) * aimag(pml_g_p(field_dir))
1277 pml(ip, 2) = pml_c(pml_dir) * tmp_partial(ip, 2) &
1278 + pml_c(pml_dir) * real(pml_a(pml_dir), real64) * real(tmp_partial(ip, 2), real64) &
1279 + m_zi * pml_c(pml_dir) * aimag(pml_a(pml_dir)) * aimag(tmp_partial(ip, 2)) &
1280 + pml_c(pml_dir) * real(pml_b(pml_dir), real64) * real(pml_g_m(field_dir), real64) &
1281 + m_zi * pml_c(pml_dir) * aimag(pml_b(pml_dir)) * aimag(pml_g_m(field_dir))
1286 safe_deallocate_a(tmp_partial)
1296 complex(real64),
intent(in) :: psi(:,:)
1297 complex(real64),
intent(inout) :: oppsi(:,:)
1299 integer :: ip, ip_in, idim
1300 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m
1301 complex(real64) :: ff_plus(3), ff_minus(3)
1306 if ((hm%bc%bc_type(idim) == mxll_bc_medium))
then
1307 do ip_in = 1, hm%bc%medium(idim)%points_number
1308 ip = hm%bc%medium(idim)%points_map(ip_in)
1309 cc = hm%bc%medium(idim)%c(ip_in)/p_c
1310 aux_ep(:) = hm%bc%medium(idim)%aux_ep(ip_in, :)
1311 aux_mu(:) = hm%bc%medium(idim)%aux_mu(ip_in, :)
1312 sigma_e = hm%bc%medium(idim)%sigma_e(ip_in)
1313 sigma_m = hm%bc%medium(idim)%sigma_m(ip_in)
1314 ff_plus(1) = psi(ip, 1)
1315 ff_plus(2) = psi(ip, 2)
1316 ff_plus(3) = psi(ip, 3)
1317 ff_minus(1) = psi(ip, 4)
1318 ff_minus(2) = psi(ip, 5)
1319 ff_minus(3) = psi(ip, 6)
1320 aux_ep = dcross_product(aux_ep,real(ff_plus+ff_minus, real64) )
1321 aux_mu = dcross_product(aux_mu,aimag(ff_plus-ff_minus))
1322 oppsi(ip, 1) = oppsi(ip, 1)*cc &
1323 - cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1324 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1325 - m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1326 oppsi(ip, 4) = oppsi(ip, 4)*cc &
1327 + cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1328 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1329 + m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1330 oppsi(ip, 2) = oppsi(ip, 2)*cc &
1331 - cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1332 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1333 - m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1334 oppsi(ip, 5) = oppsi(ip, 5)*cc &
1335 + cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1336 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1337 + m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1338 oppsi(ip, 3) = oppsi(ip, 3)*cc &
1339 - cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1340 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1341 - m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1342 oppsi(ip, 6) = oppsi(ip, 6)*cc &
1343 + cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1344 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1345 + m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1358 type(derivatives_t),
intent(in) :: der
1359 complex(real64),
intent(in) :: psi(:,:)
1360 complex(real64),
intent(inout) :: oppsi(:,:)
1363 real(real64) :: cc, aux_ep(3), aux_mu(3), sigma_e, sigma_m
1364 complex(real64) :: ff_plus(3), ff_minus(3)
1368 if (hm%calc_medium_box)
then
1369 do il = 1,
size(hm%medium_boxes)
1370 assert(.not. hm%medium_boxes(il)%has_mapping)
1371 do ip = 1, hm%medium_boxes(il)%points_number
1372 cc = hm%medium_boxes(il)%c(ip)/p_c
1373 if (abs(cc) <= m_epsilon) cycle
1374 aux_ep(1:3) = hm%medium_boxes(il)%aux_ep(ip, 1:3)
1375 aux_mu(1:3) = hm%medium_boxes(il)%aux_mu(ip, 1:3)
1376 sigma_e = hm%medium_boxes(il)%sigma_e(ip)
1377 sigma_m = hm%medium_boxes(il)%sigma_m(ip)
1378 ff_plus(1) = psi(ip, 1)
1379 ff_plus(2) = psi(ip, 2)
1380 ff_plus(3) = psi(ip, 3)
1381 ff_minus(1) = psi(ip, 4)
1382 ff_minus(2) = psi(ip, 5)
1383 ff_minus(3) = psi(ip, 6)
1384 aux_ep = dcross_product(aux_ep, real(ff_plus+ff_minus, real64) )
1385 aux_mu = dcross_product(aux_mu, aimag(ff_plus-ff_minus))
1386 oppsi(ip, 1) = oppsi(ip,1)*cc &
1387 - cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1388 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1389 - m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1390 oppsi(ip, 4) = oppsi(ip,4)*cc &
1391 + cc * aux_ep(1) - cc * m_zi * aux_mu(1) &
1392 - m_zi * sigma_e * real(ff_plus(1) + ff_minus(1), real64) &
1393 + m_zi * sigma_m * m_zi * aimag(ff_plus(1) - ff_minus(1))
1394 oppsi(ip, 2) = oppsi(ip,2)*cc &
1395 - cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1396 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1397 - m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1398 oppsi(ip, 5) = oppsi(ip,5)*cc &
1399 + cc * aux_ep(2) - cc * m_zi * aux_mu(2) &
1400 - m_zi * sigma_e * real(ff_plus(2) + ff_minus(2), real64) &
1401 + m_zi * sigma_m * m_zi * aimag(ff_plus(2) - ff_minus(2))
1402 oppsi(ip, 3) = oppsi(ip,3)*cc &
1403 - cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1404 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1405 - m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
1406 oppsi(ip, 6) = oppsi(ip,6)*cc &
1407 + cc * aux_ep(3) - cc * m_zi * aux_mu(3) &
1408 - m_zi * sigma_e * real(ff_plus(3) + ff_minus(3), real64) &
1409 + m_zi * sigma_m * m_zi * aimag(ff_plus(3) - ff_minus(3))
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.
This module implements common operations on batches of mesh functions.
Module implementing boundary conditions in Octopus.
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
integer, parameter, public der_star
real(real64), parameter, public m_zero
real(real64), parameter, public m_pi
some mathematical constants
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
real(real64), parameter, public m_one
real(real64), parameter, public m_three
This module implements the underlying real-space grid.
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.
subroutine, public bc_mxll_end(bc)
This module defines the meshes, which are used in Octopus.
subroutine, public messages_experimental(name, namespace)
This module defines non-local operators.
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
This module handles spin dimensions of the states and the k-point distribution.
The abstract Hamiltonian class defines a skeleton for specific implementations.