Merge pull request #2410 from julient31/exchange-biquadratic
Adding a new pair style in SPIN package
This commit is contained in:
@ -241,6 +241,7 @@ OPT.
|
||||
* :doc:`spin/dipole/long <pair_spin_dipole>`
|
||||
* :doc:`spin/dmi <pair_spin_dmi>`
|
||||
* :doc:`spin/exchange <pair_spin_exchange>`
|
||||
* :doc:`spin/exchange/biquadratic <pair_spin_exchange>`
|
||||
* :doc:`spin/magelec <pair_spin_magelec>`
|
||||
* :doc:`spin/neel <pair_spin_neel>`
|
||||
* :doc:`srp <pair_srp>`
|
||||
|
||||
@ -1036,9 +1036,11 @@ the usual manner via MD. Various pair, fix, and compute styles.
|
||||
* :doc:`pair_style spin/dipole/long <pair_spin_dipole>`
|
||||
* :doc:`pair_style spin/dmi <pair_spin_dmi>`
|
||||
* :doc:`pair_style spin/exchange <pair_spin_exchange>`
|
||||
* :doc:`pair_style spin/exchange/biquadratic <pair_spin_exchange>`
|
||||
* :doc:`pair_style spin/magelec <pair_spin_magelec>`
|
||||
* :doc:`pair_style spin/neel <pair_spin_neel>`
|
||||
* :doc:`fix nve/spin <fix_nve_spin>`
|
||||
* :doc:`fix langevin/spin <fix_langevin_spin>`
|
||||
* :doc:`fix precession/spin <fix_precession_spin>`
|
||||
* :doc:`compute spin <compute_spin>`
|
||||
* :doc:`neb/spin <neb_spin>`
|
||||
|
||||
@ -62,7 +62,7 @@ with:
|
||||
|
||||
The field value in Tesla is multiplied by the gyromagnetic
|
||||
ratio, :math:`g \cdot \mu_B/\hbar`, converting it into a precession frequency in
|
||||
rad.THz (in metal units and with :math:`\mu_B = 5.788 eV/T`).
|
||||
rad.THz (in metal units and with :math:`\mu_B = 5.788\cdot 10^{-5}` eV/T).
|
||||
|
||||
As a comparison, the figure below displays the simulation of a
|
||||
single spin (of norm :math:`\mu_i = 1.0`) submitted to an external
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
.. index:: pair_style spin/exchange
|
||||
.. index:: pair_style spin/exchange/biquadratic
|
||||
|
||||
pair_style spin/exchange command
|
||||
================================
|
||||
|
||||
pair_style spin/exchange/biquadratic command
|
||||
============================================
|
||||
|
||||
Syntax
|
||||
""""""
|
||||
|
||||
.. code-block:: LAMMPS
|
||||
|
||||
pair_style spin/exchange cutoff
|
||||
pair_style spin/exchange/biquadratic cutoff
|
||||
|
||||
* cutoff = global cutoff pair (distance in metal units)
|
||||
|
||||
@ -19,7 +24,11 @@ Examples
|
||||
|
||||
pair_style spin/exchange 4.0
|
||||
pair_coeff * * exchange 4.0 0.0446928 0.003496 1.4885
|
||||
pair_coeff 1 2 exchange 6.0 -0.01575 0.0 1.965
|
||||
pair_coeff 1 2 exchange 6.0 -0.01575 0.0 1.965 offset yes
|
||||
|
||||
pair_style spin/exchange/biquadratic 4.0
|
||||
pair_coeff * * biquadratic 4.0 0.05 0.03 1.48 0.05 0.03 1.48 offset no
|
||||
pair_coeff 1 2 biquadratic 6.0 -0.01 0.0 1.9 0.0 0.1 19
|
||||
|
||||
Description
|
||||
"""""""""""
|
||||
@ -31,69 +40,163 @@ pairs of magnetic spins:
|
||||
|
||||
H_{ex} = -\sum_{i,j}^N J_{ij} (r_{ij}) \,\vec{s}_i \cdot \vec{s}_j
|
||||
|
||||
where :math:`\vec{s}_i` and :math:`\vec{s}_j` are two neighboring magnetic spins of two particles,
|
||||
:math:`r_{ij} = \vert \vec{r}_i - \vec{r}_j \vert` is the inter-atomic distance between the two
|
||||
particles. The summation is over pairs of nearest neighbors.
|
||||
:math:`J(r_{ij})` is a function defining the intensity and the sign of the exchange
|
||||
interaction for different neighboring shells. This function is defined as:
|
||||
where :math:`\vec{s}_i` and :math:`\vec{s}_j` are two unit vectors representing
|
||||
the magnetic spins of two particles (usually atoms), and
|
||||
:math:`r_{ij} = \vert \vec{r}_i - \vec{r}_j \vert` is the inter-atomic distance
|
||||
between those two particles. The summation is over pairs of nearest neighbors.
|
||||
:math:`J(r_{ij})` is a function defining the intensity and the sign of the
|
||||
exchange interaction for different neighboring shells.
|
||||
|
||||
Style *spin/exchange/biquadratic* computes a biquadratic exchange interaction
|
||||
between pairs of magnetic spins:
|
||||
|
||||
.. math::
|
||||
|
||||
{J}\left( r_{ij} \right) = 4 a \left( \frac{r_{ij}}{d} \right)^2 \left( 1 - b \left( \frac{r_{ij}}{d} \right)^2 \right) e^{-\left( \frac{r_{ij}}{d} \right)^2 }\Theta (R_c - r_{ij})
|
||||
H_{bi} = -\sum_{i, j}^{N} {J}_{ij} \left(r_{ij} \right)\,
|
||||
\vec{s}_{i}\cdot \vec{s}_{j}
|
||||
-\sum_{i, j}^{N} {K}_{ij} \left(r_{ij} \right)\,
|
||||
\left(\vec{s}_{i}\cdot
|
||||
\vec{s}_{j}\right)^2
|
||||
|
||||
where :math:`a`, :math:`b` and :math:`d` are the three constant coefficients defined in the associated
|
||||
"pair_coeff" command, and :math:`R_c` is the radius cutoff associated to
|
||||
the pair interaction (see below for more explanations).
|
||||
where :math:`\vec{s}_i`, :math:`\vec{s}_j`, :math:`r_{ij}` and
|
||||
:math:`J(r_{ij})` have the same definitions as above, and :math:`K(r_{ij})` is
|
||||
a second function, defining the intensity and the sign of the biquadratic term.
|
||||
|
||||
The coefficients :math:`a`, :math:`b`, and :math:`d` need to be fitted so that the function above matches with
|
||||
the value of the exchange interaction for the :math:`N` neighbor shells taken into account.
|
||||
Examples and more explanations about this function and its parameterization are reported
|
||||
in :ref:`(Tranchida) <Tranchida3>`.
|
||||
The interatomic dependence of :math:`J(r_{ij})` and :math:`K(r_{ij})` in both
|
||||
interactions above is defined by the following function:
|
||||
|
||||
.. math::
|
||||
|
||||
{f}\left( r_{ij} \right) = 4 a \left( \frac{r_{ij}}{d} \right)^2
|
||||
\left( 1 - b \left( \frac{r_{ij}}{d} \right)^2 \right)
|
||||
e^{-\left( \frac{r_{ij}}{d} \right)^2 }\Theta (R_c - r_{ij})
|
||||
|
||||
where :math:`a`, :math:`b` and :math:`d` are the three constant coefficients
|
||||
defined in the associated "pair_coeff" command, and :math:`R_c` is the radius
|
||||
cutoff associated to the pair interaction (see below for more explanations).
|
||||
|
||||
The coefficients :math:`a`, :math:`b`, and :math:`d` need to be fitted so that
|
||||
the function above matches with the value of the exchange interaction for the
|
||||
:math:`N` neighbor shells taken into account.
|
||||
Examples and more explanations about this function and its parameterization
|
||||
are reported in :ref:`(Tranchida) <Tranchida3>`.
|
||||
|
||||
When a *spin/exchange/biquadratic* pair style is defined, six coefficients
|
||||
(three for :math:`J(r_{ij})`, and three for :math:`K(r_{ij})`) have to be
|
||||
fitted.
|
||||
|
||||
From this exchange interaction, each spin :math:`i` will be submitted
|
||||
to a magnetic torque :math:`\vec{\omega}`, and its associated atom can be submitted to a
|
||||
force :math:`\vec{F}` for spin-lattice calculations (see :doc:`fix nve/spin <fix_nve_spin>`),
|
||||
such as:
|
||||
to a magnetic torque :math:`\vec{\omega}_{i}`, and its associated atom can be
|
||||
submitted to a force :math:`\vec{F}_{i}` for spin-lattice calculations (see
|
||||
:doc:`fix nve/spin <fix_nve_spin>`), such as:
|
||||
|
||||
.. math::
|
||||
|
||||
\vec{\omega}_{i} = \frac{1}{\hbar} \sum_{j}^{Neighb} {J}
|
||||
\left(r_{ij} \right)\,\vec{s}_{j}
|
||||
~~{\rm and}~~
|
||||
\vec{F}_{i} = \sum_{j}^{Neighb} \frac{\partial {J} \left(r_{ij} \right)}{ \partial r_{ij}} \left( \vec{s}_{i}\cdot \vec{s}_{j} \right) \vec{e}_{ij}
|
||||
\vec{F}_{i} = \sum_{j}^{Neighb} \frac{\partial {J} \left(r_{ij} \right)}{
|
||||
\partial r_{ij}} \left( \vec{s}_{i}\cdot \vec{s}_{j} \right) \vec{e}_{ij}
|
||||
|
||||
with :math:`\hbar` the Planck constant (in metal units), and :math:`\vec{e}_{ij} = \frac{\vec{r}_i - \vec{r}_j}{\vert \vec{r}_i-\vec{r}_j \vert}` the unit
|
||||
with :math:`\hbar` the Planck constant (in metal units), and :math:`\vec{e}_{ij}
|
||||
= \frac{\vec{r}_i - \vec{r}_j}{\vert \vec{r}_i-\vec{r}_j \vert}` the unit
|
||||
vector between sites :math:`i` and :math:`j`.
|
||||
Equivalent forces and magnetic torques are generated for the biquadratic term
|
||||
when a *spin/exchange/biquadratic* pair style is defined.
|
||||
|
||||
More details about the derivation of these torques/forces are reported in
|
||||
:ref:`(Tranchida) <Tranchida3>`.
|
||||
|
||||
For the *spin/exchange* pair style, the following coefficients must be defined
|
||||
for each pair of atoms types via the :doc:`pair_coeff <pair_coeff>` command as in
|
||||
the examples above, or in the data file or restart files read by the
|
||||
:doc:`read_data <read_data>` or :doc:`read_restart <read_restart>` commands, and
|
||||
set in the following order:
|
||||
For the *spin/exchange* and *spin/exchange/biquadratic* pair styles, the
|
||||
following coefficients must be defined for each pair of atoms types via the
|
||||
:doc:`pair_coeff <pair_coeff>` command as in the examples above, or in the data
|
||||
file or restart files read by the :doc:`read_data <read_data>` or
|
||||
:doc:`read_restart <read_restart>` commands, and set in the following order:
|
||||
|
||||
* :math:`R_c` (distance units)
|
||||
* :math:`a` (energy units)
|
||||
* :math:`b` (adim parameter)
|
||||
* :math:`d` (distance units)
|
||||
|
||||
Note that :math:`R_c` is the radius cutoff of the considered exchange interaction,
|
||||
and :math:`a`, :math:`b` and :math:`d` are the three coefficients performing the parameterization
|
||||
of the function :math:`J(r_{ij})` defined above.
|
||||
for the *spin/exchange* pair style, and:
|
||||
|
||||
* :math:`R_c` (distance units)
|
||||
* :math:`a_j` (energy units)
|
||||
* :math:`b_j` (adim parameter)
|
||||
* :math:`d_j` (distance units)
|
||||
* :math:`a_k` (energy units)
|
||||
* :math:`b_k` (adim parameter)
|
||||
* :math:`d_k` (distance units)
|
||||
|
||||
for the *spin/exchange/biquadratic* pair style.
|
||||
|
||||
Note that :math:`R_c` is the radius cutoff of the considered exchange
|
||||
interaction, and :math:`a`, :math:`b` and :math:`d` are the three coefficients
|
||||
performing the parameterization of the function :math:`J(r_{ij})` defined
|
||||
above (in the *biquadratic* style, :math:`a_j`, :math:`b_j`, :math:`d_j` and
|
||||
:math:`a_k`, :math:`b_k`, :math:`d_k` are the coefficients of :math:`J(r_{ij})`
|
||||
and :math:`K(r_{ij})` respectively).
|
||||
|
||||
|
||||
None of those coefficients is optional. If not specified, the
|
||||
*spin/exchange* pair style cannot be used.
|
||||
|
||||
----------
|
||||
|
||||
**Offsetting magnetic forces and energies**\ :
|
||||
|
||||
For spin-lattice simulation, it can be useful to offset the
|
||||
mechanical forces and energies generated by the exchange
|
||||
interaction.
|
||||
The *offset* keyword allows to apply this offset.
|
||||
By setting *offset* to *yes*, the energy definitions above are
|
||||
replaced by:
|
||||
|
||||
.. math::
|
||||
|
||||
H_{ex} = -\sum_{i,j}^N J_{ij} (r_{ij}) \,[ \vec{s}_i \cdot \vec{s}_j-1 ]
|
||||
|
||||
for the *spin/exchange* pair style, and:
|
||||
|
||||
.. math::
|
||||
|
||||
H_{bi} = -\sum_{i, j}^{N} {J}_{ij} \left(r_{ij} \right)\,
|
||||
[ \vec{s}_{i}\cdot \vec{s}_{j} -1 ]
|
||||
-\sum_{i, j}^{N} {K}_{ij} \left(r_{ij} \right)\,
|
||||
[ \left(\vec{s}_{i}\cdot
|
||||
\vec{s}_{j}\right)^2 -1]
|
||||
|
||||
for the *spin/exchange/biquadratic* pair style.
|
||||
|
||||
Note that this offset only affects the calculation of the energy
|
||||
and mechanical forces. It does not modify the calculation of the
|
||||
precession vectors (and thus does no impact the purely magnetic
|
||||
properties).
|
||||
This ensures that when all spins are aligned, the magnetic energy
|
||||
and the associated mechanical forces (and thus the pressure
|
||||
generated by the magnetic potential) are null.
|
||||
|
||||
.. note::
|
||||
This offset term can be very important when calculations such as
|
||||
equations of state (energy vs volume, or energy vs pressure) are
|
||||
being performed. Indeed, setting the *offset* term ensures that
|
||||
at the ground state of the crystal and at the equilibrium magnetic
|
||||
configuration (typically ferromagnetic), the pressure is null,
|
||||
as expected.
|
||||
Otherwise, magnetic forces could generate a residual pressure.
|
||||
|
||||
When the *offset* option is set to *no*, no offset is applied
|
||||
(also corresponding to the default option).
|
||||
|
||||
----------
|
||||
|
||||
Restrictions
|
||||
""""""""""""
|
||||
|
||||
All the *pair/spin* styles are part of the SPIN package. These styles
|
||||
are only enabled if LAMMPS was built with this package, and if the
|
||||
atom_style "spin" was declared. See the :doc:`Build package <Build_package>` doc page for more info.
|
||||
atom_style "spin" was declared.
|
||||
See the :doc:`Build package <Build_package>` doc page for more info.
|
||||
|
||||
Related commands
|
||||
""""""""""""""""
|
||||
@ -105,7 +208,7 @@ Default
|
||||
"""""""
|
||||
|
||||
|
||||
none
|
||||
The default *offset* keyword value is *no*.
|
||||
|
||||
----------
|
||||
|
||||
|
||||
@ -305,6 +305,7 @@ accelerated styles exist.
|
||||
* :doc:`spin/dipole/long <pair_spin_dipole>` -
|
||||
* :doc:`spin/dmi <pair_spin_dmi>` -
|
||||
* :doc:`spin/exchange <pair_spin_exchange>` -
|
||||
* :doc:`spin/exchange/biquadratic <pair_spin_exchange>` -
|
||||
* :doc:`spin/magelec <pair_spin_magelec>` -
|
||||
* :doc:`spin/neel <pair_spin_neel>` -
|
||||
* :doc:`srp <pair_srp>` -
|
||||
|
||||
@ -240,6 +240,7 @@ bigint
|
||||
Bij
|
||||
bilayer
|
||||
bilayers
|
||||
biquadratic
|
||||
binsize
|
||||
binstyle
|
||||
binutils
|
||||
|
||||
@ -26,7 +26,7 @@ velocity all create 100 4928459 rot yes dist gaussian
|
||||
#pair_style hybrid/overlay eam/alloy spin/exchange 4.0 spin/neel 4.0
|
||||
pair_style hybrid/overlay eam/alloy spin/exchange 4.0
|
||||
pair_coeff * * eam/alloy Co_PurjaPun_2012.eam.alloy Co
|
||||
pair_coeff * * spin/exchange exchange 4.0 -0.3593 1.135028015e-05 1.064568567
|
||||
pair_coeff * * spin/exchange exchange 4.0 -0.3593 1.135028015e-05 1.0645 offset yes
|
||||
#pair_coeff * * spin/neel neel 4.0 0.0048 0.234 1.168 2.6905 0.705 0.652
|
||||
|
||||
neighbor 0.1 bin
|
||||
|
||||
@ -25,7 +25,7 @@ velocity all create 100 4928459 rot yes dist gaussian
|
||||
|
||||
pair_style hybrid/overlay eam/alloy spin/exchange 3.5
|
||||
pair_coeff * * eam/alloy Fe_Mishin2006.eam.alloy Fe
|
||||
pair_coeff * * spin/exchange exchange 3.4 0.02726 0.2171 1.841
|
||||
pair_coeff * * spin/exchange exchange 3.4 0.02726 0.2171 1.841 offset yes
|
||||
|
||||
neighbor 0.1 bin
|
||||
neigh_modify every 10 check yes delay 20
|
||||
|
||||
@ -21,9 +21,9 @@ mass 1 55.845
|
||||
set group all spin 2.2 -1.0 0.0 0.0
|
||||
velocity all create 100 4928459 rot yes dist gaussian
|
||||
|
||||
pair_style hybrid/overlay eam/alloy spin/exchange 3.5
|
||||
pair_style hybrid/overlay eam/alloy spin/exchange/biquadratic 3.5
|
||||
pair_coeff * * eam/alloy Fe_Mishin2006.eam.alloy Fe
|
||||
pair_coeff * * spin/exchange exchange 3.4 0.02726 0.2171 1.841
|
||||
pair_coeff * * spin/exchange/biquadratic biquadratic 3.4 0.02726 0.2171 1.841 0.0 0.0 2.0 offset yes
|
||||
neighbor 0.1 bin
|
||||
neigh_modify every 10 check yes delay 20
|
||||
|
||||
|
||||
@ -6,9 +6,17 @@ import matplotlib.pyplot as plt
|
||||
import mpmath as mp
|
||||
|
||||
hbar=0.658212 # Planck's constant (eV.fs/rad)
|
||||
J0=0.05 # per-neighbor exchange interaction (eV)
|
||||
# J0=0.05 # per-neighbor exchange interaction (eV)
|
||||
|
||||
# exchange interaction parameters
|
||||
J1 = 11.254 # in eV
|
||||
J2 = 0.0 # adim
|
||||
J3 = 1.0 # in Ang.
|
||||
|
||||
# initial spins
|
||||
S1 = np.array([1.0, 0.0, 0.0])
|
||||
S2 = np.array([0.0, 1.0, 0.0])
|
||||
|
||||
alpha=0.01 # damping coefficient
|
||||
pi=math.pi
|
||||
|
||||
@ -30,6 +38,14 @@ def rotation_matrix(axis, theta):
|
||||
[2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],
|
||||
[2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]])
|
||||
|
||||
#Definition of the Bethe-Slater function
|
||||
def func_BS(x,a,b,c):
|
||||
return 4*a*((x/c)**2)*(1-b*(x/c)**2)*np.exp(-(x/c)**2)
|
||||
|
||||
#Definition of the derivative of the Bethe-Slater function
|
||||
def func_dBS(x,a,b,c):
|
||||
return 4*a*((x/c)**2)*(1-b*(x/c)**2)*np.exp(-(x/c)**2)
|
||||
|
||||
# calculating precession field of spin Sr
|
||||
def calc_rot_vector(Sr,Sf):
|
||||
rot = (J0/hbar)*(Sf-alpha*np.cross(Sf,Sr))/(1.0+alpha**2)
|
||||
@ -65,6 +81,6 @@ for t in range (0,N):
|
||||
# calc. average magnetization
|
||||
Sm = (S1+S2)*0.5
|
||||
# calc. energy
|
||||
en = -2.0*J0*(np.dot(S1,S2))
|
||||
en = -J0*(np.dot(S1,S2))
|
||||
# print res. in ps for comparison with LAMMPS
|
||||
print(t*dt/1000.0,Sm[0],Sm[1],Sm[2],en)
|
||||
|
||||
@ -13,7 +13,7 @@ en="$(echo "$en-$in" | bc -l)"
|
||||
tail -n +$in log.lammps | head -n $en > res_lammps.dat
|
||||
|
||||
# compute Langevin
|
||||
python3 -m llg_exchange.py > res_llg.dat
|
||||
python3 llg_exchange.py > res_llg.dat
|
||||
|
||||
# plot results
|
||||
python3 -m plot_precession.py res_lammps.dat res_llg.dat
|
||||
python3 plot_precession.py res_lammps.dat res_llg.dat
|
||||
|
||||
@ -5,22 +5,24 @@ atom_style spin
|
||||
atom_modify map array
|
||||
boundary f f f
|
||||
|
||||
read_data two_spins.data
|
||||
atom_modify map array
|
||||
lattice sc 3.0
|
||||
region box block 0 2 0 1 0 1
|
||||
create_box 1 box
|
||||
create_atoms 1 box
|
||||
|
||||
mass 1 55.845
|
||||
set atom 1 spin 2.0 1.0 0.0 0.0
|
||||
set atom 2 spin 2.0 0.0 1.0 0.0
|
||||
|
||||
pair_style spin/exchange 3.1
|
||||
pair_coeff * * exchange 3.1 11.254 0.0 1.0
|
||||
|
||||
group bead type 1
|
||||
|
||||
variable H equal 0.0
|
||||
variable Kan equal 0.0
|
||||
variable Temperature equal 0.0
|
||||
variable RUN equal 30000
|
||||
|
||||
fix 1 all nve/spin lattice no
|
||||
fix 2 all precession/spin zeeman ${H} 0.0 0.0 1.0 anisotropy ${Kan} 0.0 0.0 1.0
|
||||
fix_modify 2 energy yes
|
||||
fix 3 all langevin/spin ${Temperature} 0.01 12345
|
||||
fix 1 all nve/spin lattice frozen
|
||||
fix 2 all langevin/spin ${Temperature} 0.01 12345
|
||||
|
||||
compute out_mag all spin
|
||||
compute out_pe all pe
|
||||
@ -34,6 +36,9 @@ variable emag equal c_out_mag[5]
|
||||
thermo_style custom step time v_magx v_magy v_magz v_emag pe etotal
|
||||
thermo 10
|
||||
|
||||
compute outsp all property/atom spx spy spz sp fmx fmy fmz
|
||||
dump 1 all custom 10 dump.data type x y z c_outsp[1] c_outsp[2] c_outsp[3] fx fy fz
|
||||
|
||||
timestep 0.0001
|
||||
|
||||
run ${RUN}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
LAMMPS data file via write_data, version 19 Sep 2019, timestep = 0
|
||||
|
||||
2 atoms
|
||||
1 atom types
|
||||
|
||||
0.0 6.0 xlo xhi
|
||||
0.0 3.0 ylo yhi
|
||||
0.0 3.0 zlo zhi
|
||||
|
||||
Masses
|
||||
|
||||
1 1
|
||||
|
||||
Atoms # spin
|
||||
|
||||
1 1 2.0 0.0 0.0 0.0 1.0 0.0 0.0 0 0 0
|
||||
2 1 2.0 3.0 0.0 0.0 0.0 1.0 0.0 0 0 0
|
||||
|
||||
Velocities
|
||||
|
||||
1 0.0 0.0 0.0
|
||||
2 0.0 0.0 0.0
|
||||
@ -13,4 +13,4 @@ en="$(echo "$en-$in" | bc -l)"
|
||||
tail -n +$in log.lammps | head -n $en > res_lammps.dat
|
||||
|
||||
# plot results
|
||||
python3 -m plot_nve.py res_lammps.dat res_llg.dat
|
||||
python3 plot_nve.py res_lammps.dat res_llg.dat
|
||||
|
||||
@ -30,7 +30,7 @@ neighbor 0.1 bin
|
||||
neigh_modify every 10 check yes delay 20
|
||||
|
||||
fix 1 all precession/spin zeeman 0.0 0.0 0.0 1.0
|
||||
fix 2 all langevin 200.0 200.0 10.0 48279
|
||||
fix 2 all langevin 200.0 200.0 1.0 48279
|
||||
fix 3 all langevin/spin 0.0 0.00001 321
|
||||
fix 4 all nve/spin lattice moving
|
||||
timestep 0.001
|
||||
|
||||
@ -29,7 +29,7 @@ neighbor 0.1 bin
|
||||
neigh_modify every 10 check yes delay 20
|
||||
|
||||
fix 1 all precession/spin zeeman 0.0 0.0 0.0 1.0
|
||||
fix 2 all langevin/spin 200.0 0.1 321
|
||||
fix 2 all langevin/spin 200.0 0.01 321
|
||||
fix 3 all nve/spin lattice moving
|
||||
timestep 0.001
|
||||
|
||||
|
||||
@ -39,5 +39,5 @@ plt.xlabel('Time (in ps)')
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
fig.savefig(os.path.join(os.getcwd(), "nve_spin_lattice.pdf"), bbox_inches="tight")
|
||||
fig.savefig(os.path.join(os.getcwd(), "nvt_spin_lattice.pdf"), bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
|
||||
@ -176,6 +176,9 @@ void ComputeSpin::compute_vector()
|
||||
for (i = 0; i < nlocal; i++) {
|
||||
if (mask[i] & groupbit) {
|
||||
if (atom->sp_flag) {
|
||||
|
||||
// compute first moment
|
||||
|
||||
mag[0] += sp[i][0];
|
||||
mag[1] += sp[i][1];
|
||||
mag[2] += sp[i][2];
|
||||
@ -211,11 +214,16 @@ void ComputeSpin::compute_vector()
|
||||
MPI_Allreduce(&tempdenom,&tempdenomtot,1,MPI_DOUBLE,MPI_SUM,world);
|
||||
MPI_Allreduce(&countsp,&countsptot,1,MPI_INT,MPI_SUM,world);
|
||||
|
||||
// compute average magnetization
|
||||
|
||||
double scale = 1.0/countsptot;
|
||||
magtot[0] *= scale;
|
||||
magtot[1] *= scale;
|
||||
magtot[2] *= scale;
|
||||
magtot[3] = sqrt((magtot[0]*magtot[0])+(magtot[1]*magtot[1])+(magtot[2]*magtot[2]));
|
||||
|
||||
// compute spin temperature
|
||||
|
||||
spintemperature = hbar*tempnumtot;
|
||||
spintemperature /= (2.0*kb*tempdenomtot);
|
||||
|
||||
@ -225,7 +233,6 @@ void ComputeSpin::compute_vector()
|
||||
vector[3] = magtot[3];
|
||||
vector[4] = magenergytot;
|
||||
vector[5] = spintemperature;
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
@ -45,9 +45,10 @@ PairSpinDipoleCut::PairSpinDipoleCut(LAMMPS *lmp) : PairSpin(lmp)
|
||||
|
||||
hbar = force->hplanck/MY_2PI; // eV/(rad.THz)
|
||||
mub = 9.274e-4; // in A.Ang^2
|
||||
mu_0 = 785.15; // in eV/Ang/A^2
|
||||
// mu_0 = 785.15; // in eV/Ang/A^2
|
||||
mu_0 = 784.15; // in eV/Ang/A^2
|
||||
mub2mu0 = mub * mub * mu_0 / (4.0*MY_PI); // in eV.Ang^3
|
||||
//mub2mu0 = mub * mub * mu_0 / (4.0*MY_PI); // in eV
|
||||
// mub2mu0 = mub * mub * mu_0 / (4.0*MY_PI); // in eV
|
||||
mub2mu0hbinv = mub2mu0 / hbar; // in rad.THz
|
||||
}
|
||||
|
||||
@ -232,36 +233,44 @@ void PairSpinDipoleCut::compute(int eflag, int vflag)
|
||||
|
||||
local_cut2 = cut_spin_long[itype][jtype]*cut_spin_long[itype][jtype];
|
||||
|
||||
// compute dipolar interaction
|
||||
|
||||
if (rsq < local_cut2) {
|
||||
r2inv = 1.0/rsq;
|
||||
r3inv = r2inv*rinv;
|
||||
|
||||
compute_dipolar(i,j,eij,fmi,spi,spj,r3inv);
|
||||
if (lattice_flag) compute_dipolar_mech(i,j,eij,fi,spi,spj,r2inv);
|
||||
}
|
||||
|
||||
// force accumulation
|
||||
if (lattice_flag)
|
||||
compute_dipolar_mech(i,j,eij,fi,spi,spj,r2inv);
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
if (eflag) {
|
||||
if (rsq <= local_cut2) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
}
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (eflag) {
|
||||
if (rsq <= local_cut2) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -390,7 +399,7 @@ void PairSpinDipoleCut::compute_dipolar_mech(int /* i */, int /* j */, double ei
|
||||
sjeij = spj[0]*eij[0] + spj[1]*eij[1] + spj[2]*eij[2];
|
||||
|
||||
bij = sisj - 5.0*sieij*sjeij;
|
||||
pre = 3.0*mub2mu0*gigjri4;
|
||||
pre = 0.5*3.0*mub2mu0*gigjri4;
|
||||
|
||||
fi[0] -= pre * (eij[0] * bij + (sjeij*spi[0] + sieij*spj[0]));
|
||||
fi[1] -= pre * (eij[1] * bij + (sjeij*spi[1] + sieij*spj[1]));
|
||||
|
||||
@ -49,7 +49,7 @@ PairSpinDipoleLong::PairSpinDipoleLong(LAMMPS *lmp) : PairSpin(lmp)
|
||||
|
||||
hbar = force->hplanck/MY_2PI; // eV/(rad.THz)
|
||||
mub = 9.274e-4; // in A.Ang^2
|
||||
mu_0 = 785.15; // in eV/Ang/A^2
|
||||
mu_0 = 784.15; // in eV/Ang/A^2
|
||||
mub2mu0 = mub * mub * mu_0 / (4.0*MY_PI); // in eV.Ang^3
|
||||
//mub2mu0 = mub * mub * mu_0 / (4.0*MY_PI); // in eV
|
||||
mub2mu0hbinv = mub2mu0 / hbar; // in rad.THz
|
||||
@ -281,32 +281,37 @@ void PairSpinDipoleLong::compute(int eflag, int vflag)
|
||||
bij[3] = (5.0*bij[2] + pre3*expm2) * r2inv;
|
||||
|
||||
compute_long(i,j,eij,bij,fmi,spi,spj);
|
||||
compute_long_mech(i,j,eij,bij,fmi,spi,spj);
|
||||
}
|
||||
if (lattice_flag)
|
||||
compute_long_mech(i,j,eij,bij,fmi,spi,spj);
|
||||
|
||||
// force accumulation
|
||||
if (eflag) {
|
||||
if (rsq <= local_cut2) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
}
|
||||
} else evdwl = 0.0;
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
if (rsq <= local_cut2) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
} else evdwl = 0.0;
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -373,7 +378,6 @@ void PairSpinDipoleLong::compute_single_pair(int ii, double fmi[3])
|
||||
spi[3] = sp[ii][3];
|
||||
jlist = firstneigh[ii];
|
||||
jnum = numneigh[ii];
|
||||
//itype = type[i];
|
||||
|
||||
for (jj = 0; jj < jnum; jj++) {
|
||||
j = jlist[jj];
|
||||
@ -459,7 +463,7 @@ void PairSpinDipoleLong::compute_long_mech(int /* i */, int /* j */, double eij[
|
||||
double g1,g2,g1b2_g2b3,gigj,pre;
|
||||
|
||||
gigj = spi[3] * spj[3];
|
||||
pre = gigj*mub2mu0;
|
||||
pre = 0.5 * gigj*mub2mu0;
|
||||
sisj = spi[0]*spj[0] + spi[1]*spj[1] + spi[2]*spj[2];
|
||||
sieij = spi[0]*eij[0] + spi[1]*eij[1] + spi[2]*eij[2];
|
||||
sjeij = spj[0]*eij[0] + spj[1]*eij[1] + spj[2]*eij[2];
|
||||
|
||||
@ -244,31 +244,35 @@ void PairSpinDmi::compute(int eflag, int vflag)
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_dmi(i,j,eij,fmi,spj);
|
||||
if (lattice_flag) {
|
||||
|
||||
if (lattice_flag)
|
||||
compute_dmi_mech(i,j,rsq,eij,fi,spi,spj);
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -405,9 +409,9 @@ void PairSpinDmi::compute_dmi_mech(int i, int j, double rsq, double /*eij*/[3],
|
||||
cdmy = (dmiz*csx - dmix*csz);
|
||||
cdmz = (dmix*csy - dmiy*csz);
|
||||
|
||||
fi[0] += irij*cdmx;
|
||||
fi[1] += irij*cdmy;
|
||||
fi[2] += irij*cdmz;
|
||||
fi[0] += 0.5*irij*cdmx;
|
||||
fi[1] += 0.5*irij*cdmy;
|
||||
fi[2] += 0.5*irij*cdmz;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
@ -37,6 +37,14 @@ using namespace LAMMPS_NS;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
PairSpinExchange::PairSpinExchange(LAMMPS *lmp) :
|
||||
PairSpin(lmp)
|
||||
{
|
||||
e_offset = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
PairSpinExchange::~PairSpinExchange()
|
||||
{
|
||||
if (allocated) {
|
||||
@ -59,6 +67,8 @@ void PairSpinExchange::settings(int narg, char **arg)
|
||||
{
|
||||
PairSpin::settings(narg,arg);
|
||||
|
||||
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
|
||||
|
||||
cut_spin_exchange_global = utils::numeric(FLERR,arg[0],false,lmp);
|
||||
|
||||
// reset cutoffs that have been explicitly set
|
||||
@ -84,9 +94,9 @@ void PairSpinExchange::coeff(int narg, char **arg)
|
||||
// check if args correct
|
||||
|
||||
if (strcmp(arg[2],"exchange") != 0)
|
||||
error->all(FLERR,"Incorrect args in pair_style command");
|
||||
if (narg != 7)
|
||||
error->all(FLERR,"Incorrect args in pair_style command");
|
||||
error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
if ((narg != 7) && (narg != 9))
|
||||
error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
|
||||
int ilo,ihi,jlo,jhi;
|
||||
utils::bounds(FLERR,arg[0],1,atom->ntypes,ilo,ihi,error);
|
||||
@ -94,11 +104,25 @@ void PairSpinExchange::coeff(int narg, char **arg)
|
||||
|
||||
// get exchange arguments from input command
|
||||
|
||||
int iarg = 7;
|
||||
const double rc = utils::numeric(FLERR,arg[3],false,lmp);
|
||||
const double j1 = utils::numeric(FLERR,arg[4],false,lmp);
|
||||
const double j2 = utils::numeric(FLERR,arg[5],false,lmp);
|
||||
const double j3 = utils::numeric(FLERR,arg[6],false,lmp);
|
||||
|
||||
// read energy offset flag if specified
|
||||
|
||||
while (iarg < narg) {
|
||||
if (strcmp(arg[7],"offset") == 0) {
|
||||
if (strcmp(arg[8],"yes") == 0) {
|
||||
e_offset = 1;
|
||||
} else if (strcmp(arg[8],"no") == 0) {
|
||||
e_offset = 0;
|
||||
} else error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
iarg += 2;
|
||||
} else error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = ilo; i <= ihi; i++) {
|
||||
for (int j = MAX(jlo,i); j <= jhi; j++) {
|
||||
@ -228,31 +252,34 @@ void PairSpinExchange::compute(int eflag, int vflag)
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_exchange(i,j,rsq,fmi,spj);
|
||||
if (lattice_flag) {
|
||||
|
||||
if (lattice_flag)
|
||||
compute_exchange_mech(i,j,rsq,eij,fi,spi,spj);
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= compute_energy(i,j,rsq,spi,spj);
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -361,12 +388,14 @@ void PairSpinExchange::compute_exchange(int i, int j, double rsq, double fmi[3],
|
||||
compute the mechanical force due to the exchange interaction between atom i and atom j
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchange::compute_exchange_mech(int i, int j, double rsq, double eij[3],
|
||||
double fi[3], double spi[3], double spj[3])
|
||||
void PairSpinExchange::compute_exchange_mech(int i, int j, double rsq,
|
||||
double eij[3], double fi[3], double spi[3], double spj[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
int itype, jtype;
|
||||
double Jex, Jex_mech, ra, rr, iJ3;
|
||||
double Jex, Jex_mech, ra, sdots;
|
||||
double rr, iJ3;
|
||||
double fx, fy, fz;
|
||||
itype = type[i];
|
||||
jtype = type[j];
|
||||
|
||||
@ -378,35 +407,58 @@ void PairSpinExchange::compute_exchange_mech(int i, int j, double rsq, double ei
|
||||
|
||||
Jex_mech = 1.0-ra-J2[itype][jtype]*ra*(2.0-ra);
|
||||
Jex_mech *= 8.0*Jex*rr*exp(-ra);
|
||||
Jex_mech *= (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
fi[0] -= Jex_mech*eij[0];
|
||||
fi[1] -= Jex_mech*eij[1];
|
||||
fi[2] -= Jex_mech*eij[2];
|
||||
sdots = (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
// apply or not energy and force offset
|
||||
|
||||
fx = fy = fz = 0.0;
|
||||
if (e_offset == 1) { // set offset
|
||||
fx = Jex_mech*(sdots-1.0)*eij[0];
|
||||
fy = Jex_mech*(sdots-1.0)*eij[1];
|
||||
fz = Jex_mech*(sdots-1.0)*eij[2];
|
||||
} else if (e_offset == 0) { // no offset ("normal" calculation)
|
||||
fx = Jex_mech*sdots*eij[0];
|
||||
fy = Jex_mech*sdots*eij[1];
|
||||
fz = Jex_mech*sdots*eij[2];
|
||||
} else error->all(FLERR,"Illegal option in pair exchange/biquadratic command");
|
||||
|
||||
fi[0] -= 0.5*fx;
|
||||
fi[1] -= 0.5*fy;
|
||||
fi[2] -= 0.5*fz;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
compute energy of spin pair i and j
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
// double PairSpinExchange::compute_energy(int i, int j, double rsq, double spi[3], double spj[3])
|
||||
// {
|
||||
// int *type = atom->type;
|
||||
// int itype, jtype;
|
||||
// double Jex, ra;
|
||||
// double energy = 0.0;
|
||||
// itype = type[i];
|
||||
// jtype = type[j];
|
||||
//
|
||||
// Jex = J1_mech[itype][jtype];
|
||||
// ra = rsq/J3[itype][jtype]/J3[itype][jtype];
|
||||
// Jex = 4.0*Jex*ra;
|
||||
// Jex *= (1.0-J2[itype][jtype]*ra);
|
||||
// Jex *= exp(-ra);
|
||||
//
|
||||
// energy = Jex*(spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
// return energy;
|
||||
// }
|
||||
double PairSpinExchange::compute_energy(int i, int j, double rsq, double spi[3], double spj[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
int itype, jtype;
|
||||
double Jex, ra, sdots;
|
||||
double energy = 0.0;
|
||||
itype = type[i];
|
||||
jtype = type[j];
|
||||
|
||||
Jex = J1_mech[itype][jtype];
|
||||
ra = rsq/J3[itype][jtype]/J3[itype][jtype];
|
||||
Jex = 4.0*Jex*ra;
|
||||
Jex *= (1.0-J2[itype][jtype]*ra);
|
||||
Jex *= exp(-ra);
|
||||
|
||||
sdots = (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
// apply or not energy and force offset
|
||||
|
||||
if (e_offset == 1) { // set offset
|
||||
energy = 0.5*Jex*(sdots-1.0);
|
||||
} else if (e_offset == 0) { // no offset ("normal" calculation)
|
||||
energy = 0.5*Jex*sdots;
|
||||
} else error->all(FLERR,"Illegal option in pair exchange/biquadratic command");
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
allocate all arrays
|
||||
@ -495,6 +547,7 @@ void PairSpinExchange::read_restart(FILE *fp)
|
||||
void PairSpinExchange::write_restart_settings(FILE *fp)
|
||||
{
|
||||
fwrite(&cut_spin_exchange_global,sizeof(double),1,fp);
|
||||
fwrite(&e_offset,sizeof(int),1,fp);
|
||||
fwrite(&offset_flag,sizeof(int),1,fp);
|
||||
fwrite(&mix_flag,sizeof(int),1,fp);
|
||||
}
|
||||
@ -507,10 +560,12 @@ void PairSpinExchange::read_restart_settings(FILE *fp)
|
||||
{
|
||||
if (comm->me == 0) {
|
||||
utils::sfread(FLERR,&cut_spin_exchange_global,sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&e_offset,sizeof(int),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&offset_flag,sizeof(int),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&mix_flag,sizeof(int),1,fp,nullptr,error);
|
||||
}
|
||||
MPI_Bcast(&cut_spin_exchange_global,1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&e_offset,1,MPI_INT,0,world);
|
||||
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
|
||||
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ namespace LAMMPS_NS {
|
||||
|
||||
class PairSpinExchange : public PairSpin {
|
||||
public:
|
||||
PairSpinExchange(LAMMPS *lmp) : PairSpin(lmp) {}
|
||||
PairSpinExchange(class LAMMPS *);
|
||||
virtual ~PairSpinExchange();
|
||||
void settings(int, char **);
|
||||
void coeff(int, char **);
|
||||
@ -38,8 +38,7 @@ class PairSpinExchange : public PairSpin {
|
||||
|
||||
void compute_exchange(int, int, double, double *, double *);
|
||||
void compute_exchange_mech(int, int, double, double *, double *, double *, double *);
|
||||
|
||||
// double compute_energy(int , int , double , double *, double *);
|
||||
double compute_energy(int , int , double , double *, double *);
|
||||
|
||||
void write_restart(FILE *);
|
||||
void read_restart(FILE *);
|
||||
@ -49,6 +48,7 @@ class PairSpinExchange : public PairSpin {
|
||||
double cut_spin_exchange_global; // global exchange cutoff distance
|
||||
|
||||
protected:
|
||||
int e_offset; // apply energy offset
|
||||
double **J1_mag; // exchange coeffs in eV
|
||||
double **J1_mech; // mech exchange coeffs in
|
||||
double **J2, **J3; // J1 in eV, J2 adim, J3 in Ang
|
||||
|
||||
635
src/SPIN/pair_spin_exchange_biquadratic.cpp
Normal file
635
src/SPIN/pair_spin_exchange_biquadratic.cpp
Normal file
@ -0,0 +1,635 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
Contributing authors: Julien Tranchida (SNL)
|
||||
Aidan Thompson (SNL)
|
||||
|
||||
Please cite the related publication:
|
||||
Tranchida, J., Plimpton, S. J., Thibaudeau, P., & Thompson, A. P. (2018).
|
||||
Massively parallel symplectic algorithm for coupled magnetic spin dynamics
|
||||
and molecular dynamics. Journal of Computational Physics.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "pair_spin_exchange_biquadratic.h"
|
||||
|
||||
#include "atom.h"
|
||||
#include "comm.h"
|
||||
#include "error.h"
|
||||
#include "force.h"
|
||||
#include "memory.h"
|
||||
#include "neigh_list.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
PairSpinExchangeBiquadratic::PairSpinExchangeBiquadratic(LAMMPS *lmp) :
|
||||
PairSpin(lmp)
|
||||
{
|
||||
e_offset = 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
PairSpinExchangeBiquadratic::~PairSpinExchangeBiquadratic()
|
||||
{
|
||||
if (allocated) {
|
||||
memory->destroy(setflag);
|
||||
memory->destroy(cut_spin_exchange);
|
||||
memory->destroy(J1_mag);
|
||||
memory->destroy(J1_mech);
|
||||
memory->destroy(J2);
|
||||
memory->destroy(J3);
|
||||
memory->destroy(K1_mag);
|
||||
memory->destroy(K1_mech);
|
||||
memory->destroy(K2);
|
||||
memory->destroy(K3);
|
||||
memory->destroy(cutsq); // to be implemented
|
||||
memory->destroy(emag);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
global settings
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::settings(int narg, char **arg)
|
||||
{
|
||||
PairSpin::settings(narg,arg);
|
||||
|
||||
if (narg != 1) error->all(FLERR,"Illegal pair_style command");
|
||||
|
||||
cut_spin_exchange_global = utils::numeric(FLERR,arg[0],false,lmp);
|
||||
|
||||
// reset cutoffs that have been explicitly set
|
||||
|
||||
if (allocated) {
|
||||
int i,j;
|
||||
for (i = 1; i <= atom->ntypes; i++)
|
||||
for (j = i+1; j <= atom->ntypes; j++)
|
||||
if (setflag[i][j]) {
|
||||
cut_spin_exchange[i][j] = cut_spin_exchange_global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
set coeffs for one or more type spin pairs
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::coeff(int narg, char **arg)
|
||||
{
|
||||
if (!allocated) allocate();
|
||||
|
||||
// check if args correct
|
||||
|
||||
if (strcmp(arg[2],"biquadratic") != 0)
|
||||
error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
if ((narg != 10) && (narg != 12))
|
||||
error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
|
||||
int ilo,ihi,jlo,jhi;
|
||||
utils::bounds(FLERR,arg[0],1,atom->ntypes,ilo,ihi,error);
|
||||
utils::bounds(FLERR,arg[1],1,atom->ntypes,jlo,jhi,error);
|
||||
|
||||
// get exchange arguments from input command
|
||||
|
||||
int iarg = 10;
|
||||
const double rc = utils::numeric(FLERR,arg[3],false,lmp);
|
||||
const double j1 = utils::numeric(FLERR,arg[4],false,lmp);
|
||||
const double j2 = utils::numeric(FLERR,arg[5],false,lmp);
|
||||
const double j3 = utils::numeric(FLERR,arg[6],false,lmp);
|
||||
const double k1 = utils::numeric(FLERR,arg[7],false,lmp);
|
||||
const double k2 = utils::numeric(FLERR,arg[8],false,lmp);
|
||||
const double k3 = utils::numeric(FLERR,arg[9],false,lmp);
|
||||
|
||||
// read energy offset flag if specified
|
||||
|
||||
while (iarg < narg) {
|
||||
if (strcmp(arg[10],"offset") == 0) {
|
||||
if (strcmp(arg[11],"yes") == 0) {
|
||||
e_offset = 1;
|
||||
} else if (strcmp(arg[11],"no") == 0) {
|
||||
e_offset = 0;
|
||||
} else error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
iarg += 2;
|
||||
} else error->all(FLERR,"Incorrect args for pair coefficients");
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (int i = ilo; i <= ihi; i++) {
|
||||
for (int j = MAX(jlo,i); j <= jhi; j++) {
|
||||
cut_spin_exchange[i][j] = rc;
|
||||
J1_mag[i][j] = j1/hbar;
|
||||
J1_mech[i][j] = j1;
|
||||
J2[i][j] = j2;
|
||||
J3[i][j] = j3;
|
||||
K1_mag[i][j] = k1/hbar;
|
||||
K1_mech[i][j] = k1;
|
||||
K2[i][j] = k2;
|
||||
K3[i][j] = k3;
|
||||
setflag[i][j] = 1;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) error->all(FLERR,"Incorrect args in pair_style command");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
init for one type pair i,j and corresponding j,i
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
double PairSpinExchangeBiquadratic::init_one(int i, int j)
|
||||
{
|
||||
if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
|
||||
|
||||
J1_mag[j][i] = J1_mag[i][j];
|
||||
J1_mech[j][i] = J1_mech[i][j];
|
||||
J2[j][i] = J2[i][j];
|
||||
J3[j][i] = J3[i][j];
|
||||
K1_mag[j][i] = K1_mag[i][j];
|
||||
K1_mech[j][i] = K1_mech[i][j];
|
||||
K2[j][i] = K2[i][j];
|
||||
K3[j][i] = K3[i][j];
|
||||
cut_spin_exchange[j][i] = cut_spin_exchange[i][j];
|
||||
|
||||
return cut_spin_exchange_global;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
extract the larger cutoff
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void *PairSpinExchangeBiquadratic::extract(const char *str, int &dim)
|
||||
{
|
||||
dim = 0;
|
||||
if (strcmp(str,"cut") == 0) return (void *) &cut_spin_exchange_global;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::compute(int eflag, int vflag)
|
||||
{
|
||||
int i,j,ii,jj,inum,jnum,itype,jtype;
|
||||
double evdwl, ecoul;
|
||||
double xi[3], eij[3];
|
||||
double delx,dely,delz;
|
||||
double spi[3], spj[3];
|
||||
double fi[3], fmi[3];
|
||||
double local_cut2;
|
||||
double rsq, inorm;
|
||||
int *ilist,*jlist,*numneigh,**firstneigh;
|
||||
|
||||
evdwl = ecoul = 0.0;
|
||||
ev_init(eflag,vflag);
|
||||
|
||||
double **x = atom->x;
|
||||
double **f = atom->f;
|
||||
double **fm = atom->fm;
|
||||
double **sp = atom->sp;
|
||||
int *type = atom->type;
|
||||
int nlocal = atom->nlocal;
|
||||
int newton_pair = force->newton_pair;
|
||||
|
||||
inum = list->inum;
|
||||
ilist = list->ilist;
|
||||
numneigh = list->numneigh;
|
||||
firstneigh = list->firstneigh;
|
||||
|
||||
// checking size of emag
|
||||
|
||||
if (nlocal_max < nlocal) { // grow emag lists if necessary
|
||||
nlocal_max = nlocal;
|
||||
memory->grow(emag,nlocal_max,"pair/spin:emag");
|
||||
}
|
||||
|
||||
// computation of the exchange interaction
|
||||
// loop over atoms and their neighbors
|
||||
|
||||
for (ii = 0; ii < inum; ii++) {
|
||||
i = ilist[ii];
|
||||
itype = type[i];
|
||||
|
||||
jlist = firstneigh[i];
|
||||
jnum = numneigh[i];
|
||||
xi[0] = x[i][0];
|
||||
xi[1] = x[i][1];
|
||||
xi[2] = x[i][2];
|
||||
spi[0] = sp[i][0];
|
||||
spi[1] = sp[i][1];
|
||||
spi[2] = sp[i][2];
|
||||
emag[i] = 0.0;
|
||||
|
||||
// loop on neighbors
|
||||
|
||||
for (jj = 0; jj < jnum; jj++) {
|
||||
j = jlist[jj];
|
||||
j &= NEIGHMASK;
|
||||
jtype = type[j];
|
||||
|
||||
spj[0] = sp[j][0];
|
||||
spj[1] = sp[j][1];
|
||||
spj[2] = sp[j][2];
|
||||
|
||||
evdwl = 0.0;
|
||||
fi[0] = fi[1] = fi[2] = 0.0;
|
||||
fmi[0] = fmi[1] = fmi[2] = 0.0;
|
||||
|
||||
delx = xi[0] - x[j][0];
|
||||
dely = xi[1] - x[j][1];
|
||||
delz = xi[2] - x[j][2];
|
||||
rsq = delx*delx + dely*dely + delz*delz;
|
||||
inorm = 1.0/sqrt(rsq);
|
||||
eij[0] = -inorm*delx;
|
||||
eij[1] = -inorm*dely;
|
||||
eij[2] = -inorm*delz;
|
||||
|
||||
local_cut2 = cut_spin_exchange[itype][jtype]*cut_spin_exchange[itype][jtype];
|
||||
|
||||
// compute exchange interaction
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_exchange(i,j,rsq,fmi,spi,spj);
|
||||
|
||||
if (lattice_flag)
|
||||
compute_exchange_mech(i,j,rsq,eij,fi,spi,spj);
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= compute_energy(i,j,rsq,spi,spj);
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
update the pair interactions fmi acting on the spin ii
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::compute_single_pair(int ii, double fmi[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
double **x = atom->x;
|
||||
double **sp = atom->sp;
|
||||
double local_cut2;
|
||||
double xi[3];
|
||||
double delx,dely,delz;
|
||||
double spi[3],spj[3];
|
||||
|
||||
int j,jnum,itype,jtype,ntypes;
|
||||
int k,locflag;
|
||||
int *jlist,*numneigh,**firstneigh;
|
||||
|
||||
double rsq;
|
||||
|
||||
numneigh = list->numneigh;
|
||||
firstneigh = list->firstneigh;
|
||||
|
||||
// check if interaction applies to type of ii
|
||||
|
||||
itype = type[ii];
|
||||
ntypes = atom->ntypes;
|
||||
locflag = 0;
|
||||
k = 1;
|
||||
while (k <= ntypes) {
|
||||
if (k <= itype) {
|
||||
if (setflag[k][itype] == 1) {
|
||||
locflag =1;
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
} else if (k > itype) {
|
||||
if (setflag[itype][k] == 1) {
|
||||
locflag =1;
|
||||
break;
|
||||
}
|
||||
k++;
|
||||
} else error->all(FLERR,"Wrong type number");
|
||||
}
|
||||
|
||||
// if interaction applies to type ii,
|
||||
// locflag = 1 and compute pair interaction
|
||||
|
||||
if (locflag == 1) {
|
||||
|
||||
xi[0] = x[ii][0];
|
||||
xi[1] = x[ii][1];
|
||||
xi[2] = x[ii][2];
|
||||
spi[0] = sp[ii][0];
|
||||
spi[1] = sp[ii][1];
|
||||
spi[2] = sp[ii][2];
|
||||
|
||||
jlist = firstneigh[ii];
|
||||
jnum = numneigh[ii];
|
||||
|
||||
for (int jj = 0; jj < jnum; jj++) {
|
||||
|
||||
j = jlist[jj];
|
||||
j &= NEIGHMASK;
|
||||
jtype = type[j];
|
||||
local_cut2 = cut_spin_exchange[itype][jtype]*cut_spin_exchange[itype][jtype];
|
||||
|
||||
spj[0] = sp[j][0];
|
||||
spj[1] = sp[j][1];
|
||||
spj[2] = sp[j][2];
|
||||
|
||||
delx = xi[0] - x[j][0];
|
||||
dely = xi[1] - x[j][1];
|
||||
delz = xi[2] - x[j][2];
|
||||
rsq = delx*delx + dely*dely + delz*delz;
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_exchange(ii,j,rsq,fmi,spi,spj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
compute exchange interaction between spins i and j
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::compute_exchange(int i, int j, double rsq,
|
||||
double fmi[3], double spi[3], double spj[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
int itype,jtype;
|
||||
double Jex,Kex,r2j,r2k,sdots;
|
||||
itype = type[i];
|
||||
jtype = type[j];
|
||||
|
||||
r2j = rsq/J3[itype][jtype]/J3[itype][jtype];
|
||||
r2k = rsq/J3[itype][jtype]/J3[itype][jtype];
|
||||
|
||||
Jex = 4.0*J1_mag[itype][jtype]*r2j;
|
||||
Jex *= (1.0-J2[itype][jtype]*r2j);
|
||||
Jex *= exp(-r2j);
|
||||
|
||||
Kex = 4.0*K1_mag[itype][jtype]*r2k;
|
||||
Kex *= (1.0-K2[itype][jtype]*r2k);
|
||||
Kex *= exp(-r2k);
|
||||
|
||||
sdots = (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
fmi[0] += (Jex*spj[0] + 2.0*Kex*spj[0]*sdots);
|
||||
fmi[1] += (Jex*spj[1] + 2.0*Kex*spj[1]*sdots);
|
||||
fmi[2] += (Jex*spj[2] + 2.0*Kex*spj[2]*sdots);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
compute the mechanical force due to the exchange interaction between atom i and atom j
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::compute_exchange_mech(int i, int j,
|
||||
double rsq, double eij[3], double fi[3], double spi[3], double spj[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
int itype,jtype;
|
||||
double Jex,Jex_mech,Kex,Kex_mech,sdots;
|
||||
double rja,rka,rjr,rkr,iJ3,iK3;
|
||||
double fx, fy, fz;
|
||||
itype = type[i];
|
||||
jtype = type[j];
|
||||
|
||||
Jex = J1_mech[itype][jtype];
|
||||
iJ3 = 1.0/(J3[itype][jtype]*J3[itype][jtype]);
|
||||
Kex = K1_mech[itype][jtype];
|
||||
iK3 = 1.0/(K3[itype][jtype]*K3[itype][jtype]);
|
||||
|
||||
rja = rsq*iJ3;
|
||||
rjr = sqrt(rsq)*iJ3;
|
||||
rka = rsq*iK3;
|
||||
rkr = sqrt(rsq)*iK3;
|
||||
|
||||
Jex_mech = 1.0-rja-J2[itype][jtype]*rja*(2.0-rja);
|
||||
Jex_mech *= 8.0*Jex*rjr*exp(-rja);
|
||||
|
||||
Kex_mech = 1.0-rka-K2[itype][jtype]*rka*(2.0-rka);
|
||||
Kex_mech *= 8.0*Kex*rkr*exp(-rka);
|
||||
|
||||
sdots = (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
// apply or not energy and force offset
|
||||
|
||||
fx = fy = fz = 0.0;
|
||||
if (e_offset == 1) { // set offset
|
||||
fx = (Jex_mech*(sdots-1.0) + Kex_mech*(sdots*sdots-1.0))*eij[0];
|
||||
fy = (Jex_mech*(sdots-1.0) + Kex_mech*(sdots*sdots-1.0))*eij[1];
|
||||
fz = (Jex_mech*(sdots-1.0) + Kex_mech*(sdots*sdots-1.0))*eij[2];
|
||||
} else if (e_offset == 0) { // no offset ("normal" calculation)
|
||||
fx = (Jex_mech*sdots + Kex_mech*sdots*sdots)*eij[0];
|
||||
fy = (Jex_mech*sdots + Kex_mech*sdots*sdots)*eij[1];
|
||||
fz = (Jex_mech*sdots + Kex_mech*sdots*sdots)*eij[2];
|
||||
} else error->all(FLERR,"Illegal option in pair exchange/biquadratic command");
|
||||
|
||||
fi[0] -= 0.5*fx;
|
||||
fi[1] -= 0.5*fy;
|
||||
fi[2] -= 0.5*fz;
|
||||
// fi[0] -= fx;
|
||||
// fi[1] -= fy;
|
||||
// fi[2] -= fz;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
compute energy of spin pair i and j
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
double PairSpinExchangeBiquadratic::compute_energy(int i, int j, double rsq,
|
||||
double spi[3], double spj[3])
|
||||
{
|
||||
int *type = atom->type;
|
||||
int itype,jtype;
|
||||
double Jex,Kex,ra,sdots;
|
||||
double rj,rk,r2j,r2k,ir3j,ir3k;
|
||||
double energy = 0.0;
|
||||
itype = type[i];
|
||||
jtype = type[j];
|
||||
|
||||
ra = sqrt(rsq);
|
||||
rj = ra/J3[itype][jtype];
|
||||
r2j = rsq/J3[itype][jtype]/J3[itype][jtype];
|
||||
ir3j = 1.0/(rj*rj*rj);
|
||||
rk = ra/K3[itype][jtype];
|
||||
r2k = rsq/K3[itype][jtype]/K3[itype][jtype];
|
||||
ir3k = 1.0/(rk*rk*rk);
|
||||
|
||||
Jex = 4.0*J1_mech[itype][jtype]*r2j;
|
||||
Jex *= (1.0-J2[itype][jtype]*r2j);
|
||||
Jex *= exp(-r2j);
|
||||
|
||||
Kex = 4.0*K1_mech[itype][jtype]*r2k;
|
||||
Kex *= (1.0-K2[itype][jtype]*r2k);
|
||||
Kex *= exp(-r2k);
|
||||
|
||||
sdots = (spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]);
|
||||
|
||||
// apply or not energy and force offset
|
||||
|
||||
if (e_offset == 1) { // set offset
|
||||
energy = 0.5*(Jex*(sdots-1.0) + Kex*(sdots*sdots-1.0));
|
||||
} else if (e_offset == 0) { // no offset ("normal" calculation)
|
||||
energy = 0.5*(Jex*sdots + Kex*sdots*sdots);
|
||||
} else error->all(FLERR,"Illegal option in pair exchange/biquadratic command");
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
allocate all arrays
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::allocate()
|
||||
{
|
||||
allocated = 1;
|
||||
int n = atom->ntypes;
|
||||
|
||||
memory->create(setflag,n+1,n+1,"pair:setflag");
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int j = i; j <= n; j++)
|
||||
setflag[i][j] = 0;
|
||||
|
||||
memory->create(cut_spin_exchange,n+1,n+1,"pair/spin/exchange:cut_spin_exchange");
|
||||
memory->create(J1_mag,n+1,n+1,"pair/spin/exchange:J1_mag");
|
||||
memory->create(J1_mech,n+1,n+1,"pair/spin/exchange:J1_mech");
|
||||
memory->create(J2,n+1,n+1,"pair/spin/exchange:J2");
|
||||
memory->create(J3,n+1,n+1,"pair/spin/exchange:J3");
|
||||
memory->create(K1_mag,n+1,n+1,"pair/spin/exchange:J1_mag");
|
||||
memory->create(K1_mech,n+1,n+1,"pair/spin/exchange:J1_mech");
|
||||
memory->create(K2,n+1,n+1,"pair/spin/exchange:J2");
|
||||
memory->create(K3,n+1,n+1,"pair/spin/exchange:J3");
|
||||
memory->create(cutsq,n+1,n+1,"pair:cutsq");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
proc 0 writes to restart file
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::write_restart(FILE *fp)
|
||||
{
|
||||
write_restart_settings(fp);
|
||||
|
||||
int i,j;
|
||||
for (i = 1; i <= atom->ntypes; i++) {
|
||||
for (j = i; j <= atom->ntypes; j++) {
|
||||
fwrite(&setflag[i][j],sizeof(int),1,fp);
|
||||
if (setflag[i][j]) {
|
||||
fwrite(&J1_mag[i][j],sizeof(double),1,fp);
|
||||
fwrite(&J1_mech[i][j],sizeof(double),1,fp);
|
||||
fwrite(&J2[i][j],sizeof(double),1,fp);
|
||||
fwrite(&J3[i][j],sizeof(double),1,fp);
|
||||
fwrite(&K1_mag[i][j],sizeof(double),1,fp);
|
||||
fwrite(&K1_mech[i][j],sizeof(double),1,fp);
|
||||
fwrite(&K2[i][j],sizeof(double),1,fp);
|
||||
fwrite(&K3[i][j],sizeof(double),1,fp);
|
||||
fwrite(&cut_spin_exchange[i][j],sizeof(double),1,fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
proc 0 reads from restart file, bcasts
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::read_restart(FILE *fp)
|
||||
{
|
||||
read_restart_settings(fp);
|
||||
|
||||
allocate();
|
||||
|
||||
int i,j;
|
||||
int me = comm->me;
|
||||
for (i = 1; i <= atom->ntypes; i++) {
|
||||
for (j = i; j <= atom->ntypes; j++) {
|
||||
if (me == 0) utils::sfread(FLERR,&setflag[i][j],sizeof(int),1,fp,nullptr,error);
|
||||
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
|
||||
if (setflag[i][j]) {
|
||||
if (me == 0) {
|
||||
utils::sfread(FLERR,&J1_mag[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&J1_mech[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&J2[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&J3[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&K1_mag[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&K1_mech[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&K2[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&K3[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&cut_spin_exchange[i][j],sizeof(double),1,fp,nullptr,error);
|
||||
}
|
||||
MPI_Bcast(&J1_mag[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&J1_mech[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&J2[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&J3[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&K1_mag[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&K1_mech[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&K2[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&K3[i][j],1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&cut_spin_exchange[i][j],1,MPI_DOUBLE,0,world);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
proc 0 writes to restart file
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::write_restart_settings(FILE *fp)
|
||||
{
|
||||
fwrite(&cut_spin_exchange_global,sizeof(double),1,fp);
|
||||
fwrite(&e_offset,sizeof(int),1,fp);
|
||||
fwrite(&offset_flag,sizeof(int),1,fp);
|
||||
fwrite(&mix_flag,sizeof(int),1,fp);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
proc 0 reads from restart file, bcasts
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void PairSpinExchangeBiquadratic::read_restart_settings(FILE *fp)
|
||||
{
|
||||
if (comm->me == 0) {
|
||||
utils::sfread(FLERR,&cut_spin_exchange_global,sizeof(double),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&e_offset,sizeof(int),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&offset_flag,sizeof(int),1,fp,nullptr,error);
|
||||
utils::sfread(FLERR,&mix_flag,sizeof(int),1,fp,nullptr,error);
|
||||
}
|
||||
MPI_Bcast(&cut_spin_exchange_global,1,MPI_DOUBLE,0,world);
|
||||
MPI_Bcast(&e_offset,1,MPI_INT,0,world);
|
||||
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
|
||||
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
|
||||
}
|
||||
87
src/SPIN/pair_spin_exchange_biquadratic.h
Normal file
87
src/SPIN/pair_spin_exchange_biquadratic.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef PAIR_CLASS
|
||||
|
||||
PairStyle(spin/exchange/biquadratic,PairSpinExchangeBiquadratic)
|
||||
|
||||
#else
|
||||
|
||||
#ifndef LMP_PAIR_SPIN_EXCHANGE_BIQUADRATIC_H
|
||||
#define LMP_PAIR_SPIN_EXCHANGE_BIQUADRATIC_H
|
||||
|
||||
#include "pair_spin.h"
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
||||
class PairSpinExchangeBiquadratic : public PairSpin {
|
||||
public:
|
||||
PairSpinExchangeBiquadratic(class LAMMPS *);
|
||||
virtual ~PairSpinExchangeBiquadratic();
|
||||
void settings(int, char **);
|
||||
void coeff(int, char **);
|
||||
double init_one(int, int);
|
||||
void *extract(const char *, int &);
|
||||
|
||||
void compute(int, int);
|
||||
void compute_single_pair(int, double *);
|
||||
|
||||
void compute_exchange(int, int, double, double *, double *, double *);
|
||||
void compute_exchange_mech(int, int, double, double *, double *, double *, double *);
|
||||
double compute_energy(int , int , double , double *, double *);
|
||||
|
||||
void write_restart(FILE *);
|
||||
void read_restart(FILE *);
|
||||
void write_restart_settings(FILE *);
|
||||
void read_restart_settings(FILE *);
|
||||
|
||||
double cut_spin_exchange_global; // global exchange cutoff distance
|
||||
|
||||
protected:
|
||||
|
||||
int e_offset; // apply energy offset
|
||||
double **J1_mag; // H exchange coeffs in eV
|
||||
double **J1_mech; // mech exchange coeffs in
|
||||
double **J2, **J3; // J1 in eV, J2 in Ang-1, J3 in Ang
|
||||
double **K1_mag; // Bi exchange coeffs in eV
|
||||
double **K1_mech; // mech exchange coeffs in
|
||||
double **K2, **K3; // K1 in eV, K2 Ang-1, K3 in Ang
|
||||
double **cut_spin_exchange; // cutoff distance exchange
|
||||
|
||||
void allocate();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ERROR/WARNING messages:
|
||||
|
||||
E: Incorrect args in pair_spin command
|
||||
|
||||
Self-explanatory.
|
||||
|
||||
E: Spin simulations require metal unit style
|
||||
|
||||
Self-explanatory.
|
||||
|
||||
E: Incorrect args for pair coefficients
|
||||
|
||||
Self-explanatory. Check the input script or data file.
|
||||
|
||||
E: Pair spin requires atom attribute spin
|
||||
|
||||
The atom style defined does not have these attributes.
|
||||
|
||||
*/
|
||||
@ -237,31 +237,35 @@ void PairSpinMagelec::compute(int eflag, int vflag)
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_magelec(i,j,eij,fmi,spj);
|
||||
if (lattice_flag) {
|
||||
|
||||
if (lattice_flag)
|
||||
compute_magelec_mech(i,j,fi,spi,spj);
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],delx,dely,delz);
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -400,9 +404,9 @@ void PairSpinMagelec::compute_magelec_mech(int i, int j, double fi[3], double sp
|
||||
meiy *= ME_mech[itype][jtype];
|
||||
meiz *= ME_mech[itype][jtype];
|
||||
|
||||
fi[0] += (meiy*vz - meiz*vy);
|
||||
fi[1] += (meiz*vx - meix*vz);
|
||||
fi[2] += (meix*vy - meiy*vx);
|
||||
fi[0] += 0.5*(meiy*vz - meiz*vy);
|
||||
fi[1] += 0.5*(meiz*vx - meix*vz);
|
||||
fi[2] += 0.5*(meix*vy - meiy*vx);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -246,31 +246,33 @@ void PairSpinNeel::compute(int eflag, int vflag)
|
||||
|
||||
if (rsq <= local_cut2) {
|
||||
compute_neel(i,j,rsq,eij,fmi,spi,spj);
|
||||
if (lattice_flag) {
|
||||
if (lattice_flag)
|
||||
compute_neel_mech(i,j,rsq,eij,fi,spi,spj);
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
if (newton_pair || j < nlocal) {
|
||||
f[j][0] -= fi[0];
|
||||
f[j][1] -= fi[1];
|
||||
f[j][2] -= fi[2];
|
||||
}
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
evdwl -= compute_neel_energy(i,j,rsq,eij,spi,spj);
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
}
|
||||
|
||||
f[i][0] += fi[0];
|
||||
f[i][1] += fi[1];
|
||||
f[i][2] += fi[2];
|
||||
fm[i][0] += fmi[0];
|
||||
fm[i][1] += fmi[1];
|
||||
fm[i][2] += fmi[2];
|
||||
|
||||
if (eflag) {
|
||||
evdwl = compute_neel_energy(i,j,rsq,eij,spi,spj);
|
||||
evdwl *= 0.5*hbar;
|
||||
emag[i] += evdwl;
|
||||
} else evdwl = 0.0;
|
||||
|
||||
if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair,
|
||||
evdwl,ecoul,fi[0],fi[1],fi[2],rij[0],rij[1],rij[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vflag_fdotr) virial_fdotr_compute();
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -563,9 +565,9 @@ void PairSpinNeel::compute_neel_mech(int i, int j, double rsq, double eij[3], do
|
||||
|
||||
// adding three contributions
|
||||
|
||||
fi[0] = pdx + pq1x + pq2x;
|
||||
fi[1] = pdy + pq1y + pq2y;
|
||||
fi[2] = pdz + pq1z + pq2z;
|
||||
fi[0] = 0.5*(pdx + pq1x + pq2x);
|
||||
fi[1] = 0.5*(pdy + pq1y + pq2y);
|
||||
fi[2] = 0.5*(pdz + pq1z + pq2z);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
@ -585,12 +587,12 @@ double PairSpinNeel::compute_neel_energy(int i, int j, double rsq, double eij[3]
|
||||
// compute Neel's functions
|
||||
|
||||
ra = rsq/g3[itype][jtype]/g3[itype][jtype];
|
||||
gr = 4.0*g1[itype][jtype]*ra;
|
||||
gr = 4.0*g1_mech[itype][jtype]*ra;
|
||||
gr *= (1.0-g2[itype][jtype]*ra);
|
||||
gr *= exp(-ra);
|
||||
|
||||
ra = rsq/q3[itype][jtype]/q3[itype][jtype];
|
||||
qr = 4.0*q1[itype][jtype]*ra;
|
||||
qr = 4.0*q1_mech[itype][jtype]*ra;
|
||||
qr *= (1.0-q2[itype][jtype]*ra);
|
||||
qr *= exp(-ra);
|
||||
|
||||
@ -609,7 +611,7 @@ double PairSpinNeel::compute_neel_energy(int i, int j, double rsq, double eij[3]
|
||||
eij_sj_3 = eij_sj*eij_sj_2;
|
||||
epq2 = q2r*(eij_si*eij_sj_3+eij_sj*eij_si_3);
|
||||
|
||||
return (epd+epq1+epq2);
|
||||
return 0.5*(epd+epq1+epq2);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
|
||||
@ -42,6 +42,12 @@
|
||||
#define ENERGY_MASK 0x00010000
|
||||
#define VIRIAL_MASK 0x00020000
|
||||
|
||||
// SPIN
|
||||
|
||||
#define SP_MASK 0x00000001
|
||||
#define FM_MASK 0x00000002
|
||||
#define FML_MASK 0x00000004
|
||||
|
||||
// DPD
|
||||
|
||||
#define DPDRHO_MASK 0x00040000
|
||||
|
||||
Reference in New Issue
Block a user