spirit-code / spirit

Atomistic Spin Simulation Framework
http://spirit-code.github.io
MIT License
118 stars 52 forks source link

Core: new Python bindings wrapper. #562

Open GPMueller opened 4 years ago

GPMueller commented 4 years ago

Note: this API requires Python3

A set of classes to provide a more pythonic API. This class-based API should not be used in parallel with the functional API, as it could lead to unintuitive behaviour and therefore bugs.

TODO:

Usage examples:

import os
import sys

# spirit_py_dir = os.path.dirname(os.path.realpath(__file__))
spirit_py_dir = os.path.abspath(os.path.join(os.path.dirname( __file__ ), ".."))
sys.path.insert(0, spirit_py_dir)

from spirit import constants
from spirit import version
from spirit.wrapper import State, SolverKind, LogLevel

if __name__ == '__main__':
    state = State(configfile="input/input.cfg")

    # Set some logging parameters
    state.log.console_level = LogLevel.info
    state.log.output_file_tag = 'new_state'
    state.log.output_folder = 'output'
    # print("level", state.log.console_level)

    # Set the orientations by hand
    spins = state.active_image.directions
    spins[:] = [0, 0, 1]
    spins.shape = (20, 20, 1, 3)
    spins[48:52, 48:52, :] = [0, 0, -1]
    # Use a pre-built setter
    state.systems[0].set_configuration.skyrmion(r=10.0)

    state.active_image.write_file("input/testimage.ovf")

    # The chain is easily resized
    state.systems.resize(10)
    # Also by list manipulations
    state.systems[9].set_configuration.plus_z()
    state.systems.append(state.systems[9])

    state.systems.write_file("input/testchain_first.ovf")

    # Parameters can be accessed through the systems:
    state.systems[2].parameters.llg.dt = 0.01
    # Groups of parameters can be set from a dict:
    for image in state.systems:
        # image.parameters.llg.dt = 0.001
        # image.parameters.llg.output_tag = "new_state"
        image.parameters.llg.set({
            'dt': 0.001,
            'output_tag': 'new_state' })

    # Chain-wide parameters are accessed through state.parameters
    # state.parameters.gneb.spring_force = 0.5
    state.parameters.gneb.set(
        {
            'dt': 0.001,
            'spring_force': 0.5,
            'output_tag': 'new_state'
        })

    # Logging is easy, by default messages go to 'All'
    state.log(">>>>>> Message to all")
    state.log(">>>>>> Error message", level=LogLevel.error)
    if state.log.n_errors > 0:
        state.log("this is intolerable!", level=LogLevel.severe)

    # calc = state.calculate.gneb(n_iterations=100000)
    # calc.start()

    # For pre-defined output etc, use:
    # state.calculate.llg(iterations=100)
    # To customise what happens after each iteration, use:
    # for i in state.calculation_llg(0, iterations=100):
    #     print(f'iteration {i}')
    #     if i > 10: break

    # If you call a calculation, it is executed immediately
    # state.calculation_llg()
    # You can also assign a calculation and use it later
    # calc = state.systems[0].calculation.llg(n_iterations=100)
    # # calc.start() # Maybe you want to do this asynchronously
    # # calc.stop()  # And stop it asynchronously on some event
    # calc() # Or you run it like so
    # # You can also iterate over a calculation manually
    # for i in state.calculation_llg(n_iterations=100):
    #     print(f'iteration {i}')
    # for i in calc:
    #     print(f'iteration {i}')
    #     if i >= 10: break

    state.systems[0].calculation.llg(solver=SolverKind.sib, n_iterations=1000000).start()
    # for i in state.systems[0].calculation.llg(solver=SolverKind.sib):
    #     if i >= 10: break
    state.systems[-1].calculation.llg(solver=SolverKind.vp, n_iterations=200).start()
    state.systems.interpolate()

    state.systems.write_file("input/testchain_second.ovf")

    state.calculation.gneb(solver=SolverKind.vp, n_iterations=200).start()

    state.systems.write_file("input/testchain_relaxed.ovf")

    state.log(f'Topological charge of first image: {state.systems[0].topological_charge()}')

    idx_image_minimum = 0
    idx_image_sp = 10
    htst_result = state.calculation.htst(idx_image_minimum, idx_image_sp, n_eigenmodes_keep=-1)
    state.log("------------------------")
    state.log(f"exponent   = {htst_result.temperature_exponent}")
    state.log(f"volume_min = {htst_result.volume_min}")
    state.log(f"volume_sp  = {htst_result.volume_sp}")
    eigval_min = htst_result.eigenvalues_min
    eigvec_min = htst_result.eigenvectors_min
    eigval_sp = htst_result.eigenvalues_sp
    eigvec_sp = htst_result.eigenvectors_sp
    velocities = htst_result.velocities

    print(eigval_min)
    print(eigvec_min)
coveralls commented 4 years ago

Coverage Status

Coverage remained the same at 79.423% when pulling 0c3c99485a5aab166b0e917328e631e29ef78126 on feature-pythonic-api into 55cc299074d9947a3838d47c31e41f1a1ea691ba on develop.