28 use,
intrinsic :: iso_fortran_env
49 integer,
public,
parameter :: &
58 integer,
public :: level = constrain_none
59 real(real64) :: lambda =
m_zero
60 real(real64),
allocatable :: constrain(:,:)
61 real(real64),
allocatable,
public :: pot(:,:)
62 real(real64),
public :: energy
68 real(real64),
parameter :: tol_mag_norm = 1.0e-6_real64
75 type(magnetic_constrain_t),
intent(inout) :: this
76 type(namespace_t),
intent(in) :: namespace
77 class(mesh_t),
intent(in) :: mesh
78 type(states_elec_dim_t),
intent(in) :: std
79 integer,
intent(in) :: natoms
80 real(real64),
intent(in) :: min_dist
83 real(real64) :: rmin, norm
108 call parse_variable(namespace,
'MagneticConstrain', constrain_none, this%level)
110 if (this%level == constrain_none)
then
124 call parse_variable(namespace,
'MagneticConstrainStrength', 0.01_real64, this%lambda)
129 if (
parse_block(namespace,
'AtomsMagnetDirection', blk) < 0)
then
130 message(1) =
"AtomsMagnetDirection block is not defined."
131 message(2) =
"Magnetic constrained DFT cannot be used without it."
136 message(1) =
"AtomsMagnetDirection block has the wrong number of rows."
141 message(1) =
"Magnetic constrains can only be used for spin-polized and spinor calculations."
145 safe_allocate(this%constrain(1:3, natoms))
150 this%constrain(1:2, ia) =
m_zero
154 if (abs(this%constrain(idir, ia)) < tol_mag_norm) this%constrain(idir, ia) =
m_zero
160 norm = norm2(this%constrain(1:3, ia))
161 this%constrain(1:3, ia) = this%constrain(1:3, ia) / norm
167 safe_allocate(this%pot(1:mesh%np, 1:std%nspin))
171 call parse_variable(namespace,
'LocalMagneticMomentsSphereRadius', min(
m_half*rmin, 100.0_real64), &
184 safe_deallocate_a(this%constrain)
185 safe_deallocate_a(this%pot)
194 class(
mesh_t),
intent(in) :: mesh
196 class(
space_t),
intent(in) :: space
198 real(real64),
intent(in) :: pos(:,:)
199 real(real64),
intent(in) :: rho(:,:)
201 integer :: ia, idir, ip
202 real(real64) :: bb(3), b2, lmm(3), dotp, norm, xx, max_r
203 real(real64),
allocatable :: md(:,:), mdf(:), mask(:)
208 real(real64),
parameter :: tol_sinc = 0.01_real64
210 if (this%level == constrain_none)
return
219 safe_allocate(md(1:mesh%np, 1:max(space%dim, 3)))
222 natoms =
size(pos, dim=2)
225 call submesh_init(sphere, space, mesh, latt, pos(:, ia), this%lmm_r)
231 max_r = maxval(sphere%r)
232 safe_allocate(mask(1:sphere%np))
236 xx = sphere%r(ip) *
m_pi / max_r
237 if(xx < tol_sinc)
then
238 mask(ip) =
m_one-xx*xx/6.0_real64
240 mask(ip) =
sin(xx)/xx
248 safe_allocate(mdf(1:sphere%np))
249 do idir = 1, max(space%dim, 3)
252 mdf(ip) = md(sphere%map(ip), idir) * mask(ip)
256 safe_deallocate_a(mdf)
260 select case(this%level)
263 if (norm > tol_mag_norm)
then
264 dotp = dot_product(lmm, this%constrain(1:3, ia))
265 this%energy = this%energy + this%lambda * (norm - dotp)
266 bb = lmm/norm - this%constrain(:,ia)
271 this%energy = this%energy + this%lambda * sum((lmm - this%constrain(:,ia))**2)
272 bb =
m_two * (lmm - this%constrain(:,ia))
274 bb = bb * this%lambda
277 select case(std%ispin)
279 b2 = norm2(bb(1:max(space%dim, 3)))
281 this%pot(sphere%map(ip), 1) = this%pot(sphere%map(ip), 1) + b2 * mask(ip)
282 this%pot(sphere%map(ip), 2) = this%pot(sphere%map(ip), 2) - b2 * mask(ip)
287 this%pot(sphere%map(ip), 1) = this%pot(sphere%map(ip), 1) + bb(3) * mask(ip)
288 this%pot(sphere%map(ip), 2) = this%pot(sphere%map(ip), 2) - bb(3) * mask(ip)
289 this%pot(sphere%map(ip), 3) = this%pot(sphere%map(ip), 3) + bb(1) * mask(ip)
290 this%pot(sphere%map(ip), 4) = this%pot(sphere%map(ip), 4) - bb(2) * mask(ip)
295 safe_deallocate_a(mask)
299 safe_deallocate_a(md)
300 safe_deallocate_a(mdf)
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
double sin(double __x) __attribute__((__nothrow__
integer, parameter, public unpolarized
Parameters...
integer, parameter, public spinors
integer, parameter, public spin_polarized
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public m_pi
some mathematical constants
real(real64), parameter, public m_half
real(real64), parameter, public m_one
This modules implements the routines for doing constrain DFT for noncollinear magnetism.
subroutine, public magnetic_constrain_end(this)
Releases memory of the magnetic constrain.
subroutine, public magnetic_constrain_update(this, mesh, std, space, latt, pos, rho)
Recomputes the magnetic contraining potential.
integer, parameter, public constrain_full
integer, parameter, public constrain_dir
subroutine, public magnetic_constrain_init(this, namespace, mesh, std, natoms, min_dist)
Initilializes the magnetic_constrain_t object.
subroutine, public magnetic_density(mesh, std, rho, md)
This module defines the meshes, which are used in Octopus.
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_experimental(name, namespace)
integer function, public parse_block(namespace, name, blk, check_varinfo_)
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.
real(real64) function, public dsm_integrate(mesh, sm, ff, reduce)
subroutine, public submesh_end(this)
subroutine, public submesh_init(this, space, mesh, latt, center, rc)
Datatype containing the magnetic constrain information.
Describes mesh distribution to nodes.
class for organizing spins and k-points
A submesh is a type of mesh, used for the projectors in the pseudopotentials It contains points on a ...