Lasciate ogni speranza voi ch'entrate.
Dante's Inferno, Canto III 9
Atomsk is a quite simple and dumb program, written by a humble physicist not so skilled at programming. The program was designed so that, in its properly compiled binary form, it can be understood by a computer, but that does not mean that the source code can easily be understood by a human being. I make this statement as a hint of what you will get into if you want to look at or modify the source code: lousy programming, non-optimized allocations, some GOTO statements, and a zest of global variables. And did I mention the many modules?
This page contains some informations for courageous developers who would like to make their way through the source code, and some informations for those who would like to add their contribution, be it for their personal use or for public release. Take a deep breath before diving.
Atomsk is made of many modules, each of which handling a very specific operation. For instance one module is responsible for writing XYZ file (out_xyz.f90
), and it does just that -if you need to change the format of XYZ files you have to modify only this module. This structure facilitates the maintainance of the code. Also it (hopefully) makes it easier for new users to look into the code, as they can look only at the modules dealing with the operations they need.
The global variables are stored in comv.f90
, and should be as little as possible. For more flexibility, most variables and arrays are passed to modules. The array that is used to store atomic coordinates is named "P". It has a size of (Natoms,4), where the three first columns are the X, Y and Z cartesian coordinates, and the fourth column is the atomic number. The array used to store supercell vectors is H, and has dimension (3,3).
The modules are "organized" in the following way (see also the Makefile for a list of modules corresponding to each bullet point below):
in_
).opt_
).out_
).In order to keep things simple, some rules should be respected within each type of module. Input modules, option modules, and output modules, should NOT depend on one another, so be careful when introducing a "USE" statement in any module. For instance do not introduce a dependence to an input module (like "USE in_xyz
") in an option module. In output modules, the arrays P and H must not be modified and should be INTENT(IN)
. "Modes" modules can use any of the input, options and/or output.
A good way to start digging into the source code is to look at the structure of the file "mode_normal.f90". One can see that this module reads in a file (by calling the reading module "readin.f90"), applies options if any (by calling the module "options.f90"), and then outputs one or several files (by calling "writeout.f90"). This is exactly what Atomsk uses when converting a file.
In other modes, these modules are called in more or less different ways.
From version 0.6 Atomsk reads and writes auxiliary properties, i.e. any per-atom property like velocities, forces, electric charges, etc. The array "AUXNAMES" contains strings that are the names of the auxiliary properties; the array "AUX" contains real numbers which are the values of the properties for each atom. As such, the array "AUX" must always have its first dimension equal to the first dimension of the array P.
When reading file formats Atomsk reads some or all auxiliary properties it may contain. The arrays "AUXNAMES" and "AUX" must then be allocated properly and consistently. If no auxiliary property exist then these arrays must not be allocated by input modules.
Some common properties are recognized by Atomsk by their names. Below is a list of names that one should use to store properties in AUXNAMES:
Using these names ensure that these properties are properly recognized in all modules, especially output modules. As an example, if forces are stored with the names "force_x, force_y, force_z" then they will be seen as ordinary properties, not as forces, and as a result they will not be written to XSF format for instance. On the contrary if they are saved with the names above (fx, fy, fz) then they will be recognized as forces and written to XSF format.
The AUX array is passed as a whole to output modules. It is up to each module to use the properties relevant for its file format. For instance "out_xsf.f90" searches for forces (fx, fy and fz) in the AUXNAMES array, and if present, writes forces to the XSF file. Each module shall look for properties supported by the file format it is writing.
The following describes some arrays commonly used in Atomsk and passed between modules:
.TRUE.
) or not (.FALSE.
); this array is created when the option -region
is invoked; this array is passed to some options, and the option is applied only to atoms that have a value .TRUE.
in REGION, or to all atoms if the array REGION is unallocated.One in all one can have in mind that atom properties are stored according to the following scheme:
Atom positions + atomic number | Shells positions (optional) | Auxiliary properties (optional) | REGION (optional) |
---|---|---|---|
P(1,1) P(1,2) P(1,3) P(1,4) | S(1,1) S(1,2) S(1,3) S(1,4) | AUX(1,1) AUX(1,2)...AUX(1,M) | REGION(1) |
P(2,1) P(2,2) P(2,3) P(2,4) | S(2,1) S(2,2) S(2,3) S(2,4) | AUX(2,1) AUX(2,2)...AUX(2,M) | REGION(2) |
... ... ... | ... ... ... | ... ... ... | ... ... ... |
P(NP,1) P(NP,2) P(NP,3) P(NP,4) | S(NP,1) S(NP,2) S(NP,3) S(NP,4) | AUX(NP,1) AUX(NP,2)...AUX(NP,M) | REGION(NP) |
The following UNITs are used by specific files and should be followed by all modules:
Each module managing input (which names should start with in_) should read in one specific file format, and load it to memory (supercell parameters in the array "H", atom positions in "P", and if relevant, shells in "S", auxiliary properties in "AUX", and names of auxiliary properties in "AUXNAMES").
If necessary, take example on the existing modules.
If you wrote a reading module and want to integrate it to Atomsk, the source code needs to be edited in the following way:
Also, please add the new format in the documentation (i.e. DISPLAY_HELP in the file messages_EN.f90
, and in doc/formats.html), and indicate the restrictions if there are any.
Each module managing output (whose names should start with out_) must read the arrays "H" (supercell parameters), "P" (atom positions), and if the format supports it, "S" (positions of shells), "AUX" and "AUXNAMES" (auxiliary properties), and write data to one specific file format. These input arrays ("H", "P", "S"...) must NOT be modified inside these modules, and should be declared as "INTENT(IN)
".
If necessary, take example on the existing modules.
If you wrote a writing module and want to integrate it to Atomsk, the source code needs to be edited in the following way:
SELECT CASE(extension)
), in label 300 (line likely=MAX(...)
and in the following IF
statement);Also, please add the new format in the documentation (i.e. DISPLAY_HELP in the file messages_EN.f90
, and in doc/formats.html), and indicate the restrictions if there are any.
Options can apply to the supercell (array "H"), to the atomic positions (array "P"), to the shells ("S"), and/or to the auxiliary properties ("AUX"). After the option is applied, the module must also return the values of the modified arrays. Keep in mind that these modules use the same arrays as input and output, and writing to an array while reading it can lead to errors. If necessary the arrays can be duplicated to apply the option -just don't forget to save the updated values to the correct arrays.
If you develop a module that applies such a transformation, you can include it in the program by editing the following files:
-cut
") followed by a given number of parameters. All of this should be stored as a string in the global variable options_array
.USE ...
), and to call your module in the DO loop. Please respect the alphabetical order so that other developers can find an option easily.Also, please add the new option in the documentation (i.e. DISPLAY_HELP in the file messages_EN.f90
, and in doc/options.html), and indicate the restrictions if there are any.
A "mode" is a routine that decides what is done with the atom positions. For instance the default mode (so-called "normal mode") reads a file and converts it to one or many other formats. The "mode difference" computes the difference between two files. Many different things can be imagined, and the appropriate way to do them within Atomsk is by using modes. If you add a new mode, it is advised that you take advantage of routines that are already implemented in Atomsk to read/write files, and apply transformations.
If your mode computes per-atom quantities, it is advised to save them as auxiliary properties (see definition of arrays AUX and AUXNAMES above) so that output modules can write these auxiliary properties. For instance one could compute the local von Mises strain of each atom, save it in AUX, and write it as auxiliary properties in a CFG file. This is of course a dumb example as this quantity can already be computed and displayed within Atomeye, but hopefully it gives the idea.
All messages displayed by Atomsk are in a separate module to make it easy to add translations to other languages. For the program to speak a language of your choice, you will need to edit the following files:
CASE DEFAULT
should redirect to the English messages.CASE("XX") ...
) for using the new language in the four subroutines. You may also define the one-letter abbreviations for "yes" and "no" in the subroutine PIKASHU_MSG (take example on existing languages).