diff --git a/README.md b/README.md index 58af8b20a..9dd8117ef 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,6 @@ or in the [Reference section](docs/README.md) including - [Framework build instructions](docs/BUILD.md) - [Core build instructions](core/docs/BUILD.md) - [Core API Reference](core/docs/API.md) -- [Python API Reference](core/docs/API_Python.md) - [Input File Reference](core/docs/INPUT.md) There is also a [Wiki](https://iffwiki.fz-juelich.de/index.php/Spirit "Click me..."), @@ -162,7 +161,7 @@ or simply use pip install spirit -With this package you have access to powerful [Python APIs](core/docs/API_Python.md) to run and control +With this package you have access to powerful Python APIs to run and control dynamics simulations or optimizations. This is especially useful for work on clusters, where you can now script your workflow, never having to re-compile when testing, debugging or adding features. diff --git a/conf.py b/conf.py index 500996371..73cbb5625 100644 --- a/conf.py +++ b/conf.py @@ -19,6 +19,9 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) +import sys, os +sys.path.insert( 0, os.path.join( os.path.dirname( __file__ ), "core", "python", "spirit" ) ) +sys.path.insert( 0, os.path.join( os.path.dirname( __file__ ), "core", "python" ) ) # At top on conf.py (with other import statements) @@ -44,7 +47,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx_markdown_tables', 'sphinx.ext.intersphinx', - 'sphinx.ext.coverage'] + 'sphinx.ext.coverage', 'sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -106,7 +109,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['.github', '_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['.github', '_build', 'pyapidoc/spirit.rst', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -210,3 +213,63 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} + + + +def run_apidoc(_): + """Runs sphinx-apidoc when building the documentation. + Needs to be done in conf.py in order to include the APIdoc in the + build on readthedocs. + See also https://github.com/rtfd/readthedocs.org/issues/1139 + """ + source_dir = os.path.abspath(os.path.dirname(__file__)) + apidoc_dir = os.path.join(source_dir, 'docs', 'pyapidoc') + package_dir = os.path.join(source_dir, 'core', 'python', 'spirit') + + import subprocess + cmd_path = 'sphinx-apidoc' + if hasattr(sys, 'real_prefix'): # Check to see if we are in a virtualenv + # If we are, assemble the path manually + cmd_path = os.path.abspath(os.path.join(sys.prefix, 'bin', 'sphinx-apidoc')) + + options = [ + '-o', apidoc_dir, package_dir, + '--force', + '--no-headings', + '--module-first', + '--separate', + '--no-toc', + '--maxdepth', '4', + ] + + builddir = os.path.join(source_dir, 'build') + if not os.path.exists(builddir): + os.mkdir(builddir) + subprocess.check_call(['cmake', '..', '-DSPIRIT_BUILD_FOR_CXX=OFF'], cwd=builddir) + subprocess.check_call(['make'], cwd=builddir) + + # See https://stackoverflow.com/a/30144019 + env = os.environ.copy() + env["SPHINX_APIDOC_OPTIONS"] = 'members,special-members,private-members,undoc-members,show-inheritance' + subprocess.check_call([cmd_path] + options, env=env) + + ##################### + with open(os.path.join(apidoc_dir, 'parameters.rst'), "w") as parameters_file: + parameters_file.write("Parameters\n==================================\n\n") + with open(os.path.join(apidoc_dir, 'spirit.parameters.mc.rst'), 'r') as generated_file: + parameters_file.write(generated_file.read()) + with open(os.path.join(apidoc_dir, 'spirit.parameters.llg.rst'), 'r') as generated_file: + parameters_file.write(generated_file.read()) + with open(os.path.join(apidoc_dir, 'spirit.parameters.gneb.rst'), 'r') as generated_file: + parameters_file.write(generated_file.read()) + with open(os.path.join(apidoc_dir, 'spirit.parameters.ema.rst'), 'r') as generated_file: + parameters_file.write(generated_file.read()) + with open(os.path.join(apidoc_dir, 'spirit.parameters.mmf.rst'), 'r') as generated_file: + parameters_file.write(generated_file.read()) + + + if not os.path.exists(apidoc_dir): + os.mkdir(apidoc_dir) + +def setup(app): + app.connect('builder-inited', run_apidoc) \ No newline at end of file diff --git a/core/CMake/__init__.py.in b/core/CMake/__init__.py.in index 8c77fec44..59771a0c0 100644 --- a/core/CMake/__init__.py.in +++ b/core/CMake/__init__.py.in @@ -1,3 +1,8 @@ +""" +Spirit +================================================== +""" + __version__ = "${META_VERSION}" __revision__ = "${META_VERSION_REVISION}" __title__ = "${META_PROJECT_NAME}" diff --git a/core/docs/API_Python.md b/core/docs/API_Python.md deleted file mode 100644 index 3acf51ac4..000000000 --- a/core/docs/API_Python.md +++ /dev/null @@ -1,277 +0,0 @@ -SPIRIT Python API -==================== - -State ------ - -To create a new state with one chain containing a single image, initialized by an [input file](INPUT.md), and run the most simple example of a **spin dynamics simulation**: -```python -from spirit import state -from spirit import simulation - -cfgfile = "input/input.cfg" # Input File -with state.State(cfgfile) as p_state: # State setup - simulation.start(p_state, simulation.METHOD_LLG, simulation.SOLVER_SIB) # Start a LLG simulation using the SIB solver -``` -or call setup and delete manually: -```python -from spirit import state -from spirit import simulation - -cfgfile = "input/input.cfg" # Input File -p_state = state.setup(cfgfile) # State setup -simulation.start(p_state, simulation.METHOD_LLG, simulation.SOLVER_SIB) # Start a LLG simulation using the SIB solver -state.delete(p_state) # State cleanup -``` - -You can pass a [config file](INPUT.md) specifying your initial system parameters. -If you do not pass a config file, the implemented defaults are used. -**Note that you currently cannot change the geometry of the systems in your state once they are initialized.** - -| State manipulation | Returns | -| ----------------------------------------------------------------------------------- | ---------- | -| `setup( configfile="", quiet=False )` | `None` | -| `delete(p_state )` | `None` | - - -System ------- - -| System | Returns | Description | -| --------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------ | -| `get_index(p_state)` | `int` | Returns the index of the currently active image | -| `get_nos(p_state, idx_image=-1, idx_chain=-1)` | `int` | Returns the number of spins | -| `get_spin_directions(p_state, idx_image=-1, idx_chain=-1)` | `[3*NOS]`| Returns an `numpy.Array` of size `3*NOS` with the components of each spin's vector | -| `get_energy(p_state, idx_image=-1, idx_chain=-1)` | `float` | Returns the energy of the system | -| `update_data(p_state, idx_image=-1, idx_chain=-1)` | `None` | Update the data of the state | -| `print_energy_array(p_state, idx_image=-1, idx_chain=-1)` | `None` | Print the energy array of the state | - - -Chain ------ - -For having more images one can copy the active image in the Clipboard and then insert in a specified position of the chain. -```python -chain.image_to_clipboard(p_state ) # Copy p_state to Clipboard -chain.insert_image_after(p_state ) # Insert the image from Clipboard right after the currently active image -``` -For getting the total number of images in the chain -```python -number_of_images = chain.get_noi(p_state ) -``` - -| Get Info | Returns | Description | -| --------------------------------------------------------------------------- | -------------- | ---------------------------------------------------------- | -| `get_index(p_state )` | `int` | Get Chain index | -| `get_noi(p_state, idx_chain=-1)` | `int` | Get Chain number of images | -| `get_rx(p_state, idx_chain=-1)` | `Array` | Get Rx | -| `get_rx_interpolated(p_state, idx_chain=-1)` | `Array(float)` | Get Rx interpolated | -| `get_energy(p_state, idx_chain=-1)` | `Array(float)` | Get Energy of every System in Chain | -| `get_energy_interpolated(p_state, idx_chain=-1)` | `Array(float)` | Get interpolated Energy of every System in Chain | - -| Image Manipulation | Returns | Description | -| --------------------------------------------------------------- | -------------- | ---------------------------------------------------------- | -| `next_image(p_state, idx_chain=-1)` | `None` | Switch active to next image of chain (one with largest index). If the current active is the last there is no effect. | -| `prev_image(p_state, idx_chain=-1)` | `None` | Switch active to previous image of chain (one with smaller index). If the current active is the first one there is no effect | -| `jump_to_image(p_state, idx_image=-1, idx_chain=-1)` | `None` | Switch active to specific image of chain. If this image does not exist there is no effect. | -| `image_to_clipboard(p_state, idx_image=-1, idx_chain=-1)` | `None` | Copy active image to clipboard | -| `replace_image(p_state, idx_image=-1, idx_chain=-1)` | `None` | Replace active image in chain. If the image does not exist there is no effect. | -| `insert_image_before(p_state, idx_image=-1, idx_chain=-1)` | `None` | Inserts clipboard image before the current active image. Active image index is increment by one. | -| `insert_image_after(p_state, idx_image=-1, idx_chain=-1)` | `None` | Insert clipboard image after the current active image. Active image has the same index. | -| `push_back(p_state, idx_chain=-1)` | `None` | Insert clipboard image at end of chain (after the image with the largest index). | -| `delete_image(p_state, idx_image=-1, idx_chain=-1)` | `None` | Delete active image. If index is specified delete the corresponding image. If the image does not exist there is no effect. | -| `pop_back(p_state, idx_chain=-1)` | `None` | Delete image at end of chain. | - -| Data | Returns | Description | -| ------------------------------------------- | -------------- | ---------------------------------------------------------- | -| `update_data(p_state, idx_chain=-1)` | `None` | Update the chain's data (interpolated energies etc.) | -| `setup_data(p_state, idx_chain=-1)` | `None` | Setup the chain's data arrays | - - -Constants ---------- - -| Physical Constants | Returns | Description | -| --------------------------------------- | -------------- | -------------------------------------------------- | -| `mu_B` | `float` | The Bohr Magneton [meV / T] | -| `k_B` | `float` | The Boltzmann constant [meV / K] | -| `hbar` | `float` | Planck's constant over 2pi [meV*ps / rad] | -| `mRy` | `float` | Millirydberg [mRy / meV] | -| `gamma` | `float` | The Gyromagnetic ratio of electron [rad / (ps*T)] | -| `g_e` | `float` | The Electron g-factor [unitless] | - - -Geometry --------- - -| Set Geometry parameters | Description | -| ----------------------------------------------------------------------------- | ----------------------------------------------------- | -| `set_bravais_lattice_type(p_state, lattice_type, idx_image=-1, idx_chain=-1)` | Set the bravais vectors to a pre-defined lattice type | -| `set_n_cells(p_state, n_cells=[1, 1, 1], idx_image=-1, idx_chain=-1)` | Set the number of basis cells along bravais vectors | -| `set_mu_s(p_state, mu_s, idx_image=-1, idx_chain=-1)` | Set the magnetic moment of all atoms | -| `set_cell_atom_types(p_state, atom_types, idx_image=-1, idx_chain=-1)` | Set the atom types of the cell atoms | -| `set_bravais_vectors(p_state, ta=[1.0, 0.0, 0.0], tb=[0.0, 1.0, 0.0], tc=[0.0, 0.0, 1.0], idx_image=-1, idx_chain=-1)` | Manually specify bravais vectors | -| `set_lattice_constant(p_state, lattice_constant, idx_image=-1, idx_chain=-1)` | Set the global lattice constant | - -| Get Geometry parameters | Returns | Description | -| -------------------------------------------------------------------- | --------------------- | -------------------------------------------------- | -| `get_bounds(p_state, idx_image=-1, idx_chain=-1)` | `[3], [3]` | Get bounds (minimum and maximum arrays) | -| `get_center(p_state, idx_image=-1, idx_chain=-1)` | `float, float, float` | Get center | -| `get_basis_vectors(p_state, idx_image=-1, idx_chain=-1)` | `[3],[3],[3]` | Get basis vectors | -| `get_n_cells(p_state, idx_image=-1, idx_chain=-1)` | `Int, Int, Int` | Get number of cells in each dimension | -| `get_translation_vectors(p_state, idx_image=-1, idx_chain=-1)` | `[3],[3],[3]` | Get translation vectors | -| `get_dimensionality(p_state, idx_image=-1, idx_chain=-1)` | `int` | Get dimensionality of the system | -| `get_spin_positions(p_state, idx_image=-1, idx_chain=-1)` | `[3*NOS]` | Get Spin positions | -| `get_atom_types(p_state, idx_image=-1, idx_chain=-1)` | `[NOS]` | Get atom types | - - -Hamiltonian ------------ - -| Set Parameters | Returns | Description | -| ------------------------------------------------------------------------------- | --------------------- | ----------------------------------------------------------- | -| `set_boundary_conditions(p_state, boundaries, idx_image=-1, idx_chain=-1)` | `None` | Set the boundary conditions [a, b, c]: 0=open, 1=periodical | -| `set_field(p_state, magnitude, direction, idx_image=-1, idx_chain=-1)` | `None` | Set external magnetic field | -| `set_anisotropy(p_state, magnitude, direction, idx_image=-1, idx_chain=-1)` | `None` | Set a magnitude and normal of anisotropy for all spins | -| `set_exchange(p_state, n_shells, J_ij, idx_image=-1, idx_chain=-1)` | `None` | Set the exchange pairs in terms of neighbour shells | -| `set_dmi(p_state, n_shells, D_ij, idx_image=-1, idx_chain=-1)` | `None` | Set the DMI pairs in terms of neighbour shells | -| `set_ddi(p_state, radius, idx_image=-1, idx_chain=-1)` | `None` | Set dipole-dipole cutoff radius | - - -Log ---- - -| Log manipulation | Returns | Description | -| ------------------------------------------------------------------------ | --------- | --------------------------- | -| `send(p_state, level, sender, message, idx_image=-1, idx_chain=-1)` | `None` | Send a Log message | -| `append(p_state)` | `None` | Append Log to file | - - -Parameters ----------- - -### LLG - -| Set LLG Parameters | Returns | -| --------------------------------------------------------------------------------------------- | ------------- | -| `set_iterations(p_state, n_iterations, n_iterations_log, idx_image=-1, idx_chain=-1)` | `None` | -| `set_direct_minimization(p_state, use_minimization, idx_image=-1, idx_chain=-1)` | `None` | -| `set_convergence(p_state, convergence, idx_image=-1, idx_chain=-1)` | `None` | -| `set_time_step(p_state, dt, idx_image=-1, idx_chain=-1)` | `None` | -| `set_damping(p_state, damping, idx_image=-1, idx_chain=-1)` | `None` | -| `set_stt(p_state, use_gradient, magnitude, direction, idx_image=-1, idx_chain=-1)` | `None` | -| `set_temperature(p_state, temperature, idx_image=-1, idx_chain=-1)` | `None` | - -| Get LLG Parameters | Returns | -| ---------------------------------------------------------------------- | ------------- | -| `get_iterations(p_state, idx_image=-1, idx_chain=-1)` | `int, int` | -| `get_direct_minimization(p_state, idx_image=-1, idx_chain=-1)` | `int` | -| `get_convergence(p_state, idx_image=-1, idx_chain=-1)` | `float` | -| `get_time_step(p_state, idx_image=-1, idx_chain=-1)` | `float` | -| `get_damping(p_state, idx_image=-1, idx_chain=-1)` | `float` | -| `get_stt(p_state, idx_image=-1, idx_chain=-1)` | `float, [3], bool` | -| `get_temperature(p_state, idx_image=-1, idx_chain=-1)` | `float` | - -### GNEB - -| Set GNEB Parameters | Returns | -| -------------------------------------------------------------------------------------------------- | ------------- | -| `set_iterations(p_state, n_iterations, n_iterations_log, idx_image=-1, idx_chain=-1)` | `None` | -| `set_convergence(p_state, convergence, idx_image=-1, idx_chain=-1)` | `None` | -| `set_spring_force(p_state, spring_constant=1, ratio=0, idx_image=-1, idx_chain=-1)` | `None` | -| `set_climbing_falling(p_state, image_type, idx_image=-1, idx_chain=-1)` | `None` | -| `set_image_type_automatically(p_state, idx_chain=-1)` | `None` | - -| Get GNEB Parameters | Returns | -| -------------------------------------------------------------------- | ------------- | -| `get_iterations(p_state, idx_chain=-1)` | `int, int` | -| `get_convergence(p_state, idx_image=-1, idx_chain=-1)` | `float` | -| `get_spring_force(p_state, idx_image=-1, idx_chain=-1)` | `float` | -| `get_climbing_falling(p_state, idx_image=-1, idx_chain=-1)` | `int` | -| `get_energy_interpolations(p_state, idx_chain=-1)` | `int` | - - -Quantities ----------- - -| Get Physical Quantities | Returns | -| -------------------------------------------------------------------- | ------------- | -| `get_magnetization(p_state, idx_image=-1, idx_chain=-1)` | `[3*float]` | - -Simulation ----------- - -The available `method_type`s are: - -| Method | Argument | -| ----------------------------- | :----------: | -| Monte-Carlo | `METHOD_MC` | -| Landau-Lifshitz-Gilbert | `METHOD_LLG` | -| Geodesic Nudged Elastic Band | `METHOD_GNEB`| -| Mode Following Method | `METHOD_MMF` | -| Eigenmode analysis | `METHOD_EMA` | - -The available `solver_type`s are: - -| Solver | Argument | -| ----------------------------- | :-----------: | -| Semi-Implicit Method B | `SOLVER_SIB` | -| Heun Method | `SOLVER_HEUN` | -| Depondt Method | `SOLVER_HEUN` | -| Velocity Projection | `SOLVER_VP` | - -Note that the VP and NCG Solvers are only meant for direct minimization and not for dynamics. - -| Simulation state | Returns | -| ------------------------------------------------------- | ---------- | -| `start(p_state, method_type, solver_type=None, n_iterations=-1, n_iterations_log=-1, single_shot=False, idx_image=-1, idx_chain=-1)` | `None` | -| `single_shot(p_state, idx_image=-1, idx_chain=-1)` | `None` | -| `stop(p_state, idx_image=-1, idx_chain=-1)` | `None` | -| `stop_all(p_state)` | `None` | -| `running_on_image(p_state, idx_image=-1, idx_chain=-1)` | `Boolean` | -| `running_on_chain(p_state, idx_chain=-1)` | `Boolean` | -| `running_anywhere_on_chain(p_state, idx_chain=-1)` | `Boolean` | - - -Transition ----------- - -| Transition options | Returns | Description | -| ---------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------- | -| `homogeneous(p_state, idx_1, idx_2, idx_chain=-1)` | `None` | Generate homogeneous transition between two images of a chain | -| `add_noise(p_state, temperature, idx_1, idx_2, idx_chain=-1)` | `None` | Add some temperature-scaled noise to a transition between two images of a chain | - - -Input/Output ------------- - -Note that, when reading an image or chain from file, the file will automatically be tested for an OVF header. -If it cannot be identified as OVF, it will be tried to be read as three plain text columns (Sx Sy Sz). - -Note also, IO is still being re-written and only OVF will be supported as output format. - -| For Image | Description | -| ----------------------------------------------------------------------------------------- | ------------------------------------ | -| `n_images_in_file(p_state, filename, idx_image_inchain=-1, idx_chain=-1)` | Read specified image from a file to specified image in the chain | -| `image_read(p_state, filename, idx_image_infile=0, idx_image_inchain=-1, idx_chain=-1)` | Read specified image from a file to specified image in the chain | -| `image_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_image=-1, idx_chain=-1)` | Write an image to disk | -| `image_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_image=-1, idx_chain=-1)` | Append an image to an existing file | - -| For Chain | Description | -| ----------------------------------------------------------------------------- | ------------------------------------ | -| `chain_read(p_state, filename, starting_image=-1, ending_image=-1, insert_idx=-1, idx_chain=-1)` | Read some images from a file and insert them into the chain, starting at a specified index | -| `chain_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_chain=-1)` | Write a chain of images to disk | -| `chain_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_chain=-1)` | Append a chain of images to disk | - -| Macros of File Formats for Vector Fields | values | Description | -| ---------------------------------------- | :-----: | --------------------------------------------------| -| `FILEFORMAT_OVF_BIN` | 0 | [OOMMF vector field (OVF) v2.0](http://math.nist.gov/oommf/doc/userguide12a5/userguide/OVF_2.0_format.html) file format (binary, automatically determined size) | -| `FILEFORMAT_OVF_BIN4` | 1 | [OOMMF vector field (OVF) v2.0](http://math.nist.gov/oommf/doc/userguide12a5/userguide/OVF_2.0_format.html) file format (binary 4) | -| `FILEFORMAT_OVF_BIN8` | 2 | [OOMMF vector field (OVF) v2.0](http://math.nist.gov/oommf/doc/userguide12a5/userguide/OVF_2.0_format.html) file format (binary 8) | -| `FILEFORMAT_OVF_TEXT` | 3 | [OOMMF vector field (OVF) v2.0](http://math.nist.gov/oommf/doc/userguide12a5/userguide/OVF_2.0_format.html) file format (plaintext) | -| `FILEFORMAT_OVF_CSV` | 4 | [OOMMF vector field (OVF) v2.0](http://math.nist.gov/oommf/doc/userguide12a5/userguide/OVF_2.0_format.html) file format (comma-separated plaintext) | - - ---- - -[Home](README.md) \ No newline at end of file diff --git a/core/docs/README.md b/core/docs/README.md index ae76006c8..e9a463492 100644 --- a/core/docs/README.md +++ b/core/docs/README.md @@ -26,5 +26,4 @@ The `State` is the object that holds every information needed for the simulation Further reading * [Core build instructions](BUILD.md) * [Core API Reference](API.md) -* [Python API Reference](API_Python.md) * [Input File Reference](INPUT.md) \ No newline at end of file diff --git a/core/python/spirit/chain.py b/core/python/spirit/chain.py index 515b39d21..d986b419a 100644 --- a/core/python/spirit/chain.py +++ b/core/python/spirit/chain.py @@ -1,3 +1,11 @@ +""" +Chain +-------------------- + +Manipulate the chain of spin systems (also called images), e.g. add, remove or change active image. +Get information, such as number of images or energies and reaction coordinates. +""" + import spirit.spiritlib as spiritlib import spirit.parameters as parameters import spirit.system as system @@ -12,6 +20,7 @@ _Get_NOI.argtypes = [ctypes.c_void_p, ctypes.c_int] _Get_NOI.restype = ctypes.c_int def get_noi(p_state, idx_chain=-1): + """Get number of images (NOI) in the chain.""" return int(_Get_NOI(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain))) @@ -20,6 +29,7 @@ def get_noi(p_state, idx_chain=-1): _next_Image.argtypes = [ctypes.c_void_p, ctypes.c_int] _next_Image.restype = ctypes.c_bool def next_image(p_state, idx_chain=-1): + """Switch the active image index to the next highest in the chain.""" return bool(_next_Image(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain))) ### Switch active to previous image of chain @@ -27,6 +37,7 @@ def next_image(p_state, idx_chain=-1): _prev_Image.argtypes = [ctypes.c_void_p, ctypes.c_int] _prev_Image.restype = ctypes.c_bool def prev_image(p_state, idx_chain=-1): + """Switch the active image index to the next lowest in the chain.""" return bool(_prev_Image(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain))) ### Switch active to specific image of chain @@ -34,6 +45,7 @@ def prev_image(p_state, idx_chain=-1): _Jump_To_Image.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Jump_To_Image.restype = ctypes.c_bool def jump_to_image(p_state, idx_image=-1, idx_chain=-1): + """Set the index of the active image in the chain.""" return bool(_Jump_To_Image(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) @@ -42,6 +54,16 @@ def jump_to_image(p_state, idx_image=-1, idx_chain=-1): _Set_Length.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Set_Length.restype = None def set_length(p_state, n_images, idx_chain=-1): + """Set the number of images (NOI) in the chain. + + If the chain is longer, the corresponding number of images is erased from the end. + + If the chain is shorter, the corresponding number of images is appended. + + Note that the active image might change. + + If no image is in the clipboard, no action is taken. + """ _Set_Length(ctypes.c_void_p(p_state), ctypes.c_int(n_images), ctypes.c_int(idx_chain)) ### Copy active image to clipboard @@ -49,6 +71,7 @@ def set_length(p_state, n_images, idx_chain=-1): _Image_to_Clipboard.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Image_to_Clipboard.restype = None def image_to_clipboard(p_state, idx_image=-1, idx_chain=-1): + """Copies an image to the clipboard of Spirit. It can then be later e.g. inserted or appended.""" _Image_to_Clipboard(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) ### Replace active image in chain @@ -56,6 +79,10 @@ def image_to_clipboard(p_state, idx_image=-1, idx_chain=-1): _Replace_Image.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Replace_Image.restype = None def replace_image(p_state, idx_image=-1, idx_chain=-1): + """Replaces the image from the one in the clipboard. + + If no image is in the clipboard, no action is taken. + """ _Replace_Image(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) @@ -64,6 +91,12 @@ def replace_image(p_state, idx_image=-1, idx_chain=-1): _Insert_Image_Before.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Insert_Image_Before.restype = None def insert_image_before(p_state, idx_image=-1, idx_chain=-1): + """Inserts an image in front of the specified index. + + Note that the active image might change. + + If no image is in the clipboard, no action is taken. + """ _Insert_Image_Before(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) ### Insert clipboard image after image in chain @@ -71,6 +104,12 @@ def insert_image_before(p_state, idx_image=-1, idx_chain=-1): _Insert_Image_After.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Insert_Image_After.restype = None def insert_image_after(p_state, idx_image=-1, idx_chain=-1): + """Inserts an image after the specified index. + + Note that the active image might change. + + If no image is in the clipboard, no action is taken. + """ _Insert_Image_After(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) ### Insert clipboard image at end of chain @@ -78,6 +117,10 @@ def insert_image_after(p_state, idx_image=-1, idx_chain=-1): _Push_Back.argtypes = [ctypes.c_void_p, ctypes.c_int] _Push_Back.restype = None def push_back(p_state, idx_chain=-1): + """Appends an image to the chain. + + If no image is in the clipboard, no action is taken. + """ _Push_Back(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain)) @@ -87,6 +130,12 @@ def push_back(p_state, idx_chain=-1): _Delete_Image.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Delete_Image.restype = ctypes.c_bool def delete_image(p_state, idx_image=-1, idx_chain=-1): + """Removes the specified image from the chain. + + Note that the active image might change. + + If it is the last remaining image in the chain, no action is taken. + """ return bool(_Delete_Image(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) ### Delete image at end of chain @@ -94,6 +143,12 @@ def delete_image(p_state, idx_image=-1, idx_chain=-1): _Pop_Back.argtypes = [ctypes.c_void_p, ctypes.c_int] _Pop_Back.restype = ctypes.c_bool def pop_back(p_state, idx_chain=-1): + """Removes the last image from the chain. + + Note that the active image might change. + + If it is the last remaining image in the chain, no action is taken. + """ return bool(_Pop_Back(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain))) @@ -102,6 +157,12 @@ def pop_back(p_state, idx_chain=-1): _Update_Data.argtypes = [ctypes.c_void_p, ctypes.c_int] _Update_Data.restype = None def update_data(p_state, idx_chain=-1): + """Updates various data of the chain, including: + + - Energies of images + - Reaction coordinates of images + - Interpolated energy and reaction coordinate values + """ _Update_Data(ctypes.c_void_p(p_state), ctypes.c_int(idx_chain)) @@ -118,6 +179,7 @@ def setup_data(p_state, idx_chain=-1): _Get_Rx.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int] _Get_Rx.restype = None def get_reaction_coordinate(p_state, idx_chain=-1): + """Returns an array of shape (NOI) containing the reaction coordinates of the images.""" noi = get_noi(p_state, idx_chain) Rx = (noi*ctypes.c_float)() _Get_Rx(ctypes.c_void_p(p_state), Rx, ctypes.c_int(idx_chain)) @@ -128,6 +190,10 @@ def get_reaction_coordinate(p_state, idx_chain=-1): _Get_Rx_Interpolated.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int] _Get_Rx_Interpolated.restype = None def get_reaction_coordinate_interpolated(p_state, idx_chain=-1): + """Returns an array containing the interpolated reaction coordinate values along the chain. + + The number of interpolated values between images can be set in the GNEB parameters. + """ noi = get_noi(p_state, idx_chain) n_interp = parameters.gneb.get_n_energy_interpolations(p_state, idx_chain) len_Rx = noi + (noi-1)*n_interp @@ -140,6 +206,7 @@ def get_reaction_coordinate_interpolated(p_state, idx_chain=-1): _Get_Energy.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int] _Get_Energy.restype = None def get_energy(p_state, idx_chain=-1): + """Returns an array of shape (NOI) containing the energies of the images.""" noi = get_noi(p_state, idx_chain) Energy = (noi*ctypes.c_float)() _Get_Energy(ctypes.c_void_p(p_state), Energy, ctypes.c_int(idx_chain)) @@ -150,6 +217,10 @@ def get_energy(p_state, idx_chain=-1): _Get_Energy_Interpolated.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int] _Get_Energy_Interpolated.restype = None def get_energy_interpolated(p_state, idx_chain=-1): + """Returns an array containing the interpolated energy values along the chain. + + The number of interpolated values between images can be set in the GNEB parameters. + """ noi = get_noi(p_state, idx_chain) n_interp = parameters.gneb.get_n_energy_interpolations(p_state, idx_chain) len_Energy = noi + (noi-1)*n_interp @@ -165,6 +236,19 @@ def get_energy_interpolated(p_state, idx_chain=-1): ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_int] _Get_HTST_Info.restype = None def get_htst_info(p_state, idx_chain=-1): + """Calculates and returns a set of HTST information: + + - eigenvalues at the minimum + - eigenvalues at the saddle point + - the exponent of the temperature-dependence + - `me` + - `Omega_0` + - `s` + - zero mode volume at the minimum + - zero mode volume at the saddle point + - dynamical prefactor + - full rate prefactor (without temperature dependent part) + """ nos = system.get_nos(p_state, -1, idx_chain) eigenvalues_min = (2*nos*ctypes.c_float)() eigenvalues_sp = (2*nos*ctypes.c_float)() diff --git a/core/python/spirit/configuration.py b/core/python/spirit/configuration.py index 469f3d81e..641224541 100644 --- a/core/python/spirit/configuration.py +++ b/core/python/spirit/configuration.py @@ -1,11 +1,16 @@ +""" +Configuration +-------------------- + +Set various spin configurations, such as homogeneous domains, spirals or skyrmions. +""" + import spirit.spiritlib as spiritlib import ctypes ### Load Library _spirit = spiritlib.load_spirit_library() - -### Domain (homogeneous) configuration _Domain = _spirit.Configuration_Domain _Domain.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), @@ -13,13 +18,12 @@ _Domain.restype = None def domain(p_state, dir, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Set a domain (homogeneous) configuration.""" vec3 = ctypes.c_float * 3 _Domain(ctypes.c_void_p(p_state), vec3(*dir), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### All spins in +z direction _PlusZ = _spirit.Configuration_PlusZ _PlusZ.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, ctypes.c_bool, @@ -27,13 +31,12 @@ def domain(p_state, dir, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cyli _PlusZ.restype = None def plus_z(p_state, pos=[0.0,0.0,0.0], border_rectangular=[-1.0,-1.0,-1.0], border_cylindrical=-1.0, border_spherical=-1.0, inverted=False, idx_image=-1, idx_chain=-1): + """Set a +z (homogeneous) configuration.""" vec3 = ctypes.c_float * 3 _PlusZ(ctypes.c_void_p(p_state), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### All spins in -z direction _MinusZ = _spirit.Configuration_MinusZ _MinusZ.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, @@ -41,12 +44,12 @@ def plus_z(p_state, pos=[0.0,0.0,0.0], border_rectangular=[-1.0,-1.0,-1.0], bord _MinusZ.restype = None def minus_z(p_state, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Set a -z (homogeneous) configuration.""" vec3 = ctypes.c_float * 3 _MinusZ(ctypes.c_void_p(p_state), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Random configuration _Random = _spirit.Configuration_Random _Random.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, @@ -54,13 +57,12 @@ def minus_z(p_state, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindri _Random.restype = None def random(p_state, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Distribute all spins randomly on the unit sphere.""" vec3 = ctypes.c_float * 3 _Random(ctypes.c_void_p(p_state), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), False, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### Add temperature-scaled random noise to configuration _Add_Noise_Temperature = _spirit.Configuration_Add_Noise_Temperature _Add_Noise_Temperature.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), @@ -70,31 +72,41 @@ def random(p_state, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindric def add_noise(p_state, temperature, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Add temperature-scaled random noise to configuration.""" vec3 = ctypes.c_float * 3 _Add_Noise_Temperature(ctypes.c_void_p(p_state), ctypes.c_float(temperature), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### Skyrmion configuration _Skyrmion = _spirit.Configuration_Skyrmion _Skyrmion.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.c_float, ctypes.c_float, ctypes.c_bool, ctypes.c_bool, ctypes.c_bool, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, ctypes.c_bool, ctypes.c_int, ctypes.c_int] _Skyrmion.restype = None -def skyrmion(p_state, radius, order=1, phase=1, upDown=False, achiral=False, rightleft=False, +def skyrmion(p_state, radius, order=1, phase=1, up_down=False, achiral=False, right_left=False, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Set a skyrmion configuration. + + - radius: the extent of the skyrmion, at which it points approximately upwards + - order: the number of twists along a circle cutting the skyrmion + - phase: 0 corresponds to a Neel skyrmion, -90 to a Bloch skyrmion + - up_down: if `True`, the z-orientation is inverted + - achiral: if `True`, the topological charge is inverted + - right_left: if `True`, the in-plane rotation is inverted + + The skyrmion only extends up to `radius`, meaning that `border_cylindrical` is + not usually necessary. + """ vec3 = ctypes.c_float * 3 _Skyrmion(ctypes.c_void_p(p_state), ctypes.c_float(radius), ctypes.c_float(order), - ctypes.c_float(phase), ctypes.c_bool(upDown), ctypes.c_bool(achiral), + ctypes.c_float(phase), ctypes.c_bool(up_down), ctypes.c_bool(achiral), ctypes.c_bool(rightleft), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Hopfion configuration _Hopfion = _spirit.Configuration_Hopfion _Hopfion.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.c_int, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, ctypes.c_bool, @@ -102,14 +114,19 @@ def skyrmion(p_state, radius, order=1, phase=1, upDown=False, achiral=False, rig _Hopfion.restype = None def hopfion(p_state, radius, order=1, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Set a Hopfion configuration. + + - radius: the distance from the center to the center of the corresponding tubular isosurface + - order: TODO + + In contrast to the skyrmion, it extends over the whole allowed space. + """ vec3 = ctypes.c_float * 3 _Hopfion(ctypes.c_void_p(p_state), ctypes.c_float(radius), ctypes.c_int(order), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### Spin Spiral configuration _SpinSpiral = _spirit.Configuration_SpinSpiral _SpinSpiral.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, @@ -120,6 +137,14 @@ def hopfion(p_state, radius, order=1, pos=[0,0,0], border_rectangular=[-1,-1,-1] def spin_spiral(p_state, direction_type, q_vector, axis, theta, pos=[0,0,0], border_rectangular=[-1,-1,-1], border_cylindrical=-1, border_spherical=-1, inverted=False, idx_image=-1, idx_chain=-1): + """Set a spin spiral configuration. + + TODO: document parameters + - direction_type: + - q_vector: + - axis: + - theta: + """ vec3 = ctypes.c_float * 3 _SpinSpiral(ctypes.c_void_p(p_state), ctypes.c_char_p(direction_type.encode('utf-8')), vec3(*q_vector), vec3(*axis), ctypes.c_float(theta), vec3(*pos), @@ -127,8 +152,6 @@ def spin_spiral(p_state, direction_type, q_vector, axis, theta, pos=[0,0,0], ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### Pin spins in a selected area _Set_Pinned = _spirit.Configuration_Set_Pinned _Set_Pinned.argtypes = [ctypes.c_void_p, ctypes.c_bool, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, ctypes.c_bool, @@ -136,13 +159,15 @@ def spin_spiral(p_state, direction_type, q_vector, axis, theta, pos=[0,0,0], _Set_Pinned.restype = None def set_pinned(p_state, pinned, pos=[0.0,0.0,0.0], border_rectangular=[-1.0,-1.0,-1.0], border_cylindrical=-1.0, border_spherical=-1.0, inverted=False, idx_image=-1, idx_chain=-1): + """Set whether the spins within the given region are pinned or not. + + If they are pinned, they are pinned to their current orientation. + """ vec3 = ctypes.c_float * 3 _Set_Pinned(ctypes.c_void_p(p_state), ctypes.c_bool(pinned), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), ctypes.c_bool(inverted), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - -### Set atom types in a selected area _Set_Atom_Type = _spirit.Configuration_Set_Atom_Type _Set_Atom_Type.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_float, ctypes.c_float, ctypes.c_bool, @@ -150,6 +175,10 @@ def set_pinned(p_state, pinned, pos=[0.0,0.0,0.0], border_rectangular=[-1.0,-1.0 _Set_Atom_Type.restype = None def set_atom_type(p_state, atom_type=0, pos=[0.0,0.0,0.0], border_rectangular=[-1.0,-1.0,-1.0], border_cylindrical=-1.0, border_spherical=-1.0, inverted=False, idx_image=-1, idx_chain=-1): + """Set the type of the atoms in the given region (default: 0). + + This can be used e.g. to insert defects (-1). + """ vec3 = ctypes.c_float * 3 _Set_Atom_Type(ctypes.c_void_p(p_state), ctypes.c_int(atom_type), vec3(*pos), vec3(*border_rectangular), ctypes.c_float(border_cylindrical), ctypes.c_float(border_spherical), diff --git a/core/python/spirit/constants.py b/core/python/spirit/constants.py index 2aeaaffb6..1862e9a7b 100644 --- a/core/python/spirit/constants.py +++ b/core/python/spirit/constants.py @@ -1,3 +1,8 @@ +""" +Constants +-------------------- +""" + import spirit.spiritlib as spiritlib import ctypes @@ -6,50 +11,50 @@ # Load Library _spirit = spiritlib.load_spirit_library() -# The Bohr Magneton [meV / T] _mu_B = _spirit.Constants_mu_B _mu_B.argtypes = None _mu_B.restype = scalar mu_B = _mu_B() +"""The Bohr Magneton [meV / T]""" -# The vacuum permeability [T^2 m^3 / meV] _mu_0 = _spirit.Constants_mu_0 _mu_0.argtypes = None _mu_0.restype = scalar mu_0 = _mu_0() +"""The vacuum permeability [T^2 m^3 / meV]""" -# The Boltzmann constant [meV / K] _k_B = _spirit.Constants_k_B _k_B.argtypes = None _k_B.restype = scalar k_B = _k_B() +"""The Boltzmann constant [meV / K]""" -# Planck's constant [meV*ps / rad] _hbar = _spirit.Constants_hbar _hbar.argtypes = None _hbar.restype = scalar hbar = _hbar() +"""Planck's constant [meV*ps / rad]""" -# Millirydberg [mRy / meV] _mRy = _spirit.Constants_mRy _mRy.argtypes = None _mRy.restype = scalar mRy = _mRy() +"""Millirydberg [mRy / meV]""" -# Gyromagnetic ratio of electron [rad / (ps*T)] _gamma = _spirit.Constants_gamma _gamma.argtypes = None _gamma.restype = scalar gamma = _gamma() +"""Gyromagnetic ratio of electron [rad / (ps*T)]""" -# Electron g-factor [unitless] _g_e = _spirit.Constants_g_e _g_e.argtypes = None _g_e.restype = scalar g_e = _g_e() +"""Electron g-factor [unitless]""" -# Pi [rad] _Pi = _spirit.Constants_Pi _Pi.argtypes = None _Pi.restype = scalar -pi = _Pi() \ No newline at end of file +pi = _Pi() +"""Pi [rad]""" \ No newline at end of file diff --git a/core/python/spirit/geometry.py b/core/python/spirit/geometry.py index 90c2fef85..ddbbc3167 100644 --- a/core/python/spirit/geometry.py +++ b/core/python/spirit/geometry.py @@ -1,3 +1,11 @@ +""" +Geometry +-------------------- + +Change or get info on the current geometrical configuration, e.g. +number of cells in the three crystal translation directions. +""" + import spirit.spiritlib as spiritlib import ctypes @@ -23,130 +31,152 @@ ### ---------------------------------- Set ---------------------------------- -### Set the type of Bravais lattice. Can be e.g. "sc" or "bcc" _Set_Bravais_Lattice_Type = _spirit.Geometry_Set_Bravais_Lattice_Type _Set_Bravais_Lattice_Type.argtypes = [ctypes.c_void_p, ctypes.c_int] _Set_Bravais_Lattice_Type.restype = None def set_bravais_lattice_type(p_state, lattice_type, idx_image=-1, idx_chain=-1): + """Set the bravais vectors to a pre-defined lattice type: + + - sc: simple cubic + - bcc: body centered cubic + - fcc: face centered cubic + - hex2d: hexagonal (120deg) + - hed2d120: hexagonal (120deg) + - hex2d60: hexagonal (60deg) + """ _Set_Bravais_Lattice_Type(ctypes.c_void_p(p_state), ctypes.c_int(lattice_type)) -### Set number of cells in bravais lattice directions a, b, c _Set_N_Cells = _spirit.Geometry_Set_N_Cells _Set_N_Cells.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int)] _Set_N_Cells.restype = None def set_n_cells(p_state, n_cells=[1, 1, 1], idx_image=-1, idx_chain=-1): + """Set the number of basis cells along the three bravais vectors.""" vec3 = ctypes.c_int * 3 _Set_N_Cells(ctypes.c_void_p(p_state), vec3(*n_cells)) -### Set magnetic moment globally _Set_mu_s = _spirit.Geometry_Set_mu_s _Set_mu_s.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.c_int, ctypes.c_int] _Set_mu_s.restype = None def set_mu_s(p_state, mu_s, idx_image=-1, idx_chain=-1): + """Set the magnetic moment of all atoms.""" _Set_mu_s(ctypes.c_void_p(p_state), ctypes.c_float(mu_s), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set the types of the atoms in a basis cell _Set_Cell_Atom_Types = _spirit.Geometry_Set_Cell_Atom_Types _Set_Cell_Atom_Types.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_float)] _Set_Cell_Atom_Types.restype = None def set_cell_atom_types(p_state, atom_types, idx_image=-1, idx_chain=-1): + """Set the atom types of the atoms in the basis cell.""" n = len(atom_types) vec = ctypes.c_int * n _Set_Cell_Atom_Types(ctypes.c_void_p(p_state), ctypes.c_int(n), vec(*atom_types)) -### Set the bravais vectors _Set_Bravais_Vectors = _spirit.Geometry_Set_Bravais_Vectors _Set_Bravais_Vectors.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float)] _Set_Bravais_Vectors.restype = None def set_bravais_vectors(p_state, ta=[1.0, 0.0, 0.0], tb=[0.0, 1.0, 0.0], tc=[0.0, 0.0, 1.0], idx_image=-1, idx_chain=-1): + """Manually specify the bravais vectors.""" vec3 = ctypes.c_float * 3 _Set_Bravais_Vectors(ctypes.c_void_p(p_state), vec3(ta), vec3(tb), vec3(tc)) -### Set the overall lattice constant _Set_Lattice_Constant = _spirit.Geometry_Set_Lattice_Constant _Set_Lattice_Constant.argtypes = [ctypes.c_void_p, ctypes.c_float] _Set_Lattice_Constant.restype = None def set_lattice_constant(p_state, lattice_constant, idx_image=-1, idx_chain=-1): + """Set the global lattice scaling constant.""" _Set_Lattice_Constant(p_state, ctypes.c_float(lattice_constant)) ### ---------------------------------- Get ---------------------------------- -### Get Bounds _Get_Bounds = _spirit.Geometry_Get_Bounds -_Get_Bounds.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), +_Get_Bounds.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Get_Bounds.restype = None def get_bounds(p_state, idx_image=-1, idx_chain=-1): + """Get the bounds of the system in global coordinates. + + Returns two arrays of shape (3) containing minimum and maximum bounds respectively. + """ _min = (3*ctypes.c_float)() _max = (3*ctypes.c_float)() - _Get_Bounds(ctypes.c_void_p(p_state), _min, _max, + _Get_Bounds(ctypes.c_void_p(p_state), _min, _max, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) - return [_min[i] for i in range(3)], [_max[i] for i in range(3)] + return [_min[i] for i in range(3)], [_max[i] for i in range(3)] -### Get Center _Get_Center = _spirit.Geometry_Get_Center _Get_Center.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Get_Center.restype = None def get_center(p_state, idx_image=-1, idx_chain=-1): + """Get the center of the system in global coordinates. + + Returns an array of shape (3). + """ _center = (3*ctypes.c_float)() _Get_Center(ctypes.c_void_p(p_state), _center, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return [_center[i] for i in range(3)] -### Get Bravais lattice type _Get_Bravais_Lattice_Type = _spirit.Geometry_Get_Bravais_Lattice_Type _Get_Bravais_Lattice_Type.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_Bravais_Lattice_Type.restype = ctypes.c_int def get_bravais_lattice_type(p_state, idx_image=-1, idx_chain=-1): - return int(_Get_Bravais_Lattice_Type(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), + """Get the bravais lattice type corresponding to one of the integers defined above.""" + return int(_Get_Bravais_Lattice_Type(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) -### Get Bravais vectors _Get_Bravais_Vectors = _spirit.Geometry_Get_Bravais_Vectors -_Get_Bravais_Vectors.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), - ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), +_Get_Bravais_Vectors.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), + ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Get_Bravais_Vectors.restype = None def get_bravais_vectors(p_state, idx_image=-1, idx_chain=-1): + """Get the bravais vectors. + + Returns three arrays of shape (3). + """ _a = (3*ctypes.c_float)() _b = (3*ctypes.c_float)() _c = (3*ctypes.c_float)() - _Get_Bravais_Vectors(ctypes.c_void_p(p_state), _a, _b, _c, + _Get_Bravais_Vectors(ctypes.c_void_p(p_state), _a, _b, _c, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return [a for a in _a], [b for b in _b], [c for c in _c] - -### Get N Cells + _Get_N_Cells = _spirit.Geometry_Get_N_Cells _Get_N_Cells.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.c_int, ctypes.c_int] _Get_N_Cells.restype = None def get_n_cells(p_state, idx_image=-1, idx_chain=-1): + """Get the number of basis cells along the three bravais vectors. + + Returns an array of shape (3). + """ n_cells = (3*ctypes.c_int)() _Get_N_Cells(ctypes.c_void_p(p_state), n_cells, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return [n for n in n_cells] -### Get Translation Vectors _Get_Translation_Vectors = _spirit.Geometry_Get_Translation_Vectors -_Get_Translation_Vectors.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), - ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), +_Get_Translation_Vectors.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), + ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Get_Translation_Vectors.restype = None def get_translation_vectors(p_state, idx_image=-1, idx_chain=-1): + """Get the translation vectors in global coordinates. + + Returns three arrays of shape (3). + """ ta = (3*ctypes.c_float)() tb = (3*ctypes.c_float)() tc = (3*ctypes.c_float)() - _Get_Translation_Vectors(ctypes.c_void_p(p_state), ta, tb, tc, + _Get_Translation_Vectors(ctypes.c_void_p(p_state), ta, tb, tc, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return [a for a in ta], [b for b in tb], [c for c in tc] -### Get Translation Vectors _Get_Dimensionality = _spirit.Geometry_Get_Dimensionality _Get_Dimensionality.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_Dimensionality.restype = ctypes.c_int def get_dimensionality(p_state, idx_image=-1, idx_chain=-1): - return int(_Get_Dimensionality(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), - ctypes.c_int(idx_chain))) + """Get the dimensionality of the geometry.""" + return int(_Get_Dimensionality(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) ### Get Pointer to Spin Positions # NOTE: Changing the values of the array_view one can alter the value of the data of the state @@ -154,26 +184,39 @@ def get_dimensionality(p_state, idx_image=-1, idx_chain=-1): _Get_Positions.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_Positions.restype = ctypes.POINTER(scalar) def get_positions(p_state, idx_image=-1, idx_chain=-1): + """Returns a `numpy.array_view` of shape (NOS, 3) with the components of each spins position. + + Changing the contents of this array_view will have direct effect on the state and should not be done. + """ nos = system.get_nos(p_state, idx_image, idx_chain) ArrayType = scalar*3*nos - Data = _Get_Positions(ctypes.c_void_p(p_state), - ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) + Data = _Get_Positions(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) array_pointer = ctypes.cast(Data, ctypes.POINTER(ArrayType)) array = np.frombuffer(array_pointer.contents, dtype=scalar) array_view = array.view() array_view.shape = (nos, 3) return array_view +_Get_N_Cell_Atoms = _spirit.Geometry_Get_N_Cell_Atoms +_Get_N_Cell_Atoms.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] +_Get_N_Cell_Atoms.restype = ctypes.c_int +def get_n_cell_atoms(p_state, idx_image=-1, idx_chain=-1): + """Get the number of atoms in the basis cell.""" + return int(_Get_N_Cell_Atoms(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) + ### Get Pointer to atom types # NOTE: Changing the values of the array_view one can alter the value of the data of the state _Get_Atom_Types = _spirit.Geometry_Get_Atom_Types _Get_Atom_Types.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_Atom_Types.restype = ctypes.POINTER(ctypes.c_int) def get_atom_types(p_state, idx_image=-1, idx_chain=-1): + """Get the types of all atoms as a `numpy.array_view` of shape (NOS). + + If e.g. disorder is activated, this allows to view and manipulate the types of individual atoms. + """ nos = system.get_nos(p_state, idx_image, idx_chain) ArrayType = ctypes.c_int*nos - Data = _Get_Atom_Types(ctypes.c_void_p(p_state), - ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) + Data = _Get_Atom_Types(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) array_pointer = ctypes.cast(Data, ctypes.POINTER(ArrayType)) array = np.frombuffer(array_pointer.contents, dtype=ctypes.c_int) array_view = array.view() diff --git a/core/python/spirit/hamiltonian.py b/core/python/spirit/hamiltonian.py index 44c2fd4c0..b7d116a76 100644 --- a/core/python/spirit/hamiltonian.py +++ b/core/python/spirit/hamiltonian.py @@ -1,3 +1,10 @@ +""" +Hamiltonian +-------------------- + +Set the parameters of the Heisenberg Hamiltonian, such as external field or exchange interaction. +""" + import spirit.spiritlib as spiritlib import ctypes @@ -6,114 +13,141 @@ ### DM vector chirality CHIRALITY_BLOCH = 1 +"""DMI Bloch chirality type for neighbour shells""" + CHIRALITY_NEEL = 2 +"""DMI Neel chirality type for neighbour shells""" + CHIRALITY_BLOCH_INVERSE = -1 +"""DMI Bloch chirality type for neighbour shells with opposite sign""" + CHIRALITY_NEEL_INVERSE = -2 +"""DMI Neel chirality type for neighbour shells with opposite sign""" ### DDI METHOD DDI_METHOD_NONE = 0 +"""Dipole-dipole interaction: do not calculate""" + DDI_METHOD_FFT = 1 +"""Dipole-dipole interaction: use FFT convolutions""" + DDI_METHOD_FMM = 2 +"""Dipole-dipole interaction: use a fast multipole method (FMM)""" + DDI_METHOD_CUTOFF = 3 +"""Dipole-dipole interaction: use a direct summation with a cutoff radius""" ### ---------------------------------- Set ---------------------------------- -### Set boundary conditions _Set_Boundary_Conditions = _spirit.Hamiltonian_Set_Boundary_Conditions _Set_Boundary_Conditions.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_bool), ctypes.c_int, ctypes.c_int] _Set_Boundary_Conditions.restype = None def set_boundary_conditions(p_state, boundaries, idx_image=-1, idx_chain=-1): + """Set the boundary conditions along the translation directions [a, b, c]. + + 0 = open, 1 = periodical + """ bool3 = ctypes.c_bool * 3 _Set_Boundary_Conditions(ctypes.c_void_p(p_state), bool3(*boundaries), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set global external magnetic field _Set_Field = _spirit.Hamiltonian_Set_Field _Set_Field.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Set_Field.restype = None def set_field(p_state, magnitude, direction, idx_image=-1, idx_chain=-1): + """Set the (homogeneous) external magnetic field.""" vec3 = ctypes.c_float * 3 _Set_Field(ctypes.c_void_p(p_state), ctypes.c_float(magnitude), vec3(*direction), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set global anisotropy _Set_Anisotropy = _spirit.Hamiltonian_Set_Anisotropy _Set_Anisotropy.argtypes = [ctypes.c_void_p, ctypes.c_float, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Set_Anisotropy.restype = None def set_anisotropy(p_state, magnitude, direction, idx_image=-1, idx_chain=-1): + """Set the (homogeneous) magnetocrystalline anisotropy.""" vec3 = ctypes.c_float * 3 - _Set_Anisotropy(ctypes.c_void_p(p_state), ctypes.c_float(magnitude), vec3(*direction), + _Set_Anisotropy(ctypes.c_void_p(p_state), ctypes.c_float(magnitude), vec3(*direction), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set exchange interaction in form of neighbour shells _Set_Exchange = _spirit.Hamiltonian_Set_Exchange _Set_Exchange.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Set_Exchange.restype = None def set_exchange(p_state, n_shells, J_ij, idx_image=-1, idx_chain=-1): + """Set the Exchange interaction in terms of neighbour shells.""" vec = ctypes.c_float * n_shells _Set_Exchange(ctypes.c_void_p(p_state), ctypes.c_int(n_shells), vec(*J_ij), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set Dzyaloshinskii-Moriya interaction in form of neighbour shells _Set_DMI = _spirit.Hamiltonian_Set_DMI _Set_DMI.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int, ctypes.c_int] _Set_DMI.restype = None def set_dmi(p_state, n_shells, D_ij, chirality=CHIRALITY_BLOCH, idx_image=-1, idx_chain=-1): + """Set the Dzyaloshinskii-Moriya interaction in terms of neighbour shells.""" vec = ctypes.c_float * n_shells _Set_DMI(ctypes.c_void_p(p_state), ctypes.c_int(n_shells), vec(*D_ij), ctypes.c_int(chirality), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Set dipole-dipole interaction in form of exact calculation within a cutoff radius _Set_DDI = _spirit.Hamiltonian_Set_DDI _Set_DDI.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.c_float, ctypes.c_int, ctypes.c_int] _Set_DDI.restype = None def set_ddi(p_state, ddi_method, n_periodic_images=[4,4,4], radius=0.0, idx_image=-1, idx_chain=-1): + """Set the dipolar interaction calculation method. + + - ddi_method -- one of the integers defined above + - n_periodic_images -- the number of periodical images in the three translation directions, taken into account + when boundaries in the corresponding direction are periodical + - radius -- the cutoff radius for the direct summation method + """ vec3 = ctypes.c_int * 3 _Set_DDI(ctypes.c_void_p(p_state), ctypes.c_int(ddi_method) , vec3(*n_periodic_images), ctypes.c_float(radius), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) ### ---------------------------------- Get ---------------------------------- -### Get the name of the Hamiltonian _Get_Name = _spirit.Hamiltonian_Get_Name _Get_Name.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_Name.restype = ctypes.c_char_p def get_name(p_state, idx_image=-1, idx_chain=-1): + """Returns a string containing the name of the Hamiltonian currently in use.""" return str(_Get_Name(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) -### Get the boundary conditions [a, b, c] _Get_Boundary_Conditions = _spirit.Hamiltonian_Get_Boundary_Conditions _Get_Boundary_Conditions.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_bool), ctypes.c_int, ctypes.c_int] _Get_Boundary_Conditions.restype = None def get_boundary_conditions(p_state, idx_image=-1, idx_chain=-1): + """Returns an array of shape (3) containing the boundary conditions in the + three translation directions [a, b, c] of the lattice. + """ boundaries = (3*ctypes.c_bool)() _Get_Boundary_Conditions(ctypes.c_void_p(p_state), boundaries, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return [bc for bc in boundaries] -### Get the global external magnetic field _Get_Field = _spirit.Hamiltonian_Get_Field _Get_Field.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_float), ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int] _Get_Field.restype = None def get_field(p_state, idx_image=-1, idx_chain=-1): + """Returns the magnitude and an array of shape (3) containing the direction of + the external magnetic field. + """ magnitude = (1*ctypes.c_float)() normal = (3*ctypes.c_float)() _Get_Field(ctypes.c_void_p(p_state), magnitude, normal, ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) return float(magnitude), [n for n in normal] -### Get dipole-dipole interaction cutoff radius _Get_DDI = _spirit.Hamiltonian_Get_DDI _Get_DDI.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] _Get_DDI.restype = ctypes.c_float def get_ddi(p_state, idx_image=-1, idx_chain=-1): - return float(_Get_DDI(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), + """Returns the cutoff radius of the DDI.""" + return float(_Get_DDI(ctypes.c_void_p(p_state), ctypes.c_int(idx_image), ctypes.c_int(idx_chain))) \ No newline at end of file diff --git a/core/python/spirit/io.py b/core/python/spirit/io.py index 7afe78431..811f867b2 100644 --- a/core/python/spirit/io.py +++ b/core/python/spirit/io.py @@ -1,3 +1,16 @@ +""" +I/O +-------------------- + +Read and write spin configurations, chains or eigenmodes. +Vectorfields are generally written in the `OOMMF vector field (OVF) file format `_. + +Note that, when reading an image or chain from file, the file will automatically be tested for an OVF header. +If it cannot be identified as OVF, it will be tried to be read as three plain text columns (Sx Sy Sz). + +Note also, IO is still being re-written and only OVF will be supported as output format. +""" + import spirit.spiritlib as spiritlib import ctypes @@ -6,96 +19,174 @@ ### Output file formats FILEFORMAT_OVF_BIN = 0 +"""OVF binary format corresponding to the precision with which the code was compiled""" + FILEFORMAT_OVF_BIN4 = 1 +"""OVF binary format with precision 4""" + FILEFORMAT_OVF_BIN8 = 2 +"""OVF binary format with precision 8""" + FILEFORMAT_OVF_TEXT = 3 +"""OVF text format""" + FILEFORMAT_OVF_CSV = 4 +"""OVF text format with comma-separated columns""" -### Get the number of images in a file _N_Images_In_File = _spirit.IO_N_Images_In_File _N_Images_In_File.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] _N_Images_In_File.restype = ctypes.c_int def n_images_in_file(p_state, filename, idx_image_inchain=-1, idx_chain=-1): + """Returns the number of segments or images in a given file. + + Arguments: + p_state -- state pointer + filename -- the name of the file to check + """ return int(_N_Images_In_File(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(idx_image_inchain), ctypes.c_int(idx_chain))) -### Read an image from disk _Image_Read = _spirit.IO_Image_Read _Image_Read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.c_int] _Image_Read.restype = None def image_read(p_state, filename, idx_image_infile=0, idx_image_inchain=-1, idx_chain=-1): + """Attempt to read a spin configuration from a file into an image of the chain. + + Arguments: + p_state -- state pointer + filename -- the name of the file to read + + Keyword arguments: + idx_image_infile -- the index of the image in the file which should be read in (default: 0) + idx_image_inchain -- the index of the image in the chain into which the data should be read (default: active image) + """ _Image_Read(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(idx_image_infile), ctypes.c_int(idx_image_inchain), ctypes.c_int(idx_chain)) -### Write an image to disk _Image_Write = _spirit.IO_Image_Write _Image_Write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] _Image_Write.restype = None -def image_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_image=-1, idx_chain=-1): +def image_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment="", idx_image=-1, idx_chain=-1): + """Write an image of the chain to a file. + + Arguments: + p_state -- state pointer + filename -- the name of the file to write + + Keyword arguments: + fileformat -- the format in which to write the data (default: OVF text) + comment -- a comment string to be inserted in the header (default: empty) + idx_image -- the index of the image to be written to the file (default: active image) + """ _Image_Write(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(fileformat), ctypes.c_char_p(comment.encode('utf-8')), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Append an image to an existing file _Image_Append = _spirit.IO_Image_Append _Image_Append.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] _Image_Append.restype = None -def image_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_image=-1, idx_chain=-1): +def image_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment="", idx_image=-1, idx_chain=-1): + """Append an image of the chain to a file, incrementing the segment count. + + If the file does not exist, it is created. + + Arguments: + p_state -- state pointer + filename -- the name of the file to append to + + Keyword arguments: + fileformat -- the format in which to write the data (default: OVF text) + comment -- a comment string to be inserted in the header (default: empty) + idx_image -- the index of the image to be written to the file (default: active image) + """ _Image_Append(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(fileformat), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Read a chain of images from disk _Chain_Read = _spirit.IO_Chain_Read _Chain_Read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] _Chain_Read.restype = None -def chain_read(p_state, filename, starting_image=-1, ending_image=-1, insert_idx=-1, - idx_chain=-1): +def chain_read(p_state, filename, starting_image=0, ending_image=0, insert_idx=-1, idx_chain=-1): + """Attempt to read a chain of images from a given file. + + Arguments: + p_state -- state pointer + filename -- the name of the file to read + + Keyword arguments: + starting_image -- the index within the file at which to start reading (default: 0) + ending_image -- the index within the file at which to stop reading (default: 0) + insert_idx -- the index within the chain at which to start placing the images (default: active image) + + Images of the chain will be overwritten with what is read from the file. + If the chain is not long enough for the number of images to be read, it is automatically set to the + right length. + """ _Chain_Read(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(starting_image), ctypes.c_int(ending_image), ctypes.c_int(insert_idx), ctypes.c_int(idx_chain)) -### Write a chain of images to disk _Chain_Write = _spirit.IO_Chain_Write _Chain_Write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int] _Chain_Write.restype = None -def chain_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_chain=-1): +def chain_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment="", idx_chain=-1): + """Write a chain of images to a file. + + Arguments: + p_state -- state pointer + filename -- the name of the file to write + + Keyword arguments: + fileformat -- the format in which to write the data (default: OVF text) + comment -- a comment string to be inserted in the header (default: empty) + """ _Chain_Write(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(fileformat), ctypes.c_char_p(comment.encode('utf-8')), ctypes.c_int(idx_chain)) -### Append a chain of images to disk _Chain_Append = _spirit.IO_Chain_Append _Chain_Append.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int] _Chain_Append.restype = None -def chain_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_chain=-1): +def chain_append(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment="", idx_chain=-1): + """Append a chain of images to a given file. + + If the file does not exist, it is created. + + Arguments: + p_state -- state pointer + filename -- the name of the file to append to + + Keyword arguments: + fileformat -- the format in which to write the data (default: OVF text) + comment -- a comment string to be inserted in the header (default: empty) + """ _Chain_Append(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(fileformat), ctypes.c_char_p(comment.encode('utf-8')), ctypes.c_int(idx_chain)) -### Read eigenmodes from disk _Eigenmodes_Read = _spirit.IO_Eigenmodes_Read -_Eigenmodes_Read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, +_Eigenmodes_Read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int, ctypes.c_int] _Eigenmodes_Read.restype = None def eigenmodes_read(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, idx_image_inchain=-1, idx_chain=-1): - _Eigenmodes_Read(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), - ctypes.c_int(fileformat), ctypes.c_int(idx_image_inchain), + """Read the vector fields from a file as a set of eigenmodes for the spin system.""" + _Eigenmodes_Read(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), + ctypes.c_int(fileformat), ctypes.c_int(idx_image_inchain), ctypes.c_int(idx_chain)) -### Write eigenmodes to disk _Eigenmodes_Write = _spirit.IO_Eigenmodes_Write -_Eigenmodes_Write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, +_Eigenmodes_Write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] _Eigenmodes_Write.restype = None def eigenmodes_write(p_state, filename, fileformat=FILEFORMAT_OVF_TEXT, comment=" ", idx_image=-1, idx_chain=-1): - _Eigenmodes_Write(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), + """Write the eigenmodes of a spin system to file, if they have been already calculated.""" + _Eigenmodes_Write(ctypes.c_void_p(p_state), ctypes.c_char_p(filename.encode('utf-8')), ctypes.c_int(fileformat), ctypes.c_char_p(comment.encode('utf-8')), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) \ No newline at end of file diff --git a/core/python/spirit/log.py b/core/python/spirit/log.py index 46f2a6535..6e02d5add 100644 --- a/core/python/spirit/log.py +++ b/core/python/spirit/log.py @@ -1,9 +1,15 @@ +""" +Log +-------------------- +""" + import spirit.spiritlib as spiritlib import ctypes ### Load Library _spirit = spiritlib.load_spirit_library() +# Log levels LEVEL_ALL = 0 LEVEL_SEVERE = 1 LEVEL_ERROR = 2 @@ -12,6 +18,7 @@ LEVEL_INFO = 5 LEVEL_DEBUG = 6 +# Log message senders SENDER_ALL = 0 SENDER_IO = 1 SENDER_GNEB = 2 @@ -21,95 +28,111 @@ SENDER_API = 6 SENDER_UI = 7 -### Send a Log message _Send = _spirit.Log_Send -_Send.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_char_p, +_Send.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_int] _Send.restype = None def send(p_state, level, sender, message, idx_image=-1, idx_chain=-1): - _Send(ctypes.c_void_p(p_state), ctypes.c_int(level), ctypes.c_int(sender), + """Add a message to the log. + + - level: see integers defined above. The message may be printed to the console and/or written + to the log file, depending on the current log parameters + - sender: see integers defined above. Used to distinguish context + - message: a string which to log + - idx_image: can be used to specify to which image the message relates (default: active image) + """ + _Send(ctypes.c_void_p(p_state), ctypes.c_int(level), ctypes.c_int(sender), ctypes.c_char_p(message.encode('utf-8')), ctypes.c_int(idx_image), ctypes.c_int(idx_chain)) -### Append Log to file _Append = _spirit.Log_Append _Append.argtypes = [ctypes.c_void_p] _Append.restype = None def append(p_state): + """Force the appending of new messages to the log file.""" _Append(ctypes.c_void_p(p_state)) -### Get number of Log entries _Get_N_Entries = _spirit.Log_Get_N_Entries _Get_N_Entries.argtypes = [ctypes.c_void_p] _Get_N_Entries.restype = ctypes.c_int def get_n_entries(p_state): + """Returns the number of Log entries.""" return int(_Get_N_Entries(ctypes.c_void_p(p_state))) -### Get number of error messages _Get_N_Errors = _spirit.Log_Get_N_Errors _Get_N_Errors.argtypes = [ctypes.c_void_p] _Get_N_Errors.restype = ctypes.c_int def get_n_errors(p_state): + """Returns the number of error messages that have been logged.""" return int(_Get_N_Errors(ctypes.c_void_p(p_state))) -### Get number of warning messages _Get_N_Warnings = _spirit.Log_Get_N_Warnings _Get_N_Warnings.argtypes = [ctypes.c_void_p] _Get_N_Warnings.restype = ctypes.c_int def get_n_warnings(p_state): + """Returns the number of warning messages that have been logged.""" return int(_Get_N_Warnings(ctypes.c_void_p(p_state))) -### Set the tag in front of the Log file _Set_Output_File_Tag = _spirit.Log_Set_Output_File_Tag _Set_Output_File_Tag.argtypes = [ctypes.c_void_p, ctypes.c_char_p] _Set_Output_File_Tag.restype = None def set_output_file_tag(p_state, tag): + """Set the tagging string which is placed in front of the log file. + + If "