Source code for magnopy.scenarios._optimize_sd
# MAGNOPY - Python package for magnons.
# Copyright (C) 2023-2025 Magnopy Team
#
# e-mail: anry@uv.es, web: magnopy.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import numpy as np
from magnopy._energy import Energy
from magnopy._package_info import logo
from magnopy.io._spin_directions import plot_spin_directions
# Save local scope at this moment
old_dir = set(dir())
old_dir.add("old_dir")
[docs]
def optimize_sd(
spinham,
magnetic_field=None,
energy_tolerance=1e-5,
torque_tolerance=1e-5,
output_folder="magnopy-results",
comment=None,
make_sd_image=None,
) -> None:
r"""
Optimizes classical energy of spin Hamiltonian and finds a set of spin directions
that describe local minima of energy landscape.
Parameters
----------
spinham : :py:class:`.SpinHamiltonian`
Spin Hamiltonian.
magnetic_field : (3, ) |array-like|_
Vector of external magnetic field, given in Tesla.
energy_tolerance : float, default 1e-5
Tolerance parameter. Difference between classical energies of two consecutive
optimization steps.
torque_tolerance : float, default 1e-5
Tolerance parameter. Maximum torque among all spins.
output_folder : str, default "magnopy-results"
Name for the folder where to save the output files. If the folder does not exist
then it will be created.
comment : str, optional
Any comment to output right after the logo.
make_sd_image : (3, ) tuple of int
Whether to produce an html file that displays the spin directions. Three numbers
are the repetitions of the unit cell along the three lattice vectors.
"""
all_good = True
print(logo(date_time=True))
print(f"\n{' Comment ':=^90}\n")
if comment is not None:
print(comment)
if magnetic_field is not None:
spinham.add_magnetic_field(h=magnetic_field)
print(f"\n{' Start optimization ':=^90}\n")
print(f"Energy tolerance : {energy_tolerance:.5e}")
print(f"Torque tolerance : {torque_tolerance:.5e}")
energy = Energy(spinham=spinham)
spin_directions = energy.optimize(
energy_tolerance=energy_tolerance,
torque_tolerance=torque_tolerance,
quiet=False,
)
print(f"Optimization is done.")
E_0 = energy.E_0(spin_directions=spin_directions)
print(f"\n{'Classic ground state energy (E_0)':<51} : " f"{E_0:>15.6f} meV\n")
print("Directions of spin vectors of the ground state and spin values are")
print(f"{'Name':<6} {'S':>7} {'Sx':>12} {'Sy':>12} {'Sz':>12}")
for i in range(spinham.M):
print(
f"{spinham.magnetic_atoms.names[i]:<6} "
f"{spinham.magnetic_atoms.spins[i]:7.4f} "
f"{spin_directions[i][0]:12.8f} "
f"{spin_directions[i][1]:12.8f} "
f"{spin_directions[i][2]:12.8f}"
)
# Create the output directory if it does not exist
os.makedirs(output_folder, exist_ok=True)
filename = os.path.join(output_folder, "SPIN_DIRECTIONS.txt")
with open(filename, "w") as f:
for i in range(spinham.M):
f.write(
f"{spin_directions[i][0]:12.8f} "
f"{spin_directions[i][1]:12.8f} "
f"{spin_directions[i][2]:12.8f}\n"
)
print(f"\nSpin directions are saved in file\n {os.path.abspath(filename)}")
if make_sd_image is not None:
positions = np.array(spinham.magnetic_atoms.positions) @ spinham.cell
filename = os.path.join(output_folder, "SPIN_DIRECTIONS")
plot_spin_directions(
output_name=filename,
positions=positions,
spin_directions=spin_directions,
unit_cell=spinham.cell,
repeat=make_sd_image,
)
print(
f"\nImage of spin directions is saved in file\n {os.path.abspath(filename)}.html"
)
print(f"\n{' Finished ':=^90}")
# Populate __all__ with objects defined in this file
__all__ = list(set(dir()) - old_dir)
# Remove all semi-private objects
__all__ = [i for i in __all__ if not i.startswith("_")]
del old_dir