54 type(space_t) :: space
56 integer,
public ::
type
58 character(len=1024) :: potential_formula
59 character(len=200) :: density_formula
60 character(len=MAX_PATH_LEN) :: filename
63 real(real64),
allocatable,
public :: pot(:)
65 real(real64),
allocatable,
public :: b_field(:)
67 real(real64),
allocatable,
public :: a_static(:,:)
68 real(real64),
allocatable,
public :: e_field(:)
71 real(real64),
allocatable,
public :: v_ext(:)
82 integer,
public,
parameter :: &
83 EXTERNAL_POT_USDEF = 201, & !< user-defined function for local potential
99 class(external_potential_t),
pointer,
intent(out) :: pot_out
100 class(external_potential_t),
intent(in) :: pot_in
102 type(quantity_iterator_t) :: iter
103 class(quantity_t),
pointer :: quantity
109 pot_out%namespace = pot_in%namespace
110 pot_out%space = pot_in%space
111 pot_out%type = pot_in%type
112 pot_out%potential_formula = pot_in%potential_formula
113 pot_out%density_formula = pot_in%density_formula
114 pot_out%filename = pot_in%filename
115 pot_out%omega = pot_in%omega
116 pot_out%gauge_2D = pot_in%gauge_2D
118 if (
allocated(pot_in%pot))
then
119 allocate(pot_out%pot, source=pot_in%pot)
121 if (
allocated(pot_in%b_field))
then
122 allocate(pot_out%b_field, source=pot_in%b_field)
124 if (
allocated(pot_in%a_static))
then
125 allocate(pot_out%a_static, source=pot_in%a_static)
127 if (
allocated(pot_in%e_field))
then
128 allocate(pot_out%e_field, source=pot_in%e_field)
130 if (
allocated(pot_in%v_ext))
then
131 allocate(pot_out%v_ext, source=pot_in%v_ext)
134 if (
allocated(pot_in%supported_interactions_as_partner))
then
135 allocate(pot_out%supported_interactions_as_partner, source=pot_in%supported_interactions_as_partner)
137 allocate(pot_out%supported_interactions_as_partner(0))
140 call iter%start(pot_in%quantities)
141 do while (iter%has_next())
142 quantity => iter%get_next()
143 call pot_out%quantities%add(quantity)
157 this%namespace =
namespace_t(
"ExternalPotential", parent=namespace)
162 allocate(this%supported_interactions_as_partner(0))
164 call this%quantities%add(
quantity_t(
"E field", always_available = .
true., updated_on_demand = .false., &
166 call this%quantities%add(
quantity_t(
"B field", always_available = .
true., updated_on_demand = .false., &
178 call this%deallocate_memory()
186 class(
mesh_t),
intent(in) :: mesh
190 select case (this%type)
192 safe_allocate(this%pot(1:mesh%np))
194 safe_allocate(this%a_static(1:mesh%np, 1:this%space%dim))
196 if (this%space%periodic_dim < this%space%dim)
then
197 safe_allocate(this%pot(1:mesh%np))
198 safe_allocate(this%v_ext(1:mesh%np_part))
211 safe_deallocate_a(this%pot)
212 safe_deallocate_a(this%b_field)
213 safe_deallocate_a(this%a_static)
214 safe_deallocate_a(this%e_field)
215 safe_deallocate_a(this%v_ext)
227 select type (interaction)
231 message(1) =
"Unsupported interaction."
247 select type (interaction)
250 do ip = 1, interaction%system_np
251 interaction%partner_e_field(:, ip) = partner%e_field
252 interaction%partner_b_field(:, ip) =
m_zero
255 do ip = 1, interaction%system_np
256 interaction%partner_e_field(:, ip) =
m_zero
257 interaction%partner_b_field(:, ip) = partner%b_field
264 message(1) =
"Unsupported interaction."
276 class(
mesh_t),
intent(in) :: mesh
279 real(real64) :: pot_re, pot_im, r, xx(this%space%dim)
280 real(real64),
allocatable :: den(:), grx(:)
285 select case (this%type)
287 case (external_pot_usdef)
288 assert(
allocated(this%pot))
291 call mesh_r(mesh, ip, r, coords = xx)
293 this%pot(ip) = pot_re
297 assert(
allocated(this%pot))
299 call dio_function_input(trim(this%filename), namespace, this%space, mesh, this%pot, err)
301 write(
message(1),
'(a)')
'Error loading file '//trim(this%filename)//
'.'
302 write(
message(2),
'(a,i4)')
'Error code returned = ', err
307 assert(
allocated(this%pot))
309 safe_allocate(den(1:mesh%np))
312 call mesh_r(mesh, ip, r, coords = xx)
317 call dpoisson_solve(poisson, namespace, this%pot, den, all_nodes = .false.)
319 safe_deallocate_a(den)
322 assert(
allocated(this%b_field))
328 safe_allocate(grx(1:this%space%dim))
330 select case (this%space%dim)
332 select case (this%gauge_2d)
334 if (this%space%periodic_dim == 1)
then
335 message(1) =
"For 2D system, 1D-periodic, StaticMagneticField can only be "
336 message(2) =
"applied for StaticMagneticField2DGauge = linear_y."
341 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
342 this%a_static(ip, 1) = -
m_half/
p_c * grx(2) * this%b_field(3)
343 this%a_static(ip, 2) =
m_half/
p_c * grx(1) * this%b_field(3)
348 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
349 this%a_static(ip, 1) = -
m_one/
p_c * grx(2) * this%b_field(3)
350 this%a_static(ip, 2) =
m_zero
356 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
357 this%a_static(ip, 1) = -
m_half/
p_c*(grx(2) * this%b_field(3) - grx(3) * this%b_field(2))
358 this%a_static(ip, 2) = -
m_half/
p_c*(grx(3) * this%b_field(1) - grx(1) * this%b_field(3))
359 this%a_static(ip, 3) = -
m_half/
p_c*(grx(1) * this%b_field(2) - grx(2) * this%b_field(1))
365 safe_deallocate_a(grx)
368 assert(
allocated(this%e_field))
370 if (this%space%periodic_dim < this%space%dim)
then
381 this%pot(ip) = sum(mesh%x(this%space%periodic_dim + 1:this%space%dim, ip) &
382 * this%e_field(this%space%periodic_dim + 1:this%space%dim))
386 this%v_ext(1:mesh%np) = this%pot(1:mesh%np)
387 do ip = mesh%np+1, mesh%np_part
388 this%v_ext(ip) = sum(mesh%x(this%space%periodic_dim + 1:this%space%dim, ip) &
389 * this%e_field(this%space%periodic_dim + 1:this%space%dim))
402 integer :: n_pot_block, row, read_data
406 integer :: dim, periodic_dim, idir
452 if (
parse_block(namespace,
'StaticExternalPotentials', blk) == 0)
then
455 do row = 0, n_pot_block-1
460 assert(read_data > 0)
462 call external_potentials%add(pot)
472 call parse_variable(namespace,
'PeriodicDimensions', 0, periodic_dim)
496 if (
parse_block(namespace,
'StaticMagneticField', blk) == 0)
then
515 call parse_variable(namespace,
'StaticMagneticField2DGauge', 0, pot%gauge_2d)
520 safe_allocate(pot%b_field(1:3))
528 if (periodic_dim == 2)
then
529 message(1) =
"StaticMagneticField cannot be applied in a 2D, 2D-periodic system."
532 if (pot%b_field(1)**2 + pot%b_field(2)**2 >
m_zero)
then
539 if (periodic_dim >= 2)
then
540 message(1) =
"In 3D, StaticMagneticField cannot be applied when the system is 2D- or 3D-periodic."
542 else if (periodic_dim == 1 .and. any(abs(pot%b_field(2:3)) >
m_zero))
then
543 message(1) =
"In 3D, 1D-periodic, StaticMagneticField must be zero in the y- and z-directions."
552 call external_potentials%add(pot)
570 if (
parse_block(namespace,
'StaticElectricField', blk) == 0)
then
576 safe_allocate(pot%e_field(1:dim))
581 if (idir <= periodic_dim .and. abs(pot%e_field(idir)) >
m_epsilon)
then
582 message(1) =
"Applying StaticElectricField in a periodic direction is only accurate for large supercells."
589 call external_potentials%add(pot)
602 type(
block_t),
intent(in) :: blk
603 integer,
intent(in) :: row
604 integer,
intent(out) :: read_data
606 integer :: ncols, icol, flag
620 if (pot%type >= 0)
then
621 message(1) =
'Error in reading the ExternalPotentials block'
631 call messages_input_error(namespace,
'ExternalPotentials',
"Unknown type of external potential")
638 if (icol >= ncols)
exit
644 case (option__staticexternalpotentials__file)
648 case (option__staticexternalpotentials__potential_formula)
652 if (pot%type /= external_pot_usdef)
then
653 call messages_input_error(namespace,
'ExternalPotentials',
'potential_formula can only be used with user_defined')
656 case (option__staticexternalpotentials__density_formula)
661 call messages_input_error(namespace,
'ExternalPotentials',
'density_formula can only be used with charge_density')
674 if (pot%type == external_pot_usdef .and. &
675 .not.
parameter_defined(option__staticexternalpotentials__potential_formula))
then
676 call messages_input_error(namespace,
'ExternalPotentials',
"The 'potential_formula' parameter is missing.")
681 call messages_input_error(namespace,
'ExternalPotentials',
"The 'density_formula' parameter is missing.")
695 integer(int64),
intent(in) :: param
709 integer(int64),
intent(in) :: param
714 call messages_input_error(namespace,
'ExternalPotentials',
"Duplicated parameter in external potential.")
subroutine check_duplication(param)
logical function parameter_defined(param)
integer, parameter, public external_pot_from_file
potential, defined in a file
subroutine, public load_external_potentials(external_potentials, namespace)
class(external_potential_t) function, pointer external_potential_init(namespace)
subroutine read_from_block(pot, namespace, blk, row, read_data)
integer, parameter, public external_pot_charge_density
user-defined function for charge density
subroutine external_potential_finalize(this)
subroutine external_potential_calculate(this, namespace, mesh, poisson)
subroutine external_potential_init_interaction_as_partner(partner, interaction)
subroutine external_potential_deallocate(this)
subroutine external_potential_copy_quantities_to_interaction(partner, interaction)
integer, parameter, public external_pot_static_efield
Static electric field.
integer, parameter, public external_pot_static_bfield
Static magnetic field.
subroutine external_potential_allocate(this, mesh)
subroutine, public external_potential_clone(pot_out, pot_in)
Deep-clone an external potential instance.
real(real64), parameter, public m_zero
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_half
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
real(real64), parameter, public m_one
This module implements a simple hash table for non-negative integer keys and integer values.
subroutine, public iihash_end(h)
Free a hash table.
subroutine, public iihash_insert(h, key, val)
Insert a (key, val) pair into the hash table h.
integer function, public iihash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
subroutine, public iihash_init(h)
Initialize a hash table h.
integer, parameter, public lorentz_force
This module defines classes and functions for interaction partners.
subroutine, public dio_function_input(filename, namespace, space, mesh, ff, ierr, map)
Reads a mesh function from file filename, and puts it into ff. If the map argument is passed,...
This module defines the meshes, which are used in Octopus.
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
subroutine, public messages_not_implemented(feature, namespace)
subroutine, public messages_warning(no_lines, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_input_error(namespace, var, details, row, column)
subroutine, public parse_block_string(blk, l, c, res, convert_to_c)
integer function, public parse_block(namespace, name, blk, check_varinfo_)
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
This module defines the quantity_t class and the IDs for quantities, which can be exposed by a system...
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
This module defines the unit system, used for input and output.
type(unit_system_t), public units_inp
the units systems for reading and writing
abstract class for general interaction partners
surrogate interaction class to avoid circular dependencies between modules.
This class implements the iteration counter used by the multisystem algorithms. As any iteration coun...
Lorenz force between a systems of particles and an electromagnetic field.
Describes mesh distribution to nodes.
Systems (system_t) can expose quantities that can be used to calculate interactions with other system...