53 type(space_t) :: space
55 integer,
public ::
type
57 character(len=1024) :: potential_formula
58 character(len=200) :: density_formula
59 character(len=MAX_PATH_LEN) :: filename
62 real(real64),
allocatable,
public :: pot(:)
64 real(real64),
allocatable,
public :: b_field(:)
66 real(real64),
allocatable,
public :: a_static(:,:)
67 real(real64),
allocatable,
public :: e_field(:)
70 real(real64),
allocatable,
public :: v_ext(:)
81 integer,
public,
parameter :: &
82 EXTERNAL_POT_USDEF = 201, & !< user-defined function for local potential
98 class(external_potential_t),
pointer,
intent(out) :: pot_out
99 class(external_potential_t),
intent(in) :: pot_in
101 type(quantity_iterator_t) :: iter
102 class(quantity_t),
pointer :: quantity
108 pot_out%namespace = pot_in%namespace
109 pot_out%space = pot_in%space
110 pot_out%type = pot_in%type
111 pot_out%potential_formula = pot_in%potential_formula
112 pot_out%density_formula = pot_in%density_formula
113 pot_out%filename = pot_in%filename
114 pot_out%omega = pot_in%omega
115 pot_out%gauge_2D = pot_in%gauge_2D
117 if (
allocated(pot_in%pot))
then
118 allocate(pot_out%pot, source=pot_in%pot)
120 if (
allocated(pot_in%b_field))
then
121 allocate(pot_out%b_field, source=pot_in%b_field)
123 if (
allocated(pot_in%a_static))
then
124 allocate(pot_out%a_static, source=pot_in%a_static)
126 if (
allocated(pot_in%e_field))
then
127 allocate(pot_out%e_field, source=pot_in%e_field)
129 if (
allocated(pot_in%v_ext))
then
130 allocate(pot_out%v_ext, source=pot_in%v_ext)
133 if (
allocated(pot_in%supported_interactions_as_partner))
then
134 allocate(pot_out%supported_interactions_as_partner, source=pot_in%supported_interactions_as_partner)
136 allocate(pot_out%supported_interactions_as_partner(0))
139 call iter%start(pot_in%quantities)
140 do while (iter%has_next())
141 quantity => iter%get_next()
142 call pot_out%quantities%add(quantity)
156 this%namespace =
namespace_t(
"ExternalPotential", parent=namespace)
161 allocate(this%supported_interactions_as_partner(0))
163 call this%quantities%add(
quantity_t(
"E field", always_available = .
true., updated_on_demand = .false., &
165 call this%quantities%add(
quantity_t(
"B field", always_available = .
true., updated_on_demand = .false., &
177 call this%deallocate_memory()
185 class(
mesh_t),
intent(in) :: mesh
189 select case (this%type)
191 safe_allocate(this%pot(1:mesh%np))
193 safe_allocate(this%a_static(1:mesh%np, 1:this%space%dim))
195 if (this%space%periodic_dim < this%space%dim)
then
196 safe_allocate(this%pot(1:mesh%np))
197 safe_allocate(this%v_ext(1:mesh%np_part))
210 safe_deallocate_a(this%pot)
211 safe_deallocate_a(this%b_field)
212 safe_deallocate_a(this%a_static)
213 safe_deallocate_a(this%e_field)
214 safe_deallocate_a(this%v_ext)
226 select type (interaction)
230 message(1) =
"Unsupported interaction."
246 select type (interaction)
249 do ip = 1, interaction%system_np
250 interaction%partner_e_field(:, ip) = partner%e_field
251 interaction%partner_b_field(:, ip) =
m_zero
254 do ip = 1, interaction%system_np
255 interaction%partner_e_field(:, ip) =
m_zero
256 interaction%partner_b_field(:, ip) = partner%b_field
263 message(1) =
"Unsupported interaction."
275 class(
mesh_t),
intent(in) :: mesh
278 real(real64) :: pot_re, pot_im, r, xx(this%space%dim)
279 real(real64),
allocatable :: den(:), grx(:)
284 select case (this%type)
286 case (external_pot_usdef)
287 assert(
allocated(this%pot))
290 call mesh_r(mesh, ip, r, coords = xx)
292 this%pot(ip) = pot_re
296 assert(
allocated(this%pot))
298 call dio_function_input(trim(this%filename), namespace, this%space, mesh, this%pot, err)
300 write(
message(1),
'(a)')
'Error loading file '//trim(this%filename)//
'.'
301 write(
message(2),
'(a,i4)')
'Error code returned = ', err
306 assert(
allocated(this%pot))
308 safe_allocate(den(1:mesh%np))
311 call mesh_r(mesh, ip, r, coords = xx)
316 call dpoisson_solve(poisson, namespace, this%pot, den, all_nodes = .false.)
318 safe_deallocate_a(den)
321 assert(
allocated(this%b_field))
327 safe_allocate(grx(1:this%space%dim))
329 select case (this%space%dim)
331 select case (this%gauge_2d)
333 if (this%space%periodic_dim == 1)
then
334 message(1) =
"For 2D system, 1D-periodic, StaticMagneticField can only be "
335 message(2) =
"applied for StaticMagneticField2DGauge = linear_y."
340 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
341 this%a_static(ip, 1) = -
m_half/
p_c * grx(2) * this%b_field(3)
342 this%a_static(ip, 2) =
m_half/
p_c * grx(1) * this%b_field(3)
347 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
348 this%a_static(ip, 1) = -
m_one/
p_c * grx(2) * this%b_field(3)
349 this%a_static(ip, 2) =
m_zero
355 grx(1:this%space%dim) = mesh%x(1:this%space%dim, ip)
356 this%a_static(ip, 1) = -
m_half/
p_c*(grx(2) * this%b_field(3) - grx(3) * this%b_field(2))
357 this%a_static(ip, 2) = -
m_half/
p_c*(grx(3) * this%b_field(1) - grx(1) * this%b_field(3))
358 this%a_static(ip, 3) = -
m_half/
p_c*(grx(1) * this%b_field(2) - grx(2) * this%b_field(1))
364 safe_deallocate_a(grx)
367 assert(
allocated(this%e_field))
369 if (this%space%periodic_dim < this%space%dim)
then
380 this%pot(ip) = sum(mesh%x(this%space%periodic_dim + 1:this%space%dim, ip) &
381 * this%e_field(this%space%periodic_dim + 1:this%space%dim))
385 this%v_ext(1:mesh%np) = this%pot(1:mesh%np)
386 do ip = mesh%np+1, mesh%np_part
387 this%v_ext(ip) = sum(mesh%x(this%space%periodic_dim + 1:this%space%dim, ip) &
388 * this%e_field(this%space%periodic_dim + 1:this%space%dim))
401 integer :: n_pot_block, row, read_data
405 integer :: dim, periodic_dim, idir
451 if (
parse_block(namespace,
'StaticExternalPotentials', blk) == 0)
then
454 do row = 0, n_pot_block-1
459 assert(read_data > 0)
461 call external_potentials%add(pot)
471 call parse_variable(namespace,
'PeriodicDimensions', 0, periodic_dim)
495 if (
parse_block(namespace,
'StaticMagneticField', blk) == 0)
then
514 call parse_variable(namespace,
'StaticMagneticField2DGauge', 0, pot%gauge_2d)
519 safe_allocate(pot%b_field(1:3))
527 if (periodic_dim == 2)
then
528 message(1) =
"StaticMagneticField cannot be applied in a 2D, 2D-periodic system."
531 if (pot%b_field(1)**2 + pot%b_field(2)**2 >
m_zero)
then
538 if (periodic_dim >= 2)
then
539 message(1) =
"In 3D, StaticMagneticField cannot be applied when the system is 2D- or 3D-periodic."
541 else if (periodic_dim == 1 .and. any(abs(pot%b_field(2:3)) >
m_zero))
then
542 message(1) =
"In 3D, 1D-periodic, StaticMagneticField must be zero in the y- and z-directions."
551 call external_potentials%add(pot)
569 if (
parse_block(namespace,
'StaticElectricField', blk) == 0)
then
575 safe_allocate(pot%e_field(1:dim))
580 if (idir <= periodic_dim .and. abs(pot%e_field(idir)) >
m_epsilon)
then
581 message(1) =
"Applying StaticElectricField in a periodic direction is only accurate for large supercells."
588 call external_potentials%add(pot)
601 type(
block_t),
intent(in) :: blk
602 integer,
intent(in) :: row
603 integer,
intent(out) :: read_data
605 integer :: ncols, icol, flag
619 if (pot%type >= 0)
then
620 message(1) =
'Error in reading the ExternalPotentials block'
630 call messages_input_error(namespace,
'ExternalPotentials',
"Unknown type of external potential")
637 if (icol >= ncols)
exit
643 case (option__staticexternalpotentials__file)
647 case (option__staticexternalpotentials__potential_formula)
651 if (pot%type /= external_pot_usdef)
then
652 call messages_input_error(namespace,
'ExternalPotentials',
'potential_formula can only be used with user_defined')
655 case (option__staticexternalpotentials__density_formula)
660 call messages_input_error(namespace,
'ExternalPotentials',
'density_formula can only be used with charge_density')
673 if (pot%type == external_pot_usdef .and. &
674 .not.
parameter_defined(option__staticexternalpotentials__potential_formula))
then
675 call messages_input_error(namespace,
'ExternalPotentials',
"The 'potential_formula' parameter is missing.")
680 call messages_input_error(namespace,
'ExternalPotentials',
"The 'density_formula' parameter is missing.")
694 integer(int64),
intent(in) :: param
708 integer(int64),
intent(in) :: param
713 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...